diff --git a/Oolite.xcodeproj/project.pbxproj b/Oolite.xcodeproj/project.pbxproj index 20242908..40ff967b 100644 --- a/Oolite.xcodeproj/project.pbxproj +++ b/Oolite.xcodeproj/project.pbxproj @@ -1020,7 +1020,7 @@ 083325DC09DDBCDE00F5B8E4 /* OOColor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OOColor.m; sourceTree = ""; }; 083DB4D30A70E51E00B419B2 /* OOBrain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OOBrain.h; sourceTree = ""; }; 083DB4D40A70E51E00B419B2 /* OOBrain.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OOBrain.m; sourceTree = ""; }; - 0865432206B8447D000CA0AB /* Oolite.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Oolite.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 0865432206B8447D000CA0AB /* OoliteDev.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = OoliteDev.app; sourceTree = BUILT_PRODUCTS_DIR; }; 0878FD2F086EF845004CB752 /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = /System/Library/Frameworks/Carbon.framework; sourceTree = ""; }; 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; 1A020E0A0D020AFB00C3F51E /* changedScriptHandlers.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = changedScriptHandlers.plist; sourceTree = ""; }; @@ -1688,7 +1688,7 @@ 19C28FACFE9D520D11CA2CBB /* Products */ = { isa = PBXGroup; children = ( - 0865432206B8447D000CA0AB /* Oolite.app */, + 0865432206B8447D000CA0AB /* OoliteDev.app */, 1A71E6F30BCE340C00CD5C13 /* libpng.a */, ); name = Products; @@ -2912,7 +2912,7 @@ name = Oolite; productInstallPath = "$(HOME)/Applications"; productName = Oolite; - productReference = 0865432206B8447D000CA0AB /* Oolite.app */; + productReference = 0865432206B8447D000CA0AB /* OoliteDev.app */; productType = "com.apple.product-type.application"; }; 1A71E6F20BCE340C00CD5C13 /* libpng-custom */ = { diff --git a/src/Core/Entities/PlayerEntity.h b/src/Core/Entities/PlayerEntity.h index 58e5f627..90b6fb82 100644 --- a/src/Core/Entities/PlayerEntity.h +++ b/src/Core/Entities/PlayerEntity.h @@ -669,9 +669,8 @@ waitingForStickCallback: 1; - (BOOL)showInfoFlag; -- (void) setGalacticHyperspaceBehaviour:(NSString *) galacticHyperspaceBehaviourString; +- (void) setGalacticHyperspaceBehaviour:(OOGalacticHyperspaceBehaviour) galacticHyperspaceBehaviour; - (OOGalacticHyperspaceBehaviour) galacticHyperspaceBehaviour; -- (void) setGalacticHyperspaceFixedCoords:(NSString *) galacticHyperspaceFixedCoordsString; - (void) setGalacticHyperspaceFixedCoordsX:(unsigned char)x y:(unsigned char)y; - (NSPoint) galacticHyperspaceFixedCoords; diff --git a/src/Core/Entities/PlayerEntity.m b/src/Core/Entities/PlayerEntity.m index b14a5c5d..040e13e3 100644 --- a/src/Core/Entities/PlayerEntity.m +++ b/src/Core/Entities/PlayerEntity.m @@ -917,8 +917,8 @@ static PlayerEntity *sSharedPlayer = nil; [self setSystem_seed:[UNIVERSE findSystemAtCoords:[self galaxy_coordinates] withGalaxySeed:[self galaxy_seed]]]; - [self setGalacticHyperspaceBehaviour:[[UNIVERSE planetinfo] stringForKey:@"galactic_hyperspace_behaviour" defaultValue:@"GALACTIC_HYPERSPACE_BEHAVIOUR_STANDARD"]]; - [self setGalacticHyperspaceFixedCoords:[[UNIVERSE planetinfo] stringForKey:@"galactic_hyperspace_fixed_coords" defaultValue:@"96 96"]]; + [self setGalacticHyperspaceBehaviourTo:[[UNIVERSE planetinfo] stringForKey:@"galactic_hyperspace_behaviour" defaultValue:@"GALACTIC_HYPERSPACE_BEHAVIOUR_STANDARD"]]; + [self setGalacticHyperspaceFixedCoordsTo:[[UNIVERSE planetinfo] stringForKey:@"galactic_hyperspace_fixed_coords" defaultValue:@"96 96"]]; [[OOMusicController sharedController] stop]; [OOScriptTimer noteGameReset]; @@ -6309,15 +6309,10 @@ OOSound* burnersound; } -- (void) setGalacticHyperspaceBehaviour:(NSString *) galacticHyperspaceBehaviourString +- (void) setGalacticHyperspaceBehaviour:(OOGalacticHyperspaceBehaviour)inBehaviour { - if (galacticHyperspaceBehaviourString == nil) - { - OOLog(@"player.setGalacticHyperspaceBehaviour.invalidInput", - @"setGalacticHyperspaceBehaviour: called with nil string specifier. Defaulting to Oolite standard."); - galacticHyperspaceBehaviour = GALACTIC_HYPERSPACE_BEHAVIOUR_STANDARD; - } - galacticHyperspaceBehaviour = StringToGalacticHyperspaceBehaviour(galacticHyperspaceBehaviourString); + if (EXPECT_NOT(inBehaviour <= GALACTIC_HYPERSPACE_BEHAVIOUR_UNKNOWN || inBehaviour > GALACTIC_HYPERSPACE_MAX)) + galacticHyperspaceBehaviour = inBehaviour; } @@ -6327,21 +6322,6 @@ OOSound* burnersound; } -- (void) setGalacticHyperspaceFixedCoords:(NSString *)galacticHyperspaceFixedCoordsString -{ - NSArray *coord_vals = ScanTokensFromString(galacticHyperspaceFixedCoordsString); - if ([coord_vals count] < 2) // Will be 0 if string is nil - { - OOLog(@"player.setGalacticHyperspaceFixedCoords.invalidInput", - @"setGalacticHyperspaceFixedCoords: called with bad specifier. Defaulting to Oolite standard."); - galacticHyperspaceFixedCoords.x = galacticHyperspaceFixedCoords.y = 0x60; - } - - [self setGalacticHyperspaceFixedCoordsX:[coord_vals unsignedCharAtIndex:0] - y:[coord_vals unsignedCharAtIndex:1]]; -} - - - (void) setGalacticHyperspaceFixedCoordsX:(unsigned char)x y:(unsigned char)y { galacticHyperspaceFixedCoords.x = x; diff --git a/src/Core/Entities/PlayerEntityLegacyScriptEngine.h b/src/Core/Entities/PlayerEntityLegacyScriptEngine.h index e9f436c6..ca8f9cc9 100644 --- a/src/Core/Entities/PlayerEntityLegacyScriptEngine.h +++ b/src/Core/Entities/PlayerEntityLegacyScriptEngine.h @@ -213,6 +213,9 @@ MA 02110-1301, USA. - (BOOL) mapKey:(NSString *) keycode toOXP:(OOScript *)oxp; - (void) targetNearestHostile; +- (void) setGalacticHyperspaceBehaviourTo:(NSString *) galacticHyperspaceBehaviourString; +- (void) setGalacticHyperspaceFixedCoordsTo:(NSString *) galacticHyperspaceFixedCoordsString; + /*-----------------------------------------------------*/ - (void) setGuiToMissionScreen; diff --git a/src/Core/Entities/PlayerEntityLegacyScriptEngine.m b/src/Core/Entities/PlayerEntityLegacyScriptEngine.m index 1cf94ebd..5bb349c0 100644 --- a/src/Core/Entities/PlayerEntityLegacyScriptEngine.m +++ b/src/Core/Entities/PlayerEntityLegacyScriptEngine.m @@ -2694,6 +2694,33 @@ static int scriptRandomSeed = -1; // ensure proper random function } } + +- (void) setGalacticHyperspaceBehaviourTo:(NSString *)galacticHyperspaceBehaviourString +{ + OOGalacticHyperspaceBehaviour ghBehaviour = StringToGalacticHyperspaceBehaviour(galacticHyperspaceBehaviourString); + if (ghBehaviour == GALACTIC_HYPERSPACE_BEHAVIOUR_UNKNOWN) + { + OOLog(@"player.setGalacticHyperspaceBehaviour.invalidInput", + @"setGalacticHyperspaceBehaviour: called with unknown behaviour %@.", galacticHyperspaceBehaviourString); + } + [self setGalacticHyperspaceBehaviour:ghBehaviour]; +} + + +- (void) setGalacticHyperspaceFixedCoordsTo:(NSString *)galacticHyperspaceFixedCoordsString +{ + NSArray *coord_vals = ScanTokensFromString(galacticHyperspaceFixedCoordsString); + if ([coord_vals count] < 2) // Will be 0 if string is nil + { + OOLog(@"player.setGalacticHyperspaceFixedCoords.invalidInput", + @"setGalacticHyperspaceFixedCoords: called with bad specifier. Defaulting to Oolite standard."); + galacticHyperspaceFixedCoords.x = galacticHyperspaceFixedCoords.y = 0x60; + } + + [self setGalacticHyperspaceFixedCoordsX:[coord_vals unsignedCharAtIndex:0] + y:[coord_vals unsignedCharAtIndex:1]]; +} + @end diff --git a/src/Core/Entities/PlayerEntityScriptMethods.h b/src/Core/Entities/PlayerEntityScriptMethods.h index 2a9c5db6..134b2187 100644 --- a/src/Core/Entities/PlayerEntityScriptMethods.h +++ b/src/Core/Entities/PlayerEntityScriptMethods.h @@ -45,6 +45,7 @@ MA 02110-1301, USA. - (NSString *) dockedStationDisplayName; - (BOOL) dockedAtMainStation; +- (BOOL) canAwardCargoType:(OOCargoType)type amount:(OOCargoQuantity)amount; - (void) awardCargoType:(OOCargoType)type amount:(OOCargoQuantity)amount; - (OOGalaxyID) currentGalaxyID; diff --git a/src/Core/Entities/PlayerEntityScriptMethods.m b/src/Core/Entities/PlayerEntityScriptMethods.m index 2ebd2066..a5ac2759 100644 --- a/src/Core/Entities/PlayerEntityScriptMethods.m +++ b/src/Core/Entities/PlayerEntityScriptMethods.m @@ -92,6 +92,19 @@ MA 02110-1301, USA. } +- (BOOL) canAwardCargoType:(OOCargoType)type amount:(OOCargoQuantity)amount +{ + if (type == CARGO_NOT_CARGO) return NO; + if ([UNIVERSE unitsForCommodity:type] == UNITS_TONS) + { + if ([self specialCargo] != nil) return NO; + if (amount > [self availableCargoSpace]) return NO; + } + + return YES; +} + + - (void) awardCargoType:(OOCargoType)type amount:(OOCargoQuantity)amount { OOMassUnit unit; diff --git a/src/Core/Entities/ShipEntity.h b/src/Core/Entities/ShipEntity.h index c7d1470c..aa521e12 100644 --- a/src/Core/Entities/ShipEntity.h +++ b/src/Core/Entities/ShipEntity.h @@ -507,6 +507,7 @@ MA 02110-1301, USA. - (OOCargoQuantity) commodityAmount; - (OOCargoQuantity) maxCargo; +- (OOCargoQuantity) availableCargoSpace; - (OOCargoType) cargoType; - (NSMutableArray *) cargo; - (void) setCargo:(NSArray *) some_cargo; diff --git a/src/Core/Entities/ShipEntity.m b/src/Core/Entities/ShipEntity.m index 2ed109a8..ec2bf204 100644 --- a/src/Core/Entities/ShipEntity.m +++ b/src/Core/Entities/ShipEntity.m @@ -3762,6 +3762,12 @@ NSComparisonResult planetSort(id i1, id i2, void* context) } +- (OOCargoQuantity) availableCargoSpace +{ + return [self maxCargo] - [[self cargo] count]; +} + + - (OOCargoType) cargoType { return cargo_type; @@ -7572,7 +7578,7 @@ static BOOL AuthorityPredicate(Entity *entity, void *parameter) { ShipEntity* ship = scanned_ships[i]; [ship receiveCommsMessage: expandedMessage]; - if (ship->isPlayer) + if ([ship isPlayer]) messageTime = 6.0; } [UNIVERSE resetCommsLogColor]; diff --git a/src/Core/OOConstToString.m b/src/Core/OOConstToString.m index 86b523f1..e4b2730b 100644 --- a/src/Core/OOConstToString.m +++ b/src/Core/OOConstToString.m @@ -444,7 +444,7 @@ OOGalacticHyperspaceBehaviour StringToGalacticHyperspaceBehaviour(NSString *stri REVERSE_CASE(GALACTIC_HYPERSPACE_BEHAVIOUR_ALL_SYSTEMS_REACHABLE); REVERSE_CASE(GALACTIC_HYPERSPACE_BEHAVIOUR_FIXED_COORDINATES); - return GALACTIC_HYPERSPACE_BEHAVIOUR_STANDARD; + return GALACTIC_HYPERSPACE_BEHAVIOUR_UNKNOWN; } diff --git a/src/Core/OOTypes.h b/src/Core/OOTypes.h index 656e5480..70e35da1 100644 --- a/src/Core/OOTypes.h +++ b/src/Core/OOTypes.h @@ -76,7 +76,10 @@ typedef enum { GALACTIC_HYPERSPACE_BEHAVIOUR_STANDARD, GALACTIC_HYPERSPACE_BEHAVIOUR_ALL_SYSTEMS_REACHABLE, - GALACTIC_HYPERSPACE_BEHAVIOUR_FIXED_COORDINATES + GALACTIC_HYPERSPACE_BEHAVIOUR_FIXED_COORDINATES, + + GALACTIC_HYPERSPACE_BEHAVIOUR_UNKNOWN = -1, + GALACTIC_HYPERSPACE_MAX = GALACTIC_HYPERSPACE_BEHAVIOUR_FIXED_COORDINATES } OOGalacticHyperspaceBehaviour; diff --git a/src/Core/Scripting/OOJSEntity.m b/src/Core/Scripting/OOJSEntity.m index d105a71d..66d8ff2f 100644 --- a/src/Core/Scripting/OOJSEntity.m +++ b/src/Core/Scripting/OOJSEntity.m @@ -220,31 +220,30 @@ BOOL EntityFromArgumentList(JSContext *context, NSString *scriptClass, NSString static JSBool EntityGetProperty(JSContext *context, JSObject *this, jsval name, jsval *outValue) { + BOOL OK = NO; Entity *entity = nil; id result = nil; if (!JSVAL_IS_INT(name)) return YES; - if (!JSEntityGetEntity(context, this, &entity)) return NO; // NOTE: entity may be nil. + if (EXPECT_NOT(!JSEntityGetEntity(context, this, &entity))) return NO; // NOTE: entity may be nil. switch (JSVAL_TO_INT(name)) { case kEntity_ID: *outValue = INT_TO_JSVAL([entity universalID]); + OK = YES; break; case kEntity_position: - VectorToJSValue(context, [entity position], outValue); + OK = VectorToJSValue(context, [entity position], outValue); break; case kEntity_orientation: - QuaternionToJSValue(context, [entity orientation], outValue); + OK = QuaternionToJSValue(context, [entity orientation], outValue); break; case kEntity_heading: - if (entity != nil) - { - VectorToJSValue(context, vector_forward_from_quaternion(entity->orientation), outValue); - } + OK = VectorToJSValue(context, vector_forward_from_quaternion([entity orientation]), outValue); break; case kEntity_status: @@ -256,7 +255,7 @@ static JSBool EntityGetProperty(JSContext *context, JSObject *this, jsval name, break; case kEntity_mass: - JS_NewDoubleValue(context, [entity mass], outValue); + OK = JS_NewDoubleValue(context, [entity mass], outValue); break; case kEntity_owner: @@ -266,66 +265,77 @@ static JSBool EntityGetProperty(JSContext *context, JSObject *this, jsval name, break; case kEntity_energy: - JS_NewDoubleValue(context, [entity energy], outValue); + OK = JS_NewDoubleValue(context, [entity energy], outValue); break; case kEntity_maxEnergy: - JS_NewDoubleValue(context, [entity maxEnergy], outValue); + OK = JS_NewDoubleValue(context, [entity maxEnergy], outValue); break; case kEntity_isValid: *outValue = BOOLToJSVal(entity != nil); + OK = YES; break; case kEntity_isShip: *outValue = BOOLToJSVal([entity isShip]); + OK = YES; break; case kEntity_isStation: *outValue = BOOLToJSVal([entity isStation]); + OK = YES; break; case kEntity_isSubEntity: *outValue = BOOLToJSVal([entity isSubEntity]); + OK = YES; break; case kEntity_isPlayer: *outValue = BOOLToJSVal([entity isPlayer]); + OK = YES; break; case kEntity_isPlanet: *outValue = BOOLToJSVal([entity isPlanet] && ![entity isSun]); + OK = YES; break; case kEntity_isSun: *outValue = BOOLToJSVal([entity isSun]); + OK = YES; break; case kEntity_distanceTravelled: - JS_NewDoubleValue(context, [entity distanceTravelled], outValue); + OK = JS_NewDoubleValue(context, [entity distanceTravelled], outValue); break; case kEntity_spawnTime: - JS_NewDoubleValue(context, [entity spawnTime], outValue); + OK = JS_NewDoubleValue(context, [entity spawnTime], outValue); break; default: OOReportJSBadPropertySelector(context, @"Entity", JSVAL_TO_INT(name)); - return NO; } - if (result != nil) *outValue = [result javaScriptValueInContext:context]; - return YES; + if (result != nil) + { + *outValue = [result javaScriptValueInContext:context]; + OK = YES; + } + return OK; } static JSBool EntitySetProperty(JSContext *context, JSObject *this, jsval name, jsval *value) { + BOOL OK = NO; Entity *entity = nil; double fValue; if (!JSVAL_IS_INT(name)) return YES; - if (!JSEntityGetEntity(context, this, &entity)) return NO; + if (EXPECT_NOT(!JSEntityGetEntity(context, this, &entity))) return NO; switch (JSVAL_TO_INT(name)) { @@ -334,56 +344,64 @@ static JSBool EntitySetProperty(JSContext *context, JSObject *this, jsval name, { fValue = OOClamp_0_max_d(fValue, [entity maxEnergy]); [entity setEnergy:fValue]; + OK = YES; } break; default: OOReportJSBadPropertySelector(context, @"Entity", JSVAL_TO_INT(name)); - return NO; } - return YES; + return OK; } // *** Methods *** +// setPosition(position : vectorExpression) static JSBool EntitySetPosition(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult) { - Entity *thisEnt; + Entity *thisEnt = nil; Vector vector; if (!JSEntityGetEntity(context, this, &thisEnt)) return YES; // stale reference, no-op. - if (!VectorFromArgumentList(context, @"Entity", @"setPosition", argc, argv, &vector, NULL)) return YES; + if (EXPECT_NOT(!VectorFromArgumentList(context, @"Entity", @"setPosition", argc, argv, &vector, NULL))) return NO; [thisEnt setPosition:vector]; return YES; } +// setOrientation(orientation : quaternionExpression) static JSBool EntitySetOrientation(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult) { - Entity *thisEnt; + Entity *thisEnt = nil; Quaternion quaternion; if (!JSEntityGetEntity(context, this, &thisEnt)) return YES; // stale reference, no-op. - if (!QuaternionFromArgumentList(context, @"Entity", @"setOrientation", argc, argv, &quaternion, NULL)) return YES; + if (EXPECT_NOT(!QuaternionFromArgumentList(context, @"Entity", @"setOrientation", argc, argv, &quaternion, NULL))) return NO; [thisEnt setOrientation:quaternion]; return YES; } +// *** Static methods *** + +// entityWithID(ID : Number) : Entity static JSBool EntityStaticEntityWithID(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult) { Entity *result = nil; int32 ID; - if (JS_ValueToInt32(context, *argv, &ID)) + if (EXPECT_NOT(!JS_ValueToInt32(context, *argv, &ID))) { - result = [UNIVERSE entityForUniversalID:ID]; + OOReportJSBadArguments(context, @"Entity", @"entityWithID", argc, argv, @"Invalid entity ID", @"integer"); + return NO; } + result = [UNIVERSE entityForUniversalID:ID]; if (result != nil) *outResult = [result javaScriptValueInContext:context]; + else *outResult = JSVAL_NULL; return YES; } diff --git a/src/Core/Scripting/OOJSPlanet.m b/src/Core/Scripting/OOJSPlanet.m index 1c92c63a..8d89ea77 100644 --- a/src/Core/Scripting/OOJSPlanet.m +++ b/src/Core/Scripting/OOJSPlanet.m @@ -37,7 +37,6 @@ static BOOL JSPlanetGetPlanetEntity(JSContext *context, JSObject *PlanetObj, Pla static JSBool PlanetGetProperty(JSContext *context, JSObject *this, jsval name, jsval *outValue); -static JSBool PlanetSetProperty(JSContext *context, JSObject *this, jsval name, jsval *value); static JSBool PlanetSetTexture(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult); @@ -51,7 +50,7 @@ static JSExtendedClass sPlanetClass = JS_PropertyStub, // addProperty JS_PropertyStub, // delProperty PlanetGetProperty, // getProperty - PlanetSetProperty, // setProperty + JS_PropertyStub, // setProperty JS_EnumerateStub, // enumerate JS_ResolveStub, // resolve JS_ConvertStub, // convert @@ -149,6 +148,7 @@ static BOOL JSPlanetGetPlanetEntity(JSContext *context, JSObject *stationObj, Pl static JSBool PlanetGetProperty(JSContext *context, JSObject *this, jsval name, jsval *outValue) { + BOOL OK = NO; PlanetEntity *planet = nil; if (!JSVAL_IS_INT(name)) return YES; @@ -158,40 +158,22 @@ static JSBool PlanetGetProperty(JSContext *context, JSObject *this, jsval name, { case kPlanet_isMainPlanet: *outValue = BOOLToJSVal(planet == [UNIVERSE planet]); + OK = YES; break; case kPlanet_radius: - JS_NewDoubleValue(context, [planet radius], outValue); + OK = JS_NewDoubleValue(context, [planet radius], outValue); break; case kPlanet_hasAtmosphere: *outValue = BOOLToJSVal([planet hasAtmosphere]); + OK = YES; break; default: OOReportJSBadPropertySelector(context, @"Planet", JSVAL_TO_INT(name)); - return NO; } - return YES; -} - - -static JSBool PlanetSetProperty(JSContext *context, JSObject *this, jsval name, jsval *value) -{ - PlanetEntity *entity = nil; - - if (!JSVAL_IS_INT(name)) return YES; - if (!JSPlanetGetPlanetEntity(context, this, &entity)) return NO; - - switch (JSVAL_TO_INT(name)) - { - - default: - OOReportJSBadPropertySelector(context, @"Planet", JSVAL_TO_INT(name)); - return NO; - } - - return YES; + return OK; } @@ -199,26 +181,22 @@ static JSBool PlanetSetTexture(JSContext *context, JSObject *this, uintN argc, j { PlanetEntity *thisEnt = nil; NSString *name = nil; - PlayerEntity *player = [PlayerEntity sharedPlayer]; - + PlayerEntity *player = [PlayerEntity sharedPlayer]; if (!JSPlanetGetPlanetEntity(context, this, &thisEnt)) return YES; // stale reference, no-op. name = [NSString stringWithJavaScriptValue:*argv inContext:context]; if([player status] != STATUS_LAUNCHING && [player status] != STATUS_EXITING_WITCHSPACE) { OOReportJSError(context, @"Planet.%@ must be called only during shipWillLaunchFromStation or shipWillExitWitchspace.", @"setTexture"); - return YES; } - if (name != nil) + else if (name != nil) { - if (![thisEnt setUpPlanetFromTexture:name]) - { - OOReportJSError(context, @"Planet.%@(\"%@\"): cannot set texture for planet.", @"setTexture", name); - } + if ([thisEnt setUpPlanetFromTexture:name]) return YES; + else OOReportJSError(context, @"Planet.%@(\"%@\"): cannot set texture for planet.", @"setTexture", name); } else { OOReportJSError(context, @"Planet.%@(): no texture name specified.", @"setTexture"); } - return YES; + return NO; } diff --git a/src/Core/Scripting/OOJSPlayer.m b/src/Core/Scripting/OOJSPlayer.m index 950fad84..d56d1bbf 100644 --- a/src/Core/Scripting/OOJSPlayer.m +++ b/src/Core/Scripting/OOJSPlayer.m @@ -33,6 +33,7 @@ MA 02110-1301, USA. #import "PlayerEntityScriptMethods.h" #import "PlayerEntityLegacyScriptEngine.h" +#import "OOConstToString.h" #import "OOFunctionAttributes.h" @@ -50,6 +51,7 @@ static JSBool PlayerEquipmentStatus(JSContext *context, JSObject *this, uintN ar static JSBool PlayerSetEquipmentStatus(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult); static JSBool PlayerLaunch(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult); static JSBool PlayerAwardCargo(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult); +static JSBool PlayerCanAwardCargo(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult); static JSBool PlayerRemoveAllCargo(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult); static JSBool PlayerUseSpecialCargo(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult); static JSBool PlayerCommsMessage(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult); @@ -100,6 +102,7 @@ enum kPlayer_alertEnergy, // low energy alert flag, boolean, read-only kPlayer_alertHostiles, // hostiles present alert flag, boolean, read-only kPlayer_trumbleCount, // number of trumbles, integer, read-only + kPlayer_specialCargo, // special cargo, string, read-only kPlayer_galacticHyperspaceBehaviour, // can be standard, all systems reachable or fixed coordinates, integer, read-only kPlayer_galacticHyperspaceFixedCoords, // used when fixed coords behaviour is selected, vector, read-only }; @@ -121,6 +124,7 @@ static JSPropertySpec sPlayerProperties[] = { "alertEnergy", kPlayer_alertEnergy, JSPROP_PERMANENT | JSPROP_ENUMERATE | JSPROP_READONLY }, { "alertHostiles", kPlayer_alertHostiles, JSPROP_PERMANENT | JSPROP_ENUMERATE | JSPROP_READONLY }, { "trumbleCount", kPlayer_trumbleCount, JSPROP_PERMANENT | JSPROP_ENUMERATE | JSPROP_READONLY }, + { "specialCargo", kPlayer_specialCargo, JSPROP_PERMANENT | JSPROP_ENUMERATE | JSPROP_READONLY }, { "galacticHyperspaceBehaviour", kPlayer_galacticHyperspaceBehaviour, JSPROP_PERMANENT | JSPROP_ENUMERATE | JSPROP_READONLY }, { "galacticHyperspaceFixedCoords", kPlayer_galacticHyperspaceFixedCoords, JSPROP_PERMANENT | JSPROP_ENUMERATE | JSPROP_READONLY }, { 0 } @@ -136,7 +140,8 @@ static JSFunctionSpec sPlayerMethods[] = { "equipmentStatus", PlayerEquipmentStatus, 1 }, { "setEquipmentStatus", PlayerSetEquipmentStatus, 2 }, { "launch", PlayerLaunch, 0 }, - { "awardCargo", PlayerAwardCargo, 2 }, + { "awardCargo", PlayerAwardCargo, 1 }, + { "canAwardCargo", PlayerCanAwardCargo, 1 }, { "removeAllCargo", PlayerRemoveAllCargo, 0 }, { "useSpecialCargo", PlayerUseSpecialCargo, 1 }, { "commsMessage", PlayerCommsMessage, 1 }, @@ -216,6 +221,7 @@ PlayerEntity *OOPlayerForScripting(void) static JSBool PlayerGetProperty(JSContext *context, JSObject *this, jsval name, jsval *outValue) { + BOOL OK = NO; id result = nil; PlayerEntity *player = OOPlayerForScripting(); @@ -225,77 +231,92 @@ static JSBool PlayerGetProperty(JSContext *context, JSObject *this, jsval name, { case kPlayer_name: result = [player playerName]; + OK = YES; break; case kPlayer_score: *outValue = INT_TO_JSVAL([player score]); + OK = YES; break; case kPlayer_credits: - JS_NewDoubleValue(context, [player creditBalance], outValue); + OK = JS_NewDoubleValue(context, [player creditBalance], outValue); break; case kPlayer_fuelLeakRate: - JS_NewDoubleValue(context, [player fuelLeakRate], outValue); + OK = JS_NewDoubleValue(context, [player fuelLeakRate], outValue); break; case kPlayer_alertCondition: *outValue = INT_TO_JSVAL([player alertCondition]); + OK = YES; break; case kPlayer_docked: *outValue = BOOLToJSVal([player isDocked]); + OK = YES; break; case kPlayer_dockedStation: result = [player dockedStation]; if (result == nil) result = [NSNull null]; + OK = YES; break; case kPlayer_alertTemperature: *outValue = BOOLToJSVal([player alertFlags] & ALERT_FLAG_TEMP); + OK = YES; break; case kPlayer_alertMassLocked: *outValue = BOOLToJSVal([player alertFlags] & ALERT_FLAG_MASS_LOCK); + OK = YES; break; case kPlayer_alertAltitude: *outValue = BOOLToJSVal([player alertFlags] & ALERT_FLAG_ALT); + OK = YES; break; case kPlayer_alertEnergy: *outValue = BOOLToJSVal([player alertFlags] & ALERT_FLAG_ENERGY); + OK = YES; break; case kPlayer_alertHostiles: *outValue = BOOLToJSVal([player alertFlags] & ALERT_FLAG_HOSTILES); + OK = YES; break; case kPlayer_trumbleCount: - JS_NewNumberValue(context, [player trumbleCount], outValue); + OK = JS_NewNumberValue(context, [player trumbleCount], outValue); + break; + + case kPlayer_specialCargo: + result = [player specialCargo]; + OK = YES; break; case kPlayer_galacticHyperspaceBehaviour: - JS_NewNumberValue(context, [player galacticHyperspaceBehaviour], outValue); + OK = JS_NewNumberValue(context, [player galacticHyperspaceBehaviour], outValue); break; case kPlayer_galacticHyperspaceFixedCoords: - NSPointToVectorJSValue(context, [player galacticHyperspaceFixedCoords], outValue); + OK = NSPointToVectorJSValue(context, [player galacticHyperspaceFixedCoords], outValue); break; default: OOReportJSBadPropertySelector(context, @"Player", JSVAL_TO_INT(name)); - return NO; } - if (result != nil) *outValue = [result javaScriptValueInContext:context]; - return YES; + if (OK && result != nil) *outValue = [result javaScriptValueInContext:context]; + return OK; } static JSBool PlayerSetProperty(JSContext *context, JSObject *this, jsval name, jsval *value) { + BOOL OK = NO; PlayerEntity *player = OOPlayerForScripting(); jsdouble fValue; int32 iValue; @@ -309,6 +330,7 @@ static JSBool PlayerSetProperty(JSContext *context, JSObject *this, jsval name, { iValue = MAX(iValue, 0); [player setScore:iValue]; + OK = YES; } break; @@ -316,6 +338,7 @@ static JSBool PlayerSetProperty(JSContext *context, JSObject *this, jsval name, if (JS_ValueToNumber(context, *value, &fValue)) { [player setCreditBalance:fValue]; + OK = YES; } break; @@ -323,94 +346,152 @@ static JSBool PlayerSetProperty(JSContext *context, JSObject *this, jsval name, if (JS_ValueToNumber(context, *value, &fValue)) { [player setFuelLeakRate:fValue]; + OK = YES; } break; default: OOReportJSBadPropertySelector(context, @"Player", JSVAL_TO_INT(name)); - return NO; } - return YES; + return OK; } +// *** Methods *** + +// awardEquipment(key : String) static JSBool PlayerAwardEquipment(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult) { - [OOPlayerForScripting() awardEquipment:JSValToNSString(context, argv[0])]; + PlayerEntity *player = OOPlayerForScripting(); + NSString *key = nil; + + key = JSValToNSString(context, argv[0]); + if (EXPECT_NOT(key == nil)) + { + OOReportJSBadArguments(context, @"Player", @"awardEquipment", argc, argv, @"Invalid arguments", @"equipment key"); + return NO; + } + + [player awardEquipment:key]; return YES; } +// removeEquipment(key : String) static JSBool PlayerRemoveEquipment(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult) { - [OOPlayerForScripting() removeEquipmentItem:JSValToNSString(context, argv[0])]; + PlayerEntity *player = OOPlayerForScripting(); + NSString *key = nil; + + key = JSValToNSString(context, argv[0]); + if (EXPECT_NOT(key == nil)) + { + OOReportJSBadArguments(context, @"Player", @"removeEquipment", argc, argv, @"Invalid arguments", @"equipment key"); + return NO; + } + + [player removeEquipmentItem:key]; return YES; } +// hasEquipment(key : String) : Boolean static JSBool PlayerHasEquipment(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult) { - *outResult = BOOLToJSVal([OOPlayerForScripting() hasEquipmentItem:JSValToNSString(context, argv[0])]); + PlayerEntity *player = OOPlayerForScripting(); + NSString *key = nil; + + key = JSValToNSString(context, argv[0]); + if (EXPECT_NOT(key == nil)) + { + OOReportJSBadArguments(context, @"Player", @"hasEquipment", argc, argv, @"Invalid arguments", @"equipment key"); + return NO; + } + + *outResult = BOOLToJSVal([player hasEquipmentItem:key]); return YES; } +// setEquipmentStatus(key : String, status : String) static JSBool PlayerSetEquipmentStatus(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult) { // equipment status accepted: @"EQUIPMENT_OK", @"EQUIPMENT_DAMAGED" - NSString *name = JSValToNSString(context, argv[0]); - NSString *damagedName = [NSString stringWithFormat:@"%@_DAMAGED",name]; + PlayerEntity *player = OOPlayerForScripting(); + NSString *key = JSValToNSString(context, argv[0]); + NSString *damagedKey = [key stringByAppendingString:@"_DAMAGED"]; NSString *status = JSValToNSString(context, argv[1]); - BOOL statusSet = NO; + BOOL hasOK = NO, hasDamaged = NO; - if ([UNIVERSE strict]) + if (EXPECT_NOT([UNIVERSE strict])) { + // It's OK to have a hard error here since only built-in scripts run in strict mode. OOReportJSError(context, @"Cannot set equipment status while in strict mode."); - *outResult = BOOLToJSVal(NO); - return YES; + return NO; } - if([status isEqualToString:@"EQUIPMENT_OK"] || [status isEqualToString:@"EQUIPMENT_DAMAGED"]) + if (EXPECT_NOT(key == nil || status == nil)) { - if([OOPlayerForScripting() hasEquipmentItem:name]&&[status isEqualToString:@"EQUIPMENT_DAMAGED"]) + OOReportJSBadArguments(context, @"Player", @"setEquipmentStatus", argc, argv, @"Invalid arguments", @"equipment key and status"); + return NO; + } + + hasOK = [player hasEquipmentItem:key]; + hasDamaged = [player hasEquipmentItem:damagedKey]; + + if ([status isEqualToString:@"EQUIPMENT_OK"]) + { + if (hasDamaged) { - [OOPlayerForScripting() removeEquipmentItem:name]; - //[UNIVERSE addMessage:[NSString stringWithFormat:ExpandDescriptionForCurrentSystem(@"[@-damaged]"), name] forCount:4.5]; - [OOPlayerForScripting() addEquipmentItem:damagedName]; + [player removeEquipmentItem:damagedKey]; + [player addEquipmentItem:key]; } - if([OOPlayerForScripting() hasEquipmentItem:damagedName] && [status isEqualToString:@"EQUIPMENT_OK"]) + } + else if ([status isEqualToString:@"EQUIPMENT_DAMAGED"]) + { + if (hasOK) { - [OOPlayerForScripting() removeEquipmentItem:damagedName]; - [OOPlayerForScripting() addEquipmentItem:name]; + [player removeEquipmentItem:key]; + [player addEquipmentItem:damagedKey]; } - statusSet = [OOPlayerForScripting() hasEquipmentItem:name] || [OOPlayerForScripting() hasEquipmentItem:damagedName]; } else - OOReportJSError(context, @"Second parameter for setEquipmentStatus must be either \"EQUIPMENT_OK\" or \"EQUIPMENT_DAMAGED\"."); - - *outResult = BOOLToJSVal(statusSet); - + { + OOReportJSErrorForCaller(context, @"Player", @"setEquipmentStatus", @"Second parameter for setEquipmentStatus must be either \"EQUIPMENT_OK\" or \"EQUIPMENT_DAMAGED\"."); + return NO; + } + + *outResult = BOOLToJSVal(hasOK || hasDamaged); return YES; } +// equipmentStatus(key : String) : String static JSBool PlayerEquipmentStatus(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult) { // values returned: @"EQUIPMENT_OK", @"EQUIPMENT_DAMAGED", @"EQUIPMENT_UNAVAILABLE" - - NSString *name = JSValToNSString(context, argv[0]); - NSString *result =@"EQUIPMENT_UNAVAILABLE"; - if([OOPlayerForScripting() hasEquipmentItem:name]) result = @"EQUIPMENT_OK"; - if([OOPlayerForScripting() hasEquipmentItem:[NSString stringWithFormat:@"%@_DAMAGED",name]]) result = @"EQUIPMENT_DAMAGED"; - + PlayerEntity *player = OOPlayerForScripting(); + NSString *key = JSValToNSString(context, argv[0]); + NSString *result = @"EQUIPMENT_UNAVAILABLE"; + + if (EXPECT_NOT(key == nil)) + { + OOReportJSBadArguments(context, @"Player", @"setEquipmentStatus", argc, argv, @"Invalid arguments", @"equipment key"); + return NO; + } + + if([player hasEquipmentItem:key]) result = @"EQUIPMENT_OK"; + else if([player hasEquipmentItem:[key stringByAppendingString:@"_DAMAGED"]]) result = @"EQUIPMENT_DAMAGED"; + *outResult = [result javaScriptValueInContext:context]; return YES; } +// launch() static JSBool PlayerLaunch(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult) { [OOPlayerForScripting() launchFromStation]; @@ -418,46 +499,83 @@ static JSBool PlayerLaunch(JSContext *context, JSObject *this, uintN argc, jsval } +// awardCargo(type : String [, quantity : Number]) static JSBool PlayerAwardCargo(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult) { + PlayerEntity *player = OOPlayerForScripting(); NSString *typeString = nil; OOCargoType type; - OOMassUnit unit; - int32 amount; + int32 amount = 1; + BOOL gotAmount = YES; typeString = JSValToNSString(context, argv[0]); + if (argc > 1) gotAmount = JS_ValueToInt32(context, argv[1], &amount); + if (EXPECT_NOT(typeString == nil || !gotAmount)) + { + OOReportJSBadArguments(context, @"Player", @"awardCargo", argc, argv, @"Invalid arguments", @"type and optional quantity"); + return NO; + } + type = [UNIVERSE commodityForName:typeString]; - if (type == NSNotFound) + if (EXPECT_NOT(type == NSNotFound)) { - OOReportJSError(context, @"Unknown cargo type \"%@\".", typeString); - return YES; + OOReportJSErrorForCaller(context, @"Player", @"awardCargo", @"Unknown cargo type \"%@\".", typeString); + return NO; } - if (!JS_ValueToInt32(context, argv[1], &amount)) + if (EXPECT_NOT(amount < 0)) { - OOReportJSError(context, @"Expected cargo quantity (integer), got \"%@\".", JSValToNSString(context, argv[1])); - return YES; + OOReportJSErrorForCaller(context, @"Player", @"awardCargo", @"Cargo quantity (%i) is negative.", amount); + return NO; } - if (amount < 0) + if (EXPECT_NOT(![player canAwardCargoType:type amount:amount])) { - OOReportJSError(context, @"Cargo quantity (%i) is negative.", amount); - return YES; - } - - unit = [UNIVERSE unitsForCommodity:type]; - if ([OOPlayerForScripting() specialCargo] != nil && unit == UNITS_TONS) - { - OOReportJSError(context, @"Cargo hold full with special cargo, cannot award \"%@\".", typeString); - return YES; + OOReportJSErrorForCaller(context, @"Player", @"awardCargo", @"Cannot award %u units of cargo \"%@\" at this time (use canAwardCargo() to avoid this error).", amount, typeString); + return NO; } - [OOPlayerForScripting() awardCargoType:type amount:amount]; - + [player awardCargoType:type amount:amount]; return YES; } +// canAwardCargo(type : String [, quantity : Number]) : Boolean +static JSBool PlayerCanAwardCargo(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult) +{ + PlayerEntity *player = OOPlayerForScripting(); + NSString *typeString = nil; + OOCargoType type; + int32 amount = 1; + BOOL gotAmount = YES; + + typeString = JSValToNSString(context, argv[0]); + if (argc > 1) gotAmount = JS_ValueToInt32(context, argv[1], &amount); + if (EXPECT_NOT(typeString == nil || !gotAmount)) + { + OOReportJSBadArguments(context, @"Player", @"canAwardCargo", argc, argv, @"Invalid arguments", @"type and optional quantity"); + return NO; + } + + type = [UNIVERSE commodityForName:typeString]; + if (EXPECT_NOT(type == NSNotFound)) + { + OOReportJSErrorForCaller(context, @"Player", @"canAwardCargo", @"Unknown cargo type \"%@\".", typeString); + return NO; + } + + if (EXPECT_NOT(amount < 0)) + { + OOReportJSErrorForCaller(context, @"Player", @"canAwardCargo", @"Cargo quantity (%i) is negative.", amount); + return NO; + } + + *outResult = BOOLToJSVal([player canAwardCargoType:type amount:amount]); + return YES; +} + + +// removeAllCargo() static JSBool PlayerRemoveAllCargo(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult) { PlayerEntity *player = OOPlayerForScripting(); @@ -465,71 +583,95 @@ static JSBool PlayerRemoveAllCargo(JSContext *context, JSObject *this, uintN arg if ([player isDocked]) { [player removeAllCargo]; + return YES; } else { OOReportJSError(context, @"Player.removeAllCargo() may only be called when the player is docked."); + return NO; } - return YES; } +// useSpecialCargo(name : String) static JSBool PlayerUseSpecialCargo(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult) { - [OOPlayerForScripting() useSpecialCargo:JSValToNSString(context, argv[0])]; + PlayerEntity *player = OOPlayerForScripting(); + NSString *name = nil; + + name = JSValToNSString(context, argv[0]); + if (EXPECT_NOT(name == nil)) + { + OOReportJSBadArguments(context, @"Player", @"useSpecialCargo", argc, argv, @"Invalid arguments", @"special cargo description"); + return NO; + } + + [player useSpecialCargo:JSValToNSString(context, argv[0])]; return YES; } -// commsMessage(message : String [, duration : Number]) : void +// commsMessage(message : String [, duration : Number]) static JSBool PlayerCommsMessage(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult) { - const double kDefaultTime = 4.5; NSString *message = nil; - double time = kDefaultTime; + double time = 4.5; + BOOL gotTime = YES; - message = [NSString stringWithJavaScriptValue:argv[0] inContext:context]; - if (message != nil) + message = JSValToNSString(context, argv[0]); + if (argc > 1) gotTime = JS_ValueToNumber(context, argv[1], &time); + if (EXPECT_NOT(message == nil || !gotTime)) { - if (1 < argc) - { - if (!JS_ValueToNumber(context, argv[1], &time)) time = kDefaultTime; - if (time < 1.0) time = 1.0; - if (12.0 < time) time = 10.0; - } - - [UNIVERSE addCommsMessage:message forCount:time]; + OOReportJSBadArguments(context, @"Player", @"commsMessage", argc, argv, @"Invalid arguments", @"message and optional duration"); + return NO; } + + [UNIVERSE addCommsMessage:message forCount:time]; return YES; } -// consoleMessage(message : String [, duration : Number]) : void +// commsMessage(message : String [, duration : Number]) static JSBool PlayerConsoleMessage(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult) { - const double kDefaultTime = 3; NSString *message = nil; - double time = kDefaultTime; + double time = 3.0; + BOOL gotTime = YES; - message = [NSString stringWithJavaScriptValue:argv[0] inContext:context]; - if (message != nil) + message = JSValToNSString(context, argv[0]); + if (argc > 1) gotTime = JS_ValueToNumber(context, argv[1], &time); + if (EXPECT_NOT(message == nil || !gotTime)) { - if (1 < argc) - { - if (!JS_ValueToNumber(context, argv[1], &time)) time = kDefaultTime; - if (time < 1.0) time = 1.0; - if (12.0 < time) time = 10.0; - } - - [UNIVERSE addMessage:message forCount:time]; + OOReportJSBadArguments(context, @"Player", @"commsMessage", argc, argv, @"Invalid arguments", @"message and optional duration"); + return NO; } + + [UNIVERSE addMessage:message forCount:time]; return YES; } +// setGalacticHyperspaceBehaviour(behaviour : String) static JSBool PlayerSetGalacticHyperspaceBehaviour(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult) { - [OOPlayerForScripting() setGalacticHyperspaceBehaviour:JSValToNSString(context, argv[0])]; + PlayerEntity *player = OOPlayerForScripting(); + NSString *behavString = nil; + OOGalacticHyperspaceBehaviour behaviour; + + behavString = JSValToNSString(context, argv[0]); + if (EXPECT_NOT(behavString == nil)) + { + OOReportJSBadArguments(context, @"Player", @"setGalacticHyperspaceBehaviour", argc, argv, @"Invalid arguments", @"behaviour name"); + return NO; + } + + behaviour = StringToGalacticHyperspaceBehaviour(behavString); + if (behaviour == GALACTIC_HYPERSPACE_BEHAVIOUR_UNKNOWN) + { + OOReportJSErrorForCaller(context, @"Player", @"setGalacticHyperspaceBehaviour", @"Unknown galactic hyperspace behaviour name %@.", behavString); + } + + [player setGalacticHyperspaceBehaviour:behaviour]; return YES; } @@ -537,19 +679,28 @@ static JSBool PlayerSetGalacticHyperspaceBehaviour(JSContext *context, JSObject // setGalacticHyperspaceFixedCoords(v : vectorExpression) or setGalacticHyperspaceFixedCoords(x : Number, y : Number) static JSBool PlayerSetGalacticHyperspaceFixedCoords(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult) { - double x, y; - Vector v; + PlayerEntity *player = OOPlayerForScripting(); + double x, y; + Vector v; if (argc == 2) { // Expect two integers - if (!JS_ValueToNumber(context, argv[0], &x)) x = 0x60; - if (!JS_ValueToNumber(context, argv[1], &y)) y = 0x60; + if (EXPECT_NOT(!JS_ValueToNumber(context, argv[0], &x) || + !JS_ValueToNumber(context, argv[1], &y))) + { + OOReportJSBadArguments(context, @"Player", @"setGalacticHyperspaceFixedCoords", argc, argv, @"Invalid arguments", @"vector expression or two numbers"); + return NO; + } } else { // Expect vectorExpression - if (!VectorFromArgumentList(context, @"Player", @"setGalacticHyperspaceFixedCoords", argc, argv, &v, NULL)) v = make_vector(0x60, 0x60, 0); + if (EXPECT_NOT(!VectorFromArgumentList(context, @"Player", @"setGalacticHyperspaceFixedCoords", argc, argv, &v, NULL))) + { + OOReportJSBadArguments(context, @"Player", @"setGalacticHyperspaceFixedCoords", argc, argv, @"Invalid arguments", @"vector expression or two numbers"); + return NO; + } x = v.x; y = v.y; } @@ -557,6 +708,6 @@ static JSBool PlayerSetGalacticHyperspaceFixedCoords(JSContext *context, JSObjec x = OOClamp_0_max_d(x, 255); y = OOClamp_0_max_d(y, 255); - [OOPlayerForScripting() setGalacticHyperspaceFixedCoordsX:x y:y]; + [player setGalacticHyperspaceFixedCoordsX:x y:y]; return YES; } diff --git a/src/Core/Scripting/OOJSShip.m b/src/Core/Scripting/OOJSShip.m index cf94a701..c06ea5e6 100644 --- a/src/Core/Scripting/OOJSShip.m +++ b/src/Core/Scripting/OOJSShip.m @@ -237,12 +237,13 @@ JSObject *JSShipPrototype(void) static JSBool ShipGetProperty(JSContext *context, JSObject *this, jsval name, jsval *outValue) { + BOOL OK = NO; ShipEntity *entity = nil; id result = nil; if (!JSVAL_IS_INT(name)) return YES; - if (!JSShipGetShipEntity(context, this, &entity)) return NO; // NOTE: entity may be nil. - if (!JS_EnterLocalRootScope(context)) return NO; + if (EXPECT_NOT(!JSShipGetShipEntity(context, this, &entity))) return NO; // NOTE: entity may be nil. + if (EXPECT_NOT(!JS_EnterLocalRootScope(context))) return NO; switch (JSVAL_TO_INT(name)) { @@ -275,7 +276,7 @@ static JSBool ShipGetProperty(JSContext *context, JSObject *this, jsval name, js break; case kShip_fuel: - JS_NewDoubleValue(context, [entity fuel] * 0.1, outValue); + OK = JS_NewDoubleValue(context, [entity fuel] * 0.1, outValue); break; case kShip_bounty: @@ -289,6 +290,7 @@ static JSBool ShipGetProperty(JSContext *context, JSObject *this, jsval name, js case kShip_hasSuspendedAI: *outValue = BOOLToJSVal([[entity getAI] hasSuspendedStateMachines]); + OK = YES; break; case kShip_target: @@ -302,19 +304,21 @@ static JSBool ShipGetProperty(JSContext *context, JSObject *this, jsval name, js break; case kShip_temperature: - JS_NewDoubleValue(context, [entity temperature] / SHIP_MAX_CABIN_TEMP, outValue); + OK = JS_NewDoubleValue(context, [entity temperature] / SHIP_MAX_CABIN_TEMP, outValue); break; case kShip_heatInsulation: - JS_NewDoubleValue(context, [entity heatInsulation], outValue); + OK = JS_NewDoubleValue(context, [entity heatInsulation], outValue); break; case kShip_entityPersonality: *outValue = INT_TO_JSVAL([entity entityPersonalityInt]); + OK = YES; break; case kShip_isBeacon: *outValue = BOOLToJSVal([entity isBeacon]); + OK = YES; break; case kShip_beaconCode: @@ -324,18 +328,22 @@ static JSBool ShipGetProperty(JSContext *context, JSObject *this, jsval name, js case kShip_isFrangible: *outValue = BOOLToJSVal([entity isFrangible]); + OK = YES; break; case kShip_isCloaked: *outValue = BOOLToJSVal([entity isCloaked]); + OK = YES; break; case kShip_isJamming: *outValue = BOOLToJSVal([entity isJammingScanning]); + OK = YES; break; case kShip_groupID: *outValue = INT_TO_JSVAL([entity groupID]); + OK = YES; break; case kShip_potentialCollider: @@ -345,67 +353,79 @@ static JSBool ShipGetProperty(JSContext *context, JSObject *this, jsval name, js case kShip_hasHostileTarget: *outValue = BOOLToJSVal([entity hasHostileTarget]); + OK = YES; break; case kShip_weaponRange: - JS_NewDoubleValue(context, [entity weaponRange], outValue); + OK = JS_NewDoubleValue(context, [entity weaponRange], outValue); + OK = YES; break; case kShip_scannerRange: - JS_NewDoubleValue(context, [entity scannerRange], outValue); + OK = JS_NewDoubleValue(context, [entity scannerRange], outValue); + OK = YES; break; case kShip_reportAIMessages: *outValue = BOOLToJSVal([entity reportAIMessages]); + OK = YES; break; case kShip_withinStationAegis: *outValue = BOOLToJSVal([entity withinStationAegis]); + OK = YES; break; case kShip_maxCargo: *outValue = INT_TO_JSVAL([entity maxCargo]); + OK = YES; break; case kShip_speed: - JS_NewDoubleValue(context, [entity flightSpeed], outValue); + OK = JS_NewDoubleValue(context, [entity flightSpeed], outValue); break; case kShip_desiredSpeed: - JS_NewDoubleValue(context, [entity desiredSpeed], outValue); + OK = JS_NewDoubleValue(context, [entity desiredSpeed], outValue); break; case kShip_maxSpeed: - JS_NewDoubleValue(context, [entity maxFlightSpeed], outValue); + OK = JS_NewDoubleValue(context, [entity maxFlightSpeed], outValue); break; case kShip_script: result = [entity shipScript]; if (result == nil) result = [NSNull null]; - break; + break; case kShip_isPirate: *outValue = BOOLToJSVal([entity isPirate]); + OK = YES; break; case kShip_isPlayer: *outValue = BOOLToJSVal([entity isPlayer]); + OK = YES; break; case kShip_isPolice: *outValue = BOOLToJSVal([entity isPolice]); + OK = YES; break; case kShip_isThargoid: *outValue = BOOLToJSVal([entity isThargoid]); + OK = YES; break; case kShip_isTrader: *outValue = BOOLToJSVal([entity isTrader]); + OK = YES; break; case kShip_isPirateVictim: *outValue = BOOLToJSVal([entity isPirateVictim]); + OK = YES; break; case kShip_scriptInfo: @@ -415,21 +435,26 @@ static JSBool ShipGetProperty(JSContext *context, JSObject *this, jsval name, js case kShip_trackCloseContacts: *outValue = BOOLToJSVal([entity trackCloseContacts]); + OK = YES; break; default: OOReportJSBadPropertySelector(context, @"Ship", JSVAL_TO_INT(name)); - return NO; } - if (result != nil) *outValue = [result javaScriptValueInContext:context]; + if (result != nil) + { + *outValue = [result javaScriptValueInContext:context]; + OK = YES; + } JS_LeaveLocalRootScope(context); - return YES; + return OK; } static JSBool ShipSetProperty(JSContext *context, JSObject *this, jsval name, jsval *value) { + BOOL OK = NO; ShipEntity *entity = nil; ShipEntity *target = nil; NSString *sValue = nil; @@ -438,7 +463,7 @@ static JSBool ShipSetProperty(JSContext *context, JSObject *this, jsval name, js JSBool bValue; if (!JSVAL_IS_INT(name)) return YES; - if (!JSShipGetShipEntity(context, this, &entity)) return NO; + if (EXPECT_NOT(!JSShipGetShipEntity(context, this, &entity))) return NO; switch (JSVAL_TO_INT(name)) { @@ -451,6 +476,7 @@ static JSBool ShipSetProperty(JSContext *context, JSObject *this, jsval name, js { sValue = [NSString stringWithJavaScriptValue:*value inContext:context]; if (sValue != nil) [entity setName:sValue]; + OK = YES; } break; @@ -463,6 +489,7 @@ static JSBool ShipSetProperty(JSContext *context, JSObject *this, jsval name, js { sValue = [NSString stringWithJavaScriptValue:*value inContext:context]; if (sValue != nil) [entity setDisplayName:sValue]; + OK = YES; } break; @@ -475,6 +502,7 @@ static JSBool ShipSetProperty(JSContext *context, JSObject *this, jsval name, js { sValue = [NSString stringWithJavaScriptValue:*value inContext:context]; if (sValue != nil) [entity setPrimaryRole:sValue]; + OK = YES; } break; @@ -487,6 +515,7 @@ static JSBool ShipSetProperty(JSContext *context, JSObject *this, jsval name, js { sValue = [NSString stringWithJavaScriptValue:*value inContext:context]; if (sValue != nil) [[entity getAI] setState:sValue]; + OK = YES; } break; @@ -495,6 +524,7 @@ static JSBool ShipSetProperty(JSContext *context, JSObject *this, jsval name, js { fValue = OOClamp_0_max_d(fValue, 7.0); [entity setFuel:lround(fValue * 10.0)]; + OK = YES; } break; @@ -503,6 +533,7 @@ static JSBool ShipSetProperty(JSContext *context, JSObject *this, jsval name, js { iValue = (int)OOMax_f(iValue, 0); [entity setBounty:iValue]; + OK = YES; } break; @@ -510,6 +541,7 @@ static JSBool ShipSetProperty(JSContext *context, JSObject *this, jsval name, js if (JSValueToEntity(context, *value, &target) && [target isKindOfClass:[ShipEntity class]]) { [entity setTargetForScript:target]; + OK = YES; } break; @@ -518,6 +550,7 @@ static JSBool ShipSetProperty(JSContext *context, JSObject *this, jsval name, js { fValue = OOMax_d(fValue, 0.0); [entity setTemperature:fValue * SHIP_MAX_CABIN_TEMP]; + OK = YES; } break; @@ -526,6 +559,7 @@ static JSBool ShipSetProperty(JSContext *context, JSObject *this, jsval name, js { fValue = OOMax_d(fValue, 0.125); [entity setHeatInsulation:fValue * SHIP_MAX_CABIN_TEMP]; + OK = YES; } break; @@ -533,6 +567,7 @@ static JSBool ShipSetProperty(JSContext *context, JSObject *this, jsval name, js if (JS_ValueToBoolean(context, *value, &bValue)) { [entity setCloaked:bValue]; + OK = YES; } break; @@ -540,6 +575,7 @@ static JSBool ShipSetProperty(JSContext *context, JSObject *this, jsval name, js if (JS_ValueToBoolean(context, *value, &bValue)) { [entity setReportAIMessages:bValue]; + OK = YES; } break; @@ -547,6 +583,7 @@ static JSBool ShipSetProperty(JSContext *context, JSObject *this, jsval name, js if (JS_ValueToBoolean(context, *value, &bValue)) { [entity setTrackCloseContacts:bValue]; + OK = YES; } break; @@ -560,152 +597,144 @@ static JSBool ShipSetProperty(JSContext *context, JSObject *this, jsval name, js if (JS_ValueToNumber(context, *value, &fValue)) { [entity setDesiredSpeed:fmax(fValue, 0.0)]; + OK = YES; } } break; default: OOReportJSBadPropertySelector(context, @"Ship", JSVAL_TO_INT(name)); - return NO; } - return YES; + return OK; } + +// *** Methods *** + +// setScript(scriptName : String) static JSBool ShipSetScript(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult) { ShipEntity *thisEnt = nil; NSString *name = nil; if (!JSShipGetShipEntity(context, this, &thisEnt)) return YES; // stale reference, no-op. - name = [NSString stringWithJavaScriptValue:*argv inContext:context]; + name = JSValToNSString(context, argv[0]); + if (EXPECT_NOT(name == nil)) + { + OOReportJSBadArguments(context, @"Ship", @"setScript", argc, argv, @"Invalid arguments", @"script name"); + return NO; + } + if (EXPECT_NOT([thisEnt isPlayer])) + { + OOReportJSErrorForCaller(context, @"Ship", @"setScript", @"Cannot change script for player."); + return NO; + } - if (name != nil) - { - if (![thisEnt isPlayer]) - { - [thisEnt setShipScript:name]; - } - else - { - OOReportJSError(context, @"Ship.%@(\"%@\"): cannot set script for player.", @"setScript", name); - } - } - else - { - OOReportJSError(context, @"Ship.%@(): no script name specified.", @"setScript"); - } + [thisEnt setShipScript:name]; return YES; } + +// setAI(aiName : String) static JSBool ShipSetAI(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult) { ShipEntity *thisEnt = nil; NSString *name = nil; if (!JSShipGetShipEntity(context, this, &thisEnt)) return YES; // stale reference, no-op. - name = [NSString stringWithJavaScriptValue:*argv inContext:context]; + name = JSValToNSString(context, argv[0]); + if (EXPECT_NOT(name == nil)) + { + OOReportJSBadArguments(context, @"Ship", @"setAI", argc, argv, @"Invalid arguments", @"AI name"); + return NO; + } + if (EXPECT_NOT([thisEnt isPlayer])) + { + OOReportJSErrorForCaller(context, @"Ship", @"setAI", @"Cannot modify AI for player."); + return NO; + } - if (name != nil) - { - if (!thisEnt->isPlayer) - { - [thisEnt setAITo:name]; - } - else - { - OOReportJSError(context, @"Ship.%@(\"%@\"): cannot modify AI for player.", @"setAI", name); - } - } - else - { - OOReportJSError(context, @"Ship.%@(): no AI state machine specified.", @"setAI"); - } + [thisEnt setAITo:name]; return YES; } +// switchAI(aiName : String) static JSBool ShipSwitchAI(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult) { ShipEntity *thisEnt = nil; NSString *name = nil; if (!JSShipGetShipEntity(context, this, &thisEnt)) return YES; // stale reference, no-op. - name = [NSString stringWithJavaScriptValue:*argv inContext:context]; + name = JSValToNSString(context, argv[0]); + if (EXPECT_NOT(name == nil)) + { + OOReportJSBadArguments(context, @"Ship", @"switchAI", argc, argv, @"Invalid arguments", @"AI name"); + return NO; + } + if (EXPECT_NOT([thisEnt isPlayer])) + { + OOReportJSErrorForCaller(context, @"Ship", @"switchAI", @"Cannot modify AI for player."); + return NO; + } - if (name != nil) - { - if (!thisEnt->isPlayer) - { - [thisEnt switchAITo:name]; - } - else - { - OOReportJSWarning(context, @"Ship.%@(\"%@\"): cannot modify AI for player.", @"switchAI", name); - } - } - else - { - OOReportJSWarning(context, @"Ship.%@(): no AI state machine specified.", @"switchAI"); - } + [thisEnt switchAITo:name]; return YES; } +// exitAI() static JSBool ShipExitAI(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult) { ShipEntity *thisEnt = nil; AI *thisAI = nil; if (!JSShipGetShipEntity(context, this, &thisEnt)) return YES; // stale reference, no-op. + if (EXPECT_NOT([thisEnt isPlayer])) + { + OOReportJSErrorForCaller(context, @"Ship", @"exitAI", @"Cannot modify AI for player."); + return NO; + } thisAI = [thisEnt getAI]; - if (!thisEnt->isPlayer) + if (![thisAI hasSuspendedStateMachines]) { - if ([thisAI hasSuspendedStateMachines]) - { - [thisAI exitStateMachine]; - } - else - { - OOReportJSWarning(context, @"Ship.exitAI(): cannot cannot exit current AI state machine because there are no suspended state machines."); - } + OOReportJSWarningForCaller(context, @"Ship", @"exitAI()", @"Cannot cannot exit current AI state machine because there are no suspended state machines."); } else { - OOReportJSWarning(context, @"Ship.exitAI(): cannot modify AI for player."); + [thisAI exitStateMachine]; } return YES; } +// reactToAIMessage(message : String) static JSBool ShipReactToAIMessage(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult) { ShipEntity *thisEnt = nil; NSString *message = nil; if (!JSShipGetShipEntity(context, this, &thisEnt)) return YES; // stale reference, no-op. - message = [NSString stringWithJavaScriptValue:*argv inContext:context]; + message = JSValToNSString(context, argv[0]); + if (EXPECT_NOT(message == nil)) + { + OOReportJSBadArguments(context, @"Ship", @"reactToAIMessage", argc, argv, @"Invalid arguments", @"message"); + return NO; + } + if (EXPECT_NOT([thisEnt isPlayer])) + { + OOReportJSErrorForCaller(context, @"Ship", @"reactToAIMessage", @"Cannot modify AI for player."); + return NO; + } - if (message != nil) - { - if (!thisEnt->isPlayer) - { - [thisEnt reactToAIMessage:message]; - } - else - { - OOReportJSWarning(context, @"Ship.%@(\"%@\"): cannot modify AI for player.", @"reactToAIMessage", message); - } - } - else - { - OOReportJSWarning(context, @"Ship.%@(): no message specified.", @"reactToAIMessage"); - } + [thisEnt reactToAIMessage:message]; return YES; } +// deployEscorts() static JSBool ShipDeployEscorts(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult) { ShipEntity *thisEnt = nil; @@ -717,6 +746,7 @@ static JSBool ShipDeployEscorts(JSContext *context, JSObject *this, uintN argc, } +// dockEscorts() static JSBool ShipDockEscorts(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult) { ShipEntity *thisEnt = nil; @@ -728,13 +758,19 @@ static JSBool ShipDockEscorts(JSContext *context, JSObject *this, uintN argc, js } +// hasRole(role : String) : Boolean static JSBool ShipHasRole(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult) { ShipEntity *thisEnt = nil; NSString *role = nil; if (!JSShipGetShipEntity(context, this, &thisEnt)) return YES; // stale reference, no-op. - role = [NSString stringWithJavaScriptValue:*argv inContext:context]; + role = JSValToNSString(context, argv[0]); + if (EXPECT_NOT(role == nil)) + { + OOReportJSBadArguments(context, @"Ship", @"hasRole", argc, argv, @"Invalid arguments", @"role"); + return NO; + } *outResult = BOOLToJSVal([thisEnt hasRole:role]); return YES; @@ -749,7 +785,12 @@ static JSBool ShipEjectItem(JSContext *context, JSObject *this, uintN argc, jsva ShipEntity *result = nil; if (!JSShipGetShipEntity(context, this, &thisEnt)) return YES; // stale reference, no-op. - role = [NSString stringWithJavaScriptValue:*argv inContext:context]; + role = JSValToNSString(context, argv[0]); + if (EXPECT_NOT(role == nil)) + { + OOReportJSBadArguments(context, @"Ship", @"ejectItem", argc, argv, @"Invalid arguments", @"role"); + return NO; + } result = [thisEnt ejectShipOfRole:role]; *outResult = [result javaScriptValueInContext:context]; @@ -765,7 +806,12 @@ static JSBool ShipEjectSpecificItem(JSContext *context, JSObject *this, uintN ar ShipEntity *result = nil; if (!JSShipGetShipEntity(context, this, &thisEnt)) return YES; // stale reference, no-op. - itemKey = [NSString stringWithJavaScriptValue:*argv inContext:context]; + itemKey = JSValToNSString(context, argv[0]); + if (EXPECT_NOT(itemKey == nil)) + { + OOReportJSBadArguments(context, @"Ship", @"ejectSpecificItem", argc, argv, @"Invalid arguments", @"ship key"); + return NO; + } result = [thisEnt ejectShipOfType:itemKey]; *outResult = [result javaScriptValueInContext:context]; @@ -783,7 +829,7 @@ static JSBool ShipDumpCargo(JSContext *context, JSObject *this, uintN argc, jsva if ([thisEnt isPlayer] && [(PlayerEntity *)thisEnt isDocked]) { - OOReportJSWarning(context, @"Player.dumpCargo(): can't dump cargo while docked, ignoring."); + OOReportJSWarningForCaller(context, @"Player", @"dumpCargo", @"Can't dump cargo while docked, ignoring."); return YES; } @@ -798,30 +844,20 @@ static JSBool ShipSpawn(JSContext *context, JSObject *this, uintN argc, jsval *a { ShipEntity *thisEnt = nil; NSString *role = nil; - int32 count; + int32 count = 1; + BOOL gotCount = YES; NSMutableArray *result = nil; ShipEntity *ship = nil; if (!JSShipGetShipEntity(context, this, &thisEnt)) return YES; // stale reference, no-op. - role = [NSString stringWithJavaScriptValue:*argv inContext:context]; - if (role == nil) + role = JSValToNSString(context, argv[0]); + if (argc > 1) gotCount = JS_ValueToInt32(context, argv[1], &count); + if (EXPECT_NOT(role == nil || !gotCount || count < 1 || count > 64)) { - OOReportJSError(context, @"Expected role (string), got \"%@\".", JSValToNSString(context, argv[0])); - return YES; + OOReportJSBadArguments(context, @"Ship", @"spawn", argc, argv, @"Invalid arguments", @"role and optional positive count no greater than 64"); + return NO; } - if (argc > 1) - { - if (!JS_ValueToInt32(context, argv[1], &count) || count < 1) - { - OOReportJSError(context, @"Expected spawn count (positive integer), got \"%@\".", JSValToNSString(context, argv[1])); - return YES; - } - } - else count = 1; - - assert(count > 0); - result = [NSMutableArray arrayWithCapacity:count]; do @@ -858,7 +894,7 @@ static JSBool ShipExplode(JSContext *context, JSObject *this, uintN argc, jsval } -// scriptTarget.runLegacyShipActions(target : Ship, actions : Array) +// runLegacyShipActions(target : Ship, actions : Array) static JSBool ShipRunLegacyScriptActions(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult) { ShipEntity *thisEnt = nil; @@ -869,18 +905,12 @@ static JSBool ShipRunLegacyScriptActions(JSContext *context, JSObject *this, uin player = OOPlayerForScripting(); if (!JSShipGetShipEntity(context, this, &thisEnt)) return YES; // stale reference, no-op. - target = JSValueToObject(context, argv[0]); - if (![target isKindOfClass:[ShipEntity class]]) - { - OOReportJSWarning(context, @"First argument of runLegacyScriptActions must be a Ship."); - return YES; - } - actions = JSValueToObject(context, argv[1]); - if (![actions isKindOfClass:[NSArray class]]) + if (EXPECT_NOT(!JSShipGetShipEntity(context, JSVAL_TO_OBJECT(argv[0]), &target) || + ![actions isKindOfClass:[NSArray class]])) { - OOReportJSWarning(context, @"Second argument of runLegacyScriptActions must be an Array."); - return YES; + OOReportJSBadArguments(context, @"Ship", @"runLegacyScriptActions", argc, argv, @"Invalid arguments", @"target and array of actions"); + return NO; } [player setScriptTarget:thisEnt]; @@ -889,21 +919,24 @@ static JSBool ShipRunLegacyScriptActions(JSContext *context, JSObject *this, uin return YES; } + +// commsMessage(message : String) static JSBool ShipCommsMessage(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult) { ShipEntity *thisEnt = nil; - NSString *msg = nil; + NSString *message = nil; if (!JSShipGetShipEntity(context, this, &thisEnt)) return YES; // stale reference, no-op. - msg = [NSString stringWithJavaScriptValue:*argv inContext:context]; - - if (msg != nil) + message = [NSString stringWithJavaScriptValue:*argv inContext:context]; + if (EXPECT_NOT(message == nil)) { - if (!thisEnt->isPlayer) - { - [thisEnt commsMessage:msg withUnpilotedOverride:YES]; - } - //else: player.commsMessage handles this already. + OOReportJSBadArguments(context, @"Ship", @"commsMessage", argc, argv, @"Invalid arguments", @"message"); + return NO; + } + + if (![thisEnt isPlayer]) + { + [thisEnt commsMessage:message withUnpilotedOverride:YES]; } return YES; } diff --git a/src/Core/Scripting/OOJSSound.m b/src/Core/Scripting/OOJSSound.m index d4c2cfce..031344be 100644 --- a/src/Core/Scripting/OOJSSound.m +++ b/src/Core/Scripting/OOJSSound.m @@ -137,7 +137,7 @@ static JSBool SoundGetProperty(JSContext *context, JSObject *this, jsval name, j OOSound *sound = nil; if (!JSVAL_IS_INT(name)) return YES; - if (!JSSoundGetSound(context, this, &sound)) return NO; + if (EXPECT_NOT(!JSSoundGetSound(context, this, &sound))) return NO; switch (JSVAL_TO_INT(name)) { @@ -171,7 +171,7 @@ static OOSound *GetNamedSound(NSString *name) } -// *** Methods *** +// *** Static methods *** // load(name : String) : Sound static JSBool SoundStaticLoad(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult) @@ -180,10 +180,15 @@ static JSBool SoundStaticLoad(JSContext *context, JSObject *this, uintN argc, js OOSound *sound = nil; name = JSValToNSString(context, argv[0]); - sound = GetNamedSound(name); + if (name == nil) + { + OOReportJSBadArguments(context, @"Sound", @"load", argc, argv, @"Invalid arguments", @"string"); + return NO; + } + sound = GetNamedSound(name); *outResult = [sound javaScriptValueInContext:context]; - if (*outResult == JSVAL_VOID) *outResult = JSVAL_NULL; + if (*outResult == JSVAL_VOID) *outResult = JSVAL_NULL; // No sound by that name return YES; } @@ -193,8 +198,13 @@ static JSBool SoundStaticPlayMusic(JSContext *context, JSObject *this, uintN arg NSString *name = nil; name = JSValToNSString(context, argv[0]); - [[OOMusicController sharedController] playMusicNamed:name loop:NO]; + if (name == nil) + { + OOReportJSBadArguments(context, @"Sound", @"playMusic", argc, argv, @"Invalid arguments", @"string"); + return NO; + } + [[OOMusicController sharedController] playMusicNamed:name loop:NO]; return YES; } @@ -206,13 +216,17 @@ static JSBool SoundStaticStopMusic(JSContext *context, JSObject *this, uintN arg if (argc > 0) { name = JSValToNSString(context, argv[0]); + if (name == nil) + { + OOReportJSBadArguments(context, @"Sound", @"playMusic", argc, argv, @"Invalid arguments", @"string or no argument"); + return NO; + } [[OOMusicController sharedController] stopMusicNamed:name]; } else { [[OOMusicController sharedController] stop]; } - return YES; } diff --git a/src/Core/Scripting/OOJSSoundSource.m b/src/Core/Scripting/OOJSSoundSource.m index 58f813de..fafbf20f 100644 --- a/src/Core/Scripting/OOJSSoundSource.m +++ b/src/Core/Scripting/OOJSSoundSource.m @@ -164,6 +164,7 @@ static JSBool SoundSourceGetProperty(JSContext *context, JSObject *this, jsval n static JSBool SoundSourceSetProperty(JSContext *context, JSObject *this, jsval name, jsval *value) { + BOOL OK = NO; OOSoundSource *soundSource = nil; int32 iValue; JSBool bValue; @@ -175,12 +176,14 @@ static JSBool SoundSourceSetProperty(JSContext *context, JSObject *this, jsval n { case kSoundSource_sound: [soundSource setSound:SoundFromJSValue(context, *value)]; + OK = YES; break; case kSoundSource_loop: if (JS_ValueToBoolean(context, *value, &bValue)) { [soundSource setLoop:bValue]; + OK = YES; } break; @@ -190,15 +193,15 @@ static JSBool SoundSourceSetProperty(JSContext *context, JSObject *this, jsval n if (iValue > 100) iValue = 100; if (100 < 1) iValue = 1; [soundSource setRepeatCount:iValue]; + OK = YES; } break; default: OOReportJSBadPropertySelector(context, @"SoundSource", JSVAL_TO_INT(name)); - return NO; } - return YES; + return OK; } @@ -207,13 +210,13 @@ static JSBool SoundSourceSetProperty(JSContext *context, JSObject *this, jsval n // play([count : Number]) static JSBool SoundSourcePlay(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult) { - OOSoundSource *thisv; + OOSoundSource *thisv = nil; int32 count = 0; - if (!JSSoundSourceGetSoundSource(context, this, &thisv)) return NO; - if (argc > 0) + if (EXPECT_NOT(!JSSoundSourceGetSoundSource(context, this, &thisv))) return NO; + if (argc > 0 && !JS_ValueToInt32(context, argv[0], &count)) { - JS_ValueToInt32(context, argv[0], &count); + OOReportJSBadArguments(context, @"SoundSource", @"play", argc, argv, @"Invalid arguments", @"integer count or no argument"); } if (count > 0) @@ -222,7 +225,6 @@ static JSBool SoundSourcePlay(JSContext *context, JSObject *this, uintN argc, js [thisv setRepeatCount:count]; } [thisv play]; - return YES; } @@ -230,12 +232,11 @@ static JSBool SoundSourcePlay(JSContext *context, JSObject *this, uintN argc, js // stop() static JSBool SoundSourceStop(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult) { - OOSoundSource *thisv; + OOSoundSource *thisv = nil; - if (!JSSoundSourceGetSoundSource(context, this, &thisv)) return NO; + if (EXPECT_NOT(!JSSoundSourceGetSoundSource(context, this, &thisv))) return NO; [thisv stop]; - return YES; } @@ -243,12 +244,11 @@ static JSBool SoundSourceStop(JSContext *context, JSObject *this, uintN argc, js // playOrRepeat() static JSBool SoundSourcePlayOrRepeat(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult) { - OOSoundSource *thisv; + OOSoundSource *thisv = nil; - if (!JSSoundSourceGetSoundSource(context, this, &thisv)) return NO; + if (EXPECT_NOT(!JSSoundSourceGetSoundSource(context, this, &thisv))) return NO; [thisv playOrRepeat]; - return YES; } @@ -260,12 +260,18 @@ static JSBool SoundSourcePlaySound(JSContext *context, JSObject *this, uintN arg OOSound *sound = nil; int32 count = 0; - if (!JSSoundSourceGetSoundSource(context, this, &thisv)) return NO; + if (EXPECT_NOT(!JSSoundSourceGetSoundSource(context, this, &thisv))) return NO; sound = SoundFromJSValue(context, argv[0]); - if (sound == nil) return YES; - if (argc > 1) + if (sound == nil) { - JS_ValueToInt32(context, argv[1], &count); + OOReportJSBadArguments(context, @"SoundSource", @"playSound", argc, argv, @"Invalid arguments", @"sound or sound name"); + return NO; + } + + if (argc > 1 || !JS_ValueToInt32(context, argv[1], &count)) + { + OOReportJSBadArguments(context, @"SoundSource", @"playSound", argc, argv, @"Invalid arguments", @"sound or sound name and optional integer count"); + return NO; } [thisv setSound:sound]; @@ -275,7 +281,6 @@ static JSBool SoundSourcePlaySound(JSContext *context, JSObject *this, uintN arg [thisv setRepeatCount:count]; } [thisv play]; - return YES; } diff --git a/src/Core/Scripting/OOJSStation.m b/src/Core/Scripting/OOJSStation.m index 846c2fb9..44a5334f 100644 --- a/src/Core/Scripting/OOJSStation.m +++ b/src/Core/Scripting/OOJSStation.m @@ -159,6 +159,7 @@ static JSBool StationGetProperty(JSContext *context, JSObject *this, jsval name, static JSBool StationSetProperty(JSContext *context, JSObject *this, jsval name, jsval *value) { + BOOL OK = NO; StationEntity *entity = nil; JSBool bValue; int32 iValue; @@ -173,6 +174,7 @@ static JSBool StationSetProperty(JSContext *context, JSObject *this, jsval name, if (JS_ValueToBoolean(context, *value, &bValue)) { [entity setHasNPCTraffic:bValue]; + OK = YES; } break; @@ -180,13 +182,13 @@ static JSBool StationSetProperty(JSContext *context, JSObject *this, jsval name, if (JS_ValueToInt32(context, *value, &iValue)) { [entity setAlertLevel:iValue signallingScript:NO]; // Performs range checking + OK = YES; } break; default: OOReportJSBadPropertySelector(context, @"Station", JSVAL_TO_INT(name)); - return NO; } - return YES; + return OK; } diff --git a/src/Core/Scripting/OOJSSystem.m b/src/Core/Scripting/OOJSSystem.m index 64956245..ace0d2c5 100644 --- a/src/Core/Scripting/OOJSSystem.m +++ b/src/Core/Scripting/OOJSSystem.m @@ -827,6 +827,41 @@ static JSBool SystemLegacySpawnShip(JSContext *context, JSObject *this, uintN ar } +// *** Static methods *** + +// systemNameForID(ID : Number) : String +static JSBool SystemStaticSystemNameForID(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult) +{ + int32 systemID; + + if (!JS_ValueToInt32(context, argv[0], &systemID) || systemID < 0 || 255 < systemID) + { + OOReportJSBadArguments(context, @"System", @"systemNameForID", argc, argv, @"Invalid arguments", @"system ID"); + return NO; + } + + *outResult = [[UNIVERSE generateSystemName:[UNIVERSE systemSeedForSystemNumber:systemID]] javaScriptValueInContext:context]; + return YES; +} + + +// systemIDForName(name : String) : Number +static JSBool SystemStaticSystemIDForName(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult) +{ + NSString *name = nil; + + name = JSValToNSString(context, argv[0]); + if (name == nil) + { + OOReportJSBadArguments(context, @"System", @"systemIDForName", argc, argv, @"Invalid arguments", @"string"); + return NO; + } + + *outResult = INT_TO_JSVAL([UNIVERSE systemIDForSystemSeed:[UNIVERSE systemSeedForSystemName:name]]); + return YES; +} + + // *** Helper functions *** static BOOL GetRelativeToAndRange(JSContext *context, uintN *ioArgc, jsval **ioArgv, Entity **outRelativeTo, double *outRange) @@ -889,8 +924,8 @@ static NSArray *FindShips(EntityFilterPredicate predicate, void *parameter, Enti static int CompareEntitiesByDistance(id a, id b, void *relativeTo) { Entity *ea = a, - *eb = b, - *r = (id)relativeTo; + *eb = b, + *r = (id)relativeTo; float d1, d2; d1 = distance2(ea->position, r->position); @@ -900,31 +935,3 @@ static int CompareEntitiesByDistance(id a, id b, void *relativeTo) else if (d1 > d2) return NSOrderedDescending; else return NSOrderedSame; } - - -// systemNameForID(ID : Number) : String -static JSBool SystemStaticSystemNameForID(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult) -{ - int32 systemID; - - if (!JS_ValueToInt32(context, argv[0], &systemID) || systemID < 0 || 255 < systemID) - { - OOReportJSError(context, @"%@(): expected system ID from 0 to 255, got %@.", @"systemNameForID", JSValToNSString(context, argv[0])); - return YES; - } - - *outResult = [[UNIVERSE generateSystemName:[UNIVERSE systemSeedForSystemNumber:systemID]] javaScriptValueInContext:context]; - - return YES; -} - - -// systemIDForName(name : String) : Number -static JSBool SystemStaticSystemIDForName(JSContext *context, JSObject *this, uintN argc, jsval *argv, jsval *outResult) -{ - NSString *name = nil; - - name = JSValToNSString(context, argv[0]); - *outResult = INT_TO_JSVAL([UNIVERSE systemIDForSystemSeed:[UNIVERSE systemSeedForSystemName:name]]); - return YES; -}