Oolite 1.91.0.7646-241128-10e222e
Loading...
Searching...
No Matches
OOJSSystem.m
Go to the documentation of this file.
1/*
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"
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"
36#import "OOJSSystemInfo.h"
37
39#import "OOConstToString.h"
40#import "OOConstToJSString.h"
44#import "OODebugStandards.h"
46
47static JSObject *sSystemPrototype;
48
49
50// Support functions for entity search methods.
51static BOOL GetRelativeToAndRange(JSContext *context, NSString *methodName, uintN *ioArgc, jsval **ioArgv, Entity **outRelativeTo, double *outRange);
52static NSArray *FindJSVisibleEntities(EntityFilterPredicate predicate, void *parameter, Entity *relativeTo, double range);
53static NSArray *FindShips(EntityFilterPredicate predicate, void *parameter, Entity *relativeTo, double range);
54static NSComparisonResult CompareEntitiesByDistance(id a, id b, void *relativeTo);
55
56static JSBool SystemAddShipsOrGroup(JSContext *context, uintN argc, jsval *vp, BOOL isGroup);
57static JSBool SystemAddShipsOrGroupToRoute(JSContext *context, uintN argc, jsval *vp, BOOL isGroup);
58
59
60static JSBool SystemGetProperty(JSContext *context, JSObject *this, jsid propID, jsval *value);
61static JSBool SystemSetProperty(JSContext *context, JSObject *this, jsid propID, JSBool strict, jsval *value);
62
63static JSBool SystemToString(JSContext *context, uintN argc, jsval *vp);
64static JSBool SystemAddPlanet(JSContext *context, uintN argc, jsval *vp);
65static JSBool SystemAddMoon(JSContext *context, uintN argc, jsval *vp);
66static JSBool SystemSendAllShipsAway(JSContext *context, uintN argc, jsval *vp);
67static JSBool SystemCountShipsWithPrimaryRole(JSContext *context, uintN argc, jsval *vp);
68static JSBool SystemCountShipsWithRole(JSContext *context, uintN argc, jsval *vp);
69static JSBool SystemCountEntitiesWithScanClass(JSContext *context, uintN argc, jsval *vp);
70static JSBool SystemShipsWithPrimaryRole(JSContext *context, uintN argc, jsval *vp);
71static JSBool SystemShipsWithRole(JSContext *context, uintN argc, jsval *vp);
72static JSBool SystemEntitiesWithScanClass(JSContext *context, uintN argc, jsval *vp);
73static JSBool SystemFilteredEntities(JSContext *context, uintN argc, jsval *vp);
74
75static JSBool SystemLocationFromCode(JSContext *context, uintN argc, jsval *vp);
76static JSBool SystemAddShips(JSContext *context, uintN argc, jsval *vp);
77static JSBool SystemAddGroup(JSContext *context, uintN argc, jsval *vp);
78static JSBool SystemAddShipsToRoute(JSContext *context, uintN argc, jsval *vp);
79static JSBool SystemAddGroupToRoute(JSContext *context, uintN argc, jsval *vp);
80static JSBool SystemAddVisualEffect(JSContext *context, uintN argc, jsval *vp);
81static JSBool SystemSetPopulator(JSContext *context, uintN argc, jsval *vp);
82static JSBool SystemSetWaypoint(JSContext *context, uintN argc, jsval *vp);
83
84static JSBool SystemLegacyAddShips(JSContext *context, uintN argc, jsval *vp);
85static JSBool SystemLegacyAddSystemShips(JSContext *context, uintN argc, jsval *vp);
86static JSBool SystemLegacyAddShipsAt(JSContext *context, uintN argc, jsval *vp);
87static JSBool SystemLegacyAddShipsAtPrecisely(JSContext *context, uintN argc, jsval *vp);
88static JSBool SystemLegacyAddShipsWithinRadius(JSContext *context, uintN argc, jsval *vp);
89static JSBool SystemLegacySpawnShip(JSContext *context, uintN argc, jsval *vp);
90
91static JSBool SystemStaticSystemNameForID(JSContext *context, uintN argc, jsval *vp);
92static JSBool SystemStaticSystemIDForName(JSContext *context, uintN argc, jsval *vp);
93static JSBool SystemStaticInfoForSystem(JSContext *context, uintN argc, jsval *vp);
94
95
96static JSClass sSystemClass =
97{
98 "System",
99 0,
100
101 JS_PropertyStub,
102 JS_PropertyStub,
105 JS_EnumerateStub,
106 JS_ResolveStub,
107 JS_ConvertStub,
108 JS_FinalizeStub
109};
110
111
112enum
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
148static JSPropertySpec sSystemProperties[] =
149{
150 // JS name ID flags
151 { "allDemoShips", kSystem_allDemoShips, 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 },
158 { "economyDescription", kSystem_economyDescription, OOJS_PROP_READONLY_CB },
160 { "governmentDescription", kSystem_governmentDescription, 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 },
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 },
180 { 0 }
181};
182
183
184static 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
218static JSFunctionSpec sSystemStaticMethods[] =
219{
220 { "infoForSystem", SystemStaticInfoForSystem, 2 },
221 { "systemIDForName", SystemStaticSystemIDForName, 1 },
222 { "systemNameForID", SystemStaticSystemNameForID, 1 },
223 { 0 }
224};
225
226
227void InitOOJSSystem(JSContext *context, JSObject *global)
228{
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
236static 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
257 *value = OOJSValueFromBOOL([UNIVERSE inInterstellarSpace]);
258 return YES;
259
261 result = [UNIVERSE station];
262 handled = YES;
263 break;
264
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
286 result = [UNIVERSE currentWaypoints];
287 handled = YES;
288 break;
289
291 result = [UNIVERSE wormholes];
292 handled = YES;
293 break;
294
295 case kSystem_allShips:
297 result = [UNIVERSE findShipsMatchingPredicate:JSEntityIsJavaScriptSearchablePredicate parameter:NULL inRange:-1 ofEntity:nil];
299 handled = YES;
300 break;
301
304 result = [UNIVERSE findShipsMatchingPredicate:JSEntityIsDemoShipPredicate parameter:NULL inRange:-1 ofEntity:nil];
306 handled = YES;
307 break;
308
309
312 result = [UNIVERSE findVisualEffectsMatchingPredicate:JSEntityIsJavaScriptSearchablePredicate parameter:NULL inRange:-1 ofEntity:nil];
314 handled = YES;
315 break;
316
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
325 return JS_NewNumberValue(context, [player systemPseudoRandomFloat], value);
326
328 *value = INT_TO_JSVAL([player systemPseudoRandom100]);
329 return YES;
330
332 *value = INT_TO_JSVAL([player systemPseudoRandom256]);
333 return YES;
334
336 *value = OOJSValueFromBOOL([UNIVERSE witchspaceBreakPattern]);
337 return YES;
338
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
358 result = [systemData objectForKey:KEY_DESCRIPTION];
359 break;
360
362 result = [systemData objectForKey:KEY_INHABITANTS];
363 break;
364
366 *value = INT_TO_JSVAL([systemData oo_intForKey:KEY_GOVERNMENT]);
367 return YES;
368
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
379 result = OODisplayStringFromEconomyID([systemData oo_intForKey:KEY_ECONOMY]);
380 if (result == nil) result = DESC(@"not-applicable");
381 break;
382
384 *value = INT_TO_JSVAL([systemData oo_intForKey:KEY_TECHLEVEL]);
385 return YES;
386
388 *value = INT_TO_JSVAL([systemData oo_intForKey:KEY_POPULATION]);
389 return YES;
390
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
410 result = @"";
411 break;
412
414 result = DESC(@"not-applicable");
415 break;
416
418 *value = INT_TO_JSVAL(-1);
419 return YES;
420
422 result = DESC(@"not-applicable");
423 break;
424
425 case kSystem_economy:
426 *value = INT_TO_JSVAL(-1);
427 return YES;
428
430 result = DESC(@"not-applicable");
431 break;
432
434 *value = INT_TO_JSVAL(-1);
435 return YES;
436
438 *value = INT_TO_JSVAL(0);
439 return YES;
440
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
456}
457
458
459static 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 {
482 if (JS_ValueToNumber(context, *value, &fValue))
483 {
484 [UNIVERSE setAmbientLightLevel:fValue];
485 [UNIVERSE setLighting];
486 return YES;
487 }
488 break;
489
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
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
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
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
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
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
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
591}
592
593
594// *** Methods ***
595
596// toString() : String
597static JSBool SystemToString(JSContext *context, uintN argc, jsval *vp)
598{
599 OOJS_NATIVE_ENTER(context)
600
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
608}
609
610
611// addPlanet(key : String) : Planet
612static JSBool SystemAddPlanet(JSContext *context, uintN argc, jsval *vp)
613{
614 OOJS_NATIVE_ENTER(context)
615
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
628 planet = [player addPlanet:key];
630
631 OOJS_RETURN_OBJECT(planet);
632
634}
635
636
637// addMoon(key : String) : Planet
638static JSBool SystemAddMoon(JSContext *context, uintN argc, jsval *vp)
639{
640 OOJS_NATIVE_ENTER(context)
641
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
654 planet = [player addMoon:key];
656
657 OOJS_RETURN_OBJECT(planet);
658
660}
661
662
663// sendAllShipsAway()
664static JSBool SystemSendAllShipsAway(JSContext *context, uintN argc, jsval *vp)
665{
666 OOJS_NATIVE_ENTER(context)
667
669
670 [player sendAllShipsAway];
672
674}
675
676
677// countShipsWithPrimaryRole(role : String [, relativeTo : Entity [, range : Number]]) : Number
678static 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
700 result = [UNIVERSE countShipsWithPrimaryRole:role inRange:range ofEntity:relativeTo];
702
703 OOJS_RETURN_INT(result);
704
706}
707
708
709// countShipsWithRole(role : String [, relativeTo : Entity [, range : Number]]) : Number
710static 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
732 result = [UNIVERSE countShipsWithRole:role inRange:range ofEntity:relativeTo];
734
735 OOJS_RETURN_INT(result);
736
738}
739
740
741// shipsWithPrimaryRole(role : String [, relativeTo : Entity [, range : Number]]) : Array (Entity)
742static 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
765 result = FindShips(HasPrimaryRolePredicate, role, relativeTo, range);
767
768 OOJS_RETURN_OBJECT(result);
769
771}
772
773
774// shipsWithRole(role : String [, relativeTo : Entity [, range : Number]]) : Array (Entity)
775static 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
798 result = FindShips(HasRolePredicate, role, relativeTo, range);
800
801 OOJS_RETURN_OBJECT(result);
802
804}
805
806
807// countEntitiesWithScanClass(scanClass : String [, relativeTo : Entity [, range : Number]]) : Number
808static 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
830 result = [UNIVERSE countShipsWithScanClass:scanClass inRange:range ofEntity:relativeTo];
832
833 OOJS_RETURN_INT(result);
834
836}
837
838
839// entitiesWithScanClass(scanClass : String [, relativeTo : Entity [, range : Number]]) : Array (Entity)
840static 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
863 result = FindJSVisibleEntities(HasScanClassPredicate, [NSNumber numberWithInt:scanClass], relativeTo, range);
865
866 OOJS_RETURN_OBJECT(result);
867
869}
870
871
872// filteredEntities(this : Object, predicate : Function [, relativeTo : Entity [, range : Number]]) : Array (Entity)
873static 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 };
899 result = FindJSVisibleEntities(JSFunctionPredicate, &param, relativeTo, range);
901
902 if (EXPECT_NOT(param.errorFlag)) return NO;
903
904 OOJS_RETURN_OBJECT(result);
905
907}
908
909
910// locationFromCode(populator_named_region : String)
911static 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
940}
941
942
943// addShips(role : String, count : Number [, position: Vector [, radius: Number]]) : Array
944static 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
951static 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]])
958static 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])
965static 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)
972static 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
991 while (count--) [UNIVERSE witchspaceShipWithPrimaryRole:role];
993
995
997}
998
999
1000// legacy_addSystemShips(role : String, count : Number, location : Number)
1001static 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];
1024
1026
1028}
1029
1030
1031// legacy_addShipsAt(role : String, count : Number, coordScheme : String, coords : vectorExpression)
1032static JSBool SystemLegacyAddShipsAt(JSContext *context, uintN argc, jsval *vp)
1033{
1034 OOStandardsDeprecated(@"system.legacy_addShipsAt() is deprecated");
1035 OOJS_NATIVE_ENTER(context)
1036
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];
1061
1063
1065}
1066
1067
1068// legacy_addShipsAtPrecisely(role : String, count : Number, coordScheme : String, coords : vectorExpression)
1069static JSBool SystemLegacyAddShipsAtPrecisely(JSContext *context, uintN argc, jsval *vp)
1070{
1071 OOStandardsDeprecated(@"system.legacy_addShipsAtPrecisely() is deprecated");
1072 OOJS_NATIVE_ENTER(context)
1073
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];
1098
1100
1102}
1103
1104
1105// legacy_addShipsWithinRadius(role : String, count : Number, coordScheme : String, coords : vectorExpression, radius : Number)
1106static JSBool SystemLegacyAddShipsWithinRadius(JSContext *context, uintN argc, jsval *vp)
1107{
1108 OOStandardsDeprecated(@"system.legacy_addShipsWithinRadius() is deprecated");
1109 OOJS_NATIVE_ENTER(context)
1110
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];
1138
1140
1142}
1143
1144
1145// legacy_spawnShip(key : string)
1146static 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];
1164
1166
1168}
1169
1170
1171// *** Static methods ***
1172
1173// systemNameForID(ID : Number) : String
1174static 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
1192}
1193
1194
1195// systemIDForName(name : String) : Number
1196static 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
1215
1216 OOJS_RETURN_INT(result);
1217
1219}
1220
1221
1222// infoForSystem(galaxyID : Number, systemID : Number) : SystemInfo
1223static 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
1251}
1252
1253
1254static 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
1283
1284 OOJS_RETURN_OBJECT(result);
1285
1287}
1288
1289static 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
1351
1353}
1354
1355
1356static 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
1408
1410}
1411
1412// *** Helper functions ***
1413
1414// Shared implementation of addShips() and addGroup().
1415static 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 }
1474
1475 OOJS_RETURN_OBJECT(result);
1476
1478}
1479
1480
1481static 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 }
1542
1543 OOJS_RETURN_OBJECT(result);
1544
1546}
1547
1548
1549static BOOL GetRelativeToAndRange(JSContext *context, NSString *methodName, uintN *ioArgc, jsval **ioArgv, Entity **outRelativeTo, double *outRange)
1550{
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
1581}
1582
1583
1584static NSArray *FindJSVisibleEntities(EntityFilterPredicate predicate, void *parameter, Entity *relativeTo, double range)
1585{
1587
1588 NSMutableArray *result = nil;
1590 {
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
1608}
1609
1610
1611static NSArray *FindShips(EntityFilterPredicate predicate, void *parameter, Entity *relativeTo, double range)
1612{
1614
1616 {
1617 IsShipPredicate, NULL,
1618 predicate, parameter
1619 };
1620 return FindJSVisibleEntities(ANDPredicate, &param, relativeTo, range);
1621
1623}
1624
1625
1626static NSComparisonResult CompareEntitiesByDistance(id a, id b, void *relativeTo)
1627{
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
1643}
#define SCANNER_MAX_RANGE
Definition Entity.h:51
OOScanClass
Definition Entity.h:71
OOINLINE OOScanClass OOScanClassFromJSValue(JSContext *context, jsval value)
NSString * OODisplayStringFromEconomyID(OOEconomyID economy)
NSString * OODisplayStringFromGovernmentID(OOGovernmentID government)
void OOStandardsDeprecated(NSString *message)
BOOL ANDPredicate(Entity *entity, void *parameter)
BOOL HasScanClassPredicate(Entity *entity, void *parameter)
BOOL HasPrimaryRolePredicate(Entity *ship, void *parameter)
BOOL IsShipPredicate(Entity *entity, void *parameter)
BOOL HasRolePredicate(Entity *ship, void *parameter)
#define EXPECT_NOT(x)
#define EXPECT(x)
const HPVector kZeroHPVector
Definition OOHPVector.m:28
#define OOJS_PROFILE_EXIT
#define OOJS_END_FULL_NATIVE
#define OOJS_BEGIN_FULL_NATIVE(context)
#define OOJS_NATIVE_ENTER(cx)
#define OOJS_NATIVE_EXIT
#define OOJS_PROFILE_ENTER
BOOL JSValueToEntity(JSContext *context, jsval value, Entity **outEntity)
Definition OOJSEntity.m:146
PlayerEntity * OOPlayerForScripting(void)
Definition OOJSPlayer.m:191
BOOL JSValueToQuaternion(JSContext *context, jsval value, Quaternion *outQuaternion) NONNULL_FUNC
jsval GetJSSystemInfoForSystem(JSContext *context, OOGalaxyID galaxy, OOSystemID system)
static JSPropertySpec sSystemProperties[]
Definition OOJSSystem.m:148
static NSArray * FindShips(EntityFilterPredicate predicate, void *parameter, Entity *relativeTo, double range)
static JSBool SystemFilteredEntities(JSContext *context, uintN argc, jsval *vp)
Definition OOJSSystem.m:873
static JSBool SystemAddShipsOrGroup(JSContext *context, uintN argc, jsval *vp, BOOL isGroup)
static JSBool SystemLocationFromCode(JSContext *context, uintN argc, jsval *vp)
Definition OOJSSystem.m:911
static JSBool SystemLegacySpawnShip(JSContext *context, uintN argc, jsval *vp)
static JSBool SystemStaticInfoForSystem(JSContext *context, uintN argc, jsval *vp)
static JSBool SystemAddShipsOrGroupToRoute(JSContext *context, uintN argc, jsval *vp, BOOL isGroup)
static JSBool SystemStaticSystemIDForName(JSContext *context, uintN argc, jsval *vp)
static JSBool SystemCountShipsWithRole(JSContext *context, uintN argc, jsval *vp)
Definition OOJSSystem.m:710
static BOOL GetRelativeToAndRange(JSContext *context, NSString *methodName, uintN *ioArgc, jsval **ioArgv, Entity **outRelativeTo, double *outRange)
static JSFunctionSpec sSystemStaticMethods[]
Definition OOJSSystem.m:218
static NSComparisonResult CompareEntitiesByDistance(id a, id b, void *relativeTo)
static JSBool SystemLegacyAddShips(JSContext *context, uintN argc, jsval *vp)
Definition OOJSSystem.m:972
static JSBool SystemCountShipsWithPrimaryRole(JSContext *context, uintN argc, jsval *vp)
Definition OOJSSystem.m:678
static JSBool SystemAddGroup(JSContext *context, uintN argc, jsval *vp)
Definition OOJSSystem.m:951
static JSBool SystemAddVisualEffect(JSContext *context, uintN argc, jsval *vp)
void InitOOJSSystem(JSContext *context, JSObject *global)
Definition OOJSSystem.m:227
@ kSystem_inhabitantsDescription
Definition OOJSSystem.m:127
@ kSystem_allDemoShips
Definition OOJSSystem.m:115
@ kSystem_government
Definition OOJSSystem.m:123
@ kSystem_techLevel
Definition OOJSSystem.m:141
@ kSystem_populatorSettings
Definition OOJSSystem.m:134
@ kSystem_pseudoRandom100
Definition OOJSSystem.m:136
@ kSystem_allVisualEffects
Definition OOJSSystem.m:117
@ kSystem_ambientLevel
Definition OOJSSystem.m:118
@ kSystem_info
Definition OOJSSystem.m:126
@ kSystem_waypoints
Definition OOJSSystem.m:142
@ kSystem_ID
Definition OOJSSystem.m:125
@ kSystem_governmentDescription
Definition OOJSSystem.m:124
@ kSystem_wormholes
Definition OOJSSystem.m:143
@ kSystem_planets
Definition OOJSSystem.m:132
@ kSystem_pseudoRandom256
Definition OOJSSystem.m:137
@ kSystem_population
Definition OOJSSystem.m:133
@ kSystem_pseudoRandomNumber
Definition OOJSSystem.m:138
@ kSystem_name
Definition OOJSSystem.m:131
@ kSystem_mainStation
Definition OOJSSystem.m:130
@ kSystem_economyDescription
Definition OOJSSystem.m:122
@ kSystem_isInterstellarSpace
Definition OOJSSystem.m:128
@ kSystem_mainPlanet
Definition OOJSSystem.m:129
@ kSystem_breakPattern
Definition OOJSSystem.m:119
@ kSystem_stations
Definition OOJSSystem.m:140
@ kSystem_productivity
Definition OOJSSystem.m:135
@ kSystem_description
Definition OOJSSystem.m:120
@ kSystem_sun
Definition OOJSSystem.m:139
@ kSystem_economy
Definition OOJSSystem.m:121
@ kSystem_allShips
Definition OOJSSystem.m:116
static JSBool SystemAddShips(JSContext *context, uintN argc, jsval *vp)
Definition OOJSSystem.m:944
static NSArray * FindJSVisibleEntities(EntityFilterPredicate predicate, void *parameter, Entity *relativeTo, double range)
static JSBool SystemSetWaypoint(JSContext *context, uintN argc, jsval *vp)
static JSBool SystemLegacyAddShipsAt(JSContext *context, uintN argc, jsval *vp)
static JSBool SystemShipsWithPrimaryRole(JSContext *context, uintN argc, jsval *vp)
Definition OOJSSystem.m:742
static JSBool SystemLegacyAddSystemShips(JSContext *context, uintN argc, jsval *vp)
static JSClass sSystemClass
Definition OOJSSystem.m:96
static JSBool SystemSetProperty(JSContext *context, JSObject *this, jsid propID, JSBool strict, jsval *value)
Definition OOJSSystem.m:459
static JSFunctionSpec sSystemMethods[]
Definition OOJSSystem.m:184
static JSBool SystemLegacyAddShipsAtPrecisely(JSContext *context, uintN argc, jsval *vp)
static JSBool SystemSendAllShipsAway(JSContext *context, uintN argc, jsval *vp)
Definition OOJSSystem.m:664
static JSBool SystemAddShipsToRoute(JSContext *context, uintN argc, jsval *vp)
Definition OOJSSystem.m:958
static JSBool SystemToString(JSContext *context, uintN argc, jsval *vp)
Definition OOJSSystem.m:597
static JSBool SystemEntitiesWithScanClass(JSContext *context, uintN argc, jsval *vp)
Definition OOJSSystem.m:840
static JSBool SystemGetProperty(JSContext *context, JSObject *this, jsid propID, jsval *value)
Definition OOJSSystem.m:236
static JSBool SystemAddGroupToRoute(JSContext *context, uintN argc, jsval *vp)
Definition OOJSSystem.m:965
static JSBool SystemSetPopulator(JSContext *context, uintN argc, jsval *vp)
static JSBool SystemCountEntitiesWithScanClass(JSContext *context, uintN argc, jsval *vp)
Definition OOJSSystem.m:808
static JSBool SystemAddPlanet(JSContext *context, uintN argc, jsval *vp)
Definition OOJSSystem.m:612
static JSBool SystemShipsWithRole(JSContext *context, uintN argc, jsval *vp)
Definition OOJSSystem.m:775
static JSBool SystemLegacyAddShipsWithinRadius(JSContext *context, uintN argc, jsval *vp)
static JSBool SystemStaticSystemNameForID(JSContext *context, uintN argc, jsval *vp)
static JSBool SystemAddMoon(JSContext *context, uintN argc, jsval *vp)
Definition OOJSSystem.m:638
static JSObject * sSystemPrototype
Definition OOJSSystem.m:47
BOOL JSValueToVector(JSContext *context, jsval value, Vector *outVector) NONNULL_FUNC
Definition OOJSVector.m:259
BOOL JSValueToHPVector(JSContext *context, jsval value, HPVector *outVector) NONNULL_FUNC
Definition OOJSVector.m:252
BOOL BOOL VectorFromArgumentListNoError(JSContext *context, uintN argc, jsval *argv, HPVector *outVector, uintN *outConsumed) GCC_ATTR((nonnull(1
void OOJSPauseTimeLimiter(void)
#define OOJS_RETURN(v)
BOOL JSEntityIsJavaScriptSearchablePredicate(Entity *entity, void *parameter)
#define OOJS_PROP_READWRITE_CB
BOOL JSFunctionPredicate(Entity *entity, void *parameter)
OOINLINE jsval OOJSValueFromNativeObject(JSContext *context, id object)
id OOJSNativeObjectFromJSObject(JSContext *context, JSObject *object)
#define OOJS_RETURN_OBJECT(o)
void OOJSReportBadPropertySelector(JSContext *context, JSObject *thisObj, jsid propID, JSPropertySpec *propertySpec)
NSString * OOStringFromJSValue(JSContext *context, jsval value)
JSBool OOJSUnconstructableConstruct(JSContext *context, uintN argc, jsval *vp)
#define OOJS_PROP_READONLY
OOINLINE BOOL OOJSValueIsFunction(JSContext *context, jsval value)
#define OOJS_ARGV
OOINLINE jsval OOJSValueFromBOOL(int b) INLINE_CONST_FUNC
void OOJSReportBadPropertyValue(JSContext *context, JSObject *thisObj, jsid propID, JSPropertySpec *propertySpec, jsval value)
void OOJSReportBadArguments(JSContext *context, NSString *scriptClass, NSString *function, uintN argc, jsval *argv, NSString *message, NSString *expectedArgsDescription)
#define OOJS_RETURN_HPVECTOR(value)
#define OOJS_PROP_READONLY_CB
void OOJSResumeTimeLimiter(void)
#define OOJS_RETURN_VOID
#define OOJS_RETURN_INT(v)
#define MIN(A, B)
Definition OOMaths.h:111
unsigned count
return nil
int16_t OOSystemID
Definition OOTypes.h:211
uint8_t OOGalaxyID
Definition OOTypes.h:210
@ kOOMaximumSystemID
Definition OOTypes.h:217
@ kOOMaximumGalaxyID
Definition OOTypes.h:216
@ kOOMinimumSystemID
Definition OOTypes.h:218
const Vector kZeroVector
Definition OOVector.m:28
#define UNIVERSE
Definition Universe.h:840
#define DESC(key)
Definition Universe.h:846
#define KEY_POPULATION
Definition Universe.h:121
#define KEY_ECONOMY
Definition Universe.h:117
#define KEY_TECHLEVEL
Definition Universe.h:116
#define KEY_PRODUCTIVITY
Definition Universe.h:123
#define KEY_GOVERNMENT
Definition Universe.h:119
BOOL(* EntityFilterPredicate)(Entity *entity, void *parameter)
Definition Universe.h:52
id propertyNamed:(NSString *name)
Definition OOJSScript.m:491
OOJSScript * currentlyRunningScript()
Definition OOJSScript.m:339
void addShipsWithinRadius:(NSString *roles_number_system_x_y_z_r)
void addShipsAt:(NSString *roles_number_system_x_y_z)
void addShipsAtPrecisely:(NSString *roles_number_system_x_y_z)
OOPlanetEntity * addPlanet:(NSString *planetKey)
OOPlanetEntity * addMoon:(NSString *moonKey)