Line data Source code
1 0 : /*
2 : OOJSStation.m
3 :
4 : Oolite
5 : Copyright (C) 2004-2013 Giles C Williams and contributors
6 :
7 : This program is free software; you can redistribute it and/or
8 : modify it under the terms of the GNU General Public License
9 : as published by the Free Software Foundation; either version 2
10 : of the License, or (at your option) any later version.
11 :
12 : This program is distributed in the hope that it will be useful,
13 : but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : GNU General Public License for more details.
16 :
17 : You should have received a copy of the GNU General Public License
18 : along with this program; if not, write to the Free Software
19 : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
20 : MA 02110-1301, USA.
21 :
22 : */
23 :
24 : #import "OOJSStation.h"
25 : #import "OOJSEntity.h"
26 : #import "OOJSShip.h"
27 : #import "OOJSPlayer.h"
28 : #import "PlayerEntityContracts.h"
29 : #import "OOJavaScriptEngine.h"
30 : #import "OOJSInterfaceDefinition.h"
31 :
32 : #import "OOCollectionExtractors.h"
33 : #import "OOEquipmentType.h"
34 : #import "OOShipRegistry.h"
35 : #import "OOConstToString.h"
36 : #import "StationEntity.h"
37 : #import "GameController.h"
38 :
39 :
40 0 : static JSObject *sStationPrototype;
41 :
42 : static BOOL JSStationGetStationEntity(JSContext *context, JSObject *stationObj, StationEntity **outEntity);
43 :
44 :
45 : static JSBool StationGetProperty(JSContext *context, JSObject *this, jsid propID, jsval *value);
46 : static JSBool StationSetProperty(JSContext *context, JSObject *this, jsid propID, JSBool strict, jsval *value);
47 :
48 : static JSBool StationAbortAllDockings(JSContext *context, uintN argc, jsval *vp);
49 : static JSBool StationAbortDockingForShip(JSContext *context, uintN argc, jsval *vp);
50 : static JSBool StationCanDockShip(JSContext *context, uintN argc, jsval *vp);
51 : static JSBool StationDockPlayer(JSContext *context, uintN argc, jsval *vp);
52 : static JSBool StationIncreaseAlertLevel(JSContext *context, uintN argc, jsval *vp);
53 : static JSBool StationDecreaseAlertLevel(JSContext *context, uintN argc, jsval *vp);
54 : static JSBool StationLaunchShipWithRole(JSContext *context, uintN argc, jsval *vp);
55 : static JSBool StationLaunchDefenseShip(JSContext *context, uintN argc, jsval *vp);
56 : static JSBool StationLaunchEscort(JSContext *context, uintN argc, jsval *vp);
57 : static JSBool StationLaunchScavenger(JSContext *context, uintN argc, jsval *vp);
58 : static JSBool StationLaunchMiner(JSContext *context, uintN argc, jsval *vp);
59 : static JSBool StationLaunchPirateShip(JSContext *context, uintN argc, jsval *vp);
60 : static JSBool StationLaunchShuttle(JSContext *context, uintN argc, jsval *vp);
61 : static JSBool StationLaunchPatrol(JSContext *context, uintN argc, jsval *vp);
62 : static JSBool StationLaunchPolice(JSContext *context, uintN argc, jsval *vp);
63 : static JSBool StationSetInterface(JSContext *context, uintN argc, jsval *vp);
64 : static JSBool StationSetMarketPrice(JSContext *context, uintN argc, jsval *vp);
65 : static JSBool StationSetMarketQuantity(JSContext *context, uintN argc, jsval *vp);
66 : static JSBool StationAddShipToShipyard(JSContext *context, uintN argc, jsval *vp);
67 : static JSBool StationRemoveShipFromShipyard(JSContext *context, uintN argc, jsval *vp);
68 :
69 0 : static JSClass sStationClass =
70 : {
71 : "Station",
72 : JSCLASS_HAS_PRIVATE,
73 :
74 : JS_PropertyStub, // addProperty
75 : JS_PropertyStub, // delProperty
76 : StationGetProperty, // getProperty
77 : StationSetProperty, // setProperty
78 : JS_EnumerateStub, // enumerate
79 : JS_ResolveStub, // resolve
80 : JS_ConvertStub, // convert
81 : OOJSObjectWrapperFinalize,// finalize
82 : JSCLASS_NO_OPTIONAL_MEMBERS
83 : };
84 :
85 :
86 0 : enum
87 : {
88 : // Property IDs
89 : kStation_alertCondition,
90 : kStation_allegiance,
91 : kStation_allowsAutoDocking,
92 : kStation_allowsFastDocking,
93 : kStation_breakPattern,
94 : kStation_dockedContractors, // miners and scavengers.
95 : kStation_dockedDefenders,
96 : kStation_dockedPolice,
97 : kStation_equipmentPriceFactor,
98 : kStation_equivalentTechLevel,
99 : kStation_hasNPCTraffic,
100 : kStation_hasShipyard,
101 : kStation_isMainStation, // Is [UNIVERSE station], boolean, read-only
102 : kStation_market,
103 : kStation_requiresDockingClearance,
104 : kStation_roll,
105 : kStation_suppressArrivalReports,
106 : kStation_shipyard,
107 : };
108 :
109 :
110 0 : static JSPropertySpec sStationProperties[] =
111 : {
112 : // JS name ID flags
113 : { "alertCondition", kStation_alertCondition, OOJS_PROP_READWRITE_CB },
114 : { "allegiance", kStation_allegiance, OOJS_PROP_READWRITE_CB },
115 : { "allowsAutoDocking", kStation_allowsAutoDocking, OOJS_PROP_READWRITE_CB },
116 : { "allowsFastDocking", kStation_allowsFastDocking, OOJS_PROP_READWRITE_CB },
117 : { "breakPattern", kStation_breakPattern, OOJS_PROP_READWRITE_CB },
118 : { "dockedContractors", kStation_dockedContractors, OOJS_PROP_READONLY_CB },
119 : { "dockedDefenders", kStation_dockedDefenders, OOJS_PROP_READONLY_CB },
120 : { "dockedPolice", kStation_dockedPolice, OOJS_PROP_READONLY_CB },
121 : { "equipmentPriceFactor", kStation_equipmentPriceFactor, OOJS_PROP_READONLY_CB },
122 : { "equivalentTechLevel", kStation_equivalentTechLevel, OOJS_PROP_READONLY_CB },
123 : { "hasNPCTraffic", kStation_hasNPCTraffic, OOJS_PROP_READWRITE_CB },
124 : { "hasShipyard", kStation_hasShipyard, OOJS_PROP_READONLY_CB },
125 : { "isMainStation", kStation_isMainStation, OOJS_PROP_READONLY_CB },
126 : { "market", kStation_market, OOJS_PROP_READONLY_CB },
127 : { "requiresDockingClearance", kStation_requiresDockingClearance, OOJS_PROP_READWRITE_CB },
128 : { "roll", kStation_roll, OOJS_PROP_READWRITE_CB },
129 : { "suppressArrivalReports", kStation_suppressArrivalReports, OOJS_PROP_READWRITE_CB },
130 : { "shipyard", kStation_shipyard, OOJS_PROP_READONLY_CB },
131 : { 0 }
132 : };
133 :
134 :
135 0 : static JSFunctionSpec sStationMethods[] =
136 : {
137 : // JS name Function min args
138 : { "abortAllDockings", StationAbortAllDockings, 0 },
139 : { "abortDockingForShip", StationAbortDockingForShip, 1 },
140 : { "canDockShip", StationCanDockShip, 1 },
141 : { "dockPlayer", StationDockPlayer, 0 },
142 : { "increaseAlertLevel", StationIncreaseAlertLevel, 0 },
143 : { "decreaseAlertLevel", StationDecreaseAlertLevel, 0 },
144 : { "launchDefenseShip", StationLaunchDefenseShip, 0 },
145 : { "launchEscort", StationLaunchEscort, 0 },
146 : { "launchMiner", StationLaunchMiner, 0 },
147 : { "launchPatrol", StationLaunchPatrol, 0 },
148 : { "launchPirateShip", StationLaunchPirateShip, 0 },
149 : { "launchPolice", StationLaunchPolice, 0 },
150 : { "launchScavenger", StationLaunchScavenger, 0 },
151 : { "launchShipWithRole", StationLaunchShipWithRole, 1 },
152 : { "launchShuttle", StationLaunchShuttle, 0 },
153 : { "setInterface", StationSetInterface, 0 },
154 : { "setMarketPrice", StationSetMarketPrice, 2 },
155 : { "setMarketQuantity", StationSetMarketQuantity, 2 },
156 : { "addShipToShipyard", StationAddShipToShipyard, 1 },
157 : { "removeShipFromShipyard", StationRemoveShipFromShipyard, 1 },
158 : { 0 }
159 : };
160 :
161 :
162 0 : void InitOOJSStation(JSContext *context, JSObject *global)
163 : {
164 : sStationPrototype = JS_InitClass(context, global, JSShipPrototype(), &sStationClass, OOJSUnconstructableConstruct, 0, sStationProperties, sStationMethods, NULL, NULL);
165 : OOJSRegisterObjectConverter(&sStationClass, OOJSBasicPrivateObjectConverter);
166 : OOJSRegisterSubclass(&sStationClass, JSShipClass());
167 : }
168 :
169 :
170 0 : static BOOL JSStationGetStationEntity(JSContext *context, JSObject *stationObj, StationEntity **outEntity)
171 : {
172 : OOJS_PROFILE_ENTER
173 :
174 : BOOL result;
175 : Entity *entity = nil;
176 :
177 : if (outEntity == NULL) return NO;
178 : *outEntity = nil;
179 :
180 : result = OOJSEntityGetEntity(context, stationObj, &entity);
181 : if (!result) return NO;
182 :
183 : if (![entity isKindOfClass:[StationEntity class]]) return NO;
184 :
185 : *outEntity = (StationEntity *)entity;
186 : return YES;
187 :
188 : OOJS_PROFILE_EXIT
189 : }
190 :
191 0 : static BOOL JSStationGetShipEntity(JSContext *context, JSObject *shipObj, ShipEntity **outEntity)
192 : {
193 : OOJS_PROFILE_ENTER
194 :
195 : BOOL result;
196 : Entity *entity = nil;
197 :
198 : if (outEntity == NULL) return NO;
199 : *outEntity = nil;
200 :
201 : result = OOJSEntityGetEntity(context, shipObj, &entity);
202 : if (!result) return NO;
203 :
204 : if (![entity isKindOfClass:[ShipEntity class]]) return NO;
205 :
206 : *outEntity = (ShipEntity *)entity;
207 : return YES;
208 :
209 : OOJS_PROFILE_EXIT
210 : }
211 :
212 :
213 : @implementation StationEntity (OOJavaScriptExtensions)
214 :
215 0 : - (void)getJSClass:(JSClass **)outClass andPrototype:(JSObject **)outPrototype
216 : {
217 : *outClass = &sStationClass;
218 : *outPrototype = sStationPrototype;
219 : }
220 :
221 :
222 0 : - (NSString *) oo_jsClassName
223 : {
224 : return @"Station";
225 : }
226 :
227 : @end
228 :
229 :
230 0 : static JSBool StationGetProperty(JSContext *context, JSObject *this, jsid propID, jsval *value)
231 : {
232 : if (!JSID_IS_INT(propID)) return YES;
233 :
234 : OOJS_NATIVE_ENTER(context)
235 :
236 : StationEntity *entity = nil;
237 :
238 : if (!JSStationGetStationEntity(context, this, &entity)) return NO;
239 : if (entity == nil) { *value = JSVAL_VOID; return YES; }
240 :
241 : switch (JSID_TO_INT(propID))
242 : {
243 : case kStation_isMainStation:
244 : *value = OOJSValueFromBOOL(entity == [UNIVERSE station]);
245 : return YES;
246 :
247 : case kStation_hasNPCTraffic:
248 : *value = OOJSValueFromBOOL([entity hasNPCTraffic]);
249 : return YES;
250 :
251 : case kStation_hasShipyard:
252 : *value = OOJSValueFromBOOL([entity hasShipyard]);
253 : return YES;
254 :
255 : case kStation_alertCondition:
256 : *value = INT_TO_JSVAL([entity alertLevel]);
257 : return YES;
258 :
259 : case kStation_allegiance:
260 : {
261 : NSString *result = [entity allegiance];
262 : *value = OOJSValueFromNativeObject(context, result);
263 : return YES;
264 : }
265 :
266 : case kStation_requiresDockingClearance:
267 : *value = OOJSValueFromBOOL([entity requiresDockingClearance]);
268 : return YES;
269 :
270 : case kStation_roll:
271 : // same as in ship definition, but this time read/write below
272 : return JS_NewNumberValue(context, [entity flightRoll], value);
273 :
274 : case kStation_allowsFastDocking:
275 : *value = OOJSValueFromBOOL([entity allowsFastDocking]);
276 : return YES;
277 :
278 : case kStation_allowsAutoDocking:
279 : *value = OOJSValueFromBOOL([entity allowsAutoDocking]);
280 : return YES;
281 :
282 : case kStation_dockedContractors:
283 : *value = INT_TO_JSVAL([entity countOfDockedContractors]);
284 : return YES;
285 :
286 : case kStation_dockedPolice:
287 : *value = INT_TO_JSVAL([entity countOfDockedPolice]);
288 : return YES;
289 :
290 : case kStation_dockedDefenders:
291 : *value = INT_TO_JSVAL([entity countOfDockedDefenders]);
292 : return YES;
293 :
294 : case kStation_equivalentTechLevel:
295 : *value = INT_TO_JSVAL((int32_t)[entity equivalentTechLevel]);
296 : return YES;
297 :
298 : case kStation_equipmentPriceFactor:
299 : return JS_NewNumberValue(context, [entity equipmentPriceFactor], value);
300 :
301 : case kStation_suppressArrivalReports:
302 : *value = OOJSValueFromBOOL([entity suppressArrivalReports]);
303 : return YES;
304 :
305 : case kStation_breakPattern:
306 : *value = OOJSValueFromBOOL([entity hasBreakPattern]);
307 : return YES;
308 :
309 : case kStation_shipyard:
310 : {
311 : if (![entity hasShipyard])
312 : {
313 : // return null if station has no shipyard
314 : *value = OOJSValueFromNativeObject(context, nil);
315 : }
316 : else
317 : {
318 : if ([entity localShipyard] == nil) [entity generateShipyard];
319 : NSMutableArray *shipyard = [entity localShipyard];
320 : *value = OOJSValueFromNativeObject(context, shipyard);
321 : }
322 : return YES;
323 : }
324 :
325 : case kStation_market:
326 : {
327 : NSDictionary *market = [entity localMarketForScripting];
328 : *value = OOJSValueFromNativeObject(context, market);
329 : return YES;
330 : }
331 :
332 : default:
333 : OOJSReportBadPropertySelector(context, this, propID, sStationProperties);
334 : return NO;
335 : }
336 :
337 : OOJS_NATIVE_EXIT
338 : }
339 :
340 :
341 0 : static JSBool StationSetProperty(JSContext *context, JSObject *this, jsid propID, JSBool strict, jsval *value)
342 : {
343 : if (!JSID_IS_INT(propID)) return YES;
344 :
345 : OOJS_NATIVE_ENTER(context)
346 :
347 : StationEntity *entity = nil;
348 : JSBool bValue;
349 : int32 iValue;
350 : jsdouble fValue;
351 : NSString *sValue = nil;
352 :
353 : if (!JSStationGetStationEntity(context, this, &entity)) return NO;
354 : if (entity == nil) return YES;
355 :
356 : switch (JSID_TO_INT(propID))
357 : {
358 : case kStation_hasNPCTraffic:
359 : if (JS_ValueToBoolean(context, *value, &bValue))
360 : {
361 : [entity setHasNPCTraffic:bValue];
362 : return YES;
363 : }
364 : break;
365 :
366 : case kStation_alertCondition:
367 : if (JS_ValueToInt32(context, *value, &iValue))
368 : {
369 : [entity setAlertLevel:iValue signallingScript:NO]; // Performs range checking
370 : return YES;
371 : }
372 : break;
373 :
374 : case kStation_allegiance:
375 : sValue = OOStringFromJSValue(context,*value);
376 : if (sValue != nil)
377 : {
378 : [entity setAllegiance:sValue];
379 : return YES;
380 : }
381 : break;
382 :
383 :
384 : case kStation_requiresDockingClearance:
385 : if (JS_ValueToBoolean(context, *value, &bValue))
386 : {
387 : [entity setRequiresDockingClearance:bValue];
388 : return YES;
389 : }
390 : break;
391 :
392 : case kStation_roll:
393 : if (JS_ValueToNumber(context, *value, &fValue))
394 : {
395 : /* if (fValue < -2.0) fValue = -2.0;
396 : if (fValue > 2.0) fValue = 2.0; // clamping to -2.0...2.0 gives us ±M_PI actual maximum rotation
397 : [entity setRoll:fValue]; */
398 : // use setRawRoll to make the units here equal to those in kShip_roll
399 : if (fValue < -M_PI) fValue = -M_PI;
400 : else if (fValue > M_PI) fValue = M_PI;
401 : [entity setRawRoll:fValue];
402 : return YES;
403 : }
404 : break;
405 :
406 : case kStation_allowsFastDocking:
407 : if (JS_ValueToBoolean(context, *value, &bValue))
408 : {
409 : [entity setAllowsFastDocking:bValue];
410 : return YES;
411 : }
412 : break;
413 :
414 : case kStation_allowsAutoDocking:
415 : if (JS_ValueToBoolean(context, *value, &bValue))
416 : {
417 : [entity setAllowsAutoDocking:bValue];
418 : return YES;
419 : }
420 : break;
421 :
422 : case kStation_suppressArrivalReports:
423 : if (JS_ValueToBoolean(context, *value, &bValue))
424 : {
425 : [entity setSuppressArrivalReports:bValue];
426 : return YES;
427 : }
428 : break;
429 :
430 : case kStation_breakPattern:
431 : if (JS_ValueToBoolean(context, *value, &bValue))
432 : {
433 : [entity setHasBreakPattern:bValue];
434 : return YES;
435 : }
436 : break;
437 :
438 : default:
439 : OOJSReportBadPropertySelector(context, this, propID, sStationProperties);
440 : return NO;
441 : }
442 :
443 : OOJSReportBadPropertyValue(context, this, propID, sStationProperties, *value);
444 : return NO;
445 :
446 : OOJS_NATIVE_EXIT
447 : }
448 :
449 :
450 : // *** Methods ***
451 :
452 0 : static JSBool StationAbortAllDockings(JSContext *context, uintN argc, jsval *vp)
453 : {
454 : OOJS_NATIVE_ENTER(context)
455 :
456 : StationEntity *station = nil;
457 : JSStationGetStationEntity(context, OOJS_THIS, &station);
458 : [station abortAllDockings];
459 :
460 : OOJS_RETURN_VOID;
461 :
462 : OOJS_NATIVE_EXIT
463 : }
464 :
465 0 : static JSBool StationAbortDockingForShip(JSContext *context, uintN argc, jsval *vp)
466 : {
467 : OOJS_NATIVE_ENTER(context)
468 :
469 : StationEntity *station = nil;
470 : JSStationGetStationEntity(context, OOJS_THIS, &station);
471 : if (argc == 0)
472 : {
473 : OOJSReportBadArguments(context, @"Station", @"abortDockingForShip", MIN(argc, 1U), OOJS_ARGV, nil, @"ship in docking queue");
474 : return NO;
475 : }
476 : if (!JSVAL_IS_OBJECT(OOJS_ARGV[0])) return NO;
477 : ShipEntity *ship = nil;
478 : JSStationGetShipEntity(context, JSVAL_TO_OBJECT(OOJS_ARGV[0]), &ship);
479 : if (ship != nil)
480 : {
481 : [station abortDockingForShip:ship];
482 : }
483 :
484 : OOJS_RETURN_VOID;
485 :
486 : OOJS_NATIVE_EXIT
487 : }
488 :
489 : // canDockShip(shipEntity) : boolean
490 : // Proposed by phkb (Nick Rogers) 20161206
491 0 : static JSBool StationCanDockShip(JSContext *context, uintN argc, jsval *vp)
492 : {
493 : OOJS_NATIVE_ENTER(context)
494 :
495 : BOOL result = YES;
496 : ShipEntity *shipToCheck = nil;
497 :
498 : if (argc > 0)
499 : {
500 : if (!JSVAL_IS_OBJECT(OOJS_ARGV[0]) || !JSStationGetShipEntity(context, JSVAL_TO_OBJECT(OOJS_ARGV[0]), &shipToCheck))
501 : {
502 : return NO;
503 : }
504 : }
505 : if (EXPECT_NOT(shipToCheck == nil))
506 : {
507 : OOJSReportBadArguments(context, @"Station", @"canDockShip", MIN(argc, 1U), OOJS_ARGV, nil, @"shipEntity");
508 : return NO;
509 : }
510 :
511 : StationEntity *station = nil;
512 : if (!JSStationGetStationEntity(context, OOJS_THIS, &station)) OOJS_RETURN_VOID; // stale reference, no-op
513 :
514 : OOJS_BEGIN_FULL_NATIVE(context)
515 : result = [station fitsInDock:shipToCheck andLogNoFit:NO];
516 : OOJS_END_FULL_NATIVE
517 :
518 : OOJS_RETURN_BOOL(result);
519 : OOJS_NATIVE_EXIT
520 : }
521 :
522 :
523 : // dockPlayer()
524 : // Proposed and written by Frame 20090729
525 0 : static JSBool StationDockPlayer(JSContext *context, uintN argc, jsval *vp)
526 : {
527 : OOJS_NATIVE_ENTER(context)
528 :
529 : PlayerEntity *player = OOPlayerForScripting();
530 : GameController *gameController = [UNIVERSE gameController];
531 :
532 : if (EXPECT_NOT([gameController isGamePaused]))
533 : {
534 : /* Station.dockPlayer() was executed while the game was in pause.
535 : Do we want to return an error or just unpause and continue?
536 : I think unpausing is the sensible thing to do here - Nikos 20110208
537 : */
538 : [gameController setGamePaused:NO];
539 : }
540 :
541 : if (EXPECT(![player isDocked]))
542 : {
543 : StationEntity *stationForDockingPlayer = nil;
544 : JSStationGetStationEntity(context, OOJS_THIS, &stationForDockingPlayer);
545 : [player setDockingClearanceStatus:DOCKING_CLEARANCE_STATUS_GRANTED];
546 : [player safeAllMissiles];
547 : [UNIVERSE setViewDirection:VIEW_FORWARD];
548 : [player enterDock:stationForDockingPlayer];
549 : }
550 : OOJS_RETURN_VOID;
551 :
552 : OOJS_NATIVE_EXIT
553 : }
554 :
555 :
556 0 : static JSBool StationIncreaseAlertLevel(JSContext *context, uintN argc, jsval *vp)
557 : {
558 : OOJS_NATIVE_ENTER(context)
559 : StationEntity *station = nil;
560 :
561 : if (!JSStationGetStationEntity(context, OOJS_THIS, &station)) OOJS_RETURN_VOID; // stale reference, no-op
562 :
563 : OOJS_BEGIN_FULL_NATIVE(context)
564 : if ([station alertCondition] < 3)
565 : {
566 : [station increaseAlertLevel];
567 : }
568 : OOJS_END_FULL_NATIVE
569 : OOJS_RETURN_VOID;
570 : OOJS_NATIVE_EXIT
571 : }
572 :
573 0 : static JSBool StationDecreaseAlertLevel(JSContext *context, uintN argc, jsval *vp)
574 : {
575 : OOJS_NATIVE_ENTER(context)
576 : StationEntity *station = nil;
577 :
578 : if (!JSStationGetStationEntity(context, OOJS_THIS, &station)) OOJS_RETURN_VOID; // stale reference, no-op
579 :
580 : OOJS_BEGIN_FULL_NATIVE(context)
581 : if ([station alertCondition] > 1)
582 : {
583 : [station decreaseAlertLevel];
584 : }
585 : OOJS_END_FULL_NATIVE
586 : OOJS_RETURN_VOID;
587 : OOJS_NATIVE_EXIT
588 : }
589 :
590 : // launchShipWithRole(role : String [, abortAllDockings : boolean]) : shipEntity
591 0 : static JSBool StationLaunchShipWithRole(JSContext *context, uintN argc, jsval *vp)
592 : {
593 : OOJS_NATIVE_ENTER(context)
594 :
595 : NSString *shipRole = nil;
596 : StationEntity *station = nil;
597 : ShipEntity *result = nil;
598 : JSBool abortAllDockings = NO;
599 :
600 : if (!JSStationGetStationEntity(context, OOJS_THIS, &station)) OOJS_RETURN_VOID; // stale reference, no-op
601 :
602 : if (argc > 0) shipRole = OOStringFromJSValue(context, OOJS_ARGV[0]);
603 : if (EXPECT_NOT(shipRole == nil))
604 : {
605 : OOJSReportBadArguments(context, @"Station", @"launchShipWithRole", MIN(argc, 1U), OOJS_ARGV, nil, @"string (role)");
606 : return NO;
607 : }
608 :
609 : if (argc > 1) JS_ValueToBoolean(context, OOJS_ARGV[1], &abortAllDockings);
610 :
611 : OOJS_BEGIN_FULL_NATIVE(context)
612 : result = [station launchIndependentShip:shipRole];
613 : if (abortAllDockings) [station abortAllDockings];
614 : OOJS_END_FULL_NATIVE
615 :
616 : OOJS_RETURN_OBJECT(result);
617 : OOJS_NATIVE_EXIT
618 : }
619 :
620 :
621 0 : static JSBool StationLaunchDefenseShip(JSContext *context, uintN argc, jsval *vp)
622 : {
623 : OOJS_NATIVE_ENTER(context)
624 :
625 : StationEntity *station = nil;
626 : if (!JSStationGetStationEntity(context, OOJS_THIS, &station)) OOJS_RETURN_VOID; // stale reference, no-op
627 :
628 : ShipEntity *launched = nil;
629 : OOJS_BEGIN_FULL_NATIVE(context)
630 : launched = [station launchDefenseShip];
631 : OOJS_END_FULL_NATIVE
632 : OOJS_RETURN_OBJECT(launched);
633 :
634 : OOJS_NATIVE_EXIT
635 : }
636 :
637 :
638 0 : static JSBool StationLaunchEscort(JSContext *context, uintN argc, jsval *vp)
639 : {
640 : OOJS_NATIVE_ENTER(context)
641 :
642 : StationEntity *station = nil;
643 : if (!JSStationGetStationEntity(context, OOJS_THIS, &station)) OOJS_RETURN_VOID; // stale reference, no-op
644 :
645 : ShipEntity *launched = nil;
646 : OOJS_BEGIN_FULL_NATIVE(context)
647 : launched = [station launchEscort];
648 : OOJS_END_FULL_NATIVE
649 : OOJS_RETURN_OBJECT(launched);
650 :
651 : OOJS_NATIVE_EXIT
652 : }
653 :
654 :
655 0 : static JSBool StationLaunchScavenger(JSContext *context, uintN argc, jsval *vp)
656 : {
657 : OOJS_NATIVE_ENTER(context)
658 :
659 : StationEntity *station = nil;
660 : if (!JSStationGetStationEntity(context, OOJS_THIS, &station)) OOJS_RETURN_VOID; // stale reference, no-op
661 :
662 : ShipEntity *launched = nil;
663 : OOJS_BEGIN_FULL_NATIVE(context)
664 : launched = [station launchScavenger];
665 : OOJS_END_FULL_NATIVE
666 : OOJS_RETURN_OBJECT(launched);
667 :
668 : OOJS_NATIVE_EXIT
669 : }
670 :
671 :
672 0 : static JSBool StationLaunchMiner(JSContext *context, uintN argc, jsval *vp)
673 : {
674 : OOJS_NATIVE_ENTER(context)
675 :
676 : StationEntity *station = nil;
677 : if (!JSStationGetStationEntity(context, OOJS_THIS, &station)) OOJS_RETURN_VOID; // stale reference, no-op
678 :
679 : ShipEntity *launched = nil;
680 : OOJS_BEGIN_FULL_NATIVE(context)
681 : launched = [station launchMiner];
682 : OOJS_END_FULL_NATIVE
683 : OOJS_RETURN_OBJECT(launched);
684 : OOJS_NATIVE_EXIT
685 : }
686 :
687 :
688 0 : static JSBool StationLaunchPirateShip(JSContext *context, uintN argc, jsval *vp)
689 : {
690 : OOJS_NATIVE_ENTER(context)
691 :
692 : StationEntity *station = nil;
693 : if (!JSStationGetStationEntity(context, OOJS_THIS, &station)) OOJS_RETURN_VOID; // stale reference, no-op
694 :
695 : ShipEntity *launched = nil;
696 : OOJS_BEGIN_FULL_NATIVE(context)
697 : launched = [station launchPirateShip];
698 : OOJS_END_FULL_NATIVE
699 : OOJS_RETURN_OBJECT(launched);
700 :
701 : OOJS_NATIVE_EXIT
702 : }
703 :
704 :
705 0 : static JSBool StationLaunchShuttle(JSContext *context, uintN argc, jsval *vp)
706 : {
707 : OOJS_NATIVE_ENTER(context)
708 :
709 : StationEntity *station = nil;
710 : if (!JSStationGetStationEntity(context, OOJS_THIS, &station)) OOJS_RETURN_VOID; // stale reference, no-op
711 :
712 : ShipEntity *launched = nil;
713 : OOJS_BEGIN_FULL_NATIVE(context)
714 : launched = [station launchShuttle];
715 : OOJS_END_FULL_NATIVE
716 : OOJS_RETURN_OBJECT(launched);
717 : OOJS_NATIVE_EXIT
718 : }
719 :
720 :
721 0 : static JSBool StationLaunchPatrol(JSContext *context, uintN argc, jsval *vp)
722 : {
723 : OOJS_NATIVE_ENTER(context)
724 :
725 : StationEntity *station = nil;
726 : if (!JSStationGetStationEntity(context, OOJS_THIS, &station)) OOJS_RETURN_VOID; // stale reference, no-op
727 :
728 : ShipEntity *launched = nil;
729 : OOJS_BEGIN_FULL_NATIVE(context)
730 : launched = [station launchPatrol];
731 : OOJS_END_FULL_NATIVE
732 : OOJS_RETURN_OBJECT(launched);
733 : OOJS_NATIVE_EXIT
734 : }
735 :
736 :
737 0 : static JSBool StationLaunchPolice(JSContext *context, uintN argc, jsval *vp)
738 : {
739 : OOJS_NATIVE_ENTER(context)
740 :
741 : StationEntity *station = nil;
742 : if (!JSStationGetStationEntity(context, OOJS_THIS, &station)) OOJS_RETURN_VOID; // stale reference, no-op
743 :
744 : NSArray *launched = nil;
745 : OOJS_BEGIN_FULL_NATIVE(context)
746 : launched = [station launchPolice];
747 : OOJS_END_FULL_NATIVE
748 : OOJS_RETURN_OBJECT(launched);
749 : OOJS_NATIVE_EXIT
750 : }
751 :
752 0 : static JSBool StationSetInterface(JSContext *context, uintN argc, jsval *vp)
753 : {
754 : OOJS_NATIVE_ENTER(context)
755 :
756 : StationEntity *station = nil;
757 : if (!JSStationGetStationEntity(context, OOJS_THIS, &station)) OOJS_RETURN_VOID; // stale reference, no-op
758 :
759 : if (argc < 1)
760 : {
761 : OOJSReportBadArguments(context, @"Station", @"setInterface", MIN(argc, 1U), OOJS_ARGV, NULL, @"key [, definition]");
762 : return NO;
763 : }
764 : NSString *key = OOStringFromJSValue(context, OOJS_ARGV[0]);
765 :
766 : if (argc < 2 || JSVAL_IS_NULL(OOJS_ARGV[1]))
767 : {
768 : [station setInterfaceDefinition:nil forKey:key];
769 : OOJS_RETURN_VOID;
770 : }
771 :
772 :
773 : jsval value = JSVAL_NULL;
774 : jsval callback = JSVAL_NULL;
775 : JSObject *callbackThis = NULL;
776 : JSObject *params = NULL;
777 :
778 : NSString *title = nil;
779 : NSString *summary = nil;
780 : NSString *category = nil;
781 :
782 : if (!JS_ValueToObject(context, OOJS_ARGV[1], ¶ms))
783 : {
784 : OOJSReportBadArguments(context, @"Station", @"setInterface", MIN(argc, 1U), OOJS_ARGV, NULL, @"key [, definition]");
785 : return NO;
786 : }
787 :
788 : // get and validate title
789 : if (JS_GetProperty(context, params, "title", &value) == JS_FALSE || JSVAL_IS_VOID(value))
790 : {
791 : OOJSReportBadArguments(context, @"Station", @"setInterface", MIN(argc, 1U), OOJS_ARGV, NULL, @"key [, definition]; if definition is set, it must have a 'title' property.");
792 : return NO;
793 : }
794 : title = OOStringFromJSValue(context, value);
795 : if (title == nil || [title length] == 0)
796 : {
797 : OOJSReportBadArguments(context, @"Station", @"setInterface", MIN(argc, 1U), OOJS_ARGV, NULL, @"key [, definition]; if definition is set, 'title' property must be a non-empty string.");
798 : return NO;
799 : }
800 :
801 : // get category with default
802 : if (JS_GetProperty(context, params, "category", &value) == JS_FALSE || JSVAL_IS_VOID(value))
803 : {
804 : category = [NSString stringWithString:DESC(@"interfaces-category-uncategorised")];
805 : }
806 : else
807 : {
808 : category = OOStringFromJSValue(context, value);
809 : if (category == nil || [category length] == 0) {
810 : category = [NSString stringWithString:DESC(@"interfaces-category-uncategorised")];
811 : }
812 : }
813 :
814 : // get and validate summary
815 : if (JS_GetProperty(context, params, "summary", &value) == JS_FALSE || JSVAL_IS_VOID(value))
816 : {
817 : OOJSReportBadArguments(context, @"Station", @"setInterface", MIN(argc, 1U), OOJS_ARGV, NULL, @"key [, definition]; if definition is set, it must have a 'summary' property.");
818 : return NO;
819 : }
820 : summary = OOStringFromJSValue(context, value);
821 : if (summary == nil || [summary length] == 0)
822 : {
823 : OOJSReportBadArguments(context, @"Station", @"setInterface", MIN(argc, 1U), OOJS_ARGV, NULL, @"key [, definition]; if definition is set, 'summary' property must be a non-empty string.");
824 : return NO;
825 : }
826 :
827 : // get and validate callback
828 : if (JS_GetProperty(context, params, "callback", &callback) == JS_FALSE || JSVAL_IS_VOID(callback))
829 : {
830 : OOJSReportBadArguments(context, @"Station", @"setInterface", MIN(argc, 1U), OOJS_ARGV, NULL, @"key [, definition]; if definition is set, it must have a 'callback' property.");
831 : return NO;
832 : }
833 : if (!OOJSValueIsFunction(context,callback))
834 : {
835 : OOJSReportBadArguments(context, @"Station", @"setInterface", MIN(argc, 1U), OOJS_ARGV, NULL, @"key [, definition]; 'callback' property must be a function.");
836 : return NO;
837 : }
838 :
839 : OOJSInterfaceDefinition* definition = [[OOJSInterfaceDefinition alloc] init];
840 : [definition setTitle:title];
841 : [definition setCategory:category];
842 : [definition setSummary:summary];
843 : [definition setCallback:callback];
844 :
845 : // get callback 'this'
846 : if (JS_GetProperty(context, params, "cbThis", &value) == JS_TRUE && !JSVAL_IS_VOID(value))
847 : {
848 : JS_ValueToObject(context, value, &callbackThis);
849 : [definition setCallbackThis:callbackThis];
850 : // can do .bind(this) for callback instead
851 : }
852 :
853 : [station setInterfaceDefinition:definition forKey:key];
854 :
855 : [definition release];
856 :
857 : OOJS_RETURN_VOID;
858 :
859 : OOJS_NATIVE_EXIT
860 : }
861 :
862 :
863 0 : static JSBool StationSetMarketPrice(JSContext *context, uintN argc, jsval *vp)
864 : {
865 : OOJS_NATIVE_ENTER(context)
866 :
867 : StationEntity *station = nil;
868 : if (!JSStationGetStationEntity(context, OOJS_THIS, &station)) OOJS_RETURN_VOID; // stale reference, no-op
869 :
870 : if (argc < 2)
871 : {
872 : OOJSReportBadArguments(context, @"Station", @"setMarketPrice", MIN(argc, 2U), OOJS_ARGV, NULL, @"commodity, credits");
873 : return NO;
874 : }
875 :
876 : OOCommodityType commodity = OOStringFromJSValue(context, OOJS_ARGV[0]);
877 : if (EXPECT_NOT(![[UNIVERSE commodities] goodDefined:commodity]))
878 : {
879 : OOJSReportBadArguments(context, @"Station", @"setMarketPrice", MIN(argc, 2U), OOJS_ARGV, NULL, @"Unrecognised commodity type");
880 : return NO;
881 : }
882 :
883 : int32 price;
884 : BOOL gotPrice = JS_ValueToInt32(context, OOJS_ARGV[1], &price);
885 : if (EXPECT_NOT(!gotPrice || price < 0))
886 : {
887 : OOJSReportBadArguments(context, @"Station", @"setMarketPrice", MIN(argc, 2U), OOJS_ARGV, NULL, @"Price must be at least 0 decicredits");
888 : return NO;
889 : }
890 :
891 : [station setPrice:(NSUInteger)price forCommodity:commodity];
892 :
893 : if (station == [PLAYER dockedStation] && [PLAYER guiScreen] == GUI_SCREEN_MARKET)
894 : {
895 : [PLAYER setGuiToMarketScreen]; // refresh screen
896 : }
897 :
898 : OOJS_RETURN_BOOL(YES);
899 :
900 : OOJS_NATIVE_EXIT
901 : }
902 :
903 :
904 0 : static JSBool StationSetMarketQuantity(JSContext *context, uintN argc, jsval *vp)
905 : {
906 : OOJS_NATIVE_ENTER(context)
907 :
908 : StationEntity *station = nil;
909 : if (!JSStationGetStationEntity(context, OOJS_THIS, &station)) OOJS_RETURN_VOID; // stale reference, no-op
910 :
911 : if (argc < 2)
912 : {
913 : OOJSReportBadArguments(context, @"Station", @"setMarketQuantity", MIN(argc, 2U), OOJS_ARGV, NULL, @"commodity, units");
914 : return NO;
915 : }
916 :
917 : OOCommodityType commodity = OOStringFromJSValue(context, OOJS_ARGV[0]);
918 : if (EXPECT_NOT(![[UNIVERSE commodities] goodDefined:commodity]))
919 : {
920 : OOJSReportBadArguments(context, @"Station", @"setMarketQuantity", MIN(argc, 2U), OOJS_ARGV, NULL, @"Unrecognised commodity type");
921 : return NO;
922 : }
923 :
924 : int32 quantity;
925 : BOOL gotQuantity = JS_ValueToInt32(context, OOJS_ARGV[1], &quantity);
926 : if (EXPECT_NOT(!gotQuantity || quantity < 0 || (OOCargoQuantity)quantity > [[station localMarket] capacityForGood:commodity]))
927 : {
928 : OOJSReportBadArguments(context, @"Station", @"setMarketQuantity", MIN(argc, 2U), OOJS_ARGV, NULL, @"Quantity must be between 0 and the station market capacity");
929 : return NO;
930 : }
931 :
932 : [station setQuantity:(OOCargoQuantity)quantity forCommodity:commodity];
933 :
934 : if (station == [PLAYER dockedStation] && [PLAYER guiScreen] == GUI_SCREEN_MARKET)
935 : {
936 : [PLAYER setGuiToMarketScreen]; // refresh screen
937 : }
938 :
939 : OOJS_RETURN_BOOL(YES);
940 :
941 : OOJS_NATIVE_EXIT
942 : }
943 :
944 :
945 0 : static JSBool StationAddShipToShipyard(JSContext *context, uintN argc, jsval *vp)
946 : {
947 : OOJS_NATIVE_ENTER(context)
948 :
949 : JSObject *params = NULL;
950 : StationEntity *station = nil;
951 : if (!JSStationGetStationEntity(context, OOJS_THIS, &station)) OOJS_RETURN_VOID; // stale reference, no-op
952 :
953 : if (argc != 1 || (!JSVAL_IS_NULL(OOJS_ARGV[0]) && !JS_ValueToObject(context, OOJS_ARGV[0], ¶ms)))
954 : {
955 : OOJSReportBadArguments(context, @"Station", @"addShipToShipyard", MIN(argc, 1U), OOJS_ARGV, NULL, @"shipyard item definition");
956 : return NO;
957 : }
958 :
959 : // make sure the station has a shipyard
960 : if (![station hasShipyard]) {
961 : OOJSReportWarningForCaller(context, @"Station", @"removeShipFromShipyard", @"Station does not have shipyard.");
962 : return NO;
963 : }
964 : // make sure the shipyard has been generated
965 : if (![station localShipyard]) [station generateShipyard];
966 : NSMutableArray *shipyard = [station localShipyard];
967 :
968 : if (JSVAL_IS_NULL(OOJS_ARGV[0])) OOJS_RETURN_VOID; // OK, do nothing for null ship.
969 :
970 : NSMutableDictionary *result = [NSMutableDictionary dictionary];
971 : NSDictionary *shipyardDefinition = OOJSNativeObjectFromJSObject(context, JSVAL_TO_OBJECT(OOJS_ARGV[0]));
972 : // validate each element of the dictionary
973 : if (!shipyardDefinition)
974 : {
975 : OOJSReportBadArguments(context, @"Station", @"addShipToShipyard", MIN(argc, 1U), OOJS_ARGV, nil, @"valid dictionary object");
976 : return NO;
977 : }
978 : if (![shipyardDefinition objectForKey:KEY_SHORT_DESCRIPTION])
979 : {
980 : OOJSReportBadArguments(context, @"Station", @"addShipToShipyard", MIN(argc, 1U), OOJS_ARGV, nil, @"'short_description' in dictionary");
981 : return NO;
982 : }
983 : [result setObject:[shipyardDefinition oo_stringForKey:@"short_description"] forKey:KEY_SHORT_DESCRIPTION];
984 : if (![shipyardDefinition objectForKey:SHIPYARD_KEY_SHIPDATA_KEY])
985 : {
986 : OOJSReportBadArguments(context, @"Station", @"addShipToShipyard", MIN(argc, 1U), OOJS_ARGV, nil, @"'shipdata_key' in dictionary");
987 : return NO;
988 : }
989 : // get the shipInfo and shipyardInfo for this key
990 : NSString *shipKey = [shipyardDefinition oo_stringForKey:SHIPYARD_KEY_SHIPDATA_KEY defaultValue:nil];
991 : OOShipRegistry *registry = [OOShipRegistry sharedRegistry];
992 : NSMutableDictionary *shipInfo = [NSMutableDictionary dictionaryWithDictionary:[registry shipInfoForKey:shipKey]];
993 : NSDictionary *shipyardInfo = [registry shipyardInfoForKey:shipKey];
994 : if (!shipInfo)
995 : {
996 : OOJSReportWarningForCaller(context, @"Station", @"addShipToShipyard", @"Invalid shipdata_key provided.");
997 : return NO;
998 : }
999 : // make sure the ship is a player ship
1000 : if ([[shipInfo oo_stringForKey:@"roles"] rangeOfString:@"player"].location == NSNotFound)
1001 : {
1002 : OOJSReportWarningForCaller(context, @"Station", @"addShipToShipyard", @"shipdata_key not suitable for player role.");
1003 : return NO;
1004 : }
1005 : if (!shipyardInfo)
1006 : {
1007 : OOJSReportWarningForCaller(context, @"Station", @"addShipToShipyard", @"No shipyard information found for shipdata_key.");
1008 : return NO;
1009 : }
1010 : // ok, feel pretty safe to include this ship now
1011 : [result setObject:shipKey forKey:SHIPYARD_KEY_SHIPDATA_KEY];
1012 :
1013 : // add an ID
1014 : Random_Seed ship_seed = [UNIVERSE marketSeed];
1015 : int superRand1 = ship_seed.a * 0x10000 + ship_seed.c * 0x100 + ship_seed.e;
1016 : uint32_t superRand2 = ship_seed.b * 0x10000 + ship_seed.d * 0x100 + ship_seed.f;
1017 : superRand2 &= Ranrot();
1018 : NSString *shipID = [NSString stringWithFormat:@"%06x-%06x", superRand1, superRand2];
1019 : [result setObject:shipID forKey:SHIPYARD_KEY_ID];
1020 :
1021 : if (![shipyardDefinition objectForKey:SHIPYARD_KEY_PRICE])
1022 : {
1023 : // if not provided, get the price from the registry
1024 : OOCreditsQuantity price = [shipyardInfo oo_unsignedIntForKey:KEY_PRICE];
1025 : [result setObject:[NSNumber numberWithUnsignedLongLong:price] forKey:SHIPYARD_KEY_PRICE];
1026 : }
1027 : else
1028 : {
1029 : OOCreditsQuantity price = [shipyardDefinition oo_unsignedIntForKey:SHIPYARD_KEY_PRICE];
1030 : if (price > 0)
1031 : {
1032 : [result setObject:[NSNumber numberWithUnsignedLongLong:price] forKey:SHIPYARD_KEY_PRICE];
1033 : }
1034 : else
1035 : {
1036 : OOJSReportBadArguments(context, @"Station", @"addShipToShipyard", MIN(argc, 1U), OOJS_ARGV, nil, @"'price' in dictionary");
1037 : return NO;
1038 : }
1039 : }
1040 :
1041 : if (![shipyardDefinition objectForKey:SHIPYARD_KEY_PERSONALITY])
1042 : {
1043 : // default to 0 if not supplied
1044 : [result setObject:0 forKey:SHIPYARD_KEY_PERSONALITY];
1045 : }
1046 : else
1047 : {
1048 : [result setObject:[NSNumber numberWithUnsignedLongLong:[shipyardDefinition oo_unsignedIntForKey:SHIPYARD_KEY_PERSONALITY]] forKey:SHIPYARD_KEY_PERSONALITY];
1049 : }
1050 :
1051 : NSArray *extras = [shipyardDefinition oo_arrayForKey:KEY_EQUIPMENT_EXTRAS];
1052 : if (!extras)
1053 : {
1054 : // pick up defaults if extras not supplied
1055 : extras = [NSArray arrayWithArray:[[shipyardInfo oo_dictionaryForKey:KEY_STANDARD_EQUIPMENT] oo_arrayForKey:KEY_EQUIPMENT_EXTRAS]];
1056 : }
1057 : if ([extras count] > 0) {
1058 : // go looking for lasers and add them directly to our shipInfo
1059 : NSString* fwdWeaponString = [[shipyardInfo oo_dictionaryForKey:KEY_STANDARD_EQUIPMENT] oo_stringForKey:KEY_EQUIPMENT_FORWARD_WEAPON];
1060 : NSString* aftWeaponString = [[shipyardInfo oo_dictionaryForKey:KEY_STANDARD_EQUIPMENT] oo_stringForKey:KEY_EQUIPMENT_AFT_WEAPON];
1061 : OOWeaponFacingSet availableFacings = [shipyardInfo oo_unsignedIntForKey:KEY_WEAPON_FACINGS defaultValue:VALID_WEAPON_FACINGS] & VALID_WEAPON_FACINGS;
1062 :
1063 : OOWeaponType fwdWeapon = OOWeaponTypeFromEquipmentIdentifierSloppy(fwdWeaponString);
1064 : OOWeaponType aftWeapon = OOWeaponTypeFromEquipmentIdentifierSloppy(aftWeaponString);
1065 :
1066 : unsigned int i;
1067 : NSString *equipmentKey = nil;
1068 : for (i = 0; i < [extras count]; i++) {
1069 : equipmentKey = [extras oo_stringAtIndex:i];
1070 : if ([equipmentKey hasPrefix:@"EQ_WEAPON"])
1071 : {
1072 : OOWeaponType new_weapon = OOWeaponTypeFromEquipmentIdentifierSloppy(equipmentKey);
1073 : //fit best weapon forward
1074 : if (availableFacings & WEAPON_FACING_FORWARD && [new_weapon weaponThreatAssessment] > [fwdWeapon weaponThreatAssessment])
1075 : {
1076 : //again remember to divide price by 10 to get credits from tenths of credit
1077 : fwdWeaponString = equipmentKey;
1078 : fwdWeapon = new_weapon;
1079 : [shipInfo setObject:fwdWeaponString forKey:KEY_EQUIPMENT_FORWARD_WEAPON];
1080 : }
1081 : else
1082 : {
1083 : //if less good than current forward, try fitting is to rear
1084 : if (availableFacings & WEAPON_FACING_AFT && (isWeaponNone(aftWeapon) || [new_weapon weaponThreatAssessment] > [aftWeapon weaponThreatAssessment]))
1085 : {
1086 : aftWeaponString = equipmentKey;
1087 : aftWeapon = new_weapon;
1088 : [shipInfo setObject:aftWeaponString forKey:KEY_EQUIPMENT_AFT_WEAPON];
1089 : }
1090 : }
1091 : }
1092 : }
1093 : }
1094 : // add the extras
1095 : [result setObject:extras forKey:KEY_EQUIPMENT_EXTRAS];
1096 : // add the ship spec
1097 : [result setObject:shipInfo forKey:SHIPYARD_KEY_SHIP];
1098 : // add it to the station's shipyard
1099 : [shipyard addObject:result];
1100 :
1101 : // refresh the screen if the shipyard is currently being displayed
1102 : if(station == [PLAYER dockedStation] && [PLAYER guiScreen] == GUI_SCREEN_SHIPYARD)
1103 : {
1104 : [PLAYER setGuiToShipyardScreen:0];
1105 : }
1106 :
1107 : OOJS_RETURN_BOOL(YES);
1108 :
1109 : OOJS_NATIVE_EXIT
1110 : }
1111 :
1112 :
1113 0 : static JSBool StationRemoveShipFromShipyard(JSContext *context, uintN argc, jsval *vp)
1114 : {
1115 : OOJS_NATIVE_ENTER(context)
1116 :
1117 : StationEntity *station = nil;
1118 : if (!JSStationGetStationEntity(context, OOJS_THIS, &station)) OOJS_RETURN_VOID; // stale reference, no-op
1119 :
1120 : // make sure the station has a shipyard
1121 : if (![station hasShipyard]) {
1122 : OOJSReportWarningForCaller(context, @"Station", @"removeShipFromShipyard", @"Station does not have shipyard.");
1123 : return NO;
1124 : }
1125 : // make sure the shipyard has been generated
1126 : if (![station localShipyard]) [station generateShipyard];
1127 : NSMutableArray *shipyard = [station localShipyard];
1128 :
1129 : int32 shipIndex = -1;
1130 : BOOL gotIndex = YES;
1131 : gotIndex = JS_ValueToInt32(context, OOJS_ARGV[0], &shipIndex);
1132 :
1133 : if (argc != 1 || (!JSVAL_IS_NULL(OOJS_ARGV[0]) && !gotIndex) || shipIndex < 0 || (shipIndex + 1) > [shipyard count])
1134 : {
1135 : OOJSReportBadArguments(context, @"Station", @"removeShipFromShipyard", MIN(argc, 1U), OOJS_ARGV, NULL, @"valid ship index");
1136 : return NO;
1137 : }
1138 :
1139 : [shipyard removeObjectAtIndex:shipIndex];
1140 :
1141 : // refresh the screen if the shipyard is currently being displayed
1142 : if(station == [PLAYER dockedStation] && [PLAYER guiScreen] == GUI_SCREEN_SHIPYARD)
1143 : {
1144 : [PLAYER setGuiToShipyardScreen:0];
1145 : }
1146 :
1147 : OOJS_RETURN_BOOL(YES);
1148 :
1149 : OOJS_NATIVE_EXIT
1150 : }
1151 :
|