diff --git a/GNUmakefile b/GNUmakefile index 7058dd6c..520c1b43 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -26,7 +26,7 @@ endif OBJC_PROGRAM_NAME = oolite oolite_C_FILES = legacy_random.c strlcpy.c -oolite_OBJC_FILES = Comparison.m AI.m DustEntity.m Entity.m GameController.m GuiDisplayGen.m HeadUpDisplay.m main.m MyOpenGLView.m OpenGLSprite.m ParticleEntity.m PlanetEntity.m PlayerEntityLegacyScriptEngine.m PlayerEntityContracts.m PlayerEntityControls.m PlayerEntityLoadSave.m PlayerEntitySound.m PlayerEntity.m ResourceManager.m RingEntity.m ShipEntityAI.m ShipEntity.m SkyEntity.m StationEntity.m Universe.m OOSound.m SDLMusic.m NSFileManagerOOExtensions.m JoystickHandler.m PlayerEntityStickMapper.m OOBasicSoundReferencePoint.m OOBasicSoundSource.m OOCharacter.m OOTrumble.m WormholeEntity.m NSScannerOOExtensions.m OOXMLExtensions.m NSMutableDictionaryOOExtensions.m Geometry.m Octree.m CollisionRegion.m OOColor.m OOLogging.m OOCacheManager.m OOCache.m OOStringParsing.m OOCollectionExtractors.m OOVector.m OOMatrix.m OOQuaternion.m OOVoxel.m OOTriangle.m OOPListParsing.m OOFastArithmetic.m OOTextureScaling.m OOConstToString.m OOScript.m OOJSScript.m OOJavaScriptEngine.m OOPListScript.m NSStringOOExtensions.m PlayerEntityScriptMethods.m OOWeakReference.m OOJSEntity.m EntityOOJavaScriptExtensions.m OOJSQuaternion.m OOMaterial.m OOShaderMaterial.m OOShaderProgram.m OOShaderUniform.m OOTexture.m OOTextureLoader.m OOPNGTextureLoader.m OOOpenGLExtensionManager.m OOBasicMaterial.m OOSingleTextureMaterial.m OOCPUInfo.m OOSelfDrawingEntity.m OOEntityWithDrawable.m OODrawable.m OOJSVector.m OOMesh.m OOOpenGL.m OOGraphicsResetManager.m OOProbabilisticTextureManager.m OODebugGLDrawing.m OOShaderUniformMethodType.m OOAsyncQueue.m TextureStore.m OOOXPVerifier.m OOOXPVerifierStage.m OOFileScannerVerifierStage.m OOCheckRequiresPListVerifierStage.m OOCheckDemoShipsPListVerifierStage.m OOCheckEquipmentPListVerifierStage.m OOTextureVerifierStage.m OOModelVerifierStage.m OOCheckShipDataPListVerifierStage.m OOPListSchemaVerifier.m OOJSShip.m OOJSPlayer.m OOJSCall.m OOJSStation.m OOJSSystem.m OOLegacyEventHandlerScript.m OOPlayerProxyScript.m +oolite_OBJC_FILES = Comparison.m AI.m DustEntity.m Entity.m GameController.m GuiDisplayGen.m HeadUpDisplay.m main.m MyOpenGLView.m OpenGLSprite.m ParticleEntity.m PlanetEntity.m PlayerEntityLegacyScriptEngine.m PlayerEntityContracts.m PlayerEntityControls.m PlayerEntityLoadSave.m PlayerEntitySound.m PlayerEntity.m ResourceManager.m RingEntity.m ShipEntityAI.m ShipEntity.m SkyEntity.m StationEntity.m Universe.m OOSound.m SDLMusic.m NSFileManagerOOExtensions.m JoystickHandler.m PlayerEntityStickMapper.m OOBasicSoundReferencePoint.m OOBasicSoundSource.m OOCharacter.m OOTrumble.m WormholeEntity.m NSScannerOOExtensions.m OOXMLExtensions.m NSMutableDictionaryOOExtensions.m Geometry.m Octree.m CollisionRegion.m OOColor.m OOLogging.m OOCacheManager.m OOCache.m OOStringParsing.m OOCollectionExtractors.m OOVector.m OOMatrix.m OOQuaternion.m OOVoxel.m OOTriangle.m OOPListParsing.m OOFastArithmetic.m OOTextureScaling.m OOConstToString.m OOScript.m OOJSScript.m OOJavaScriptEngine.m OOPListScript.m NSStringOOExtensions.m PlayerEntityScriptMethods.m OOWeakReference.m OOJSEntity.m EntityOOJavaScriptExtensions.m OOJSQuaternion.m OOMaterial.m OOShaderMaterial.m OOShaderProgram.m OOShaderUniform.m OOTexture.m OOTextureLoader.m OOPNGTextureLoader.m OOOpenGLExtensionManager.m OOBasicMaterial.m OOSingleTextureMaterial.m OOCPUInfo.m OOSelfDrawingEntity.m OOEntityWithDrawable.m OODrawable.m OOJSVector.m OOMesh.m OOOpenGL.m OOGraphicsResetManager.m OOProbabilisticTextureManager.m OODebugGLDrawing.m OOShaderUniformMethodType.m OOAsyncQueue.m TextureStore.m OOOXPVerifier.m OOOXPVerifierStage.m OOFileScannerVerifierStage.m OOCheckRequiresPListVerifierStage.m OOCheckDemoShipsPListVerifierStage.m OOCheckEquipmentPListVerifierStage.m OOTextureVerifierStage.m OOModelVerifierStage.m OOCheckShipDataPListVerifierStage.m OOPListSchemaVerifier.m OOJSShip.m OOJSPlayer.m OOJSCall.m OOJSStation.m OOJSSystem.m OOLegacyEventHandlerScript.m include $(GNUSTEP_MAKEFILES)/objc.make include GNUmakefile.postamble diff --git a/Oolite.xcodeproj/project.pbxproj b/Oolite.xcodeproj/project.pbxproj index 99c061c9..3ea51c7f 100644 --- a/Oolite.xcodeproj/project.pbxproj +++ b/Oolite.xcodeproj/project.pbxproj @@ -372,8 +372,6 @@ 1A73712E0C623DAE0097AC37 /* OOJSStation.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A73712C0C623DAE0097AC37 /* OOJSStation.m */; }; 1A7376BE0C64AE330097AC37 /* OOJSSystem.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A7376BC0C64AE330097AC37 /* OOJSSystem.h */; }; 1A7376BF0C64AE330097AC37 /* OOJSSystem.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A7376BD0C64AE330097AC37 /* OOJSSystem.m */; }; - 1A7378E40C6515720097AC37 /* OOPlayerProxyScript.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A7378E20C6515720097AC37 /* OOPlayerProxyScript.h */; }; - 1A7378E50C6515720097AC37 /* OOPlayerProxyScript.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A7378E30C6515720097AC37 /* OOPlayerProxyScript.m */; }; 1A73795D0C65CF090097AC37 /* OOLegacyEventHandlerScript.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A73795B0C65CF090097AC37 /* OOLegacyEventHandlerScript.h */; }; 1A73795E0C65CF090097AC37 /* OOLegacyEventHandlerScript.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A73795C0C65CF090097AC37 /* OOLegacyEventHandlerScript.m */; }; 1A7D3A180C4F6162008EDC33 /* OOCheckRequiresPListVerifierStage.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A7D3A160C4F6162008EDC33 /* OOCheckRequiresPListVerifierStage.h */; }; @@ -1274,8 +1272,6 @@ 1A73712C0C623DAE0097AC37 /* OOJSStation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OOJSStation.m; sourceTree = ""; }; 1A7376BC0C64AE330097AC37 /* OOJSSystem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OOJSSystem.h; sourceTree = ""; }; 1A7376BD0C64AE330097AC37 /* OOJSSystem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OOJSSystem.m; sourceTree = ""; }; - 1A7378E20C6515720097AC37 /* OOPlayerProxyScript.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OOPlayerProxyScript.h; sourceTree = ""; }; - 1A7378E30C6515720097AC37 /* OOPlayerProxyScript.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OOPlayerProxyScript.m; sourceTree = ""; }; 1A73795B0C65CF090097AC37 /* OOLegacyEventHandlerScript.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OOLegacyEventHandlerScript.h; sourceTree = ""; }; 1A73795C0C65CF090097AC37 /* OOLegacyEventHandlerScript.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OOLegacyEventHandlerScript.m; sourceTree = ""; }; 1A7D3A160C4F6162008EDC33 /* OOCheckRequiresPListVerifierStage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OOCheckRequiresPListVerifierStage.h; sourceTree = ""; }; @@ -1916,8 +1912,6 @@ 1A5DBAA20BC000DC00D57389 /* OOScript.m */, 1A5DBA9E0BC000DC00D57389 /* OOPListScript.h */, 1A5DBA9F0BC000DC00D57389 /* OOPListScript.m */, - 1A7378E20C6515720097AC37 /* OOPlayerProxyScript.h */, - 1A7378E30C6515720097AC37 /* OOPlayerProxyScript.m */, 1A73795B0C65CF090097AC37 /* OOLegacyEventHandlerScript.h */, 1A73795C0C65CF090097AC37 /* OOLegacyEventHandlerScript.m */, 1A5DBAB50BC000E700D57389 /* JavaScript */, @@ -2607,7 +2601,6 @@ 1A736C7F0C61FD220097AC37 /* OOJSCall.h in Headers */, 1A73712D0C623DAE0097AC37 /* OOJSStation.h in Headers */, 1A7376BE0C64AE330097AC37 /* OOJSSystem.h in Headers */, - 1A7378E40C6515720097AC37 /* OOPlayerProxyScript.h in Headers */, 1A73795D0C65CF090097AC37 /* OOLegacyEventHandlerScript.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -2914,7 +2907,6 @@ 1A736C800C61FD220097AC37 /* OOJSCall.m in Sources */, 1A73712E0C623DAE0097AC37 /* OOJSStation.m in Sources */, 1A7376BF0C64AE330097AC37 /* OOJSSystem.m in Sources */, - 1A7378E50C6515720097AC37 /* OOPlayerProxyScript.m in Sources */, 1A73795E0C65CF090097AC37 /* OOLegacyEventHandlerScript.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Resources/Config/shipdata.plist b/Resources/Config/shipdata.plist index 57007109..2ba8cb3d 100644 --- a/Resources/Config/shipdata.plist +++ b/Resources/Config/shipdata.plist @@ -1410,6 +1410,8 @@ do awardEquipment: EQ_CLOAKING_DEVICE + diff --git a/src/Cocoa/MyOpenGLView.m b/src/Cocoa/MyOpenGLView.m index d828dc98..717b9d7d 100644 --- a/src/Cocoa/MyOpenGLView.m +++ b/src/Cocoa/MyOpenGLView.m @@ -78,7 +78,7 @@ static NSString * kOOLogKeyDown = @"input.keyMapping.keyPress.keyDown"; NSOpenGLPFAAccelerated, 0 }; - long rendererID; + GLint rendererID; // Create our non-FullScreen pixel format. NSOpenGLPixelFormat* pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs]; diff --git a/src/Core/Entities/Entity.h b/src/Core/Entities/Entity.h index 7f40a759..87691899 100644 --- a/src/Core/Entities/Entity.h +++ b/src/Core/Entities/Entity.h @@ -254,4 +254,6 @@ typedef struct - (GLfloat)spawnTime; - (GLfloat)timeElapsedSinceSpawn; +- (void)setShaderBindingTarget:(Entity *)ent; + @end diff --git a/src/Core/Entities/Entity.m b/src/Core/Entities/Entity.m index 3c9478bd..e39e3b21 100644 --- a/src/Core/Entities/Entity.m +++ b/src/Core/Entities/Entity.m @@ -1045,4 +1045,10 @@ static NSString * const kOOLogEntityUpdateError = @"entity.linkedList.update. return [UNIVERSE getTime] - spawnTime; } + +- (void)setShaderBindingTarget:(Entity *)ent +{ + +} + @end diff --git a/src/Core/Entities/OOEntityWithDrawable.m b/src/Core/Entities/OOEntityWithDrawable.m index 6bf38ca3..e882fd26 100644 --- a/src/Core/Entities/OOEntityWithDrawable.m +++ b/src/Core/Entities/OOEntityWithDrawable.m @@ -82,4 +82,10 @@ MA 02110-1301, USA. else [drawable renderOpaqueParts]; } + +- (void)setShaderBindingTarget:(Entity *)ent +{ + [[self drawable] setBindingTarget:ent]; +} + @end diff --git a/src/Core/Entities/PlanetEntity.m b/src/Core/Entities/PlanetEntity.m index 3705718d..b90e12a8 100644 --- a/src/Core/Entities/PlanetEntity.m +++ b/src/Core/Entities/PlanetEntity.m @@ -1673,8 +1673,6 @@ void drawActiveCorona(GLfloat inner_radius, GLfloat outer_radius, GLfloat step, [shuttle_ship setStatus:STATUS_IN_FLIGHT]; - //[shuttle_ship setReportAIMessages:YES]; // debug - [UNIVERSE addEntity:shuttle_ship]; [[shuttle_ship getAI] setStateMachine:@"risingShuttleAI.plist"]; // must happen after adding to the universe! diff --git a/src/Core/Entities/PlayerEntity.h b/src/Core/Entities/PlayerEntity.h index a031e8db..6bfae727 100644 --- a/src/Core/Entities/PlayerEntity.h +++ b/src/Core/Entities/PlayerEntity.h @@ -211,7 +211,7 @@ typedef enum NSString *specialCargo; - NSMutableArray *comm_log; + NSMutableArray *commLog; NSMutableDictionary *oxpKeys; @@ -550,7 +550,7 @@ typedef enum - (NSString *) dial_fpsinfo; - (NSString *) dial_objinfo; -- (NSMutableArray *) comm_log; +- (NSMutableArray *) commLog; - (OOCompassMode) compassMode; - (void) setCompassMode:(OOCompassMode)value; @@ -670,11 +670,10 @@ typedef enum - (NSString *)customViewDescription; - (void)setCustomViewDataFromDictionary:(NSDictionary*) viewDict; -/* -- */ - -- (void) sendMessageToScripts:(NSString *)message; -- (void) sendMessageToScripts:(NSString *)message withString:(NSString *)argument; -- (void) sendMessageToScripts:(NSString *)message withArguments:(NSArray *)arguments; +// *** World cript events. +// In general, script events should be sent through doScriptEvent:..., which +// will forward to the world scripts. +- (void) doWorldScriptEvent:(NSString *)message withArguments:(NSArray *)arguments; - (BOOL)showInfoFlag; diff --git a/src/Core/Entities/PlayerEntity.m b/src/Core/Entities/PlayerEntity.m index 465c858e..fa8ab887 100644 --- a/src/Core/Entities/PlayerEntity.m +++ b/src/Core/Entities/PlayerEntity.m @@ -51,7 +51,6 @@ MA 02110-1301, USA. #import "OOConstToString.h" #import "OOScript.h" -#import "OOPlayerProxyScript.h" #import "HeadUpDisplay.h" #ifndef GNUSTEP @@ -68,6 +67,14 @@ MA 02110-1301, USA. #define OG_ELITE_FORWARD_DRIFT 10.0f +enum +{ + // If comm log is kCommLogTrimThreshold or more lines long, it will be cut to kCommLogTrimSize. + kCommLogTrimThreshold = 125, + kCommLogTrimSize = 100 +}; + + static NSString * const kOOLogBuyMountedOK = @"equip.buy.mounted"; static NSString * const kOOLogBuyMountedFailed = @"equip.buy.mounted.failed"; @@ -303,12 +310,8 @@ static PlayerEntity *sSharedPlayer = nil; [result setObject:[NSDictionary dictionaryWithDictionary:mission_variables] forKey:@"mission_variables"]; // communications log - if (comm_log) - { - while ([comm_log count] > 200) // only keep the last 200 lines - [comm_log removeObjectAtIndex:0]; - [result setObject:comm_log forKey:@"comm_log"]; - } + NSArray *log = [self commLog]; + if (log != nil) [result setObject:commLog forKey:@"comm_log"]; // extra equipment flags if (extra_equipment) @@ -678,11 +681,8 @@ static PlayerEntity *sSharedPlayer = nil; } // communications log - if ([dict objectForKey:@"comm_log"]) - { - if (comm_log) [comm_log release]; - comm_log = [[NSMutableArray alloc] initWithArray:(NSArray*)[dict objectForKey:@"comm_log"]]; // retained - } + [commLog release]; + commLog = [[dict arrayForKey:@"comm_log"] mutableCopy]; // set up missiles unsigned i; @@ -951,8 +951,8 @@ static PlayerEntity *sSharedPlayer = nil; dockedStation = [UNIVERSE station]; - [comm_log release]; - comm_log = [[NSMutableArray alloc] init]; // retained + [commLog release]; + commLog = nil; [specialCargo release]; specialCargo = nil; @@ -990,7 +990,7 @@ static PlayerEntity *sSharedPlayer = nil; [self setSystem_seed:[UNIVERSE findSystemAtCoords:[self galaxy_coordinates] withGalaxySeed:[self galaxy_seed]]]; - [self sendMessageToScripts:@"reset"]; + [self doScriptEvent:@"reset"]; } @@ -1167,7 +1167,7 @@ static PlayerEntity *sSharedPlayer = nil; if (subent == nil) { // Failing to find a subentity could result in a partial ship, which'd be, y'know, weird. - return nil; + return NO; } if ((self->isStation)&&([subdesc rangeOfString:@"dock"].location != NSNotFound)) @@ -1209,8 +1209,10 @@ static PlayerEntity *sSharedPlayer = nil; subentityRotationalVelocity = kIdentityQuaternion; ScanQuaternionFromString([shipDict objectForKey:@"rotational_velocity"], &subentityRotationalVelocity); - [script release]; - script = [[OOPlayerProxyScript alloc] init]; + // Load script + [script release]; + script = [OOScript nonLegacyScriptFromFileNamed:[shipDict stringForKey:@"script"] + properties:[NSDictionary dictionaryWithObject:self forKey:@"ship"]]; return YES; } @@ -1220,7 +1222,7 @@ static PlayerEntity *sSharedPlayer = nil; { [ship_desc release]; [hud release]; - [comm_log release]; + [commLog release]; [worldScripts release]; [mission_variables release]; @@ -1318,7 +1320,8 @@ double scoopSoundPlayTime = 0.0; */ if ([self alertCondition] != lastScriptAlertCondition) { - [self sendMessageToScripts:@"alertConditionChanged"]; + [self doScriptEvent:@"alertConditionChanged"]; + lastScriptAlertCondition = [self alertCondition]; } if (scoopsActive) @@ -1478,7 +1481,7 @@ double scoopSoundPlayTime = 0.0; // next check in 10s status = STATUS_IN_FLIGHT; - [self sendMessageToScripts:@"didLaunch"]; + [self doScriptEvent:@"didLaunch"]; } } @@ -1504,7 +1507,7 @@ double scoopSoundPlayTime = 0.0; if (![UNIVERSE playCustomSound:@"[witch-blocked-by-@]"]) [witchAbortSound play]; status = STATUS_IN_FLIGHT; - [self sendMessageToScripts:@"didFailToJump" withString:@"blocked"]; + [self doScriptEvent:@"didFailToJump" withArgument:@"blocked"]; go = NO; } @@ -1520,7 +1523,7 @@ double scoopSoundPlayTime = 0.0; if (![UNIVERSE playCustomSound:@"[witch-too-far]"]) [witchAbortSound play]; status = STATUS_IN_FLIGHT; - [self sendMessageToScripts:@"didFailToJump" withString:@"too far"]; + [self doScriptEvent:@"didFailToJump" withArgument:@"too far"]; go = NO; } } @@ -1536,7 +1539,7 @@ double scoopSoundPlayTime = 0.0; if (![UNIVERSE playCustomSound:@"[witch-no-fuel]"]) [witchAbortSound play]; status = STATUS_IN_FLIGHT; - [self sendMessageToScripts:@"didFailToJump" withString:@"insufficient fuel"]; + [self doScriptEvent:@"didFailToJump" withArgument:@"insufficient fuel"]; go = NO; } @@ -1569,7 +1572,7 @@ double scoopSoundPlayTime = 0.0; [UNIVERSE addMessage:ExpandDescriptionForCurrentSystem(@"[witch-engine-malfunction]") forCount:3.0]; status = STATUS_IN_FLIGHT; - [self sendMessageToScripts:@"didExitWitchSpace"]; + [self doScriptEvent:@"didExitWitchSpace"]; } } @@ -2353,9 +2356,26 @@ double scoopSoundPlayTime = 0.0; } -- (NSMutableArray*) comm_log +- (NSMutableArray*) commLog { - return comm_log; + unsigned count; + + assert(kCommLogTrimSize < kCommLogTrimThreshold); + + if (commLog != nil) + { + count = [commLog count]; + if (count >= kCommLogTrimThreshold) + { + [commLog removeObjectsInRange:NSMakeRange(kCommLogTrimSize, count - kCommLogTrimSize)]; + } + } + else + { + commLog = [[NSMutableArray alloc] init]; + } + + return commLog; } @@ -2649,7 +2669,7 @@ double scoopSoundPlayTime = 0.0; [[UNIVERSE gameController] playiTunesPlaylist:@"Oolite-Inflight"]; docking_music_on = NO; } - [self sendMessageToScripts:@"didRecieveDockingRefusal"]; + [self doScriptEvent:@"didRecieveDockingRefusal"]; } // aegis messages to advanced compass so in planet mode it behaves like the old compass @@ -3260,7 +3280,7 @@ double scoopSoundPlayTime = 0.0; [UNIVERSE addMessage:ExpandDescriptionForCurrentSystem(@"[escape-sequence]") forCount:4.5]; shot_time = 0.0; - [self sendMessageToScripts:@"didLaunchEscapePod"]; + [self doScriptEvent:@"didLaunchEscapePod"]; return result; } @@ -3497,7 +3517,7 @@ double scoopSoundPlayTime = 0.0; shot_time = 0.0; if (whom == nil) whom = (id)[NSNull null]; - [self sendMessageToScripts:@"didBecomeDead" withArguments:[NSArray arrayWithObjects:whom, why, nil]]; + [self doScriptEvent:@"didBecomeDead" withArguments:[NSArray arrayWithObjects:whom, why, nil]]; [self loseTargetStatus]; } @@ -3535,7 +3555,7 @@ double scoopSoundPlayTime = 0.0; return; status = STATUS_DOCKING; - [self sendMessageToScripts:@"willDock"]; + [self doScriptEvent:@"willDock"]; afterburner_engaged = NO; @@ -3641,7 +3661,7 @@ double scoopSoundPlayTime = 0.0; [[OOCacheManager sharedCache] flush]; - [self sendMessageToScripts:@"didDock"]; + [self doScriptEvent:@"didDock"]; } @@ -3671,9 +3691,8 @@ double scoopSoundPlayTime = 0.0; [UNIVERSE setDisplayText:NO]; [UNIVERSE setDisplayCursor:NO]; [UNIVERSE set_up_break_pattern:position quaternion:orientation]; - [self playBreakPattern]; - [(MyOpenGLView *)[UNIVERSE gameView] clearKeys]; // try to stop keybounces + [[UNIVERSE gameView] clearKeys]; // try to stop keybounces if (ootunes_on) { @@ -3692,7 +3711,7 @@ double scoopSoundPlayTime = 0.0; - (void) enterGalacticWitchspace { status = STATUS_ENTERING_WITCHSPACE; - [self sendMessageToScripts:@"willEnterWitchSpace" withString:@"galactic jump"]; + [self doScriptEvent:@"willEnterWitchSpace" withArgument:@"galactic jump"]; if (primaryTarget != NO_TARGET) primaryTarget = NO_TARGET; @@ -3763,7 +3782,7 @@ double scoopSoundPlayTime = 0.0; { target_system_seed = [w_hole destination]; status = STATUS_ENTERING_WITCHSPACE; - [self sendMessageToScripts:@"willEnterWitchSpace" withString:@"wormhole"]; + [self doScriptEvent:@"willEnterWitchSpace" withArgument:@"wormhole"]; hyperspeed_engaged = NO; @@ -3808,7 +3827,7 @@ double scoopSoundPlayTime = 0.0; double distance = distanceBetweenPlanetPositions(target_system_seed.d,target_system_seed.b,galaxy_coordinates.x,galaxy_coordinates.y); status = STATUS_ENTERING_WITCHSPACE; - [self sendMessageToScripts:@"willEnterWitchSpace" withString:@"standard jump"]; + [self doScriptEvent:@"willEnterWitchSpace" withArgument:@"standard jump"]; hyperspeed_engaged = NO; @@ -3917,7 +3936,7 @@ double scoopSoundPlayTime = 0.0; [UNIVERSE setDisplayText:NO]; [UNIVERSE set_up_break_pattern:position quaternion:orientation]; [self playBreakPattern]; - [self sendMessageToScripts:@"willExitWitchSpace"]; + [self doScriptEvent:@"willExitWitchSpace"]; } @@ -5025,8 +5044,10 @@ static int last_outfitting_index; NSString *eq_key = [[equipdata objectAtIndex:index] objectAtIndex:EQUIPMENT_KEY_INDEX]; NSString *eq_key_damaged = [NSString stringWithFormat:@"%@_DAMAGED", eq_key]; double price = ([eq_key isEqual:@"EQ_FUEL"]) ? ((PLAYER_MAX_FUEL - fuel) * price_per_unit) : (price_per_unit) ; - double price_factor = 1.0; - OOCargoQuantity cargo_space = max_cargo - current_cargo; + double price_factor = 1.0; + OOCargoQuantity cargo_space = max_cargo - current_cargo; + OOCreditsQuantity tradeIn = 0; + BOOL done = NO; // repairs cost 50% if ([self hasExtraEquipment:eq_key_damaged]) @@ -5051,13 +5072,13 @@ static int last_outfitting_index; return NO; } - if (([eq_key hasPrefix:@"EQ_WEAPON"])&&(chosen_weapon_facing == WEAPON_FACING_NONE)) + if ([eq_key hasPrefix:@"EQ_WEAPON"] && chosen_weapon_facing == WEAPON_FACING_NONE) { - [self setGuiToEquipShipScreen:-1:index]; // reset + [self setGuiToEquipShipScreen:-1:index]; // reset return YES; } - if (([eq_key hasPrefix:@"EQ_WEAPON"])&&(chosen_weapon_facing != WEAPON_FACING_NONE)) + if ([eq_key hasPrefix:@"EQ_WEAPON"] && chosen_weapon_facing != WEAPON_FACING_NONE) { int chosen_weapon = WEAPON_NONE; int current_weapon = WEAPON_NONE; @@ -5105,7 +5126,6 @@ static int last_outfitting_index; Acknowledgment: bug and fix both reported by Cmdr James on forum. -- Ahruman 20070724 */ - OOCreditsQuantity tradeIn = 0; switch (current_weapon) { case WEAPON_PLASMA_CANNON : @@ -5129,41 +5149,43 @@ static int last_outfitting_index; case WEAPON_NONE : break; } - if (price_factor < 1.0f) credits += tradeIn * price_factor; - + [self setGuiToEquipShipScreen:-1:-1]; - return YES; + done = YES; } - if (([eq_key hasSuffix:@"MISSILE"]||[eq_key hasSuffix:@"MINE"])&&(missiles >= max_missiles)) { + if (([eq_key hasSuffix:@"MISSILE"] || [eq_key hasSuffix:@"MINE"]) && missiles >= max_missiles) + { NSLog(@"rejecting missile because already full"); return NO; } - if (([eq_key isEqual:@"EQ_PASSENGER_BERTH"])&&(cargo_space < 5)) + if ([eq_key isEqual:@"EQ_PASSENGER_BERTH"] && cargo_space < 5) + { return NO; - + } + if ([eq_key isEqual:@"EQ_FUEL"]) { fuel = PLAYER_MAX_FUEL; credits -= price; [self setGuiToEquipShipScreen:-1:-1]; - return YES; + done = YES; } - + // check energy unit replacement - if ([eq_key hasSuffix:@"ENERGY_UNIT"]&&(energy_unit != ENERGY_UNIT_NONE)) + if ([eq_key hasSuffix:@"ENERGY_UNIT"] && energy_unit != ENERGY_UNIT_NONE) { switch (energy_unit) { case ENERGY_UNIT_NAVAL : [self removeEquipment:@"EQ_NAVAL_ENERGY_UNIT"]; - credits += [UNIVERSE getPriceForWeaponSystemWithKey:@"EQ_NAVAL_ENERGY_UNIT"] / 2; // 50 % refund + tradeIn = [UNIVERSE getPriceForWeaponSystemWithKey:@"EQ_NAVAL_ENERGY_UNIT"] / 2; // 50 % refund break; case ENERGY_UNIT_NORMAL : [self removeEquipment:@"EQ_ENERGY_UNIT"]; - credits += [UNIVERSE getPriceForWeaponSystemWithKey:@"EQ_ENERGY_UNIT"] * 3 / 4; // 75 % refund + tradeIn = [UNIVERSE getPriceForWeaponSystemWithKey:@"EQ_ENERGY_UNIT"] * 3 / 4; // 75 % refund break; case ENERGY_UNIT_NONE : @@ -5171,7 +5193,7 @@ static int last_outfitting_index; break; } } - + // maintain ship if ([eq_key isEqual:@"EQ_RENOVATION"]) { @@ -5185,10 +5207,10 @@ static int last_outfitting_index; ship_trade_in_factor = 100; [self setGuiToEquipShipScreen:-1:-1]; - return YES; + done = YES; } - if ([eq_key hasSuffix:@"MISSILE"]||[eq_key hasSuffix:@"MINE"]) + if ([eq_key hasSuffix:@"MISSILE"] || [eq_key hasSuffix:@"MINE"]) { ShipEntity* weapon = [[UNIVERSE newShipWithRole:eq_key] autorelease]; if (weapon) OOLog(kOOLogBuyMountedOK, @"Got ship for mounted weapon role %@", eq_key); @@ -5212,7 +5234,7 @@ static int last_outfitting_index; max_cargo -= 5; credits -= price; [self setGuiToEquipShipScreen:-1:-1]; - return YES; + done = YES; } if ([eq_key isEqual:@"EQ_PASSENGER_BERTH_REMOVAL"]) @@ -5221,7 +5243,7 @@ static int last_outfitting_index; max_cargo += 5; credits -= price; [self setGuiToEquipShipScreen:-1:-1]; - return YES; + done = YES; } if ([eq_key isEqual:@"EQ_MISSILE_REMOVAL"]) @@ -5238,13 +5260,13 @@ static int last_outfitting_index; { NSString* weapon_key = [weapon roles]; int weapon_value = [UNIVERSE getPriceForWeaponSystemWithKey:weapon_key]; - credits += weapon_value; + tradeIn += weapon_value; [weapon release]; } } missiles = 0; [self setGuiToEquipShipScreen:-1:-1]; - return YES; + done = YES; } unsigned i; @@ -5257,11 +5279,18 @@ static int last_outfitting_index; [self addExtraEquipment:eq_key]; [self setGuiToEquipShipScreen:-1:-1]; - return YES; + done = YES; + break; } } + + if (tradeIn != 0) + { + if (price_factor < 1.0f) tradeIn *= price_factor; + credits += tradeIn; + } - return NO; + return done; } @@ -6217,22 +6246,14 @@ OOSound* burnersound; } -- (void) sendMessageToScripts:(NSString *)message +- (void) doScriptEvent:(NSString *)message withArguments:(NSArray *)arguments { - [self sendMessageToScripts:message withArguments:nil]; + [super doScriptEvent:message withArguments:arguments]; + [self doWorldScriptEvent:message withArguments:arguments]; } -- (void) sendMessageToScripts:(NSString *)message withString:(NSString *)argument -{ - NSArray *arguments = nil; - - if (argument != nil) arguments = [NSArray arrayWithObject:argument]; - [self sendMessageToScripts:message withArguments:arguments]; -} - - -- (void) sendMessageToScripts:(NSString *)message withArguments:(NSArray *)arguments +- (void) doWorldScriptEvent:(NSString *)message withArguments:(NSArray *)arguments { NSEnumerator *scriptEnum; OOScript *theScript; diff --git a/src/Core/Entities/PlayerEntityControls.m b/src/Core/Entities/PlayerEntityControls.m index 70b061df..ef667d76 100644 --- a/src/Core/Entities/PlayerEntityControls.m +++ b/src/Core/Entities/PlayerEntityControls.m @@ -667,7 +667,7 @@ static NSTimeInterval time_last_frame; if (![UNIVERSE playCustomSound:@"[autopilot-on]"]) [self beep]; [UNIVERSE addMessage:ExpandDescriptionForCurrentSystem(@"[autopilot-on]") forCount:4.5]; - [self sendMessageToScripts:@"didStartAutoPilot"]; + [self doScriptEvent:@"didStartAutoPilot"]; // if (ootunes_on) { @@ -710,7 +710,7 @@ static NSTimeInterval time_last_frame; if (![UNIVERSE playCustomSound:@"[autopilot-on]"]) [self beep]; [UNIVERSE addMessage:ExpandDescriptionForCurrentSystem(@"[autopilot-on]") forCount:4.5]; - [self sendMessageToScripts:@"didStartAutoPilot"]; + [self doScriptEvent:@"didStartAutoPilot"]; // if (ootunes_on) { @@ -831,7 +831,7 @@ static NSTimeInterval time_last_frame; [UNIVERSE clearPreviousMessage]; [UNIVERSE addMessage:ExpandDescriptionForCurrentSystem(@"[witch-user-abort]") forCount:3.0]; - [self sendMessageToScripts:@"didCancelJumpCountDown"]; + [self doScriptEvent:@"didCancelJumpCountDown"]; } if (jumpOK) @@ -845,7 +845,7 @@ static NSTimeInterval time_last_frame; [UNIVERSE clearPreviousMessage]; [UNIVERSE addMessage:[NSString stringWithFormat:ExpandDescriptionForCurrentSystem(@"[witch-to-@-in-f-seconds]"), [UNIVERSE getSystemName:target_system_seed], witchspaceCountdown] forCount:1.0]; - [self sendMessageToScripts:@"didBeginJumpCountDown"withString:@"standard"]; + [self doScriptEvent:@"didBeginJumpCountDown" withArgument:@"standard"]; } } hyperspace_pressed = YES; @@ -877,7 +877,7 @@ static NSTimeInterval time_last_frame; [UNIVERSE clearPreviousMessage]; [UNIVERSE addMessage:ExpandDescriptionForCurrentSystem(@"[witch-user-abort]") forCount:3.0]; - [self sendMessageToScripts:@"didCancelJumpCountDown"]; + [self doScriptEvent:@"didCancelJumpCountDown"]; } if (jumpOK) @@ -891,7 +891,7 @@ static NSTimeInterval time_last_frame; // say it! [UNIVERSE addMessage:[NSString stringWithFormat:ExpandDescriptionForCurrentSystem(@"[witch-galactic-in-f-seconds]"), witchspaceCountdown] forCount:1.0]; - [self sendMessageToScripts:@"didBeginJumpCountDown" withString:@"galactic"]; + [self doScriptEvent:@"didBeginJumpCountDown" withArgument:@"galactic"]; } } galhyperspace_pressed = YES; @@ -2507,7 +2507,7 @@ static BOOL toggling_music; if (![UNIVERSE playCustomSound:@"[autopilot-off]"]) [self beep]; [UNIVERSE addMessage:ExpandDescriptionForCurrentSystem(@"[autopilot-off]") forCount:4.5]; - [self sendMessageToScripts:@"didAbortAutoPilot"]; + [self doScriptEvent:@"didAbortAutoPilot"]; // if (ootunes_on) { @@ -2554,7 +2554,8 @@ static BOOL toggling_music; dockedStation = [UNIVERSE station]; [self leaveDock:dockedStation]; [UNIVERSE setDisplayCursor:NO]; - [self sendMessageToScripts:@"willLaunch"]; + [self doScriptEvent:@"willLaunch"]; + [self playBreakPattern]; } } // diff --git a/src/Core/Entities/PlayerEntityLegacyScriptEngine.m b/src/Core/Entities/PlayerEntityLegacyScriptEngine.m index acb818a7..1cd69957 100644 --- a/src/Core/Entities/PlayerEntityLegacyScriptEngine.m +++ b/src/Core/Entities/PlayerEntityLegacyScriptEngine.m @@ -1745,10 +1745,11 @@ static int scriptRandomSeed = -1; // ensure proper random function { ShipEntity *ship; - if (!dockedStation) - return; + if (!dockedStation) return; [UNIVERSE removeDemoShips]; // get rid of any pre-existing models on display + if ([shipKey isEqualToString:@"none"] || [shipKey length] == 0) return; + [[PlayerEntity sharedPlayer] setShowDemoShips: YES]; Quaternion q2 = { (GLfloat)0.707, (GLfloat)0.707, (GLfloat)0.0, (GLfloat)0.0}; @@ -1769,7 +1770,6 @@ static int scriptRandomSeed = -1; // ensure proper random function [ship release]; } - // } diff --git a/src/Core/Entities/ShipEntity.h b/src/Core/Entities/ShipEntity.h index 92451dd0..3e5f9127 100644 --- a/src/Core/Entities/ShipEntity.h +++ b/src/Core/Entities/ShipEntity.h @@ -326,6 +326,8 @@ MA 02110-1301, USA. - (BOOL)isFrangible; +- (void)respondToAttackFrom:(Entity *)from becauseOf:(Entity *)other; + // Behaviours - (void) behaviour_stop_still:(double) delta_t; - (void) behaviour_idle:(double) delta_t; @@ -627,6 +629,13 @@ inline BOOL pairOK(NSString* my_role, NSString* their_role); - (Entity *)entityForShaderProperties; +// *** Script events. +// For NPC ships, these call doEvent: on the ship script. +// For the player, they do that and also call doWorldScriptEvent:. +- (void) doScriptEvent:(NSString *)message; +- (void) doScriptEvent:(NSString *)message withArgument:(id)argument; +- (void) doScriptEvent:(NSString *)message withArguments:(NSArray *)arguments; + @end diff --git a/src/Core/Entities/ShipEntity.m b/src/Core/Entities/ShipEntity.m index e4b23529..f6050385 100644 --- a/src/Core/Entities/ShipEntity.m +++ b/src/Core/Entities/ShipEntity.m @@ -95,6 +95,7 @@ static NSString * const kOOLogEntityBehaviourChanged = @"entity.behaviour.change isShip = YES; entity_personality = ranrot_rand() & 0x7FFF; + status = STATUS_IN_FLIGHT; zero_distance = SCANNER_MAX_RANGE2 * 2.0; weapon_recharge_rate = 6.0; @@ -291,14 +292,14 @@ static NSString * const kOOLogEntityBehaviourChanged = @"entity.behaviour.change Vector sub_pos, ref; Quaternion sub_q; Entity* subent; - NSString* subdesc = (NSString *)[details objectAtIndex:0]; - sub_pos.x = [(NSString *)[details objectAtIndex:1] floatValue]; - sub_pos.y = [(NSString *)[details objectAtIndex:2] floatValue]; - sub_pos.z = [(NSString *)[details objectAtIndex:3] floatValue]; - sub_q.w = [(NSString *)[details objectAtIndex:4] floatValue]; - sub_q.x = [(NSString *)[details objectAtIndex:5] floatValue]; - sub_q.y = [(NSString *)[details objectAtIndex:6] floatValue]; - sub_q.z = [(NSString *)[details objectAtIndex:7] floatValue]; + NSString* subdesc = [details stringAtIndex:0]; + sub_pos.x = [details floatAtIndex:1]; + sub_pos.y = [details floatAtIndex:2]; + sub_pos.z = [details floatAtIndex:3]; + sub_q.w = [details floatAtIndex:4]; + sub_q.x = [details floatAtIndex:5]; + sub_q.y = [details floatAtIndex:6]; + sub_q.z = [details floatAtIndex:7]; if ([subdesc isEqual:@"*FLASHER*"]) { @@ -322,7 +323,7 @@ static NSString * const kOOLogEntityBehaviourChanged = @"entity.behaviour.change if (subent == nil) { // Failing to find a subentity could result in a partial ship, which'd be, y'know, weird. - return nil; + return NO; } if ((self->isStation)&&([subdesc rangeOfString:@"dock"].location != NSNotFound)) @@ -343,7 +344,7 @@ static NSString * const kOOLogEntityBehaviourChanged = @"entity.behaviour.change if (sub_entities == nil) sub_entities = [[NSMutableArray alloc] init]; [sub_entities addObject:subent]; [subent setOwner: self]; - + [subent release]; } } @@ -524,6 +525,24 @@ static NSString * const kOOLogEntityBehaviourChanged = @"entity.behaviour.change } +- (void)setOwner:(Entity *)ent +{ + [super setOwner:ent]; + if (isSubentity) + { + // Ensure shader bindings have correct target. + [self setShaderBindingTarget:ent]; + } +} + + +- (void)setShaderBindingTarget:(Entity *)ent +{ + [super setShaderBindingTarget:ent]; + [sub_entities makeObjectsPerformSelector:@selector(setShaderBindingTarget:) withObject:ent]; +} + + - (OOScript *)shipScript { return script; @@ -624,7 +643,6 @@ static NSString * const kOOLogEntityBehaviourChanged = @"entity.behaviour.change if (universalID != NO_TARGET) { // set up escorts - // if (status == STATUS_IN_FLIGHT) // just popped into existence { if ((!escortsAreSetUp) && (escortCount > 0)) [self setUpEscorts]; @@ -735,7 +753,7 @@ static NSString * const kOOLogEntityBehaviourChanged = @"entity.behaviour.change if ([shipinfoDictionary objectForKey:@"escort-role"]) { - escortRole = [shipinfoDictionary stringForKey:@"escort-role"]; + escortRole = [shipinfoDictionary stringForKey:@"escort-role" defaultValue:escortRole]; if (![[UNIVERSE newShipWithRole:escortRole] autorelease]) escortRole = @"escort"; } @@ -1287,7 +1305,8 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other) if (!haveExecutedSpawnAction && script != nil && status == STATUS_IN_FLIGHT) { [[PlayerEntity sharedPlayer] setScriptTarget:self]; - [script doEvent:@"didSpawn"]; + [self doScriptEvent:@"didSpawn"]; + haveExecutedSpawnAction = YES; } // behaviours according to status and behaviour @@ -1552,6 +1571,20 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other) } + +- (void)respondToAttackFrom:(Entity *)from becauseOf:(Entity *)other +{ + Entity *source = nil; + + [shipAI reactToMessage:@"ATTACKED"]; + + if ([other isKindOfClass:[ShipEntity class]]) source = other; + else source = from; + + [self doScriptEvent:@"beingAttacked" withArgument:source]; +} + + //////////////// // // // behaviours // @@ -3465,7 +3498,7 @@ static GLfloat mascem_color2[4] = { 0.4, 0.1, 0.4, 1.0}; // purple if (script != nil) { [[PlayerEntity sharedPlayer] setScriptTarget:self]; - [script doEvent:@"didDie"]; + [self doScriptEvent:@"didDie"]; } if ([roles isEqual:@"thargoid"]) @@ -3954,7 +3987,7 @@ Vector positionOffsetForShipInRotationToAlignment(ShipEntity* ship, Quaternion q if (script != nil) { [[PlayerEntity sharedPlayer] setScriptTarget:self]; - [script doEvent:@"didDie"]; + [self doScriptEvent:@"didDie"]; } // two parts to the explosion: @@ -6092,8 +6125,8 @@ BOOL class_masslocks(int some_class) //scripting PlayerEntity *player = [PlayerEntity sharedPlayer]; [player setScriptTarget:self]; - [other->script doEvent:@"wasScooped" withArgument:self]; - [script doEvent:@"didScoop" withArgument:other]; + [other doScriptEvent:@"wasScooped" withArgument:self]; + [self doScriptEvent:@"didScoop" withArgument:other]; if (isPlayer) { @@ -6216,7 +6249,7 @@ BOOL class_masslocks(int some_class) // tell ourselves we've been attacked if (energy > 0) - [shipAI reactToMessage:@"ATTACKED"]; // note use the reactToMessage: method NOT the think-delayed message: method + [self respondToAttackFrom:ent becauseOf:other]; // firing on an innocent ship is an offence [self broadcastHitByLaserFrom:(ShipEntity*) other]; @@ -6231,7 +6264,7 @@ BOOL class_masslocks(int some_class) { [group_leader setFound_target:hunter]; [group_leader setPrimaryAggressor:hunter]; - [[group_leader getAI] reactToMessage:@"ATTACKED"]; + [group_leader respondToAttackFrom:ent becauseOf:hunter]; } else groupID = NO_TARGET; @@ -6246,7 +6279,7 @@ BOOL class_masslocks(int some_class) { [other_pirate setFound_target:hunter]; [other_pirate setPrimaryAggressor:hunter]; - [[other_pirate getAI] reactToMessage:@"ATTACKED"]; + [other_pirate respondToAttackFrom:ent becauseOf:hunter]; } } } @@ -6258,7 +6291,7 @@ BOOL class_masslocks(int some_class) ShipEntity *other_police = (ShipEntity *)[fellow_police objectAtIndex:i]; [other_police setFound_target:hunter]; [other_police setPrimaryAggressor:hunter]; - [[other_police getAI] reactToMessage:@"ATTACKED"]; + [other_police respondToAttackFrom:ent becauseOf:hunter]; } } } @@ -6609,6 +6642,8 @@ inline BOOL pairOK(NSString* my_role, NSString* their_role) { if (escortCount < 1) return; + + if (!escortsAreSetUp) return; if (![self primaryTarget]) return; @@ -6631,12 +6666,7 @@ inline BOOL pairOK(NSString* my_role, NSString* their_role) int escort_id = escort_ids[i_deploy]; ShipEntity *escorter = [UNIVERSE entityForUniversalID:escort_id]; // check it's still an escort ship - BOOL escorter_okay = YES; - if (!escorter) - escorter_okay = NO; - else - escorter_okay = escorter->isShip; - if (escorter_okay) + if (escorter != nil && escorter->isShip) { [escorter setGroupID:NO_TARGET]; // act individually now! [escorter addTarget:[self primaryTarget]]; @@ -7227,8 +7257,8 @@ inline BOOL pairOK(NSString* my_role, NSString* their_role) OOLog(@"dumpState.shipEntity", @"Name: %@", name); OOLog(@"dumpState.shipEntity", @"Roles: %@", roles); + OOLog(@"dumpState.shipEntity", @"Script: %@", script); if (sub_entities != nil) OOLog(@"dumpState.shipEntity", @"Subentity count: %u", [sub_entities count]); - OOLog(@"dumpState.shipEntity", @"Time since shot: %g", shot_time); OOLog(@"dumpState.shipEntity", @"Behaviour: %@", BehaviourToString(behaviour)); if (primaryTarget != NO_TARGET) OOLog(@"dumpState.shipEntity", @"Target: %@", [self primaryTarget]); OOLog(@"dumpState.shipEntity", @"Destination: %@", VectorDescription(destination)); @@ -7264,6 +7294,8 @@ inline BOOL pairOK(NSString* my_role, NSString* their_role) OOLog(@"dumpState.shipEntity", @"Frustration: %g", frustration); OOLog(@"dumpState.shipEntity", @"Success factor: %g", success_factor); OOLog(@"dumpState.shipEntity", @"Shots fired: %u", shot_counter); + OOLog(@"dumpState.shipEntity", @"Time since shot: %g", shot_time); + OOLog(@"dumpState.shipEntity", @"Spawn time: %g (%g seconds ago)", [self spawnTime], [self timeElapsedSinceSpawn]); if (beaconChar != '\0') { OOLog(@"dumpState.shipEntity", @"Beacon character: '%c'", beaconChar); @@ -7306,6 +7338,26 @@ inline BOOL pairOK(NSString* my_role, NSString* their_role) else return [self owner]; } + +// *** Script event dispatch. +// For ease of overriding, these all go through doScriptEvent:withArguments:. +- (void) doScriptEvent:(NSString *)message +{ + [self doScriptEvent:message withArguments:nil]; +} + + +- (void) doScriptEvent:(NSString *)message withArgument:(id)argument +{ + [self doScriptEvent:message withArguments:[NSArray arrayWithObject:argument]]; +} + + +- (void) doScriptEvent:(NSString *)message withArguments:(NSArray *)arguments +{ + [script doEvent:message withArguments:arguments]; +} + @end diff --git a/src/Core/Entities/StationEntity.m b/src/Core/Entities/StationEntity.m index e362a5b7..96d29ecb 100644 --- a/src/Core/Entities/StationEntity.m +++ b/src/Core/Entities/StationEntity.m @@ -1253,7 +1253,7 @@ static NSDictionary* instructions(int station_id, Vector coords, float speed, fl found_target = primaryAggressor; } [self increaseAlertLevel]; - [shipAI reactToMessage:@"ATTACKED"]; // note use the reactToMessage: method NOT the think-delayed message: method + [self respondToAttackFrom:ent becauseOf:other]; // ...and don't blow up. return; diff --git a/src/Core/GameController.m b/src/Core/GameController.m index d4c1c276..97f97ad6 100644 --- a/src/Core/GameController.m +++ b/src/Core/GameController.m @@ -443,8 +443,8 @@ static int CompareDisplayModes(id arg1, id arg2, void *context) { CGLContextObj cglContext; CGDisplayErr err; - long oldSwapInterval; - long newSwapInterval; + GLint oldSwapInterval; + GLint newSwapInterval; CGMouseDelta mouse_dx, mouse_dy; // empty the event queue and strip all keys - stop problems with hangover keys @@ -503,7 +503,7 @@ static int CompareDisplayModes(id arg1, id arg2, void *context) NSOpenGLPFAAccelerated, 0 }; - long rendererID; + GLint rendererID; // Create the FullScreen NSOpenGLContext with the attributes listed above. NSOpenGLPixelFormat *pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs]; diff --git a/src/Core/Materials/OOBasicMaterial.m b/src/Core/Materials/OOBasicMaterial.m index 8224248d..e262addf 100644 --- a/src/Core/Materials/OOBasicMaterial.m +++ b/src/Core/Materials/OOBasicMaterial.m @@ -87,8 +87,8 @@ static OOBasicMaterial *sDefaultMaterial = nil; colorDesc = [configuration objectForKey:@"ambient"]; if (colorDesc != nil) [self setAmbientColor:[OOColor colorWithDescription:colorDesc]]; - else [self setAmbientColor:[self diffuseColor]]; + colorDesc = [configuration objectForKey:@"emission"]; if (colorDesc != nil) [self setEmissionColor:[OOColor colorWithDescription:colorDesc]]; diff --git a/src/Core/Materials/OOShaderMaterial.m b/src/Core/Materials/OOShaderMaterial.m index c328904d..86337db1 100644 --- a/src/Core/Materials/OOShaderMaterial.m +++ b/src/Core/Materials/OOShaderMaterial.m @@ -373,7 +373,6 @@ static NSString *MacrosToString(NSDictionary *macros); for (i = 0; i != texCount; ++i) { glActiveTextureARB(GL_TEXTURE0_ARB + i); - /*glBindTexture(GL_TEXTURE_2D, textures[i]);*/ [textures[i] apply]; } glActiveTextureARB(GL_TEXTURE0_ARB); @@ -410,9 +409,28 @@ static NSString *MacrosToString(NSDictionary *macros); - (void)unapplyWithNext:(OOMaterial *)next { + uint32_t i, count; + if (![next isKindOfClass:[OOShaderMaterial class]]) // Avoid redundant state change { + OO_ENTER_OPENGL(); [OOShaderProgram applyNone]; + + /* BUG: unapplyWithNext: was failing to clear texture state. If a + shader material was followed by a basic material (with no texture), + the shader's #0 texture would be used. + It is necessary to clear at least one texture for the case where a + shader material with textures is followed by a shader material + without textures, then a basic material. + -- Ahruman 2007-08-13 + */ + count = texCount ? texCount : 1; + for (i = 0; i != count; ++i) + { + glActiveTextureARB(GL_TEXTURE0_ARB + i); + glBindTexture(GL_TEXTURE_2D, 0); + } + glActiveTextureARB(GL_TEXTURE0_ARB); } } diff --git a/src/Core/Materials/OOSingleTextureMaterial.m b/src/Core/Materials/OOSingleTextureMaterial.m index 5aefdcea..bb2b52b5 100644 --- a/src/Core/Materials/OOSingleTextureMaterial.m +++ b/src/Core/Materials/OOSingleTextureMaterial.m @@ -60,7 +60,7 @@ SOFTWARE. self = [super initWithName:name configuration:configuration]; if (name != nil && self != nil) { - if (texSpec != nil) + if (configuration != nil) { texSpec = [configuration textureSpecifierForKey:@"diffuse_map" defaultName:name]; } diff --git a/src/Core/OXPVerifier/OOCheckShipDataPListVerifierStage.m b/src/Core/OXPVerifier/OOCheckShipDataPListVerifierStage.m index c6a2790e..65b19cf2 100644 --- a/src/Core/OXPVerifier/OOCheckShipDataPListVerifierStage.m +++ b/src/Core/OXPVerifier/OOCheckShipDataPListVerifierStage.m @@ -290,13 +290,23 @@ static NSString * const kStageName = @"Checking shipdata.plist"; materials = [_info dictionaryForKey:@"materials"]; shaders = [_info dictionaryForKey:@"shaders"]; - if (![[[self verifier] modelVerifierStage] modelNamed:model - usedForEntry:_name - inFile:@"shipdata.plist" - withMaterials:materials - andShaders:shaders]) + if (model != nil) { - [self message:@"WARNING: model \"%@\" could not be found in %@ or in Oolite.", model, [[self verifier] oxpDisplayName]]; + if (![[[self verifier] modelVerifierStage] modelNamed:model + usedForEntry:_name + inFile:@"shipdata.plist" + withMaterials:materials + andShaders:shaders]) + { + [self message:@"WARNING: model \"%@\" could not be found in %@ or in Oolite.", model, [[self verifier] oxpDisplayName]]; + } + } + else + { + if ([_info stringForKey:@"like_ship"] == nil) + { + [self message:@"ERROR: ship does not specify model or like_ship."]; + } } } diff --git a/src/Core/Scripting/OOJSEntity.h b/src/Core/Scripting/OOJSEntity.h index 47c605e8..60e9cb8e 100644 --- a/src/Core/Scripting/OOJSEntity.h +++ b/src/Core/Scripting/OOJSEntity.h @@ -43,9 +43,6 @@ BOOL JSEntityGetEntity(JSContext *context, JSObject *entityObj, Entity **outEnti JSClass *JSEntityClass(void); JSObject *JSEntityPrototype(void); -// Hack to support psuedo-class-hierarchy. -void JSEntityRegisterEntitySubclass(JSClass *theClass); - // For subclasses. SUBCLASSES MUST USE THESE or scripts will crash. JSBool JSEntityConvert(JSContext *context, JSObject *this, JSType type, jsval *outValue); void JSEntityFinalize(JSContext *context, JSObject *this); diff --git a/src/Core/Scripting/OOJSEntity.m b/src/Core/Scripting/OOJSEntity.m index c652a8a8..b88c9fea 100644 --- a/src/Core/Scripting/OOJSEntity.m +++ b/src/Core/Scripting/OOJSEntity.m @@ -35,7 +35,6 @@ MA 02110-1301, USA. static JSObject *sEntityPrototype; -static NSMutableSet *sEntitySubClasses; static JSBool EntityGetProperty(JSContext *context, JSObject *this, jsval name, jsval *outValue); @@ -145,7 +144,7 @@ static JSFunctionSpec sEntityStaticMethods[] = void InitOOJSEntity(JSContext *context, JSObject *global) { sEntityPrototype = JS_InitClass(context, global, NULL, &sEntityClass.base, NULL, 0, sEntityProperties, sEntityMethods, NULL, sEntityStaticMethods); - JSEntityRegisterEntitySubclass(&sEntityClass.base); + JSRegisterObjectConverter(&sEntityClass.base, JSBasicPrivateObjectConverter); } @@ -213,23 +212,11 @@ BOOL JSValueToEntity(JSContext *context, jsval value, Entity **outEntity) BOOL JSEntityGetEntity(JSContext *context, JSObject *entityObj, Entity **outEntity) { -// OOWeakReference *proxy = nil; - if (outEntity == NULL) return NO; *outEntity = nil; if (entityObj == NULL) return NO; if (EXPECT_NOT(context == NULL)) context = [[OOJavaScriptEngine sharedEngine] context]; - /* - // If it is an entity proxy... - if ([sEntitySubClasses member:[NSValue valueWithPointer:JS_GetClass(entityObj)]] != nil) - { - proxy = JS_GetPrivate(context, entityObj); - if (proxy != nil) - { - *outEntity = [proxy weakRefUnderlyingObject]; - return YES; - } - }*/ + *outEntity = JSObjectToObject(context, entityObj); if ([*outEntity isKindOfClass:[Entity class]]) return YES; @@ -250,14 +237,6 @@ JSObject *JSEntityPrototype(void) } -void JSEntityRegisterEntitySubclass(JSClass *theClass) -{ - if (sEntitySubClasses == nil) sEntitySubClasses = [[NSMutableSet alloc] init]; - [sEntitySubClasses addObject:[NSValue valueWithPointer:theClass]]; - JSRegisterObjectConverter(theClass, JSBasicPrivateObjectConverter); -} - - BOOL EntityFromArgumentList(JSContext *context, NSString *scriptClass, NSString *function, uintN argc, jsval *argv, Entity **outEntity, uintN *outConsumed) { // Sanity checks. diff --git a/src/Core/Scripting/OOJSPlayer.m b/src/Core/Scripting/OOJSPlayer.m index 69ee4b2b..675bbb19 100644 --- a/src/Core/Scripting/OOJSPlayer.m +++ b/src/Core/Scripting/OOJSPlayer.m @@ -133,7 +133,7 @@ static JSFunctionSpec sPlayerMethods[] = void InitOOJSPlayer(JSContext *context, JSObject *global) { sPlayerPrototype = JS_InitClass(context, global, JSShipPrototype(), &sPlayerClass.base, NULL, 0, sPlayerProperties, sPlayerMethods, NULL, NULL); - JSEntityRegisterEntitySubclass(&sPlayerClass.base); + JSRegisterObjectConverter(&sPlayerClass.base, JSBasicPrivateObjectConverter); // Create player object as a property of the global object. sPlayerObject = JS_DefineObject(context, global, "player", &sPlayerClass.base, sPlayerPrototype, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); diff --git a/src/Core/Scripting/OOJSQuaternion.m b/src/Core/Scripting/OOJSQuaternion.m index d0145148..901a66fd 100644 --- a/src/Core/Scripting/OOJSQuaternion.m +++ b/src/Core/Scripting/OOJSQuaternion.m @@ -58,6 +58,8 @@ static JSBool QuaternionVectorForward(JSContext *context, JSObject *this, uintN static JSBool QuaternionVectorUp(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult); static JSBool QuaternionVectorRight(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult); +static JSBool QuaternionStaticRandom(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult); + static JSExtendedClass sQuaternionClass = { @@ -120,11 +122,19 @@ static JSFunctionSpec sQuaternionMethods[] = }; +static JSFunctionSpec sQuaternionStaticMethods[] = +{ + // JS name Function min args + { "random", QuaternionStaticRandom, 0, }, + { 0 } +}; + + // *** Public *** void InitOOJSQuaternion(JSContext *context, JSObject *global) { - sQuaternionPrototype = JS_InitClass(context, global, NULL, &sQuaternionClass.base, QuaternionConstruct, 4, sQuaternionProperties, sQuaternionMethods, NULL, NULL); + sQuaternionPrototype = JS_InitClass(context, global, NULL, &sQuaternionClass.base, QuaternionConstruct, 4, sQuaternionProperties, sQuaternionMethods, NULL, sQuaternionStaticMethods); } @@ -555,3 +565,10 @@ static JSBool QuaternionVectorRight(JSContext *context, JSObject *this, uintN ar return VectorToJSValue(context, result, outResult); } + + +// Quaternion random() +static JSBool QuaternionStaticRandom(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult) +{ + return QuaternionToJSValue(context, OORandomQuaternion(), outResult); +} diff --git a/src/Core/Scripting/OOJSScript.m b/src/Core/Scripting/OOJSScript.m index 4a767225..3cc6098d 100644 --- a/src/Core/Scripting/OOJSScript.m +++ b/src/Core/Scripting/OOJSScript.m @@ -114,7 +114,7 @@ static JSClass sScriptClass = if (!problem) { - if (!JS_AddRoot(context, &object)) // note 2nd arg is a pointer-to-pointer + if (!JS_AddNamedRoot(context, &object, "Script object")) // note 2nd arg is a pointer-to-pointer { problem = @"could not add JavaScript root object"; } @@ -246,10 +246,10 @@ static JSClass sScriptClass = BOOL OK; jsval value; JSFunction *function; - uintN argc; + uintN i, argc; jsval *argv = NULL; RunningStack stackElement; - + OK = JS_GetProperty(context, object, [eventName cString], &value); if (OK && !JSVAL_IS_VOID(value)) { @@ -261,9 +261,34 @@ static JSClass sScriptClass = stackElement.current = self; sRunningStack = &stackElement; - JSArgumentsFromArray(context, arguments, &argc, &argv); + // Convert arguments to JS values and make them temporarily un-garbage-collectable + argc = [arguments count]; + if (argc != 0) + { + argv = malloc(sizeof *argv * argc); + if (argv != NULL) + { + for (i = 0; i != argc; ++i) + { + argv[i] = [arguments javaScriptValueInContext:context]; + if (JSVAL_IS_GCTHING(argv[i])) JS_AddNamedRoot(context, &argv[i], "JSScript event parameter"); + } + } + else argc = 0; + } + + // Actually call the function OK = JS_CallFunction(context, object, function, argc, argv, &value); - if (argv != NULL) free(argv); + + // Re-garbage-collectibalize the arguments and free the array + if (argv != NULL) + { + for (i = 0; i != argc; ++i) + { + if (JSVAL_IS_GCTHING(argv[i])) JS_RemoveRoot(context, &argv[i]); + } + free(argv); + } // Pop running scripts stack sRunningStack = stackElement.back; @@ -279,7 +304,7 @@ static JSClass sScriptClass = - (id)propertyNamed:(NSString *)propName { BOOL OK; - jsval value = nil; + jsval value = JSVAL_VOID; if (propName == nil) return nil; diff --git a/src/Core/Scripting/OOJSShip.m b/src/Core/Scripting/OOJSShip.m index e18d8e04..5e3efb76 100644 --- a/src/Core/Scripting/OOJSShip.m +++ b/src/Core/Scripting/OOJSShip.m @@ -117,7 +117,7 @@ static JSPropertySpec sShipProperties[] = { "bounty", kShip_bounty, JSPROP_PERMANENT | JSPROP_ENUMERATE }, { "subEntities", kShip_subEntities, JSPROP_PERMANENT | JSPROP_ENUMERATE | JSPROP_READONLY }, { "hasSuspendedAI", kShip_hasSuspendedAI, JSPROP_PERMANENT | JSPROP_ENUMERATE | JSPROP_READONLY }, - { "target", kShip_target, JSPROP_PERMANENT | JSPROP_ENUMERATE | JSPROP_READONLY }, + { "target", kShip_target, JSPROP_PERMANENT | JSPROP_ENUMERATE }, { "escorts", kShip_escorts, JSPROP_PERMANENT | JSPROP_ENUMERATE | JSPROP_READONLY }, { "temperature", kShip_temperature, JSPROP_PERMANENT | JSPROP_ENUMERATE }, { "heatInsulation", kShip_heatInsulation, JSPROP_PERMANENT | JSPROP_ENUMERATE }, @@ -158,7 +158,7 @@ static JSFunctionSpec sShipMethods[] = void InitOOJSShip(JSContext *context, JSObject *global) { sShipPrototype = JS_InitClass(context, global, JSEntityPrototype(), &sShipClass.base, NULL, 0, sShipProperties, sShipMethods, NULL, NULL); - JSEntityRegisterEntitySubclass(&sShipClass.base); + JSRegisterObjectConverter(&sShipClass.base, JSBasicPrivateObjectConverter); } @@ -345,7 +345,7 @@ static JSBool ShipSetProperty(JSContext *context, JSObject *this, jsval name, js if (!JSVAL_IS_INT(name)) return YES; if (!JSShipGetShipEntity(context, this, &entity)) return NO; - switch (name) + switch (JSVAL_TO_INT(name)) { case kShip_AIState: if (entity->isPlayer) diff --git a/src/Core/Scripting/OOJSStation.m b/src/Core/Scripting/OOJSStation.m index 84460498..393157cb 100644 --- a/src/Core/Scripting/OOJSStation.m +++ b/src/Core/Scripting/OOJSStation.m @@ -85,7 +85,7 @@ static JSFunctionSpec sStationMethods[] = void InitOOJSStation(JSContext *context, JSObject *global) { sStationPrototype = JS_InitClass(context, global, JSShipPrototype(), &sStationClass.base, NULL, 0, sStationProperties, sStationMethods, NULL, NULL); - JSEntityRegisterEntitySubclass(&sStationClass.base); + JSRegisterObjectConverter(&sStationClass.base, JSBasicPrivateObjectConverter); } diff --git a/src/Core/Scripting/OOJavaScriptEngine.h b/src/Core/Scripting/OOJavaScriptEngine.h index df539671..9612c4c6 100644 --- a/src/Core/Scripting/OOJavaScriptEngine.h +++ b/src/Core/Scripting/OOJavaScriptEngine.h @@ -62,22 +62,17 @@ void OOReportJavaScriptBadPropertySelector(JSContext *context, NSString *classNa BOOL NumberFromArgumentList(JSContext *context, NSString *scriptClass, NSString *function, uintN argc, jsval *argv, double *outNumber, uintN *outConsumed); -/* JSArgumentsFromArray() - - Convert an ObjC array to an array of JavaScript values. For objects which - don't respond to -javaScriptValueInContext:, JSVAL_VOID will be used. - - *outArgv will be NULL if *outArgc is 0. If *outArgv is not NULL, it should - be free()d when finished with. -*/ -BOOL JSArgumentsFromArray(JSContext *context, NSArray *array, uintN *outArgc, jsval **outArgv); - /* JSArrayFromArray() + JSNewNSArrayValue() - Convert an ObjC array to a JavaScript array. This is a wrapper around - JSArgumentsFromArray() and js_NewArrayObject(). + Convert an ObjC array to a JavaScript array. + + JSNewNSArrayValue() will return YES and set value to JSVAL_NULL if passed + a nil array, but return NO and set value to JSVAL_VOID on failure. + JSArrayFromArray() will return NULL if the count is 0 or if it fails. */ JSObject *JSArrayFromNSArray(JSContext *context, NSArray *array); +BOOL JSNewNSArrayValue(JSContext *context, NSArray *array, jsval *value); OOINLINE jsval BOOLToJSVal(BOOL b) INLINE_CONST_FUNC; diff --git a/src/Core/Scripting/OOJavaScriptEngine.m b/src/Core/Scripting/OOJavaScriptEngine.m index a069a8d9..6a7f298a 100644 --- a/src/Core/Scripting/OOJavaScriptEngine.m +++ b/src/Core/Scripting/OOJavaScriptEngine.m @@ -674,67 +674,54 @@ BOOL NumberFromArgumentList(JSContext *context, NSString *scriptClass, NSString } -BOOL JSArgumentsFromArray(JSContext *context, NSArray *array, uintN *outArgc, jsval **outArgv) +JSObject *JSArrayFromNSArray(JSContext *context, NSArray *array) { - if (outArgc != NULL) *outArgc = 0; - if (outArgv != NULL) *outArgv = NULL; + JSObject *result = NULL; + unsigned i, count; + jsval value; + BOOL OK = YES; - if (array == nil) return YES; + if (array == nil) return NULL; - // Sanity checks. - if (outArgc == NULL || outArgv == NULL) - { - OOLogGenericParameterError(); - return NO; - } - if (context == NULL) context = [[OOJavaScriptEngine sharedEngine] context]; + result = JS_NewArrayObject(context, 0, NULL); + if (result == NULL) return NULL; - uintN i = 0, argc = [array count]; - NSEnumerator *objectEnum = nil; - id object = nil; - jsval *argv = NULL; - - if (argc == 0) return YES; - - // Allocate result buffer - argv = malloc(sizeof *argv * argc); - if (argv == NULL) - { - OOLog(kOOLogAllocationFailure, @"Failed to allocate space for %u JavaScript parameters.", argc); - return NO; - } - - // Convert objects - JSContext * volatile vCtxt = context; - for (objectEnum = [array objectEnumerator]; (object = [objectEnum nextObject]); ) + count = [array count]; + for (i = 0; i != count; ++i) { NS_DURING - argv[i] = [object javaScriptValueInContext:vCtxt]; + value = [[array objectAtIndex:i] javaScriptValueInContext:context]; NS_HANDLER - argv[i] = JSVAL_VOID; + value = JSVAL_VOID; NS_ENDHANDLER - ++i; + OK = JS_SetElement(context, result, i, &value); + if (!OK) return NULL; } - *outArgc = argc; - *outArgv = argv; - return YES; + return result; } -JSObject *JSArrayFromNSArray(JSContext *context, NSArray *array) +BOOL JSNewNSArrayValue(JSContext *context, NSArray *array, jsval *value) { - uintN count; - jsval *values; - JSObject *result = NULL; + JSObject *object = NULL; - if (JSArgumentsFromArray(context, array, &count, &values)) + if (value == NULL) return NO; + if ([array count] == 0) { - result = JS_NewArrayObject(context, count, values); + *value = JSVAL_NULL; + return YES; } - if (values != NULL) free(values); - return result; + object = JSArrayFromNSArray(context, array); + if (object == NULL) + { + *value = JSVAL_VOID; + return NO; + } + + *value = OBJECT_TO_JSVAL(object); + return YES; } @@ -852,7 +839,9 @@ JSObject *JSArrayFromNSArray(JSContext *context, NSArray *array) - (jsval)javaScriptValueInContext:(JSContext *)context { - return OBJECT_TO_JSVAL(JSArrayFromNSArray(context, self)); + jsval value; + JSNewNSArrayValue(context, self, &value); + return value; } @end diff --git a/src/Core/Scripting/OOPlayerProxyScript.h b/src/Core/Scripting/OOPlayerProxyScript.h deleted file mode 100644 index 92cc47a5..00000000 --- a/src/Core/Scripting/OOPlayerProxyScript.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - -OOPlayerProxyScript.h - -Script which passes messages on to all world scripts, acting as the player's -ship script. This ensures all ship script messages for the player are passed -to the world scripts without needing special treatment. - - -Oolite -Copyright (C) 2004-2007 Giles C Williams and contributors - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -MA 02110-1301, USA. - -*/ - -#import "OOScript.h" - - -@interface OOPlayerProxyScript: OOScript -@end diff --git a/src/Core/Scripting/OOPlayerProxyScript.m b/src/Core/Scripting/OOPlayerProxyScript.m deleted file mode 100644 index 25b0cfc7..00000000 --- a/src/Core/Scripting/OOPlayerProxyScript.m +++ /dev/null @@ -1,74 +0,0 @@ -/* - -OOPlayerProxyScript.m - - -Oolite -Copyright (C) 2004-2007 Giles C Williams and contributors - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -MA 02110-1301, USA. - -*/ - -#import "OOPlayerProxyScript.h" -#import "PlayerEntity.h" - - -@implementation OOPlayerProxyScript - -- (void)resetState -{ - OOLog(@"temp", @"FIXME!"); -} - - -- (NSString *)name -{ - return @""; -} - - -- (NSString *)scriptDescription -{ - return @"Pseudo-script which passes all messages to all world scripts."; -} - - -- (NSString *)version -{ - return nil; -} - -- (void)runWithTarget:(Entity *)target -{ - OOLog(@"temp", @"FIXME!"); -} - - -- (BOOL)doEvent:(NSString *)eventName -{ - OOLog(@"temp", @"FIXME!"); - return NO; -} - - -- (BOOL)doEvent:(NSString *)eventName withArguments:(NSArray *)arguments -{ - OOLog(@"temp", @"FIXME!"); - return NO; -} - -@end diff --git a/src/Core/Universe.m b/src/Core/Universe.m index cdfdf89b..c251729c 100644 --- a/src/Core/Universe.m +++ b/src/Core/Universe.m @@ -86,6 +86,7 @@ static NSComparisonResult comparePrice(NSDictionary *dict1, NSDictionary *dict2, @interface Universe (OOPrivate) - (BOOL)doRemoveEntity:(Entity *)entity; +- (NSDictionary *)getDictionaryForShip:(NSString *)desc recursionLimit:(uint32_t)recursionLimit; @end @@ -260,8 +261,8 @@ static NSComparisonResult comparePrice(NSDictionary *dict1, NSDictionary *dict2, doProcedurallyTexturedPlanets = NO; #endif - [player sendMessageToScripts:@"startUp"]; - + [player doWorldScriptEvent:@"startUp" withArguments:nil]; + return self; } @@ -647,7 +648,7 @@ static NSComparisonResult comparePrice(NSDictionary *dict1, NSDictionary *dict2, [self setViewDirection:VIEW_FORWARD]; [comm_log_gui printLongText:[NSString stringWithFormat:@"%@ %@", [self generateSystemName:system_seed], [player dial_clock_adjusted]] - align:GUI_ALIGN_CENTER color:[OOColor whiteColor] fadeTime:0 key:nil addToArray:[player comm_log]]; + align:GUI_ALIGN_CENTER color:[OOColor whiteColor] fadeTime:0 key:nil addToArray:[player commLog]]; // /* test stuff */ @@ -2831,7 +2832,7 @@ GLfloat docked_light_specular[] = { (GLfloat) 1.0, (GLfloat) 1.0, (GLfloat) 0.5, [ship setRoles:search]; // set its roles to this one particular chosen role shipDict = [shipdata dictionaryForKey:shipKey]; - if ([shipDict fuzzyBooleanForKey:@"auto_ai"]) + if ([shipDict fuzzyBooleanForKey:@"auto_ai" defaultValue:YES]) { // Set AI based on role autoAIMap = [ResourceManager dictionaryFromFilesNamed:@"autoAImap.plist" inFolder:@"Config" andMerge:YES]; @@ -2905,64 +2906,7 @@ GLfloat docked_light_specular[] = { (GLfloat) 1.0, (GLfloat) 1.0, (GLfloat) 0.5, - (NSDictionary *)getDictionaryForShip:(NSString *)desc { - static NSDictionary *cachedResult = nil; - static NSString *cachedKey = nil; - - if (desc == nil) return nil; - if ([desc isEqualToString:cachedKey]) return [[cachedResult retain] autorelease]; - - NSMutableDictionary *shipdict = [[[shipdata dictionaryForKey:desc] mutableCopy] autorelease]; - if (shipdict == nil) - { - /* There used to be an attempt to throw a OOLITE_EXCEPTION_SHIP_NOT_FOUND - exception here. However, it never worked -- the line above was - broken so an empty dictionary was created instead, which was - rather pointless. Once this was fixed, it turned out there are OXPs - causing bad ships to be created, which wasn't noticed because the - exception wasn't handled. - -- Ahruman - */ - return nil; - } - // check if this is based upon a different ship - // TODO: move all like_ship handling into one place. (Actually, it may be that this already _is_ that place and all others are redundant.) Should probably fold resolved like_ships back into dictionary. -- Ahruman - unsigned recursionLimiter = 0; - - while ([shipdict stringForKey:@"like_ship"]) - { - NSString* other_shipdesc = [shipdict stringForKey:@"like_ship"]; - NSDictionary* other_shipdict = nil; - - if (++recursionLimiter == 30) - { - OOLog(@"universe.getShip.badReference", @"Failed to construct ship dictionary for \"%@\" -- hit safety limit of %u like_ship redirections.", desc, recursionLimiter); - return nil; - } - - if (other_shipdesc != nil) - { - other_shipdict = [self getDictionaryForShip:other_shipdesc]; - } - if (other_shipdict != nil) - { - [shipdict removeObjectForKey:@"like_ship"]; // so it may inherit a new one from the like_ship - NSMutableDictionary* this_shipdict = [NSMutableDictionary dictionaryWithDictionary:other_shipdict]; // basics from that one - [this_shipdict addEntriesFromDictionary:shipdict]; // overrides from this one - shipdict = [NSMutableDictionary dictionaryWithDictionary:this_shipdict]; // synthesis' - } - else - { - OOLog(@"universe.getShip.badReference", @"Failed to construct ship dictionary for \"%@\" -- like_ship reference to unknown ship type \"%@\".", desc, other_shipdesc); - return nil; - } - } - - [cachedResult release]; - cachedResult = [shipdict copy]; - [cachedKey release]; - cachedKey = [desc copy]; - - return shipdict; + return [self getDictionaryForShip:desc recursionLimit:32]; } @@ -5004,7 +4948,7 @@ static BOOL MaintainLinkedLists(Universe* uni) [message_gui printLongText:text align:GUI_ALIGN_CENTER color:[OOColor greenColor] fadeTime:(float)count key:nil addToArray:nil]; - [comm_log_gui printLongText:text align:GUI_ALIGN_LEFT color:nil fadeTime:0.0 key:nil addToArray:[player comm_log]]; + [comm_log_gui printLongText:text align:GUI_ALIGN_LEFT color:nil fadeTime:0.0 key:nil addToArray:[player commLog]]; [comm_log_gui setAlpha:1.0]; [comm_log_gui fadeOutFromTime:[self getTime] overDuration:6.0]; @@ -7671,4 +7615,66 @@ static NSComparisonResult comparePrice(NSDictionary *dict1, NSDictionary *dict2, return NO; } + +- (NSDictionary *)getDictionaryForShip:(NSString *)desc recursionLimit:(uint32_t)recursionLimit +{ + static NSDictionary *cachedResult = nil; + static NSString *cachedKey = nil; + + if (desc == nil) return nil; + if ([desc isEqualToString:cachedKey]) return [[cachedResult retain] autorelease]; + + NSMutableDictionary *shipdict = [[[shipdata dictionaryForKey:desc] mutableCopy] autorelease]; + if (shipdict == nil) + { + /* There used to be an attempt to throw a OOLITE_EXCEPTION_SHIP_NOT_FOUND + exception here. However, it never worked -- the line above was + broken so an empty dictionary was created instead, which was + rather pointless. Once this was fixed, it turned out there are OXPs + causing bad ships to be created, which wasn't noticed because the + exception wasn't handled. + -- Ahruman + */ + return nil; + } + // check if this is based upon a different ship + // TODO: move all like_ship handling into one place. (Actually, it may be that this already _is_ that place and all others are redundant.) Should probably fold resolved like_ships back into dictionary. -- Ahruman + + while ([shipdict stringForKey:@"like_ship"]) + { + NSString* other_shipdesc = [shipdict stringForKey:@"like_ship"]; + NSDictionary* other_shipdict = nil; + + if (recursionLimit == 0) + { + OOLog(@"universe.getShip.badReference", @"Failed to construct ship dictionary for \"%@\" -- hit safety limit for like_ship redirections.", desc); + return nil; + } + + if (other_shipdesc != nil) + { + other_shipdict = [self getDictionaryForShip:other_shipdesc recursionLimit:recursionLimit - 1]; + } + if (other_shipdict != nil) + { + [shipdict removeObjectForKey:@"like_ship"]; // so it may inherit a new one from the like_ship + NSMutableDictionary* this_shipdict = [NSMutableDictionary dictionaryWithDictionary:other_shipdict]; // basics from that one + [this_shipdict addEntriesFromDictionary:shipdict]; // overrides from this one + shipdict = [NSMutableDictionary dictionaryWithDictionary:this_shipdict]; // synthesis' + } + else + { + OOLog(@"universe.getShip.badReference", @"Failed to construct ship dictionary for \"%@\" -- like_ship reference to unknown ship type \"%@\".", desc, other_shipdesc); + return nil; + } + } + + [cachedResult release]; + cachedResult = [shipdict copy]; + [cachedKey release]; + cachedKey = [desc copy]; + + return shipdict; +} + @end