For the past two weeks I've been procrastinating from fixing a double-free bug in the JS accessor for Ship.escorts (or, more precisely, in the code constructing a JS array). The bug was in r1129, so not checking stuff in doesn't really make much sense.

Fixes in that time:
* Clean, integrated model for JS ship scripts and world scripts.
* Player ships support JS ship scripts (but not ones synthesized from legacy actions).
* Subentity shader uniform bindings bind to owning ship as intended.
* Fixed like_ship recursion limiter in -[Universe getDictionaryForShip:].
* Fixed a bug in material configuration parsing.
* Fixed a material bug where a shader material with textures, followed by a shader material with no textures, followed by a basic material with no textures would leave a texture bound.
* Cleaned up NSArray -> JS array conversion, without fixing aforementioned bug.
* Made JS Ship property "target" read/write, and made property setting work.
* Added JS Quaternion.random() static method.


git-svn-id: http://svn.berlios.de/svnroot/repos/oolite-linux/trunk@1136 127b21dd-08f5-0310-b4b7-95ae10353056
This commit is contained in:
Jens Ayton 2007-08-19 23:05:48 +00:00
parent abe8cea08f
commit 0ffb248771
32 changed files with 428 additions and 412 deletions

View File

@ -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

View File

@ -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 = "<group>"; };
1A7376BC0C64AE330097AC37 /* OOJSSystem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OOJSSystem.h; sourceTree = "<group>"; };
1A7376BD0C64AE330097AC37 /* OOJSSystem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OOJSSystem.m; sourceTree = "<group>"; };
1A7378E20C6515720097AC37 /* OOPlayerProxyScript.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OOPlayerProxyScript.h; sourceTree = "<group>"; };
1A7378E30C6515720097AC37 /* OOPlayerProxyScript.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OOPlayerProxyScript.m; sourceTree = "<group>"; };
1A73795B0C65CF090097AC37 /* OOLegacyEventHandlerScript.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OOLegacyEventHandlerScript.h; sourceTree = "<group>"; };
1A73795C0C65CF090097AC37 /* OOLegacyEventHandlerScript.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OOLegacyEventHandlerScript.m; sourceTree = "<group>"; };
1A7D3A160C4F6162008EDC33 /* OOCheckRequiresPListVerifierStage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OOCheckRequiresPListVerifierStage.h; sourceTree = "<group>"; };
@ -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;

View File

@ -1410,6 +1410,8 @@
<key>do</key>
<array>
<string>awardEquipment: EQ_CLOAKING_DEVICE</string>
<!-- To consider:
<string>set: mission_TL_FOR_EQ_CLOAKING_DEVICE 14</string> -->
</array>
</dict>
<dict>

View File

@ -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];

View File

@ -254,4 +254,6 @@ typedef struct
- (GLfloat)spawnTime;
- (GLfloat)timeElapsedSinceSpawn;
- (void)setShaderBindingTarget:(Entity *)ent;
@end

View File

@ -1045,4 +1045,10 @@ static NSString * const kOOLogEntityUpdateError = @"entity.linkedList.update.
return [UNIVERSE getTime] - spawnTime;
}
- (void)setShaderBindingTarget:(Entity *)ent
{
}
@end

View File

@ -82,4 +82,10 @@ MA 02110-1301, USA.
else [drawable renderOpaqueParts];
}
- (void)setShaderBindingTarget:(Entity *)ent
{
[[self drawable] setBindingTarget:ent];
}
@end

View File

@ -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!

View File

@ -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;

View File

@ -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);
// Load script
[script release];
script = [[OOPlayerProxyScript alloc] init];
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"];
}
@ -5027,6 +5046,8 @@ static int last_outfitting_index;
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;
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
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 :
@ -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;
}
}
return NO;
if (tradeIn != 0)
{
if (price_factor < 1.0f) tradeIn *= price_factor;
credits += tradeIn;
}
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;

View File

@ -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];
}
}
//

View File

@ -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];
}
//
}

View File

@ -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

View File

@ -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))
@ -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];
}
}
}
@ -6610,6 +6643,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

View File

@ -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;

View File

@ -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];

View File

@ -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]];

View File

@ -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);
}
}

View File

@ -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];
}

View File

@ -290,6 +290,8 @@ static NSString * const kStageName = @"Checking shipdata.plist";
materials = [_info dictionaryForKey:@"materials"];
shaders = [_info dictionaryForKey:@"shaders"];
if (model != nil)
{
if (![[[self verifier] modelVerifierStage] modelNamed:model
usedForEntry:_name
inFile:@"shipdata.plist"
@ -298,6 +300,14 @@ static NSString * const kStageName = @"Checking shipdata.plist";
{
[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."];
}
}
}

View File

@ -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);

View File

@ -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.

View File

@ -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);

View File

@ -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);
}

View File

@ -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,7 +246,7 @@ static JSClass sScriptClass =
BOOL OK;
jsval value;
JSFunction *function;
uintN argc;
uintN i, argc;
jsval *argv = NULL;
RunningStack stackElement;
@ -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;

View File

@ -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)

View File

@ -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);
}

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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 @"<player proxy script>";
}
- (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

View File

@ -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,7 +261,7 @@ 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