Line data Source code
1 0 : /*
2 :
3 : OOJSPlayer.h
4 :
5 : Oolite
6 : Copyright (C) 2004-2013 Giles C Williams and contributors
7 :
8 : This program is free software; you can redistribute it and/or
9 : modify it under the terms of the GNU General Public License
10 : as published by the Free Software Foundation; either version 2
11 : of the License, or (at your option) any later version.
12 :
13 : This program is distributed in the hope that it will be useful,
14 : but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : GNU General Public License for more details.
17 :
18 : You should have received a copy of the GNU General Public License
19 : along with this program; if not, write to the Free Software
20 : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21 : MA 02110-1301, USA.
22 :
23 : */
24 :
25 : #import "OOJSPlayer.h"
26 : #import "OOJSEntity.h"
27 : #import "OOJSShip.h"
28 : #import "OOJSVector.h"
29 : #import "OOJavaScriptEngine.h"
30 : #import "EntityOOJavaScriptExtensions.h"
31 :
32 : #import "PlayerEntity.h"
33 : #import "PlayerEntityContracts.h"
34 : #import "PlayerEntityScriptMethods.h"
35 : #import "PlayerEntityLegacyScriptEngine.h"
36 :
37 : #import "OOConstToString.h"
38 : #import "OOFunctionAttributes.h"
39 : #import "OOCollectionExtractors.h"
40 : #import "OOStringParsing.h"
41 :
42 :
43 0 : static JSObject *sPlayerPrototype;
44 0 : static JSObject *sPlayerObject;
45 :
46 :
47 : static JSBool PlayerGetProperty(JSContext *context, JSObject *this, jsid propID, jsval *value);
48 : static JSBool PlayerSetProperty(JSContext *context, JSObject *this, jsid propID, JSBool strict, jsval *value);
49 :
50 : static JSBool PlayerAddMessageToArrivalReport(JSContext *context, uintN argc, jsval *vp);
51 : static JSBool PlayerAudioMessage(JSContext *context, uintN argc, jsval *vp);
52 : static JSBool PlayerCommsMessage(JSContext *context, uintN argc, jsval *vp);
53 : static JSBool PlayerConsoleMessage(JSContext *context, uintN argc, jsval *vp);
54 : static JSBool PlayerEndScenario(JSContext *context, uintN argc, jsval *vp);
55 : static JSBool PlayerIncreaseContractReputation(JSContext *context, uintN argc, jsval *vp);
56 : static JSBool PlayerDecreaseContractReputation(JSContext *context, uintN argc, jsval *vp);
57 : static JSBool PlayerIncreasePassengerReputation(JSContext *context, uintN argc, jsval *vp);
58 : static JSBool PlayerDecreasePassengerReputation(JSContext *context, uintN argc, jsval *vp);
59 : static JSBool PlayerIncreaseParcelReputation(JSContext *context, uintN argc, jsval *vp);
60 : static JSBool PlayerDecreaseParcelReputation(JSContext *context, uintN argc, jsval *vp);
61 : static JSBool PlayerReplaceShip(JSContext *context, uintN argc, jsval *vp);
62 : static JSBool PlayerSetEscapePodDestination(JSContext *context, uintN argc, jsval *vp);
63 : static JSBool PlayerSetPlayerRole(JSContext *context, uintN argc, jsval *vp);
64 : static JSBool PlayerStopAudioMessage(JSContext *context, uintN argc, jsval *vp);
65 :
66 :
67 0 : static JSClass sPlayerClass =
68 : {
69 : "Player",
70 : JSCLASS_HAS_PRIVATE,
71 :
72 : JS_PropertyStub, // addProperty
73 : JS_PropertyStub, // delProperty
74 : PlayerGetProperty, // getProperty
75 : PlayerSetProperty, // setProperty
76 : JS_EnumerateStub, // enumerate
77 : JS_ResolveStub, // resolve
78 : JS_ConvertStub, // convert
79 : OOJSObjectWrapperFinalize,// finalize
80 : JSCLASS_NO_OPTIONAL_MEMBERS
81 : };
82 :
83 :
84 0 : enum
85 : {
86 : // Property IDs
87 : kPlayer_alertAltitude, // low altitude alert flag, boolean, read-only
88 : kPlayer_alertCondition, // alert level, integer, read-only
89 : kPlayer_alertEnergy, // low energy alert flag, boolean, read-only
90 : kPlayer_alertHostiles, // hostiles present alert flag, boolean, read-only
91 : kPlayer_alertMassLocked, // mass lock alert flag, boolean, read-only
92 : kPlayer_alertTemperature, // cabin temperature alert flag, boolean, read-only
93 : kPlayer_bounty, // bounty, unsigned int, read/write
94 : kPlayer_contractReputation, // reputation for cargo contracts, integer, read only
95 : kPlayer_contractReputationPrecise, // reputation for cargo contracts, float, read only
96 : kPlayer_credits, // credit balance, float, read/write
97 : kPlayer_dockingClearanceStatus, // docking clearance status, string, read only
98 : kPlayer_escapePodRescueTime, // override for the amount of time an escape pod rescue takes, read/write
99 : kPlayer_legalStatus, // legalStatus, string, read-only
100 : kPlayer_name, // Player name, string, read/write
101 : kPlayer_parcelReputation, // reputation for parcel contracts, integer, read-only
102 : kPlayer_parcelReputationPrecise, // reputation for parcel contracts, float, read-only
103 : kPlayer_passengerReputation, // reputation for passenger contracts, integer, read-only
104 : kPlayer_passengerReputationPrecise, // reputation for passenger contracts, float, read-only
105 : kPlayer_rank, // rank, string, read-only
106 : kPlayer_roleWeights, // role weights, array, read-only
107 : kPlayer_score, // kill count, integer, read/write
108 : kPlayer_trumbleCount, // number of trumbles, integer, read-only
109 : };
110 :
111 :
112 0 : static JSPropertySpec sPlayerProperties[] =
113 : {
114 : // JS name ID flags
115 : { "alertAltitude", kPlayer_alertAltitude, OOJS_PROP_READONLY_CB },
116 : { "alertCondition", kPlayer_alertCondition, OOJS_PROP_READONLY_CB },
117 : { "alertEnergy", kPlayer_alertEnergy, OOJS_PROP_READONLY_CB },
118 : { "alertHostiles", kPlayer_alertHostiles, OOJS_PROP_READONLY_CB },
119 : { "alertMassLocked", kPlayer_alertMassLocked, OOJS_PROP_READONLY_CB },
120 : { "alertTemperature", kPlayer_alertTemperature, OOJS_PROP_READONLY_CB },
121 : { "bounty", kPlayer_bounty, OOJS_PROP_READWRITE_CB },
122 : { "contractReputation", kPlayer_contractReputation, OOJS_PROP_READONLY_CB },
123 : { "contractReputationPrecise", kPlayer_contractReputationPrecise, OOJS_PROP_READONLY_CB },
124 : { "credits", kPlayer_credits, OOJS_PROP_READWRITE_CB },
125 : { "dockingClearanceStatus", kPlayer_dockingClearanceStatus, OOJS_PROP_READONLY_CB },
126 : { "escapePodRescueTime", kPlayer_escapePodRescueTime, OOJS_PROP_READWRITE_CB },
127 : { "legalStatus", kPlayer_legalStatus, OOJS_PROP_READONLY_CB },
128 : { "name", kPlayer_name, OOJS_PROP_READWRITE_CB },
129 : { "parcelReputation", kPlayer_parcelReputation, OOJS_PROP_READONLY_CB },
130 : { "parcelReputationPrecise", kPlayer_parcelReputationPrecise, OOJS_PROP_READONLY_CB },
131 : { "passengerReputation", kPlayer_passengerReputation, OOJS_PROP_READONLY_CB },
132 : { "passengerReputationPrecise", kPlayer_passengerReputationPrecise, OOJS_PROP_READONLY_CB },
133 : { "rank", kPlayer_rank, OOJS_PROP_READONLY_CB },
134 : { "roleWeights", kPlayer_roleWeights, OOJS_PROP_READONLY_CB },
135 : { "score", kPlayer_score, OOJS_PROP_READWRITE_CB },
136 : { "trumbleCount", kPlayer_trumbleCount, OOJS_PROP_READONLY_CB },
137 : { 0 }
138 : };
139 :
140 :
141 0 : static JSFunctionSpec sPlayerMethods[] =
142 : {
143 : // JS name Function min args
144 : { "addMessageToArrivalReport", PlayerAddMessageToArrivalReport, 1 },
145 : { "audioMessage", PlayerAudioMessage, 1 },
146 : { "commsMessage", PlayerCommsMessage, 1 },
147 : { "consoleMessage", PlayerConsoleMessage, 1 },
148 : { "decreaseContractReputation", PlayerDecreaseContractReputation, 0 },
149 : { "decreaseParcelReputation", PlayerDecreaseParcelReputation, 0 },
150 : { "decreasePassengerReputation", PlayerDecreasePassengerReputation, 0 },
151 : { "endScenario", PlayerEndScenario, 1 },
152 : { "increaseContractReputation", PlayerIncreaseContractReputation, 0 },
153 : { "increaseParcelReputation", PlayerIncreaseParcelReputation, 0 },
154 : { "increasePassengerReputation", PlayerIncreasePassengerReputation, 0 },
155 : { "replaceShip", PlayerReplaceShip, 1 },
156 : { "setEscapePodDestination", PlayerSetEscapePodDestination, 1 }, // null destination must be set explicitly
157 : { "setPlayerRole", PlayerSetPlayerRole, 1 },
158 : { "stopAudioMessage", PlayerStopAudioMessage, 0 },
159 : { 0 }
160 : };
161 :
162 :
163 0 : void InitOOJSPlayer(JSContext *context, JSObject *global)
164 : {
165 : sPlayerPrototype = JS_InitClass(context, global, NULL, &sPlayerClass, OOJSUnconstructableConstruct, 0, sPlayerProperties, sPlayerMethods, NULL, NULL);
166 : OOJSRegisterObjectConverter(&sPlayerClass, OOJSBasicPrivateObjectConverter);
167 :
168 : // Create player object as a property of the global object.
169 : sPlayerObject = JS_DefineObject(context, global, "player", &sPlayerClass, sPlayerPrototype, OOJS_PROP_READONLY);
170 : }
171 :
172 :
173 0 : JSClass *JSPlayerClass(void)
174 : {
175 : return &sPlayerClass;
176 : }
177 :
178 :
179 0 : JSObject *JSPlayerPrototype(void)
180 : {
181 : return sPlayerPrototype;
182 : }
183 :
184 :
185 0 : JSObject *JSPlayerObject(void)
186 : {
187 : return sPlayerObject;
188 : }
189 :
190 :
191 0 : PlayerEntity *OOPlayerForScripting(void)
192 : {
193 : PlayerEntity *player = PLAYER;
194 : [player setScriptTarget:player];
195 :
196 : return player;
197 : }
198 :
199 :
200 0 : static JSBool PlayerGetProperty(JSContext *context, JSObject *this, jsid propID, jsval *value)
201 : {
202 : if (!JSID_IS_INT(propID)) return YES;
203 :
204 : OOJS_NATIVE_ENTER(context)
205 :
206 : id result = nil;
207 : PlayerEntity *player = OOPlayerForScripting();
208 :
209 : switch (JSID_TO_INT(propID))
210 : {
211 : case kPlayer_name:
212 : result = [player commanderName];
213 : break;
214 :
215 : case kPlayer_score:
216 : *value = INT_TO_JSVAL([player score]);
217 : return YES;
218 :
219 : case kPlayer_credits:
220 : return JS_NewNumberValue(context, [player creditBalance], value);
221 :
222 : case kPlayer_rank:
223 : *value = OOJSValueFromNativeObject(context, OODisplayRatingStringFromKillCount([player score]));
224 : return YES;
225 :
226 : case kPlayer_legalStatus:
227 : *value = OOJSValueFromNativeObject(context, OODisplayStringFromLegalStatus([player legalStatus]));
228 : return YES;
229 :
230 : case kPlayer_alertCondition:
231 : *value = INT_TO_JSVAL([player alertCondition]);
232 : return YES;
233 :
234 : case kPlayer_alertTemperature:
235 : *value = OOJSValueFromBOOL([player alertFlags] & ALERT_FLAG_TEMP);
236 : return YES;
237 :
238 : case kPlayer_alertMassLocked:
239 : *value = OOJSValueFromBOOL([player alertFlags] & ALERT_FLAG_MASS_LOCK);
240 : return YES;
241 :
242 : case kPlayer_alertAltitude:
243 : *value = OOJSValueFromBOOL([player alertFlags] & ALERT_FLAG_ALT);
244 : return YES;
245 :
246 : case kPlayer_alertEnergy:
247 : *value = OOJSValueFromBOOL([player alertFlags] & ALERT_FLAG_ENERGY);
248 : return YES;
249 :
250 : case kPlayer_alertHostiles:
251 : *value = OOJSValueFromBOOL([player alertFlags] & ALERT_FLAG_HOSTILES);
252 : return YES;
253 :
254 : case kPlayer_escapePodRescueTime:
255 : return JS_NewNumberValue(context, [player escapePodRescueTime], value);
256 :
257 : case kPlayer_trumbleCount:
258 : return JS_NewNumberValue(context, [player trumbleCount], value);
259 :
260 : /* For compatibility with previous versions, these are still on
261 : * a -7 to +7 scale */
262 : case kPlayer_contractReputation:
263 : return JS_NewNumberValue(context, (int)(((float)[player contractReputation])/10.0), value);
264 :
265 : case kPlayer_passengerReputation:
266 : return JS_NewNumberValue(context, (int)(((float)[player passengerReputation])/10.0), value);
267 :
268 : case kPlayer_parcelReputation:
269 : return JS_NewNumberValue(context, (int)(((float)[player parcelReputation])/10.0), value);
270 :
271 : /* Full-precision reputations */
272 : case kPlayer_contractReputationPrecise:
273 : return JS_NewNumberValue(context, ((float)[player contractReputation])/10.0, value);
274 :
275 : case kPlayer_passengerReputationPrecise:
276 : return JS_NewNumberValue(context, ((float)[player passengerReputation])/10.0, value);
277 :
278 : case kPlayer_parcelReputationPrecise:
279 : return JS_NewNumberValue(context, ((float)[player parcelReputation])/10.0, value);
280 :
281 : case kPlayer_dockingClearanceStatus:
282 : // EMMSTRAN: OOConstToJSString-ify this.
283 : *value = OOJSValueFromNativeObject(context, DockingClearanceStatusToString([player getDockingClearanceStatus]));
284 : return YES;
285 :
286 : case kPlayer_bounty:
287 : *value = INT_TO_JSVAL([player legalStatus]);
288 : return YES;
289 :
290 : case kPlayer_roleWeights:
291 : result = [player roleWeights];
292 : break;
293 :
294 : default:
295 : OOJSReportBadPropertySelector(context, this, propID, sPlayerProperties);
296 : return NO;
297 : }
298 :
299 : *value = OOJSValueFromNativeObject(context, result);
300 : return YES;
301 :
302 : OOJS_NATIVE_EXIT
303 : }
304 :
305 :
306 0 : static JSBool PlayerSetProperty(JSContext *context, JSObject *this, jsid propID, JSBool strict, jsval *value)
307 : {
308 : if (!JSID_IS_INT(propID)) return YES;
309 :
310 : OOJS_NATIVE_ENTER(context)
311 :
312 : PlayerEntity *player = OOPlayerForScripting();
313 : jsdouble fValue;
314 : int32 iValue;
315 : NSString *sValue;
316 :
317 : switch (JSID_TO_INT(propID))
318 : {
319 : case kPlayer_name:
320 : sValue = OOStringFromJSValue(context,*value);
321 : if (sValue != nil)
322 : {
323 : [player setCommanderName:sValue];
324 : return YES;
325 : }
326 : break;
327 :
328 : case kPlayer_score:
329 : if (JS_ValueToInt32(context, *value, &iValue))
330 : {
331 : iValue = MAX(iValue, 0);
332 : [player setScore:iValue];
333 : return YES;
334 : }
335 : break;
336 :
337 : case kPlayer_credits:
338 : if (JS_ValueToNumber(context, *value, &fValue))
339 : {
340 : [player setCreditBalance:fValue];
341 : return YES;
342 : }
343 : break;
344 :
345 : case kPlayer_bounty:
346 : if (JS_ValueToInt32(context, *value, &iValue))
347 : {
348 : if (iValue < 0) iValue = 0;
349 : [player setBounty:iValue withReason:kOOLegalStatusReasonByScript];
350 : return YES;
351 : }
352 : break;
353 :
354 : case kPlayer_escapePodRescueTime:
355 : if (JS_ValueToNumber(context, *value, &fValue))
356 : {
357 : [player setEscapePodRescueTime:fValue];
358 : return YES;
359 : }
360 : break;
361 :
362 : default:
363 : OOJSReportBadPropertySelector(context, this, propID, sPlayerProperties);
364 : return NO;
365 : }
366 :
367 : OOJSReportBadPropertyValue(context, this, propID, sPlayerProperties, *value);
368 : return NO;
369 :
370 : OOJS_NATIVE_EXIT
371 : }
372 :
373 :
374 : // *** Methods ***
375 :
376 : // commsMessage(message : String [, duration : Number])
377 0 : static JSBool PlayerCommsMessage(JSContext *context, uintN argc, jsval *vp)
378 : {
379 : OOJS_NATIVE_ENTER(context)
380 :
381 : NSString *message = nil;
382 : double time = 4.5;
383 : BOOL gotTime = YES;
384 :
385 : if (argc > 0) message = OOStringFromJSValue(context, OOJS_ARGV[0]);
386 : if (argc > 1) gotTime = JS_ValueToNumber(context, OOJS_ARGV[1], &time);
387 : if (message == nil || !gotTime)
388 : {
389 : OOJSReportBadArguments(context, @"Player", @"commsMessage", argc, OOJS_ARGV, nil, @"message and optional duration");
390 : return NO;
391 : }
392 :
393 : [UNIVERSE addCommsMessage:message forCount:time];
394 : [PLAYER doScriptEvent:OOJSID("commsMessageReceived") withArgument:message andArgument:nil];
395 : OOJS_RETURN_VOID;
396 :
397 : OOJS_NATIVE_EXIT
398 : }
399 :
400 :
401 : // consoleMessage(message : String [, duration : Number])
402 0 : static JSBool PlayerConsoleMessage(JSContext *context, uintN argc, jsval *vp)
403 : {
404 : OOJS_NATIVE_ENTER(context)
405 :
406 : NSString *message = nil;
407 : double time = 3.0;
408 : BOOL gotTime = YES;
409 :
410 : if (argc > 0) message = OOStringFromJSValue(context, OOJS_ARGV[0]);
411 : if (argc > 1) gotTime = JS_ValueToNumber(context, OOJS_ARGV[1], &time);
412 : if (message == nil || !gotTime)
413 : {
414 : OOJSReportBadArguments(context, @"Player", @"consoleMessage", argc, OOJS_ARGV, nil, @"message and optional duration");
415 : return NO;
416 : }
417 :
418 : [UNIVERSE addMessage:message forCount:time];
419 : OOJS_RETURN_VOID;
420 :
421 : OOJS_NATIVE_EXIT
422 : }
423 :
424 :
425 : // endScenario(scenario : String)
426 0 : static JSBool PlayerEndScenario(JSContext *context, uintN argc, jsval *vp)
427 : {
428 : OOJS_NATIVE_ENTER(context)
429 :
430 : NSString *scenario = nil;
431 :
432 : if (argc > 0) scenario = OOStringFromJSValue(context, OOJS_ARGV[0]);
433 : if (scenario == nil)
434 : {
435 : OOJSReportBadArguments(context, @"Player", @"endScenario", argc, OOJS_ARGV, nil, @"scenario key");
436 : return NO;
437 : }
438 :
439 : OOJS_RETURN_BOOL([PLAYER endScenario:scenario]);
440 :
441 : OOJS_NATIVE_EXIT
442 : }
443 :
444 :
445 : // increaseContractReputation()
446 0 : static JSBool PlayerIncreaseContractReputation(JSContext *context, uintN argc, jsval *vp)
447 : {
448 : OOJS_NATIVE_ENTER(context)
449 :
450 : [OOPlayerForScripting() increaseContractReputation:1];
451 : OOJS_RETURN_VOID;
452 :
453 : OOJS_NATIVE_EXIT
454 : }
455 :
456 :
457 : // decreaseContractReputation()
458 0 : static JSBool PlayerDecreaseContractReputation(JSContext *context, uintN argc, jsval *vp)
459 : {
460 : OOJS_NATIVE_ENTER(context)
461 :
462 : [OOPlayerForScripting() decreaseContractReputation:1];
463 : OOJS_RETURN_VOID;
464 :
465 : OOJS_NATIVE_EXIT
466 : }
467 :
468 :
469 : // increaseParcelReputation()
470 0 : static JSBool PlayerIncreaseParcelReputation(JSContext *context, uintN argc, jsval *vp)
471 : {
472 : OOJS_NATIVE_ENTER(context)
473 :
474 : [OOPlayerForScripting() increaseParcelReputation:1];
475 : OOJS_RETURN_VOID;
476 :
477 : OOJS_NATIVE_EXIT
478 : }
479 :
480 :
481 : // decreaseParcelReputation()
482 0 : static JSBool PlayerDecreaseParcelReputation(JSContext *context, uintN argc, jsval *vp)
483 : {
484 : OOJS_NATIVE_ENTER(context)
485 :
486 : [OOPlayerForScripting() decreaseParcelReputation:1];
487 : OOJS_RETURN_VOID;
488 :
489 : OOJS_NATIVE_EXIT
490 : }
491 :
492 :
493 : // increasePassengerReputation()
494 0 : static JSBool PlayerIncreasePassengerReputation(JSContext *context, uintN argc, jsval *vp)
495 : {
496 : OOJS_NATIVE_ENTER(context)
497 :
498 : [OOPlayerForScripting() increasePassengerReputation:1];
499 : OOJS_RETURN_VOID;
500 :
501 : OOJS_NATIVE_EXIT
502 : }
503 :
504 :
505 : // decreasePassengerReputation()
506 0 : static JSBool PlayerDecreasePassengerReputation(JSContext *context, uintN argc, jsval *vp)
507 : {
508 : OOJS_NATIVE_ENTER(context)
509 :
510 : [OOPlayerForScripting() decreasePassengerReputation:1];
511 : OOJS_RETURN_VOID;
512 :
513 : OOJS_NATIVE_EXIT
514 : }
515 :
516 : // addMessageToArrivalReport(message : String)
517 0 : static JSBool PlayerAddMessageToArrivalReport(JSContext *context, uintN argc, jsval *vp)
518 : {
519 : OOJS_NATIVE_ENTER(context)
520 :
521 : NSString *report = nil;
522 : PlayerEntity *player = OOPlayerForScripting();
523 :
524 : if (argc > 0) report = OOStringFromJSValue(context, OOJS_ARGV[0]);
525 : if (report == nil)
526 : {
527 : OOJSReportBadArguments(context, @"Player", @"addMessageToArrivalReport", MIN(argc, 1U), OOJS_ARGV, nil, @"string (arrival message)");
528 : return NO;
529 : }
530 :
531 : [player addMessageToReport:report];
532 : OOJS_RETURN_VOID;
533 :
534 : OOJS_NATIVE_EXIT
535 : }
536 :
537 :
538 0 : static JSBool PlayerAudioMessage(JSContext *context, uintN argc, jsval *vp)
539 : {
540 : OOJS_NATIVE_ENTER(context)
541 :
542 : NSString *audioMessage = nil;
543 : PlayerEntity *player = OOPlayerForScripting();
544 :
545 : if (argc > 0) audioMessage = OOStringFromJSValue(context, OOJS_ARGV[0]);
546 : if (audioMessage == nil)
547 : {
548 : OOJSReportBadArguments(context, @"Player", @"audioMessage", argc, OOJS_ARGV, nil, @"audiomessage (string)");
549 : return NO;
550 : }
551 :
552 : if ([player isSpeechOn] >= OOSPEECHSETTINGS_COMMS) [UNIVERSE startSpeakingString:audioMessage];
553 : OOJS_RETURN_VOID;
554 :
555 : OOJS_NATIVE_EXIT
556 : }
557 :
558 :
559 : // replaceShip (shipyard-key : String)
560 0 : static JSBool PlayerReplaceShip(JSContext *context, uintN argc, jsval *vp)
561 : {
562 : OOJS_NATIVE_ENTER(context)
563 :
564 : NSString *shipKey = nil;
565 : PlayerEntity *player = OOPlayerForScripting();
566 : BOOL success = NO;
567 : int personality = 0;
568 :
569 : if (argc > 0) shipKey = OOStringFromJSValue(context, OOJS_ARGV[0]);
570 : if (shipKey == nil)
571 : {
572 : OOJSReportBadArguments(context, @"Player", @"replaceShip", MIN(argc, 1U), OOJS_ARGV, nil, @"string (shipyard key)");
573 : return NO;
574 : }
575 :
576 : if (EXPECT_NOT(!([player status] == STATUS_DOCKED)))
577 : {
578 : OOJSReportError(context, @"Player.replaceShip() only works while the player is docked.");
579 : return NO;
580 : }
581 :
582 : success = [player replaceShipWithNamedShip:shipKey];
583 : if (argc > 1)
584 : {
585 : JS_ValueToInt32(context,OOJS_ARGV[1],&personality);
586 : if (personality >= 0 && (uint16_t)personality < ENTITY_PERSONALITY_MAX)
587 : {
588 : [player setEntityPersonalityInt:(uint16_t)personality];
589 : }
590 : }
591 :
592 : if (success)
593 : {
594 : [player doScriptEvent:OOJSID("playerReplacedShip") withArgument:player];
595 : // slightly misnamed world event now - to be deprecated
596 : [player doScriptEvent:OOJSID("playerBoughtNewShip") withArgument:player andArgument:[NSNumber numberWithInt:0]];
597 : }
598 :
599 : OOJS_RETURN_BOOL(success);
600 :
601 : OOJS_NATIVE_EXIT
602 : }
603 :
604 :
605 : // setEscapePodDestination(Entity | 'NEARBY_SYSTEM')
606 0 : static JSBool PlayerSetEscapePodDestination(JSContext *context, uintN argc, jsval *vp)
607 : {
608 : OOJS_NATIVE_ENTER(context)
609 :
610 : if (EXPECT_NOT(!OOIsPlayerStale()))
611 : {
612 : OOJSReportError(context, @"Player.setEscapePodDestination() only works while the escape pod is in flight.");
613 : return NO;
614 : }
615 :
616 : BOOL OK = NO;
617 : id destValue = nil;
618 : PlayerEntity *player = OOPlayerForScripting();
619 :
620 : if (argc == 1)
621 : {
622 : destValue = OOJSNativeObjectFromJSValue(context, OOJS_ARGV[0]);
623 :
624 : if (destValue == nil)
625 : {
626 : [player setDockTarget:NULL];
627 : OK = YES;
628 : }
629 : else if ([destValue isKindOfClass:[ShipEntity class]] && [destValue isStation])
630 : {
631 : [player setDockTarget:destValue];
632 : OK = YES;
633 : }
634 : else if ([destValue isKindOfClass:[NSString class]])
635 : {
636 : if ([destValue isEqualToString:@"NEARBY_SYSTEM"])
637 : {
638 : // find the nearest system with a main station, or die in the attempt!
639 : [player setDockTarget:NULL];
640 :
641 : double rescueRange = MAX_JUMP_RANGE; // reach at least 1 other system!
642 : if ([UNIVERSE inInterstellarSpace])
643 : {
644 : // Set 3.5 ly as the limit, enough to reach at least 2 systems!
645 : rescueRange = MAX_JUMP_RANGE / 2.0;
646 : }
647 : NSMutableArray *sDests = [UNIVERSE nearbyDestinationsWithinRange:rescueRange];
648 : NSUInteger i = 0, nDests = [sDests count];
649 :
650 : if (nDests > 0) for (i = --nDests; i > 0; i--)
651 : {
652 : if ([[sDests oo_dictionaryAtIndex:i] oo_boolForKey:@"nova"])
653 : {
654 : [sDests removeObjectAtIndex:i];
655 : }
656 : }
657 :
658 : // i is back to 0, nDests could have changed...
659 : nDests = [sDests count];
660 : if (nDests > 0) // we have a system with a main station!
661 : {
662 : if (nDests > 1) i = ranrot_rand() % nDests; // any nearby system will do.
663 : NSDictionary *dest = [sDests objectAtIndex:i];
664 :
665 : // add more time until rescue, with overheads for entering witchspace in case of overlapping systems.
666 : double dist = [dest oo_doubleForKey:@"distance"];
667 : [player addToAdjustTime:(.2 + dist * dist) * 3600.0 + 5400.0 * (ranrot_rand() & 127)];
668 :
669 : // at the end of the docking sequence we'll check if the target system is the same as the system we're in...
670 : [player setTargetSystemID:i];
671 : }
672 : OK = YES;
673 : }
674 : }
675 : else
676 : {
677 : JSBool bValue;
678 : if (JS_ValueToBoolean(context, OOJS_ARGV[0], &bValue) && bValue == NO)
679 : {
680 : [player setDockTarget:NULL];
681 : OK = YES;
682 : }
683 : }
684 : }
685 :
686 : if (OK == NO)
687 : {
688 : OOJSReportBadArguments(context, @"Player", @"setEscapePodDestination", argc, OOJS_ARGV, nil, @"a valid station, null, or 'NEARBY_SYSTEM'");
689 : }
690 : return OK;
691 :
692 : OOJS_NATIVE_EXIT
693 : }
694 :
695 :
696 : // setPlayerRole (role-key : String [, index : Number])
697 0 : static JSBool PlayerSetPlayerRole(JSContext *context, uintN argc, jsval *vp)
698 : {
699 : OOJS_NATIVE_ENTER(context)
700 :
701 : NSString *role = nil;
702 : PlayerEntity *player = OOPlayerForScripting();
703 : uint32 index = 0;
704 :
705 : if (argc > 0) role = OOStringFromJSValue(context, OOJS_ARGV[0]);
706 : if (role == nil)
707 : {
708 : OOJSReportBadArguments(context, @"Player", @"setPlayerRole", MIN(argc, 1U), OOJS_ARGV, nil, @"string (role) [, number (index)]");
709 : return NO;
710 : }
711 :
712 : if (argc > 1)
713 : {
714 : if (JS_ValueToECMAUint32(context,OOJS_ARGV[1],&index))
715 : {
716 : [player addRoleToPlayer:role inSlot:index];
717 : return YES;
718 : }
719 : }
720 : [player addRoleToPlayer:role];
721 : return YES;
722 :
723 : OOJS_NATIVE_EXIT
724 : }
725 :
726 :
727 0 : static JSBool PlayerStopAudioMessage(JSContext *context, uintN argc, jsval *vp)
728 : {
729 : OOJS_NATIVE_ENTER(context)
730 : if ([UNIVERSE isSpeaking]) [UNIVERSE stopSpeaking];
731 : OOJS_RETURN_VOID;
732 :
733 : OOJS_NATIVE_EXIT
734 : }
|