LCOV - code coverage report
Current view: top level - Core/Scripting - OOJSSystem.m (source / functions) Hit Total Coverage
Test: coverxygen.info Lines: 0 44 0.0 %
Date: 2025-05-28 07:50:54 Functions: 0 0 -

          Line data    Source code
       1           0 : /*
       2             :  
       3             :  OOJSSystem.m
       4             :  
       5             :  
       6             :  Oolite
       7             :  Copyright (C) 2004-2013 Giles C Williams and contributors
       8             :  
       9             :  This program is free software; you can redistribute it and/or
      10             :  modify it under the terms of the GNU General Public License
      11             :  as published by the Free Software Foundation; either version 2
      12             :  of the License, or (at your option) any later version.
      13             :  
      14             :  This program is distributed in the hope that it will be useful,
      15             :  but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :  GNU General Public License for more details.
      18             :  
      19             :  You should have received a copy of the GNU General Public License
      20             :  along with this program; if not, write to the Free Software
      21             :  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
      22             :  MA 02110-1301, USA.
      23             :  
      24             :  */
      25             : 
      26             : #import "OOJSSystem.h"
      27             : #import "OOJavaScriptEngine.h"
      28             : 
      29             : #import "OOJSVector.h"
      30             : #import "OOJSQuaternion.h"
      31             : #import "OOJSEntity.h"
      32             : #import "OOJSPlayer.h"
      33             : #import "Universe.h"
      34             : #import "OOPlanetEntity.h"
      35             : #import "PlayerEntityScriptMethods.h"
      36             : #import "OOJSSystemInfo.h"
      37             : 
      38             : #import "OOCollectionExtractors.h"
      39             : #import "OOConstToString.h"
      40             : #import "OOConstToJSString.h"
      41             : #import "OOEntityFilterPredicate.h"
      42             : #import "OOFilteringEnumerator.h"
      43             : #import "OOJSPopulatorDefinition.h"
      44             : #import "OODebugStandards.h"
      45             : #import "EntityOOJavaScriptExtensions.h"
      46             : 
      47           0 : static JSObject *sSystemPrototype;
      48             : 
      49             : 
      50             : // Support functions for entity search methods.
      51             : static BOOL GetRelativeToAndRange(JSContext *context, NSString *methodName, uintN *ioArgc, jsval **ioArgv, Entity **outRelativeTo, double *outRange);
      52             : static NSArray *FindJSVisibleEntities(EntityFilterPredicate predicate, void *parameter, Entity *relativeTo, double range);
      53             : static NSArray *FindShips(EntityFilterPredicate predicate, void *parameter, Entity *relativeTo, double range);
      54             : static NSComparisonResult CompareEntitiesByDistance(id a, id b, void *relativeTo);
      55             : 
      56             : static JSBool SystemAddShipsOrGroup(JSContext *context, uintN argc, jsval *vp, BOOL isGroup);
      57             : static JSBool SystemAddShipsOrGroupToRoute(JSContext *context, uintN argc, jsval *vp, BOOL isGroup);
      58             : 
      59             : 
      60             : static JSBool SystemGetProperty(JSContext *context, JSObject *this, jsid propID, jsval *value);
      61             : static JSBool SystemSetProperty(JSContext *context, JSObject *this, jsid propID, JSBool strict, jsval *value);
      62             : 
      63             : static JSBool SystemToString(JSContext *context, uintN argc, jsval *vp);
      64             : static JSBool SystemAddPlanet(JSContext *context, uintN argc, jsval *vp);
      65             : static JSBool SystemAddMoon(JSContext *context, uintN argc, jsval *vp);
      66             : static JSBool SystemSendAllShipsAway(JSContext *context, uintN argc, jsval *vp);
      67             : static JSBool SystemCountShipsWithPrimaryRole(JSContext *context, uintN argc, jsval *vp);
      68             : static JSBool SystemCountShipsWithRole(JSContext *context, uintN argc, jsval *vp);
      69             : static JSBool SystemCountEntitiesWithScanClass(JSContext *context, uintN argc, jsval *vp);
      70             : static JSBool SystemShipsWithPrimaryRole(JSContext *context, uintN argc, jsval *vp);
      71             : static JSBool SystemShipsWithRole(JSContext *context, uintN argc, jsval *vp);
      72             : static JSBool SystemEntitiesWithScanClass(JSContext *context, uintN argc, jsval *vp);
      73             : static JSBool SystemFilteredEntities(JSContext *context, uintN argc, jsval *vp);
      74             : 
      75             : static JSBool SystemLocationFromCode(JSContext *context, uintN argc, jsval *vp);
      76             : static JSBool SystemAddShips(JSContext *context, uintN argc, jsval *vp);
      77             : static JSBool SystemAddGroup(JSContext *context, uintN argc, jsval *vp);
      78             : static JSBool SystemAddShipsToRoute(JSContext *context, uintN argc, jsval *vp);
      79             : static JSBool SystemAddGroupToRoute(JSContext *context, uintN argc, jsval *vp);
      80             : static JSBool SystemAddVisualEffect(JSContext *context, uintN argc, jsval *vp);
      81             : static JSBool SystemSetPopulator(JSContext *context, uintN argc, jsval *vp);
      82             : static JSBool SystemSetWaypoint(JSContext *context, uintN argc, jsval *vp);
      83             : 
      84             : static JSBool SystemLegacyAddShips(JSContext *context, uintN argc, jsval *vp);
      85             : static JSBool SystemLegacyAddSystemShips(JSContext *context, uintN argc, jsval *vp);
      86             : static JSBool SystemLegacyAddShipsAt(JSContext *context, uintN argc, jsval *vp);
      87             : static JSBool SystemLegacyAddShipsAtPrecisely(JSContext *context, uintN argc, jsval *vp);
      88             : static JSBool SystemLegacyAddShipsWithinRadius(JSContext *context, uintN argc, jsval *vp);
      89             : static JSBool SystemLegacySpawnShip(JSContext *context, uintN argc, jsval *vp);
      90             : 
      91             : static JSBool SystemStaticSystemNameForID(JSContext *context, uintN argc, jsval *vp);
      92             : static JSBool SystemStaticSystemIDForName(JSContext *context, uintN argc, jsval *vp);
      93             : static JSBool SystemStaticInfoForSystem(JSContext *context, uintN argc, jsval *vp);
      94             : 
      95             : 
      96           0 : static JSClass sSystemClass =
      97             : {
      98             :         "System",
      99             :         0,
     100             :         
     101             :         JS_PropertyStub,
     102             :         JS_PropertyStub,
     103             :         SystemGetProperty,
     104             :         SystemSetProperty,
     105             :         JS_EnumerateStub,
     106             :         JS_ResolveStub,
     107             :         JS_ConvertStub,
     108             :         JS_FinalizeStub
     109             : };
     110             : 
     111             : 
     112           0 : enum
     113             : {
     114             :         // Property IDs
     115             :         kSystem_allDemoShips,                           // demo ships, array of Ship, read-only
     116             :         kSystem_allShips,                               // ships in system, array of Ship, read-only
     117             :         kSystem_allVisualEffects,                               // VEs in system, array of VEs, read-only
     118             :         kSystem_ambientLevel,                   // ambient light level, float, read/write
     119             :         kSystem_breakPattern, // witchspace break pattern shown
     120             :         kSystem_description,                    // description, string, read/write
     121             :         kSystem_economy,                                // economy ID, integer, read/write
     122             :         kSystem_economyDescription,             // economy ID description, string, read-only
     123             :         kSystem_government,                             // government ID, integer, read/write
     124             :         kSystem_governmentDescription,  // government ID description, string, read-only
     125             :         kSystem_ID,                                             // planet number, integer, read-only
     126             :         kSystem_info,                                   // system info dictionary, SystemInfo, read/write
     127             :         kSystem_inhabitantsDescription, // description of inhabitant species, string, read/write
     128             :         kSystem_isInterstellarSpace,    // is interstellar space, boolean, read-only
     129             :         kSystem_mainPlanet,                             // system's main planet, Planet, read-only
     130             :         kSystem_mainStation,                    // system's main station, Station, read-only
     131             :         kSystem_name,                                   // name, string, read/write
     132             :         kSystem_planets,                                // planets in system, array of Planet, read-only
     133             :         kSystem_population,                             // population, integer, read/write
     134             :         kSystem_populatorSettings,                              // populator settings, dictionary, read-only
     135             :         kSystem_productivity,                   // productivity, integer, read/write
     136             :         kSystem_pseudoRandom100,                // constant-per-system pseudorandom number in [0..100), integer, read-only
     137             :         kSystem_pseudoRandom256,                // constant-per-system pseudorandom number in [0..256), integer, read-only
     138             :         kSystem_pseudoRandomNumber,             // constant-per-system pseudorandom number in [0..1), double, read-only
     139             :         kSystem_sun,                                    // system's sun, Planet, read-only
     140             :         kSystem_stations,     // list of dockable entities, read-only
     141             :         kSystem_techLevel,                              // tech level ID, integer, read/write
     142             :         kSystem_waypoints,     // dictionary of current player waypoints, read-only
     143             :         kSystem_wormholes,     // list of active entry wormholes, read-only
     144             : 
     145             : };
     146             : 
     147             : 
     148           0 : static JSPropertySpec sSystemProperties[] =
     149             : {
     150             :         // JS name                                      ID                                                              flags
     151             :         { "allDemoShips",                     kSystem_allDemoShips,                   OOJS_PROP_READONLY_CB },
     152             :         { "allShips",                         kSystem_allShips,                               OOJS_PROP_READONLY_CB },
     153             :         { "allVisualEffects",  kSystem_allVisualEffects,              OOJS_PROP_READONLY_CB },
     154             :         { "ambientLevel",                     kSystem_ambientLevel,                   OOJS_PROP_READWRITE_CB },
     155             :         { "breakPattern",                     kSystem_breakPattern,                   OOJS_PROP_READWRITE_CB },
     156             :         { "description",                      kSystem_description,                    OOJS_PROP_READWRITE_CB },
     157             :         { "economy",                          kSystem_economy,                                OOJS_PROP_READWRITE_CB },
     158             :         { "economyDescription",               kSystem_economyDescription,             OOJS_PROP_READONLY_CB },
     159             :         { "government",                               kSystem_government,                             OOJS_PROP_READWRITE_CB },
     160             :         { "governmentDescription",    kSystem_governmentDescription,  OOJS_PROP_READONLY_CB },
     161             :         { "ID",                                               kSystem_ID,                                             OOJS_PROP_READONLY_CB },
     162             :         { "info",                                     kSystem_info,                                   OOJS_PROP_READONLY_CB },
     163             :         { "inhabitantsDescription",   kSystem_inhabitantsDescription, OOJS_PROP_READWRITE_CB },
     164             :         { "isInterstellarSpace",      kSystem_isInterstellarSpace,    OOJS_PROP_READONLY_CB},
     165             :         { "mainPlanet",                               kSystem_mainPlanet,                             OOJS_PROP_READONLY_CB },
     166             :         { "mainStation",                      kSystem_mainStation,                    OOJS_PROP_READONLY_CB },
     167             :         { "name",                                     kSystem_name,                                   OOJS_PROP_READWRITE_CB },
     168             :         { "planets",                          kSystem_planets,                                OOJS_PROP_READONLY_CB },
     169             :         { "population",                               kSystem_population,                             OOJS_PROP_READWRITE_CB },
     170             :         { "populatorSettings",                                kSystem_populatorSettings,                              OOJS_PROP_READONLY_CB },
     171             :         { "productivity",                     kSystem_productivity,                   OOJS_PROP_READWRITE_CB },
     172             :         { "pseudoRandom100",          kSystem_pseudoRandom100,                OOJS_PROP_READONLY_CB },
     173             :         { "pseudoRandom256",          kSystem_pseudoRandom256,                OOJS_PROP_READONLY_CB },
     174             :         { "pseudoRandomNumber",               kSystem_pseudoRandomNumber,             OOJS_PROP_READONLY_CB },
     175             :         { "stations",                                 kSystem_stations,                                       OOJS_PROP_READONLY_CB },
     176             :         { "sun",                                      kSystem_sun,                                    OOJS_PROP_READONLY_CB },
     177             :         { "techLevel",                                kSystem_techLevel,                              OOJS_PROP_READWRITE_CB },
     178             :         { "waypoints",                                        kSystem_waypoints,                                      OOJS_PROP_READONLY_CB },
     179             :         { "wormholes",                                        kSystem_wormholes,                                      OOJS_PROP_READONLY_CB },
     180             :         { 0 }
     181             : };
     182             : 
     183             : 
     184           0 : static JSFunctionSpec sSystemMethods[] =
     185             : {
     186             :         // JS name                                                      Function                                                        min args
     187             :         { "toString",                                         SystemToString,                                         0 },
     188             :         { "addGroup",                                         SystemAddGroup,                                         3 },
     189             :         { "addGroupToRoute",                          SystemAddGroupToRoute,                          2 },
     190             :         { "addMoon",                                          SystemAddMoon,                                          1 },
     191             :         { "addPlanet",                                                SystemAddPlanet,                                        1 },
     192             :         { "addShips",                                         SystemAddShips,                                         3 },
     193             :         { "addShipsToRoute",                          SystemAddShipsToRoute,                          2 },
     194             :         { "addVisualEffect",                                          SystemAddVisualEffect,                                          2 },
     195             :         { "countEntitiesWithScanClass",               SystemCountEntitiesWithScanClass,       1 },
     196             :         { "countShipsWithPrimaryRole",                SystemCountShipsWithPrimaryRole,        1 },
     197             :         { "countShipsWithRole",                               SystemCountShipsWithRole,                       1 },
     198             :         { "entitiesWithScanClass",                    SystemEntitiesWithScanClass,            1 },
     199             :         { "filteredEntities",                         SystemFilteredEntities,                         2 },
     200             :         { "locationFromCode",                         SystemLocationFromCode,                         1 },
     201             :         // scrambledPseudoRandomNumber is implemented in oolite-global-prefix.js
     202             :         { "sendAllShipsAway",                         SystemSendAllShipsAway,                         1 },
     203             :         { "setPopulator",                                     SystemSetPopulator,                                     2 },
     204             :         { "setWaypoint",                                      SystemSetWaypoint,                                      4 },
     205             :         { "shipsWithPrimaryRole",                     SystemShipsWithPrimaryRole,                     1 },
     206             :         { "shipsWithRole",                                    SystemShipsWithRole,                            1 },
     207             :         
     208             :         { "legacy_addShips",                          SystemLegacyAddShips,                           2 },
     209             :         { "legacy_addSystemShips",                    SystemLegacyAddSystemShips,                     3 },
     210             :         { "legacy_addShipsAt",                                SystemLegacyAddShipsAt,                         6 },
     211             :         { "legacy_addShipsAtPrecisely",               SystemLegacyAddShipsAtPrecisely,        6 },
     212             :         { "legacy_addShipsWithinRadius",      SystemLegacyAddShipsWithinRadius,       7 },
     213             :         { "legacy_spawnShip",                         SystemLegacySpawnShip,                          1 },
     214             :         { 0 }
     215             : };
     216             : 
     217             : 
     218           0 : static JSFunctionSpec sSystemStaticMethods[] =
     219             : {
     220             :         { "infoForSystem",                    SystemStaticInfoForSystem,                                      2 },
     221             :         { "systemIDForName",          SystemStaticSystemIDForName,                            1 },
     222             :         { "systemNameForID",          SystemStaticSystemNameForID,                            1 },
     223             :         { 0 }
     224             : };
     225             : 
     226             : 
     227           0 : void InitOOJSSystem(JSContext *context, JSObject *global)
     228             : {
     229             :         sSystemPrototype = JS_InitClass(context, global, NULL, &sSystemClass, OOJSUnconstructableConstruct, 0, sSystemProperties, sSystemMethods, NULL, sSystemStaticMethods);
     230             :         
     231             :         // Create system object as a property of the global object.
     232             :         JS_DefineObject(context, global, "system", &sSystemClass, sSystemPrototype, OOJS_PROP_READONLY);
     233             : }
     234             : 
     235             : 
     236           0 : static JSBool SystemGetProperty(JSContext *context, JSObject *this, jsid propID, jsval *value)
     237             : {
     238             :         if (!JSID_IS_INT(propID))  return YES;
     239             :         
     240             :         OOJS_NATIVE_ENTER(context)
     241             :         
     242             :         id                                                      result = nil;
     243             :         PlayerEntity                            *player = nil;
     244             :         NSDictionary                            *systemData = nil;
     245             :         BOOL                                            handled = NO;
     246             :         
     247             :         player = OOPlayerForScripting();
     248             :         
     249             :         // Handle cases which don't require systemData.
     250             :         switch (JSID_TO_INT(propID))
     251             :         {
     252             :                 case kSystem_ID:
     253             :                         *value = INT_TO_JSVAL([player currentSystemID]);
     254             :                         return YES;
     255             :                         
     256             :                 case kSystem_isInterstellarSpace:
     257             :                         *value = OOJSValueFromBOOL([UNIVERSE inInterstellarSpace]);
     258             :                         return YES;
     259             :                         
     260             :                 case kSystem_mainStation:
     261             :                         result = [UNIVERSE station];
     262             :                         handled = YES;
     263             :                         break;
     264             :                         
     265             :                 case kSystem_mainPlanet:
     266             :                         result = [UNIVERSE planet];
     267             :                         handled = YES;
     268             :                         break;
     269             :                         
     270             :                 case kSystem_sun:
     271             :                         result = [UNIVERSE sun];
     272             :                         handled = YES;
     273             :                         break;
     274             :                         
     275             :                 case kSystem_planets:
     276             :                         result = [[[UNIVERSE planets] objectEnumeratorFilteredWithSelector:@selector(isVisibleToScripts)] allObjects];
     277             :                         handled = YES;
     278             :                         break;
     279             :                         
     280             :                 case kSystem_stations:
     281             :                         result = [UNIVERSE stations];
     282             :                         handled = YES;
     283             :                         break;
     284             : 
     285             :                 case kSystem_waypoints:
     286             :                         result = [UNIVERSE currentWaypoints];
     287             :                         handled = YES;
     288             :                         break;
     289             : 
     290             :                 case kSystem_wormholes:
     291             :                         result = [UNIVERSE wormholes];
     292             :                         handled = YES;
     293             :                         break;
     294             : 
     295             :                 case kSystem_allShips:
     296             :                         OOJS_BEGIN_FULL_NATIVE(context)
     297             :                         result = [UNIVERSE findShipsMatchingPredicate:JSEntityIsJavaScriptSearchablePredicate parameter:NULL inRange:-1 ofEntity:nil];
     298             :                         OOJS_END_FULL_NATIVE
     299             :                         handled = YES;
     300             :                         break;
     301             : 
     302             :                 case kSystem_allDemoShips:
     303             :                         OOJS_BEGIN_FULL_NATIVE(context)
     304             :                         result = [UNIVERSE findShipsMatchingPredicate:JSEntityIsDemoShipPredicate parameter:NULL inRange:-1 ofEntity:nil];
     305             :                         OOJS_END_FULL_NATIVE
     306             :                         handled = YES;
     307             :                         break;
     308             : 
     309             : 
     310             :                 case kSystem_allVisualEffects:
     311             :                         OOJS_BEGIN_FULL_NATIVE(context)
     312             :                         result = [UNIVERSE findVisualEffectsMatchingPredicate:JSEntityIsJavaScriptSearchablePredicate parameter:NULL inRange:-1 ofEntity:nil];
     313             :                         OOJS_END_FULL_NATIVE
     314             :                         handled = YES;
     315             :                         break;
     316             :                         
     317             :                 case kSystem_ambientLevel:
     318             :                         return JS_NewNumberValue(context, [UNIVERSE ambientLightLevel], value);
     319             :                         
     320             :                 case kSystem_info:
     321             :                         *value = GetJSSystemInfoForSystem(context, [player currentGalaxyID], [player currentSystemID]);
     322             :                         return YES;
     323             :                 
     324             :                 case kSystem_pseudoRandomNumber:
     325             :                         return JS_NewNumberValue(context, [player systemPseudoRandomFloat], value);
     326             :                         
     327             :                 case kSystem_pseudoRandom100:
     328             :                         *value = INT_TO_JSVAL([player systemPseudoRandom100]);
     329             :                         return YES;
     330             :                         
     331             :                 case kSystem_pseudoRandom256:
     332             :                         *value = INT_TO_JSVAL([player systemPseudoRandom256]);
     333             :                         return YES;
     334             : 
     335             :                 case kSystem_breakPattern:
     336             :                         *value = OOJSValueFromBOOL([UNIVERSE witchspaceBreakPattern]);
     337             :                         return YES;
     338             : 
     339             :                 case kSystem_populatorSettings:
     340             :                         *value = OOJSValueFromNativeObject(context, [UNIVERSE getPopulatorSettings]);
     341             :                         return YES;
     342             :         }
     343             :         
     344             :         if (!handled)
     345             :         {
     346             :                 // Handle cases which do require systemData.
     347             :                 if (EXPECT (![UNIVERSE inInterstellarSpace]))
     348             :                 {
     349             :                         systemData = [UNIVERSE currentSystemData];
     350             :                         
     351             :                         switch (JSID_TO_INT(propID))
     352             :                         {
     353             :                                 case kSystem_name:
     354             :                                         result = [systemData objectForKey:KEY_NAME];
     355             :                                         break;
     356             :                                         
     357             :                                 case kSystem_description:
     358             :                                         result = [systemData objectForKey:KEY_DESCRIPTION];
     359             :                                         break;
     360             :                                         
     361             :                                 case kSystem_inhabitantsDescription:
     362             :                                         result = [systemData objectForKey:KEY_INHABITANTS];
     363             :                                         break;
     364             :                                         
     365             :                                 case kSystem_government:
     366             :                                         *value = INT_TO_JSVAL([systemData oo_intForKey:KEY_GOVERNMENT]);
     367             :                                         return YES;
     368             :                                         
     369             :                                 case kSystem_governmentDescription:
     370             :                                         result = OODisplayStringFromGovernmentID([systemData oo_intForKey:KEY_GOVERNMENT]);
     371             :                                         if (result == nil)  result = DESC(@"not-applicable");
     372             :                                         break;
     373             :                                         
     374             :                                 case kSystem_economy:
     375             :                                         *value = INT_TO_JSVAL([systemData oo_intForKey:KEY_ECONOMY]);
     376             :                                         return YES;
     377             :                                         
     378             :                                 case kSystem_economyDescription:
     379             :                                         result = OODisplayStringFromEconomyID([systemData oo_intForKey:KEY_ECONOMY]);
     380             :                                         if (result == nil)  result = DESC(@"not-applicable");
     381             :                                         break;
     382             :                                 
     383             :                                 case kSystem_techLevel:
     384             :                                         *value = INT_TO_JSVAL([systemData oo_intForKey:KEY_TECHLEVEL]);
     385             :                                         return YES;
     386             :                                         
     387             :                                 case kSystem_population:
     388             :                                         *value = INT_TO_JSVAL([systemData oo_intForKey:KEY_POPULATION]);
     389             :                                         return YES;
     390             :                                         
     391             :                                 case kSystem_productivity:
     392             :                                         *value = INT_TO_JSVAL([systemData oo_intForKey:KEY_PRODUCTIVITY]);
     393             :                                         return YES;
     394             :                                         
     395             :                                 default:
     396             :                                         OOJSReportBadPropertySelector(context, this, propID, sSystemProperties);
     397             :                                         return NO;
     398             :                         }
     399             :                 }
     400             :                 else
     401             :                 {
     402             :                         // if in interstellar space, systemData values are null & void!
     403             :                         switch (JSID_TO_INT(propID))
     404             :                         {
     405             :                                 case kSystem_name:
     406             :                                         result = DESC(@"interstellar-space");
     407             :                                         break;
     408             :                                         
     409             :                                 case kSystem_description:
     410             :                                         result = @"";
     411             :                                         break;
     412             :                                         
     413             :                                 case kSystem_inhabitantsDescription:
     414             :                                         result = DESC(@"not-applicable");
     415             :                                         break;
     416             :                                         
     417             :                                 case kSystem_government:
     418             :                                         *value = INT_TO_JSVAL(-1);
     419             :                                         return YES;
     420             :                                         
     421             :                                 case kSystem_governmentDescription:
     422             :                                         result = DESC(@"not-applicable");
     423             :                                         break;
     424             :                                         
     425             :                                 case kSystem_economy:
     426             :                                         *value = INT_TO_JSVAL(-1);
     427             :                                         return YES;
     428             :                                         
     429             :                                 case kSystem_economyDescription:
     430             :                                         result = DESC(@"not-applicable");
     431             :                                         break;
     432             :                                 
     433             :                                 case kSystem_techLevel:
     434             :                                         *value = INT_TO_JSVAL(-1);
     435             :                                         return YES;
     436             :                                         
     437             :                                 case kSystem_population:
     438             :                                         *value = INT_TO_JSVAL(0);
     439             :                                         return YES;
     440             :                                         
     441             :                                 case kSystem_productivity:
     442             :                                         *value = INT_TO_JSVAL(0);
     443             :                                         return YES;
     444             :                                         
     445             :                                 default:
     446             :                                         OOJSReportBadPropertySelector(context, this, propID, sSystemProperties);
     447             :                                         return NO;
     448             :                         }
     449             :                 }
     450             :         }
     451             :         
     452             :         *value = OOJSValueFromNativeObject(context, result);
     453             :         return YES;
     454             :         
     455             :         OOJS_NATIVE_EXIT
     456             : }
     457             : 
     458             : 
     459           0 : static JSBool SystemSetProperty(JSContext *context, JSObject *this, jsid propID, JSBool strict, jsval *value)
     460             : {
     461             :         if (!JSID_IS_INT(propID))  return YES;
     462             :         
     463             :         OOJS_NATIVE_ENTER(context)
     464             :         
     465             :         PlayerEntity                            *player = nil;
     466             :         OOGalaxyID                                      galaxy;
     467             :         OOSystemID                                      system;
     468             :         NSString                                        *stringValue = nil;
     469             :         NSString                                        *manifest = nil;
     470             :         jsdouble                                        fValue;
     471             :         int32                                           iValue;
     472             :         JSBool            bValue;
     473             :         
     474             :         player = OOPlayerForScripting();
     475             :         
     476             :         galaxy = [player currentGalaxyID];
     477             :         system = [player currentSystemID];
     478             : 
     479             :         switch (JSID_TO_INT(propID))
     480             :         {
     481             :                 case kSystem_ambientLevel:
     482             :                         if (JS_ValueToNumber(context, *value, &fValue))
     483             :                         {
     484             :                                 [UNIVERSE setAmbientLightLevel:fValue];
     485             :                                 [UNIVERSE setLighting];
     486             :                                 return YES;
     487             :                         }
     488             :                         break;
     489             :                         
     490             :                 case kSystem_breakPattern:
     491             :                         if (JS_ValueToBoolean(context, *value, &bValue))
     492             :                         {
     493             :                                 [UNIVERSE setWitchspaceBreakPattern:bValue];
     494             :                                 return YES;
     495             :                         }
     496             : 
     497             :                         break;
     498             :                 default:
     499             :                 {}// do nothing yet
     500             :         }
     501             : 
     502             :         
     503             :         if (system == -1)  return YES;  // Can't change anything else in interstellar space.
     504             : 
     505             :         manifest = [[OOJSScript currentlyRunningScript] propertyNamed:kLocalManifestProperty];
     506             :         
     507             :         switch (JSID_TO_INT(propID))
     508             :         {
     509             :                 case kSystem_name:
     510             :                         stringValue = OOStringFromJSValue(context, *value);
     511             :                         if (stringValue != nil)
     512             :                         {
     513             :                                 [UNIVERSE setSystemDataForGalaxy:galaxy planet:system key:KEY_NAME value:stringValue fromManifest:manifest forLayer:OO_LAYER_OXP_DYNAMIC];
     514             :                                 return YES;
     515             :                         }
     516             :                         break;
     517             :                         
     518             :                 case kSystem_description:
     519             :                         stringValue = OOStringFromJSValue(context, *value);
     520             :                         if (stringValue != nil)
     521             :                         {
     522             :                                 [UNIVERSE setSystemDataForGalaxy:galaxy planet:system key:KEY_DESCRIPTION value:stringValue fromManifest:manifest forLayer:OO_LAYER_OXP_DYNAMIC];
     523             :                                 return YES;
     524             :                         }
     525             :                         break;
     526             :                         
     527             :                 case kSystem_inhabitantsDescription:
     528             :                         stringValue = OOStringFromJSValue(context, *value);
     529             :                         if (stringValue != nil)
     530             :                         {
     531             :                                 [UNIVERSE setSystemDataForGalaxy:galaxy planet:system key:KEY_INHABITANTS value:stringValue fromManifest:manifest forLayer:OO_LAYER_OXP_DYNAMIC];
     532             :                                 return YES;
     533             :                         }
     534             :                         break;
     535             :                         
     536             :                 case kSystem_government:
     537             :                         if (JS_ValueToInt32(context, *value, &iValue))
     538             :                         {
     539             :                                 if (iValue < 0)  iValue = 0;
     540             :                                 if (7 < iValue)  iValue = 7;
     541             :                                 [UNIVERSE setSystemDataForGalaxy:galaxy planet:system key:KEY_GOVERNMENT value:[NSNumber numberWithInt:iValue] fromManifest:manifest forLayer:OO_LAYER_OXP_DYNAMIC];
     542             :                                 return YES;
     543             :                         }
     544             :                         break;
     545             :                         
     546             :                 case kSystem_economy:
     547             :                         if (JS_ValueToInt32(context, *value, &iValue))
     548             :                         {
     549             :                                 if (iValue < 0)  iValue = 0;
     550             :                                 if (7 < iValue)  iValue = 7;
     551             :                                 [UNIVERSE setSystemDataForGalaxy:galaxy planet:system key:KEY_ECONOMY value:[NSNumber numberWithInt:iValue] fromManifest:manifest forLayer:OO_LAYER_OXP_DYNAMIC];
     552             :                                 return YES;
     553             :                         }
     554             :                         break;
     555             :                         
     556             :                 case kSystem_techLevel:
     557             :                         if (JS_ValueToInt32(context, *value, &iValue))
     558             :                         {
     559             :                                 if (iValue < 0)  iValue = 0;
     560             :                                 if (15 < iValue)  iValue = 15;
     561             :                                 [UNIVERSE setSystemDataForGalaxy:galaxy planet:system key:KEY_TECHLEVEL value:[NSNumber numberWithInt:iValue] fromManifest:manifest forLayer:OO_LAYER_OXP_DYNAMIC];
     562             :                                 return YES;
     563             :                         }
     564             :                         break;
     565             :                         
     566             :                 case kSystem_population:
     567             :                         if (JS_ValueToInt32(context, *value, &iValue))
     568             :                         {
     569             :                                 [UNIVERSE setSystemDataForGalaxy:galaxy planet:system key:KEY_POPULATION value:[NSNumber numberWithInt:iValue] fromManifest:manifest forLayer:OO_LAYER_OXP_DYNAMIC];
     570             :                                 return YES;
     571             :                         }
     572             :                         break;
     573             :                         
     574             :                 case kSystem_productivity:
     575             :                         if (JS_ValueToInt32(context, *value, &iValue))
     576             :                         {
     577             :                                 [UNIVERSE setSystemDataForGalaxy:galaxy planet:system key:KEY_PRODUCTIVITY value:[NSNumber numberWithInt:iValue] fromManifest:manifest forLayer:OO_LAYER_OXP_DYNAMIC];
     578             :                                 return YES;
     579             :                         }
     580             :                         break;
     581             :                         
     582             :                 default:
     583             :                         OOJSReportBadPropertySelector(context, this, propID, sSystemProperties);
     584             :                         return NO;
     585             :         }
     586             :         
     587             :         OOJSReportBadPropertyValue(context, this, propID, sSystemProperties, *value);
     588             :         return NO;
     589             :         
     590             :         OOJS_NATIVE_EXIT
     591             : }
     592             : 
     593             : 
     594             : // *** Methods ***
     595             : 
     596             : // toString() : String
     597           0 : static JSBool SystemToString(JSContext *context, uintN argc, jsval *vp)
     598             : {
     599             :         OOJS_NATIVE_ENTER(context)
     600             :         
     601             :         PlayerEntity            *player = OOPlayerForScripting();
     602             :         NSString                        *systemDesc = nil;
     603             :         
     604             :         systemDesc = [NSString stringWithFormat:@"[System %u:%u \"%@\"]", [player currentGalaxyID], [player currentSystemID], [[UNIVERSE currentSystemData] objectForKey:KEY_NAME]];
     605             :         OOJS_RETURN_OBJECT(systemDesc);
     606             :         
     607             :         OOJS_NATIVE_EXIT
     608             : }
     609             : 
     610             : 
     611             : // addPlanet(key : String) : Planet
     612           0 : static JSBool SystemAddPlanet(JSContext *context, uintN argc, jsval *vp)
     613             : {
     614             :         OOJS_NATIVE_ENTER(context)
     615             :         
     616             :         PlayerEntity            *player = OOPlayerForScripting();
     617             :         NSString                        *key = nil;
     618             :         OOPlanetEntity          *planet = nil;
     619             :         
     620             :         if (argc > 0)  key = OOStringFromJSValue(context, OOJS_ARGV[0]);
     621             :         if (EXPECT_NOT(key == nil))
     622             :         {
     623             :                 OOJSReportBadArguments(context, @"System", @"addPlanet", MIN(argc, 1U), OOJS_ARGV, nil, @"string (planet key)");
     624             :                 return NO;
     625             :         }
     626             :         
     627             :         OOJS_BEGIN_FULL_NATIVE(context)
     628             :         planet = [player addPlanet:key];
     629             :         OOJS_END_FULL_NATIVE
     630             :         
     631             :         OOJS_RETURN_OBJECT(planet);
     632             :         
     633             :         OOJS_NATIVE_EXIT
     634             : }
     635             : 
     636             : 
     637             : // addMoon(key : String) : Planet
     638           0 : static JSBool SystemAddMoon(JSContext *context, uintN argc, jsval *vp)
     639             : {
     640             :         OOJS_NATIVE_ENTER(context)
     641             :         
     642             :         PlayerEntity            *player = OOPlayerForScripting();
     643             :         NSString                        *key = nil;
     644             :         OOPlanetEntity          *planet = nil;
     645             :         
     646             :         if (argc > 0)  key = OOStringFromJSValue(context, OOJS_ARGV[0]);
     647             :         if (EXPECT_NOT(key == nil))
     648             :         {
     649             :                 OOJSReportBadArguments(context, @"System", @"addMoon", MIN(argc, 1U), OOJS_ARGV, nil, @"string (planet key)");
     650             :                 return NO;
     651             :         }
     652             :         
     653             :         OOJS_BEGIN_FULL_NATIVE(context)
     654             :         planet = [player addMoon:key];
     655             :         OOJS_END_FULL_NATIVE
     656             :         
     657             :         OOJS_RETURN_OBJECT(planet);
     658             :         
     659             :         OOJS_NATIVE_EXIT
     660             : }
     661             : 
     662             : 
     663             : // sendAllShipsAway()
     664           0 : static JSBool SystemSendAllShipsAway(JSContext *context, uintN argc, jsval *vp)
     665             : {
     666             :         OOJS_NATIVE_ENTER(context)
     667             :         
     668             :         PlayerEntity *player = OOPlayerForScripting();
     669             :         
     670             :         [player sendAllShipsAway];
     671             :         OOJS_RETURN_VOID;
     672             :         
     673             :         OOJS_NATIVE_EXIT
     674             : }
     675             : 
     676             : 
     677             : // countShipsWithPrimaryRole(role : String [, relativeTo : Entity [, range : Number]]) : Number
     678           0 : static JSBool SystemCountShipsWithPrimaryRole(JSContext *context, uintN argc, jsval *vp)
     679             : {
     680             :         OOJS_NATIVE_ENTER(context)
     681             :         
     682             :         NSString                        *role = nil;
     683             :         Entity                          *relativeTo = nil;
     684             :         double                          range = -1;
     685             :         unsigned                        result;
     686             :         
     687             :         if (argc > 0)  role = OOStringFromJSValue(context, OOJS_ARGV[0]);
     688             :         if (EXPECT_NOT(role == nil))
     689             :         {
     690             :                 OOJSReportBadArguments(context, @"System", @"countShipsWithPrimaryRole", MIN(argc, 1U), OOJS_ARGV, nil, @"string (role)");
     691             :                 return NO;
     692             :         }
     693             :         
     694             :         // Get optional arguments
     695             :         argc -= 1;
     696             :         jsval *argv = OOJS_ARGV + 1;
     697             :         if (EXPECT_NOT(!GetRelativeToAndRange(context, @"countShipsWithPrimaryRole", &argc, &argv, &relativeTo, &range)))  return NO;
     698             :         
     699             :         OOJS_BEGIN_FULL_NATIVE(context)
     700             :         result = [UNIVERSE countShipsWithPrimaryRole:role inRange:range ofEntity:relativeTo];
     701             :         OOJS_END_FULL_NATIVE
     702             :         
     703             :         OOJS_RETURN_INT(result);
     704             :         
     705             :         OOJS_NATIVE_EXIT
     706             : }
     707             : 
     708             : 
     709             : // countShipsWithRole(role : String [, relativeTo : Entity [, range : Number]]) : Number
     710           0 : static JSBool SystemCountShipsWithRole(JSContext *context, uintN argc, jsval *vp)
     711             : {
     712             :         OOJS_NATIVE_ENTER(context)
     713             :         
     714             :         NSString                        *role = nil;
     715             :         Entity                          *relativeTo = nil;
     716             :         double                          range = -1;
     717             :         unsigned                        result;
     718             :         
     719             :         if (argc > 0)  role = OOStringFromJSValue(context, OOJS_ARGV[0]);
     720             :         if (EXPECT_NOT(role == nil))
     721             :         {
     722             :                 OOJSReportBadArguments(context, @"System", @"countShipsWithRole", MIN(argc, 1U), OOJS_ARGV, nil, @"string (role)");
     723             :                 return NO;
     724             :         }
     725             :         
     726             :         // Get optional arguments
     727             :         argc -= 1;
     728             :         jsval *argv = OOJS_ARGV + 1;
     729             :         if (EXPECT_NOT(!GetRelativeToAndRange(context, @"countShipsWithRole", &argc, &argv, &relativeTo, &range)))  return NO;
     730             :         
     731             :         OOJS_BEGIN_FULL_NATIVE(context)
     732             :         result = [UNIVERSE countShipsWithRole:role inRange:range ofEntity:relativeTo];
     733             :         OOJS_END_FULL_NATIVE
     734             :         
     735             :         OOJS_RETURN_INT(result);
     736             :         
     737             :         OOJS_NATIVE_EXIT
     738             : }
     739             : 
     740             : 
     741             : // shipsWithPrimaryRole(role : String [, relativeTo : Entity [, range : Number]]) : Array (Entity)
     742           0 : static JSBool SystemShipsWithPrimaryRole(JSContext *context, uintN argc, jsval *vp)
     743             : {
     744             :         OOJS_NATIVE_ENTER(context)
     745             :         
     746             :         NSString                        *role = nil;
     747             :         Entity                          *relativeTo = nil;
     748             :         double                          range = -1;
     749             :         NSArray                         *result = nil;
     750             :         
     751             :         if (argc > 0)  role = OOStringFromJSValue(context, OOJS_ARGV[0]);
     752             :         if (EXPECT_NOT(role == nil))
     753             :         {
     754             :                 OOJSReportBadArguments(context, @"System", @"countShipsWithRole", MIN(argc, 1U), OOJS_ARGV, nil, @"string (role)");
     755             :                 return NO;
     756             :         }
     757             :         
     758             :         // Get optional arguments
     759             :         argc -= 1;
     760             :         jsval *argv = OOJS_ARGV + 1;
     761             :         if (EXPECT_NOT(!GetRelativeToAndRange(context, @"shipsWithPrimaryRole", &argc, &argv, &relativeTo, &range)))  return NO;
     762             :         
     763             :         // Search for entities
     764             :         OOJS_BEGIN_FULL_NATIVE(context)
     765             :         result = FindShips(HasPrimaryRolePredicate, role, relativeTo, range);
     766             :         OOJS_END_FULL_NATIVE
     767             :         
     768             :         OOJS_RETURN_OBJECT(result);
     769             :         
     770             :         OOJS_NATIVE_EXIT
     771             : }
     772             : 
     773             : 
     774             : // shipsWithRole(role : String [, relativeTo : Entity [, range : Number]]) : Array (Entity)
     775           0 : static JSBool SystemShipsWithRole(JSContext *context, uintN argc, jsval *vp)
     776             : {
     777             :         OOJS_NATIVE_ENTER(context)
     778             :         
     779             :         NSString                        *role = nil;
     780             :         Entity                          *relativeTo = nil;
     781             :         double                          range = -1;
     782             :         NSArray                         *result = nil;
     783             :         
     784             :         if (argc > 0)  role = OOStringFromJSValue(context, OOJS_ARGV[0]);
     785             :         if (EXPECT_NOT(role == nil))
     786             :         {
     787             :                 OOJSReportBadArguments(context, @"System", @"shipsWithRole", MIN(argc, 1U), OOJS_ARGV, nil, @"string (role)");
     788             :                 return NO;
     789             :         }
     790             :         
     791             :         // Get optional arguments
     792             :         argc -= 1;
     793             :         jsval *subargv = OOJS_ARGV + 1;
     794             :         if (EXPECT_NOT(!GetRelativeToAndRange(context, @"shipsWithRole", &argc, &subargv, &relativeTo, &range)))  return NO;
     795             :         
     796             :         // Search for entities
     797             :         OOJS_BEGIN_FULL_NATIVE(context)
     798             :         result = FindShips(HasRolePredicate, role, relativeTo, range);
     799             :         OOJS_END_FULL_NATIVE
     800             :         
     801             :         OOJS_RETURN_OBJECT(result);
     802             :         
     803             :         OOJS_NATIVE_EXIT
     804             : }
     805             : 
     806             : 
     807             : // countEntitiesWithScanClass(scanClass : String [, relativeTo : Entity [, range : Number]]) : Number
     808           0 : static JSBool SystemCountEntitiesWithScanClass(JSContext *context, uintN argc, jsval *vp)
     809             : {
     810             :         OOJS_NATIVE_ENTER(context)
     811             :         
     812             :         OOScanClass                     scanClass = CLASS_NOT_SET;
     813             :         Entity                          *relativeTo = nil;
     814             :         double                          range = -1;
     815             :         unsigned                        result;
     816             :         
     817             :         if (argc > 0)  scanClass = OOScanClassFromJSValue(context, OOJS_ARGV[0]);
     818             :         if (scanClass == CLASS_NOT_SET)
     819             :         {
     820             :                 OOJSReportBadArguments(context, @"System", @"countEntitiesWithScanClass", MIN(argc, 1U), OOJS_ARGV, nil, @"string (scan class)");
     821             :                 return NO;
     822             :         }
     823             :         
     824             :         // Get optional arguments
     825             :         argc -= 1;
     826             :         jsval *argv = OOJS_ARGV + 1;
     827             :         if (EXPECT_NOT(!GetRelativeToAndRange(context, @"countEntitiesWithScanClass", &argc, &argv, &relativeTo, &range)))  return NO;
     828             :         
     829             :         OOJS_BEGIN_FULL_NATIVE(context)
     830             :         result = [UNIVERSE countShipsWithScanClass:scanClass inRange:range ofEntity:relativeTo];
     831             :         OOJS_END_FULL_NATIVE
     832             :         
     833             :         OOJS_RETURN_INT(result);
     834             :         
     835             :         OOJS_NATIVE_EXIT
     836             : }
     837             : 
     838             : 
     839             : // entitiesWithScanClass(scanClass : String [, relativeTo : Entity [, range : Number]]) : Array (Entity)
     840           0 : static JSBool SystemEntitiesWithScanClass(JSContext *context, uintN argc, jsval *vp)
     841             : {
     842             :         OOJS_NATIVE_ENTER(context)
     843             :         
     844             :         OOScanClass                     scanClass = CLASS_NOT_SET;
     845             :         Entity                          *relativeTo = nil;
     846             :         double                          range = -1;
     847             :         NSArray                         *result = nil;
     848             :         
     849             :         if (argc > 0)  scanClass = OOScanClassFromJSValue(context, OOJS_ARGV[0]);
     850             :         if (scanClass == CLASS_NOT_SET)
     851             :         {
     852             :                 OOJSReportBadArguments(context, @"System", @"countEntitiesWithScanClass", MIN(argc, 1U), OOJS_ARGV, nil, @"string (scan class)");
     853             :                 return NO;
     854             :         }
     855             :         
     856             :         // Get optional arguments
     857             :         argc -= 1;
     858             :         jsval *argv = OOJS_ARGV + 1;
     859             :         if (EXPECT_NOT(!GetRelativeToAndRange(context, @"entitiesWithScanClass", &argc, &argv, &relativeTo, &range)))  return NO;
     860             :         
     861             :         // Search for entities
     862             :         OOJS_BEGIN_FULL_NATIVE(context)
     863             :         result = FindJSVisibleEntities(HasScanClassPredicate, [NSNumber numberWithInt:scanClass], relativeTo, range);
     864             :         OOJS_END_FULL_NATIVE
     865             :         
     866             :         OOJS_RETURN_OBJECT(result);
     867             :         
     868             :         OOJS_NATIVE_EXIT
     869             : }
     870             : 
     871             : 
     872             : // filteredEntities(this : Object, predicate : Function [, relativeTo : Entity [, range : Number]]) : Array (Entity)
     873           0 : static JSBool SystemFilteredEntities(JSContext *context, uintN argc, jsval *vp)
     874             : {
     875             :         OOJS_NATIVE_ENTER(context)
     876             :         
     877             :         JSObject                        *jsThis = NULL;
     878             :         jsval                           predicate;
     879             :         Entity                          *relativeTo = nil;
     880             :         double                          range = -1;
     881             :         NSArray                         *result = nil;
     882             :         
     883             :         // Get this and predicate arguments
     884             :         if (argc < 2 || !OOJSValueIsFunction(context, OOJS_ARGV[1]) || !JS_ValueToObject(context, OOJS_ARGV[0], &jsThis))
     885             :         {
     886             :                 OOJSReportBadArguments(context, @"System", @"filteredEntities", argc, OOJS_ARGV, nil, @"this, predicate function, and optional reference entity and range");
     887             :                 return NO;
     888             :         }
     889             :         predicate = OOJS_ARGV[1];
     890             :         
     891             :         // Get optional arguments
     892             :         argc -= 2;
     893             :         jsval *argv = OOJS_ARGV + 2;
     894             :         if (EXPECT_NOT(!GetRelativeToAndRange(context, @"filteredEntities", &argc, &argv, &relativeTo, &range)))  return NO;
     895             :         
     896             :         // Search for entities
     897             :         JSFunctionPredicateParameter param = { context, predicate, jsThis, NO };
     898             :         OOJSPauseTimeLimiter();
     899             :         result = FindJSVisibleEntities(JSFunctionPredicate, &param, relativeTo, range);
     900             :         OOJSResumeTimeLimiter();
     901             :         
     902             :         if (EXPECT_NOT(param.errorFlag))  return NO;
     903             :         
     904             :         OOJS_RETURN_OBJECT(result);
     905             :         
     906             :         OOJS_NATIVE_EXIT
     907             : }
     908             : 
     909             : 
     910             : // locationFromCode(populator_named_region : String)
     911           0 : static JSBool SystemLocationFromCode(JSContext *context, uintN argc, jsval *vp)
     912             : {
     913             :         OOJS_NATIVE_ENTER(context)
     914             :         
     915             :         NSString                        *code = nil;
     916             :         if (argc > 0)  
     917             :         {
     918             :                 code = OOStringFromJSValue(context, OOJS_ARGV[0]);
     919             :         }
     920             :         if (EXPECT_NOT(code == nil))
     921             :         {
     922             :                 OOJSReportBadArguments(context, @"System", @"locationFromCode", argc, OOJS_ARGV, nil, @"location code");
     923             :                 return NO;
     924             :         }
     925             :         OOSunEntity *sun = [UNIVERSE sun];
     926             :         OOPlanetEntity *planet = [UNIVERSE planet];
     927             :         HPVector position = kZeroHPVector;
     928             :         if (sun == nil || planet == nil)
     929             :         {
     930             :                 position = [UNIVERSE locationByCode:@"WITCHPOINT" withSun:nil andPlanet:nil];
     931             :         }
     932             :         else
     933             :         {
     934             :                 position = [UNIVERSE locationByCode:code withSun:sun andPlanet:planet];
     935             :         }
     936             : 
     937             :         OOJS_RETURN_HPVECTOR(position);
     938             : 
     939             :         OOJS_NATIVE_EXIT
     940             : }
     941             : 
     942             : 
     943             : // addShips(role : String, count : Number [, position: Vector [, radius: Number]]) : Array
     944           0 : static JSBool SystemAddShips(JSContext *context, uintN argc, jsval *vp)
     945             : {
     946             :         return SystemAddShipsOrGroup(context, argc, vp, NO);
     947             : }
     948             : 
     949             : 
     950             : // addGroup(role : String, count : Number [, position: Vector [, radius: Number]]) : Array
     951           0 : static JSBool SystemAddGroup(JSContext *context, uintN argc, jsval *vp)
     952             : {
     953             :         return SystemAddShipsOrGroup(context, argc, vp, YES);
     954             : }
     955             : 
     956             : 
     957             : // addShipsToRoute(role : String, count : Number [, position: Number [, route: String]])
     958           0 : static JSBool SystemAddShipsToRoute(JSContext *context, uintN argc, jsval *vp)
     959             : {
     960             :         return SystemAddShipsOrGroupToRoute(context, argc, vp, NO);
     961             : }
     962             : 
     963             : 
     964             : // addGroupToRoute(role : String, count : Number,  position: Number[, route: String])
     965           0 : static JSBool SystemAddGroupToRoute(JSContext *context, uintN argc, jsval *vp)
     966             : {
     967             :         return SystemAddShipsOrGroupToRoute(context, argc, vp, YES);
     968             : }
     969             : 
     970             : 
     971             : // legacy_addShips(role : String, count : Number)
     972           0 : static JSBool SystemLegacyAddShips(JSContext *context, uintN argc, jsval *vp)
     973             : {
     974             :         OOStandardsDeprecated(@"system.legacy_addShips() is deprecated");
     975             :         OOJS_NATIVE_ENTER(context)
     976             :                 
     977             :         NSString                        *role = nil;
     978             :         int32                           count;
     979             :         
     980             :         if (argc > 0)  role = OOStringFromJSValue(context, OOJS_ARGV[0]);
     981             :         if (EXPECT_NOT(role == nil ||
     982             :                                    !JS_ValueToInt32(context, OOJS_ARGV[1], &count) ||
     983             :                                    argc < 2 ||
     984             :                                    count < 1 || 64 < count))
     985             :         {
     986             :                 OOJSReportBadArguments(context, @"System", @"legacy_addShips", argc, OOJS_ARGV, nil, @"role and positive count no greater than 64");
     987             :                 return NO;
     988             :         }
     989             :         
     990             :         OOJS_BEGIN_FULL_NATIVE(context)
     991             :         while (count--)  [UNIVERSE witchspaceShipWithPrimaryRole:role];
     992             :         OOJS_END_FULL_NATIVE
     993             :         
     994             :         OOJS_RETURN_VOID;
     995             :         
     996             :         OOJS_NATIVE_EXIT
     997             : }
     998             : 
     999             : 
    1000             : // legacy_addSystemShips(role : String, count : Number, location : Number)
    1001           0 : static JSBool SystemLegacyAddSystemShips(JSContext *context, uintN argc, jsval *vp)
    1002             : {
    1003             :         OOStandardsDeprecated(@"system.legacy_addSystemShips() is deprecated");
    1004             :         OOJS_NATIVE_ENTER(context)
    1005             :         
    1006             :         jsdouble                        position;
    1007             :         NSString                        *role = nil;
    1008             :         int32                           count;
    1009             :         
    1010             :         if (argc > 0)  role = OOStringFromJSValue(context, OOJS_ARGV[0]);
    1011             :         if (EXPECT_NOT(role == nil ||
    1012             :                                    !JS_ValueToInt32(context, OOJS_ARGV[1], &count) ||
    1013             :                                    count < 1 || 64 < count ||
    1014             :                                    argc < 3 ||
    1015             :                                    !JS_ValueToNumber(context, OOJS_ARGV[2], &position)))
    1016             :         {
    1017             :                 OOJSReportBadArguments(context, @"System", @"legacy_addSystemShips", argc, OOJS_ARGV, nil, @"role, positive count no greater than 64, and position along route");
    1018             :                 return NO;
    1019             :         }
    1020             :         
    1021             :         OOJS_BEGIN_FULL_NATIVE(context)
    1022             :         while (count--)  [UNIVERSE addShipWithRole:role nearRouteOneAt:position];
    1023             :         OOJS_END_FULL_NATIVE
    1024             :         
    1025             :         OOJS_RETURN_VOID;
    1026             :         
    1027             :         OOJS_NATIVE_EXIT
    1028             : }
    1029             : 
    1030             : 
    1031             : // legacy_addShipsAt(role : String, count : Number, coordScheme : String, coords : vectorExpression)
    1032           0 : static JSBool SystemLegacyAddShipsAt(JSContext *context, uintN argc, jsval *vp)
    1033             : {
    1034             :         OOStandardsDeprecated(@"system.legacy_addShipsAt() is deprecated");
    1035             :         OOJS_NATIVE_ENTER(context)
    1036             :         
    1037             :         PlayerEntity            *player = OOPlayerForScripting();
    1038             :         HPVector                                where;
    1039             :         NSString                        *role = nil;
    1040             :         int32                           count;
    1041             :         NSString                        *coordScheme = nil;
    1042             :         NSString                        *arg = nil;
    1043             :         
    1044             :         if (argc > 0)  role = OOStringFromJSValue(context, OOJS_ARGV[0]);
    1045             :         coordScheme = OOStringFromJSValue(context, OOJS_ARGV[2]);
    1046             :         if (EXPECT_NOT(role == nil ||
    1047             :                                    !JS_ValueToInt32(context, OOJS_ARGV[1], &count) ||
    1048             :                                    count < 1 || 64 < count ||
    1049             :                                    coordScheme == nil ||
    1050             :                                    argc < 4 ||
    1051             :                                    !VectorFromArgumentListNoError(context, argc - 3, OOJS_ARGV + 3, &where, NULL)))
    1052             :         {
    1053             :                 OOJSReportBadArguments(context, @"System", @"legacy_addShipsAt", argc, OOJS_ARGV, nil, @"role, positive count no greater than 64, coordinate scheme and coordinates");
    1054             :                 return NO;
    1055             :         }
    1056             :         
    1057             :         OOJS_BEGIN_FULL_NATIVE(context)
    1058             :         arg = [NSString stringWithFormat:@"%@ %d %@ %f %f %f", role, count, coordScheme, where.x, where.y, where.z];
    1059             :         [player addShipsAt:arg];
    1060             :         OOJS_END_FULL_NATIVE
    1061             :         
    1062             :         OOJS_RETURN_VOID;
    1063             :         
    1064             :         OOJS_NATIVE_EXIT
    1065             : }
    1066             : 
    1067             : 
    1068             : // legacy_addShipsAtPrecisely(role : String, count : Number, coordScheme : String, coords : vectorExpression)
    1069           0 : static JSBool SystemLegacyAddShipsAtPrecisely(JSContext *context, uintN argc, jsval *vp)
    1070             : {
    1071             :         OOStandardsDeprecated(@"system.legacy_addShipsAtPrecisely() is deprecated");
    1072             :         OOJS_NATIVE_ENTER(context)
    1073             :         
    1074             :         PlayerEntity            *player = OOPlayerForScripting();
    1075             :         HPVector                                where;
    1076             :         NSString                        *role = nil;
    1077             :         int32                           count;
    1078             :         NSString                        *coordScheme = nil;
    1079             :         NSString                        *arg = nil;
    1080             :         
    1081             :         if (argc > 0)  role = OOStringFromJSValue(context, OOJS_ARGV[0]);
    1082             :         coordScheme = OOStringFromJSValue(context, OOJS_ARGV[2]);
    1083             :         if (EXPECT_NOT(role == nil ||
    1084             :                                    !JS_ValueToInt32(context, OOJS_ARGV[1], &count) ||
    1085             :                                    count < 1 || 64 < count ||
    1086             :                                    coordScheme == nil ||
    1087             :                                    argc < 4 ||
    1088             :                                    !VectorFromArgumentListNoError(context, argc - 3, OOJS_ARGV + 3, &where, NULL)))
    1089             :         {
    1090             :                 OOJSReportBadArguments(context, @"System", @"legacy_addShipsAtPrecisely", argc, OOJS_ARGV, nil, @"role, positive count no greater than 64, coordinate scheme and coordinates");
    1091             :                 return NO;
    1092             :         }
    1093             :         
    1094             :         OOJS_BEGIN_FULL_NATIVE(context)
    1095             :         arg = [NSString stringWithFormat:@"%@ %d %@ %f %f %f", role, count, coordScheme, where.x, where.y, where.z];
    1096             :         [player addShipsAtPrecisely:arg];
    1097             :         OOJS_END_FULL_NATIVE
    1098             :         
    1099             :         OOJS_RETURN_VOID;
    1100             :         
    1101             :         OOJS_NATIVE_EXIT
    1102             : }
    1103             : 
    1104             : 
    1105             : // legacy_addShipsWithinRadius(role : String, count : Number, coordScheme : String, coords : vectorExpression, radius : Number)
    1106           0 : static JSBool SystemLegacyAddShipsWithinRadius(JSContext *context, uintN argc, jsval *vp)
    1107             : {
    1108             :         OOStandardsDeprecated(@"system.legacy_addShipsWithinRadius() is deprecated");
    1109             :         OOJS_NATIVE_ENTER(context)
    1110             :         
    1111             :         PlayerEntity            *player = OOPlayerForScripting();
    1112             :         HPVector                                where;
    1113             :         jsdouble                        radius;
    1114             :         NSString                        *role = nil;
    1115             :         int32                           count;
    1116             :         NSString                        *coordScheme = nil;
    1117             :         NSString                        *arg = nil;
    1118             :         uintN                           consumed = 0;
    1119             :         
    1120             :         if (argc > 0)  role = OOStringFromJSValue(context, OOJS_ARGV[0]);
    1121             :         if (argc > 2)  coordScheme = OOStringFromJSValue(context, OOJS_ARGV[2]);
    1122             :         if (EXPECT_NOT(role == nil ||
    1123             :                                    !JS_ValueToInt32(context, OOJS_ARGV[1], &count) ||
    1124             :                                    count < 1 || 64 < count ||
    1125             :                                    coordScheme == nil ||
    1126             :                                    argc < 5 ||
    1127             :                                    !VectorFromArgumentListNoError(context, argc - 3, OOJS_ARGV + 3, &where, &consumed) ||
    1128             :                                    !JS_ValueToNumber(context, OOJS_ARGV[3 + consumed], &radius)))
    1129             :         {
    1130             :                 OOJSReportBadArguments(context, @"System", @"legacy_addShipWithinRadius", argc, OOJS_ARGV, nil, @"role, positive count no greater than 64, coordinate scheme, coordinates and radius");
    1131             :                 return NO;
    1132             :         }
    1133             :         
    1134             :         OOJS_BEGIN_FULL_NATIVE(context)
    1135             :         arg = [NSString stringWithFormat:@"%@ %d %@ %f %f %f %f", role, count, coordScheme, where.x, where.y, where.z, radius];
    1136             :         [player addShipsWithinRadius:arg];
    1137             :         OOJS_END_FULL_NATIVE
    1138             :         
    1139             :         OOJS_RETURN_VOID;
    1140             :         
    1141             :         OOJS_NATIVE_EXIT
    1142             : }
    1143             : 
    1144             : 
    1145             : // legacy_spawnShip(key : string)
    1146           0 : static JSBool SystemLegacySpawnShip(JSContext *context, uintN argc, jsval *vp)
    1147             : {
    1148             :         OOStandardsDeprecated(@"system.legacy_spawnShip() is deprecated");
    1149             :         OOJS_NATIVE_ENTER(context)
    1150             :         
    1151             :         NSString                        *key = nil;
    1152             :         OOPlayerForScripting(); // For backwards-compatibility
    1153             :         
    1154             :         if (argc > 0)  key = OOStringFromJSValue(context, OOJS_ARGV[0]);
    1155             :         if (key == nil)
    1156             :         {
    1157             :                 OOJSReportBadArguments(context, @"System", @"legacy_spawnShip", MIN(argc, 1U), OOJS_ARGV, nil, @"string (ship key)");
    1158             :                 return NO;
    1159             :         }
    1160             :         
    1161             :         OOJS_BEGIN_FULL_NATIVE(context)
    1162             :         [UNIVERSE spawnShip:key];
    1163             :         OOJS_END_FULL_NATIVE
    1164             :         
    1165             :         OOJS_RETURN_VOID;
    1166             :         
    1167             :         OOJS_NATIVE_EXIT
    1168             : }
    1169             : 
    1170             : 
    1171             : // *** Static methods ***
    1172             : 
    1173             : // systemNameForID(ID : Number) : String
    1174           0 : static JSBool SystemStaticSystemNameForID(JSContext *context, uintN argc, jsval *vp)
    1175             : {
    1176             :         OOJS_NATIVE_ENTER(context)
    1177             :         
    1178             :         int32                           systemID;
    1179             :         
    1180             :         if (argc < 1 || !JS_ValueToInt32(context, OOJS_ARGV[0], &systemID) || systemID < -1 || kOOMaximumSystemID < systemID)      // -1 interstellar space!
    1181             :         {
    1182             :                 OOJSReportBadArguments(context, @"System", @"systemNameForID", MIN(argc, 1U), OOJS_ARGV, nil, @"system ID");
    1183             :                 return NO;
    1184             :         }
    1185             :         
    1186             :         if (systemID == -1)
    1187             :                 OOJS_RETURN_OBJECT(DESC(@"interstellar-space"));
    1188             :         else
    1189             :                 OOJS_RETURN_OBJECT([UNIVERSE getSystemName:systemID]);
    1190             :         
    1191             :         OOJS_NATIVE_EXIT
    1192             : }
    1193             : 
    1194             : 
    1195             : // systemIDForName(name : String) : Number
    1196           0 : static JSBool SystemStaticSystemIDForName(JSContext *context, uintN argc, jsval *vp)
    1197             : {
    1198             :         OOJS_NATIVE_ENTER(context)
    1199             :         
    1200             :         NSString                        *name = nil;
    1201             :         unsigned                        result;
    1202             :         
    1203             :         if (argc > 0)  name = OOStringFromJSValue(context, OOJS_ARGV[0]);
    1204             :         if (name == nil)
    1205             :         {
    1206             :                 OOJSReportBadArguments(context, @"System", @"systemIDForName", MIN(argc, 1U), OOJS_ARGV, nil, @"string");
    1207             :                 return NO;
    1208             :         }
    1209             :         
    1210             :         OOJS_BEGIN_FULL_NATIVE(context)
    1211             : 
    1212             :         result = [UNIVERSE findSystemFromName:name];
    1213             : 
    1214             :         OOJS_END_FULL_NATIVE
    1215             :         
    1216             :         OOJS_RETURN_INT(result);
    1217             :         
    1218             :         OOJS_NATIVE_EXIT
    1219             : }
    1220             : 
    1221             : 
    1222             : // infoForSystem(galaxyID : Number, systemID : Number) : SystemInfo
    1223           0 : static JSBool SystemStaticInfoForSystem(JSContext *context, uintN argc, jsval *vp)
    1224             : {
    1225             :         OOJS_NATIVE_ENTER(context)
    1226             :         
    1227             :         int32                           galaxyID;
    1228             :         int32                           systemID;
    1229             :         
    1230             :         if (argc < 2 || !JS_ValueToInt32(context, OOJS_ARGV[0], &galaxyID) || !JS_ValueToInt32(context, OOJS_ARGV[1], &systemID))
    1231             :         {
    1232             :                 OOJSReportBadArguments(context, @"System", @"infoForSystem", argc, OOJS_ARGV, nil, @"galaxy ID and system ID");
    1233             :                 return NO;
    1234             :         }
    1235             :         
    1236             :         if (galaxyID < 0 || galaxyID > kOOMaximumGalaxyID)
    1237             :         {
    1238             :                 OOJSReportBadArguments(context, @"System", @"infoForSystem", 1, OOJS_ARGV, @"Invalid galaxy ID", [NSString stringWithFormat:@"number in the range 0 to %u", kOOMaximumGalaxyID]);
    1239             :                 return NO;
    1240             :         }
    1241             :         
    1242             :         if (systemID < kOOMinimumSystemID || systemID > kOOMaximumSystemID)
    1243             :         {
    1244             :                 OOJSReportBadArguments(context, @"System", @"infoForSystem", 1, OOJS_ARGV + 1, @"Invalid system ID", [NSString stringWithFormat:@"number in the range %i to %i", kOOMinimumSystemID, kOOMaximumSystemID]);
    1245             :                 return NO;
    1246             :         }
    1247             :         
    1248             :         OOJS_RETURN(GetJSSystemInfoForSystem(context, galaxyID, systemID));
    1249             :         
    1250             :         OOJS_NATIVE_EXIT
    1251             : }
    1252             : 
    1253             : 
    1254           0 : static JSBool SystemAddVisualEffect(JSContext *context, uintN argc, jsval *vp)
    1255             : {
    1256             :         OOJS_NATIVE_ENTER(context)
    1257             :         
    1258             :         NSString                        *key = nil;
    1259             :         HPVector         where;
    1260             :         
    1261             :         uintN                           consumed = 0;
    1262             : 
    1263             :         if (argc > 0)  key = OOStringFromJSValue(context, OOJS_ARGV[0]);
    1264             :         if (key == nil)
    1265             :         {
    1266             :                 OOJSReportBadArguments(context, @"System", @"addVisualEffect", MIN(argc, 1U), &OOJS_ARGV[0], nil, @"string (key)");
    1267             :                 return NO;
    1268             :         }
    1269             : 
    1270             :         if (!VectorFromArgumentListNoError(context, argc - 1, OOJS_ARGV + 1, &where, &consumed))
    1271             :         {
    1272             :                 OOJSReportBadArguments(context, @"System", @"addVisualEffect", MIN(argc - 1, 1U), &OOJS_ARGV[1], nil, @"vector");
    1273             :                 return NO;
    1274             :         }
    1275             : 
    1276             :         OOVisualEffectEntity *result = nil;
    1277             : 
    1278             :         OOJS_BEGIN_FULL_NATIVE(context)
    1279             : 
    1280             :         result = [UNIVERSE addVisualEffectAt:where withKey:key];
    1281             : 
    1282             :         OOJS_END_FULL_NATIVE
    1283             :         
    1284             :         OOJS_RETURN_OBJECT(result);
    1285             : 
    1286             :         OOJS_NATIVE_EXIT
    1287             : }
    1288             : 
    1289           0 : static JSBool SystemSetPopulator(JSContext *context, uintN argc, jsval *vp)
    1290             : {
    1291             :         OOJS_NATIVE_ENTER(context)
    1292             : 
    1293             :         NSString *key;
    1294             :         NSMutableDictionary *settings;
    1295             :         JSObject                        *params = NULL;
    1296             : 
    1297             :         if (argc < 1) 
    1298             :         {
    1299             :                 OOJSReportBadArguments(context, @"System", @"setPopulator", MIN(argc, 0U), &OOJS_ARGV[0], nil, @"string (key), object (settings)");
    1300             :                 return NO;
    1301             :         }
    1302             :         key = OOStringFromJSValue(context, OOJS_ARGV[0]);
    1303             :         if (key == nil)
    1304             :         {
    1305             :                 OOJSReportBadArguments(context, @"System", @"setPopulator", MIN(argc, 0U), &OOJS_ARGV[0], nil, @"key, settings");
    1306             :                 return NO;
    1307             :         }
    1308             :         if (argc < 2 || JSVAL_IS_NULL(OOJS_ARGV[1]))
    1309             :         {
    1310             :                 // clearing
    1311             :                 [UNIVERSE setPopulatorSetting:key to:nil];
    1312             :         }
    1313             :         else
    1314             :         {
    1315             :                 // adding
    1316             :                 if (!JS_ValueToObject(context, OOJS_ARGV[1], &params))
    1317             :                 {
    1318             :                         OOJSReportBadArguments(context, @"System", @"setPopulator", MIN(argc, 1U), OOJS_ARGV, NULL, @"key, settings");
    1319             :                         return NO;
    1320             :                 }
    1321             :                 jsval                           callback = JSVAL_NULL;
    1322             :                 if (JS_GetProperty(context, params, "callback", &callback) == JS_FALSE || JSVAL_IS_VOID(callback))
    1323             :                 {
    1324             :                         OOJSReportBadArguments(context, @"System", @"setPopulator", MIN(argc, 1U), OOJS_ARGV, NULL, @"settings must have a 'callback' property.");
    1325             :                         return NO;
    1326             :                 }
    1327             : 
    1328             :                 OOJSPopulatorDefinition *populator = [[OOJSPopulatorDefinition alloc] init];
    1329             :                 [populator setCallback:callback];
    1330             : 
    1331             :                 settings = OOJSNativeObjectFromJSObject(context, JSVAL_TO_OBJECT(OOJS_ARGV[1]));
    1332             :                 [settings setObject:populator forKey:@"callbackObj"];
    1333             : 
    1334             :                 jsval                           coords = JSVAL_NULL;
    1335             :                 if (JS_GetProperty(context, params, "coordinates", &coords) != JS_FALSE && !JSVAL_IS_VOID(coords))
    1336             :                 {
    1337             :                         Vector coordinates = kZeroVector;
    1338             :                         if (JSValueToVector(context, coords, &coordinates))
    1339             :                         {
    1340             :                                 // convert vector in NS-storable form
    1341             :                                 [settings setObject:[NSArray arrayWithObjects:[NSNumber numberWithFloat:coordinates.x],[NSNumber numberWithFloat:coordinates.y],[NSNumber numberWithFloat:coordinates.z],nil] forKey:@"coordinates"];
    1342             :                         }
    1343             :                 }
    1344             : 
    1345             :                 [populator release];
    1346             : 
    1347             :                 [UNIVERSE setPopulatorSetting:key to:settings];
    1348             :         }       
    1349             : 
    1350             :         OOJS_RETURN_VOID;
    1351             : 
    1352             :         OOJS_NATIVE_EXIT
    1353             : }
    1354             : 
    1355             : 
    1356           0 : static JSBool SystemSetWaypoint(JSContext *context, uintN argc, jsval *vp)
    1357             : {
    1358             :         OOJS_NATIVE_ENTER(context)
    1359             : 
    1360             :         NSString *key;
    1361             :         NSMutableDictionary *settings;
    1362             :         HPVector position;
    1363             :         Quaternion orientation;
    1364             : 
    1365             :         if (argc < 1) 
    1366             :         {
    1367             :                 OOJSReportBadArguments(context, @"System", @"setWaypoint", MIN(argc, 0U), &OOJS_ARGV[0], nil, @"key, position, orientation, definition");
    1368             :                 return NO;
    1369             :         }
    1370             :         key = OOStringFromJSValue(context, OOJS_ARGV[0]);
    1371             :         if (key == nil)
    1372             :         {
    1373             :                 OOJSReportBadArguments(context, @"System", @"setWaypoint", MIN(argc, 0U), &OOJS_ARGV[0], nil, @"key, position, orientation, definition");
    1374             :                 return NO;
    1375             :         }
    1376             :         if (argc < 4 || JSVAL_IS_NULL(OOJS_ARGV[3]))
    1377             :         {
    1378             :                 // clearing
    1379             :                 [UNIVERSE defineWaypoint:nil forKey:key];
    1380             :         }
    1381             :         else
    1382             :         {
    1383             :                 // adding
    1384             :                 if (!JSValueToHPVector(context, OOJS_ARGV[1], &position))
    1385             :                 {
    1386             :                         OOJSReportBadArguments(context, @"System", @"setWaypoint", MIN(argc, 2U), OOJS_ARGV, NULL, @"key, position, orientation, definition");
    1387             :                         return NO;
    1388             :                 }
    1389             :                 if (!JSValueToQuaternion(context, OOJS_ARGV[2], &orientation))
    1390             :                 {
    1391             :                         OOJSReportBadArguments(context, @"System", @"setWaypoint", MIN(argc, 3U), OOJS_ARGV, NULL, @"key, position, orientation, definition");
    1392             :                         return NO;
    1393             :                 }
    1394             :                 if (!JSVAL_IS_OBJECT(OOJS_ARGV[3]) || JSVAL_IS_NULL(OOJS_ARGV[3]))
    1395             :                 {
    1396             :                         OOJSReportBadArguments(context, @"System", @"setWaypoint", MIN(argc, 4U), OOJS_ARGV, NULL, @"key, position, orientation, definition");
    1397             :                         return NO;
    1398             :                 }
    1399             :                 
    1400             :                 settings = [[OOJSNativeObjectFromJSObject(context, JSVAL_TO_OBJECT(OOJS_ARGV[3])) mutableCopy] autorelease];
    1401             :                 [settings setObject:[NSArray arrayWithObjects:[NSNumber numberWithDouble:position.x],[NSNumber numberWithDouble:position.y],[NSNumber numberWithDouble:position.z],nil] forKey:@"position"];
    1402             :                 [settings setObject:[NSArray arrayWithObjects:[NSNumber numberWithDouble:orientation.w],[NSNumber numberWithDouble:orientation.x],[NSNumber numberWithDouble:orientation.y],[NSNumber numberWithDouble:orientation.z],nil] forKey:@"orientation"];
    1403             : 
    1404             :                 [UNIVERSE defineWaypoint:settings forKey:key];
    1405             :         }       
    1406             : 
    1407             :         OOJS_RETURN_VOID;
    1408             : 
    1409             :         OOJS_NATIVE_EXIT
    1410             : }
    1411             : 
    1412             : // *** Helper functions ***
    1413             : 
    1414             : // Shared implementation of addShips() and addGroup().
    1415           0 : static JSBool SystemAddShipsOrGroup(JSContext *context, uintN argc, jsval *vp, BOOL isGroup)
    1416             : {
    1417             :         OOJS_NATIVE_ENTER(context)
    1418             :         
    1419             :         NSString                        *role = nil;
    1420             :         int32                           count = 0;
    1421             :         uintN                           consumed = 0;
    1422             :         HPVector                                where;
    1423             :         double                          radius = NSNotFound;    // a negative value means 
    1424             :         id                                      result = nil;
    1425             :         
    1426             :         NSString                        *func = isGroup ? @"addGroup" : @"addShips";
    1427             :         
    1428             :         if (argc > 0)  role = OOStringFromJSValue(context, OOJS_ARGV[0]);
    1429             :         if (role == nil)
    1430             :         {
    1431             :                 OOJSReportBadArguments(context, @"System", func, MIN(argc, 1U), &OOJS_ARGV[0], nil, @"string (role)");
    1432             :                 return NO;
    1433             :         }
    1434             :         if (argc < 2 || !JS_ValueToInt32(context, OOJS_ARGV[1], &count) || count < 1 || 64 < count)
    1435             :         {
    1436             :                 OOJSReportBadArguments(context, @"System", func, MIN(argc - 1, 1U), &OOJS_ARGV[1], nil, @"number (positive count no greater than 64)");
    1437             :                 return NO;
    1438             :         }
    1439             :         
    1440             :         if (argc < 3)
    1441             :         {
    1442             :                 where = [UNIVERSE getWitchspaceExitPosition];
    1443             :                 radius = SCANNER_MAX_RANGE;
    1444             :         }
    1445             :         else
    1446             :         {
    1447             :                 if (!VectorFromArgumentListNoError(context, argc - 2, OOJS_ARGV + 2, &where, &consumed))
    1448             :                 {
    1449             :                         OOJSReportBadArguments(context, @"System", func, MIN(argc - 2, 1U), &OOJS_ARGV[2], nil, @"vector");
    1450             :                         return NO;
    1451             :                 }
    1452             :                 
    1453             :                 if (argc > 2 + consumed)
    1454             :                 {
    1455             :                         if (!JS_ValueToNumber(context, OOJS_ARGV[2 + consumed], &radius))
    1456             :                         {
    1457             :                                 OOJSReportBadArguments(context, @"System", func, MIN(argc - 2 - consumed, 1U), &OOJS_ARGV[2 + consumed], nil, @"number (radius)");
    1458             :                                 return NO;
    1459             :                         }
    1460             :                 }
    1461             :         }
    1462             :         
    1463             :         OOJS_BEGIN_FULL_NATIVE(context)
    1464             :         // Note: the use of witchspace-in effects (as in legacy_addShips) depends on proximity to the witchpoint.
    1465             :         result = [UNIVERSE addShipsAt:where withRole:role quantity:count withinRadius:radius asGroup:isGroup];
    1466             :         
    1467             :         if (isGroup)
    1468             :         {
    1469             :                 NSArray *array = result;
    1470             :                 if ([array count] > 0)  result = [(ShipEntity *)[array objectAtIndex:0] group];
    1471             :                 else  result = nil;
    1472             :         }
    1473             :         OOJS_END_FULL_NATIVE
    1474             :         
    1475             :         OOJS_RETURN_OBJECT(result);
    1476             :         
    1477             :         OOJS_NATIVE_EXIT
    1478             : }
    1479             : 
    1480             : 
    1481           0 : static JSBool SystemAddShipsOrGroupToRoute(JSContext *context, uintN argc, jsval *vp, BOOL isGroup)
    1482             : {
    1483             :         OOJS_NATIVE_ENTER(context)
    1484             :         
    1485             :         NSString                        *role = nil;
    1486             :         NSString                        *route = @"st"; // default route witchpoint -> station. ("st" itself is not selectable by script)
    1487             :         static NSSet            *validRoutes = nil;
    1488             :         int32                           count = 0;
    1489             :         double                          where = NSNotFound;             // a negative value means random positioning!
    1490             :         id                                      result = nil;
    1491             :         
    1492             :         NSString                        *func = isGroup ? @"addGroup" : @"addShips";
    1493             :         
    1494             :         if (argc > 0)  role = OOStringFromJSValue(context, OOJS_ARGV[0]);
    1495             :         if (role == nil)
    1496             :         {
    1497             :                 OOJSReportBadArguments(context, @"System", func, MIN(argc, 1U), &OOJS_ARGV[0], nil, @"string (role)");
    1498             :                 return NO;
    1499             :         }
    1500             :         if (argc < 2 || !JS_ValueToInt32(context, OOJS_ARGV[1], &count) || count < 1 || 64 < count)
    1501             :         {
    1502             :                 OOJSReportBadArguments(context, @"System", func, MIN(argc - 1, 1U), &OOJS_ARGV[1], nil, @"number (positive count no greater than 64)");
    1503             :                 return NO;
    1504             :         }
    1505             :         
    1506             :         if (argc > 2)
    1507             :         {
    1508             :                 if (!JS_ValueToNumber(context, OOJS_ARGV[2], &where) || !isfinite(where) || where < 0.0f || where > 1.0f)
    1509             :                 {
    1510             :                         OOJSReportBadArguments(context, @"System", func, MIN(argc - 2, 1U), &OOJS_ARGV[2], nil, @"number (position along route)");
    1511             :                         return NO;
    1512             :                 }
    1513             :                 
    1514             :                 if (argc > 3)
    1515             :                 {
    1516             :                         route = [OOStringFromJSValue(context, OOJS_ARGV[3]) lowercaseString];
    1517             :                         
    1518             :                         if (validRoutes == nil)
    1519             :                         {
    1520             :                                 validRoutes = [[NSSet alloc] initWithObjects:@"wp", @"pw", @"ws", @"sw", @"sp", @"ps", nil];
    1521             :                         }
    1522             :                         
    1523             :                         if (route == nil || ![validRoutes containsObject:route])
    1524             :                         {
    1525             :                                 OOJSReportBadArguments(context, @"System", func, MIN(argc - 3, 1U), &OOJS_ARGV[3], nil, @"string (route specifier)");
    1526             :                                 return NO;
    1527             :                         }
    1528             :                 }
    1529             :         }
    1530             :         
    1531             :         OOJS_BEGIN_FULL_NATIVE(context)
    1532             :         // Note: the use of witchspace-in effects (as in legacy_addShips) depends on proximity to the witchpoint.       
    1533             :         result = [UNIVERSE addShipsToRoute:route withRole:role quantity:count routeFraction:where asGroup:isGroup];
    1534             :         
    1535             :         if (isGroup)
    1536             :         {
    1537             :                 NSArray *array = result;
    1538             :                 if ([array count] > 0)  result = [(ShipEntity *)[array objectAtIndex:0] group];
    1539             :                 else  result = nil;
    1540             :         }
    1541             :         OOJS_END_FULL_NATIVE
    1542             :         
    1543             :         OOJS_RETURN_OBJECT(result);
    1544             :         
    1545             :         OOJS_NATIVE_EXIT
    1546             : }
    1547             : 
    1548             : 
    1549           0 : static BOOL GetRelativeToAndRange(JSContext *context, NSString *methodName, uintN *ioArgc, jsval **ioArgv, Entity **outRelativeTo, double *outRange)
    1550             : {
    1551             :         OOJS_PROFILE_ENTER
    1552             :         
    1553             :         // No NULL arguments accepted.
    1554             :         assert(ioArgc && ioArgv && outRelativeTo && outRange);
    1555             :         
    1556             :         // Get optional argument relativeTo : Entity
    1557             :         if (*ioArgc != 0)
    1558             :         {
    1559             :                 if (EXPECT_NOT(JSVAL_IS_NULL(**ioArgv) || !JSValueToEntity(context, **ioArgv, outRelativeTo)))
    1560             :                 {
    1561             :                         OOJSReportBadArguments(context, @"System", methodName, 1, *ioArgv, nil, @"entity");
    1562             :                         return NO;
    1563             :                 }
    1564             :                 (*ioArgv)++; (*ioArgc)--;
    1565             :         }
    1566             :         
    1567             :         // Get optional argument range : Number
    1568             :         if (*ioArgc != 0)
    1569             :         {
    1570             :                 if (!EXPECT_NOT(JS_ValueToNumber(context, **ioArgv, outRange)))
    1571             :                 {
    1572             :                         OOJSReportBadArguments(context, @"System", methodName, 1, *ioArgv, nil, @"number");
    1573             :                         return NO;
    1574             :                 }
    1575             :                 (*ioArgv)++; (*ioArgc)--;
    1576             :         }
    1577             :         
    1578             :         return YES;
    1579             :         
    1580             :         OOJS_PROFILE_EXIT
    1581             : }
    1582             : 
    1583             : 
    1584           0 : static NSArray *FindJSVisibleEntities(EntityFilterPredicate predicate, void *parameter, Entity *relativeTo, double range)
    1585             : {
    1586             :         OOJS_PROFILE_ENTER
    1587             :         
    1588             :         NSMutableArray                                          *result = nil;
    1589             :         BinaryOperationPredicateParameter       param =
    1590             :         {
    1591             :                 JSEntityIsJavaScriptSearchablePredicate, NULL,
    1592             :                 predicate, parameter
    1593             :         };
    1594             :         
    1595             :         result = [UNIVERSE findEntitiesMatchingPredicate:ANDPredicate
    1596             :                                                                                    parameter:&param
    1597             :                                                                                          inRange:range
    1598             :                                                                                         ofEntity:relativeTo];
    1599             :         
    1600             :         if (result != nil && relativeTo != nil && ![relativeTo isPlayer])
    1601             :         {
    1602             :                 [result sortUsingFunction:CompareEntitiesByDistance context:relativeTo];
    1603             :         }
    1604             :         if (result == nil)  return [NSArray array];
    1605             :         return result;
    1606             :         
    1607             :         OOJS_PROFILE_EXIT
    1608             : }
    1609             : 
    1610             : 
    1611           0 : static NSArray *FindShips(EntityFilterPredicate predicate, void *parameter, Entity *relativeTo, double range)
    1612             : {
    1613             :         OOJS_PROFILE_ENTER
    1614             :         
    1615             :         BinaryOperationPredicateParameter       param =
    1616             :         {
    1617             :                 IsShipPredicate, NULL,
    1618             :                 predicate, parameter
    1619             :         };
    1620             :         return FindJSVisibleEntities(ANDPredicate, &param, relativeTo, range);
    1621             :         
    1622             :         OOJS_PROFILE_EXIT
    1623             : }
    1624             : 
    1625             : 
    1626           0 : static NSComparisonResult CompareEntitiesByDistance(id a, id b, void *relativeTo)
    1627             : {
    1628             :         OOJS_PROFILE_ENTER
    1629             :         
    1630             :         Entity                          *ea = a,
    1631             :         *eb = b,
    1632             :         *r = (id)relativeTo;
    1633             :         float                           d1, d2;
    1634             :         
    1635             :         d1 = HPdistance2(ea->position, r->position);
    1636             :         d2 = HPdistance2(eb->position, r->position);
    1637             :         
    1638             :         if (d1 < d2)  return NSOrderedAscending;
    1639             :         else if (d1 > d2)  return NSOrderedDescending;
    1640             :         else return NSOrderedSame;
    1641             :         
    1642             :         OOJS_PROFILE_EXIT
    1643             : }

Generated by: LCOV version 1.14