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

          Line data    Source code
       1           0 : /*
       2             : 
       3             : OOJSMission.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 "OOJSMission.h"
      27             : #import "OOJavaScriptEngine.h"
      28             : #import "OOJSScript.h"
      29             : #import "OOConstToJSString.h"
      30             : #import "OOJSVector.h"
      31             : 
      32             : #import "OOJSPlayer.h"
      33             : #import "PlayerEntityScriptMethods.h"
      34             : #import "OOStringExpander.h"
      35             : #import "OOCollectionExtractors.h"
      36             : #import "OOMusicController.h"
      37             : #import "GuiDisplayGen.h"
      38             : #import "OODebugStandards.h"
      39             : 
      40             : static JSBool MissionGetProperty(JSContext *context, JSObject *this, jsid propID, jsval *value);
      41             : static JSBool MissionSetProperty(JSContext *context, JSObject *this, jsid propID, JSBool strict, jsval *value);
      42             : 
      43             : static JSBool MissionMarkSystem(JSContext *context, uintN argc, jsval *vp);
      44             : static JSBool MissionUnmarkSystem(JSContext *context, uintN argc, jsval *vp);
      45             : static JSBool MissionAddMessageText(JSContext *context, uintN argc, jsval *vp);
      46             : static JSBool MissionSetInstructions(JSContext *context, uintN argc, jsval *vp);
      47             : static JSBool MissionSetInstructionsKey(JSContext *context, uintN argc, jsval *vp);
      48             : static JSBool MissionRunScreen(JSContext *context, uintN argc, jsval *vp);
      49             : static JSBool MissionRunShipLibrary(JSContext *context, uintN argc, jsval *vp);
      50             : 
      51             : static JSBool MissionSetInstructionsInternal(JSContext *context, uintN argc, jsval *vp, BOOL isKey);
      52             : 
      53             : //  Mission screen  callback varibables
      54           0 : static jsval                    sCallbackFunction;
      55           0 : static jsval                    sCallbackThis;
      56           0 : static OOJSScript               *sCallbackScript = nil;
      57             : 
      58           0 : static JSObject                 *sMissionObject;
      59             : 
      60           0 : static JSClass sMissionClass =
      61             : {
      62             :         "Mission",
      63             :         0,
      64             :         
      65             :         JS_PropertyStub,
      66             :         JS_PropertyStub,
      67             :         MissionGetProperty,
      68             :         MissionSetProperty,
      69             :         JS_EnumerateStub,
      70             :         JS_ResolveStub,
      71             :         JS_ConvertStub,
      72             :         JS_FinalizeStub
      73             : };
      74             : 
      75             : 
      76           0 : enum
      77             : {
      78             :         kMission_markedSystems,
      79             :         kMission_screenID,
      80             :         kMission_exitScreen
      81             : };
      82             : 
      83             : 
      84           0 : static JSPropertySpec sMissionProperties[] = 
      85             : {
      86             :         // JS name                                      ID                                                              flags
      87             :         { "markedSystems", kMission_markedSystems, OOJS_PROP_READONLY_CB },
      88             :         { "screenID", kMission_screenID, OOJS_PROP_READONLY_CB },
      89             :         { "exitScreen", kMission_exitScreen, OOJS_PROP_READWRITE_CB },
      90             :         { 0 }
      91             : };
      92             : 
      93             : 
      94           0 : static JSFunctionSpec sMissionMethods[] =
      95             : {
      96             :         // JS name                                      Function                                        min args
      97             :         { "addMessageText",                   MissionAddMessageText,          1 },
      98             :         { "markSystem",                               MissionMarkSystem,                      1 },
      99             :         { "runScreen",                                MissionRunScreen,                       1 }, // the callback function is optional!
     100             :         { "setInstructions",          MissionSetInstructions,         1 },
     101             :         { "setInstructionsKey",               MissionSetInstructionsKey,      1 },
     102             :         { "unmarkSystem",                     MissionUnmarkSystem,            1 },
     103             :         { "runShipLibrary",                   MissionRunShipLibrary,          0 },
     104             :         { 0 }
     105             : };
     106             : 
     107             : 
     108           0 : void InitOOJSMission(JSContext *context, JSObject *global)
     109             : {
     110             :         sCallbackFunction = JSVAL_NULL;
     111             :         sCallbackThis = JSVAL_NULL;
     112             :         
     113             :         JSObject *missionPrototype = JS_InitClass(context, global, NULL, &sMissionClass, OOJSUnconstructableConstruct, 0, sMissionProperties, sMissionMethods, NULL, NULL);
     114             :         sMissionObject = JS_DefineObject(context, global, "mission", &sMissionClass, missionPrototype, OOJS_PROP_READONLY);
     115             :         
     116             :         // Ensure JS objects are rooted.
     117             :         OOJSAddGCValueRoot(context, &sCallbackFunction, "Pending mission callback function");
     118             :         OOJSAddGCValueRoot(context, &sCallbackThis, "Pending mission callback this");
     119             : }
     120             : 
     121             : 
     122           0 : void MissionRunCallback()
     123             : {
     124             :         // don't do anything if we don't have a function.
     125             :         if (JSVAL_IS_NULL(sCallbackFunction) || JSVAL_IS_VOID(sCallbackFunction))  return;
     126             :         
     127             :         jsval                           argval = JSVAL_VOID;
     128             :         jsval                           argval2 = JSVAL_VOID;
     129             :         jsval                           rval = JSVAL_VOID;
     130             :         PlayerEntity            *player = OOPlayerForScripting();
     131             :         OOJavaScriptEngine      *engine  = [OOJavaScriptEngine sharedEngine];
     132             :         JSContext                       *context = OOJSAcquireContext();
     133             :         
     134             :         /*      Create temporarily-rooted local copies of sCallbackFunction and
     135             :                 sCallbackThis, then clear the statics. This must be done in advance
     136             :                 since the callback might call runScreen() and clobber the statics.
     137             :         */
     138             :         jsval                           cbFunction = JSVAL_VOID;
     139             :         JSObject                        *cbThis = NULL;
     140             :         OOJSScript                      *cbScript = sCallbackScript;
     141             :         
     142             :         OOJSAddGCValueRoot(context, &cbFunction, "Mission callback function");
     143             :         OOJSAddGCObjectRoot(context, &cbThis, "Mission callback this");
     144             :         cbFunction = sCallbackFunction;
     145             :         cbScript = sCallbackScript;
     146             :         JS_ValueToObject(context, sCallbackThis, &cbThis);
     147             :         
     148             :         sCallbackScript = nil;
     149             :         sCallbackFunction = JSVAL_NULL;
     150             :         sCallbackThis = JSVAL_NULL;
     151             :         
     152             :         jsval args[2];
     153             :         argval = OOJSValueFromNativeObject(context, [player missionChoice_string]);
     154             :         argval2 = OOJSValueFromNativeObject(context, [player missionKeyPress_string]);
     155             :         args[0] = argval;
     156             :         args[1] = argval2;
     157             : 
     158             :         // now reset the mission choice silently, before calling the callback script.
     159             :         [player setMissionChoice:nil keyPress:@"" withEvent:NO];
     160             :         
     161             :         // Call the callback.
     162             :         @try
     163             :         {
     164             :                 [OOJSScript pushScript:cbScript];
     165             :                 [engine callJSFunction:cbFunction
     166             :                                          forObject:cbThis
     167             :                                                   argc:2
     168             :                                                   argv:args
     169             :                                                 result:&rval];
     170             :         }
     171             :         @catch (NSException *exception)
     172             :         {
     173             :                 // Squash any exception, allow cleanup to happen and so forth.
     174             :                 OOLog(kOOLogException, @"Ignoring exception %@:%@ during handling of mission screen completion callback.", [exception name], [exception reason]);
     175             :         }
     176             :         [OOJSScript popScript:cbScript];
     177             :         
     178             :         // Manage that memory.
     179             :         [cbScript release];
     180             :         JS_RemoveValueRoot(context, &cbFunction);
     181             :         JS_RemoveObjectRoot(context, &cbThis);
     182             :         
     183             :         OOJSRelinquishContext(context);
     184             : }
     185             : 
     186             : 
     187           0 : static JSBool MissionGetProperty(JSContext *context, JSObject *this, jsid propID, jsval *value) 
     188             : {
     189             :         if (!JSID_IS_INT(propID))  return YES;
     190             :         
     191             :         OOJS_NATIVE_ENTER(context)
     192             : 
     193             :         id result = nil;
     194             :         PlayerEntity            *player = OOPlayerForScripting();
     195             : 
     196             :         switch (JSID_TO_INT(propID))
     197             :         {
     198             :                 case kMission_markedSystems:
     199             :                         result = [player getMissionDestinations];
     200             :                         if (result == nil)  result = [NSDictionary dictionary];
     201             :                         result = [result allValues];
     202             :                         break;
     203             : 
     204             :                 case kMission_screenID:
     205             :                         result = [player missionScreenID];
     206             :                         break;
     207             : 
     208             :                 case kMission_exitScreen:
     209             :                         *value = OOJSValueFromGUIScreenID(context, [player missionExitScreen]);
     210             :                         return YES;
     211             : 
     212             :                 default:
     213             :                         OOJSReportBadPropertySelector(context, this, propID, sMissionProperties);
     214             :                         return NO;
     215             :         }
     216             : 
     217             :         *value = OOJSValueFromNativeObject(context, result);
     218             :         return YES;
     219             :         
     220             :         OOJS_NATIVE_EXIT
     221             : }
     222             : 
     223             : 
     224           0 : static JSBool MissionSetProperty(JSContext *context, JSObject *this, jsid propID, JSBool strict, jsval *value)
     225             : {
     226             :         if (!JSID_IS_INT(propID))  return YES;
     227             :         
     228             :         OOJS_NATIVE_ENTER(context)
     229             :         
     230             :         OOGUIScreenID exitScreen;
     231             :         PlayerEntity            *player = OOPlayerForScripting();
     232             : 
     233             :         switch (JSID_TO_INT(propID))
     234             :         {
     235             :                 case kMission_exitScreen:
     236             :                         exitScreen = OOGUIScreenIDFromJSValue(context, *value);
     237             :                         [player setMissionExitScreen:exitScreen];
     238             :                         return YES;
     239             :         
     240             :                 default:
     241             :                         OOJSReportBadPropertySelector(context, this, propID, sMissionProperties);
     242             :         }
     243             :         
     244             :         OOJSReportBadPropertyValue(context, this, propID, sMissionProperties, *value);
     245             :         return NO;
     246             :         
     247             :         OOJS_NATIVE_EXIT
     248             : }
     249             : 
     250             : 
     251             : 
     252             : // *** Methods ***
     253             : 
     254             : // markSystem(integer+)
     255           0 : static JSBool MissionMarkSystem(JSContext *context, uintN argc, jsval *vp)
     256             : {
     257             :         OOJS_NATIVE_ENTER(context)
     258             :         
     259             :         PlayerEntity            *player = OOPlayerForScripting();
     260             :         unsigned i;
     261             :         int dest;
     262             : 
     263             :         // two pass. Once to validate, once to apply if they validate
     264             :         for (i=0;i<argc;i++)
     265             :         {
     266             :                 if (!JS_ValueToInt32(context, OOJS_ARGV[i], &dest)) 
     267             :                 {
     268             :                         JS_ClearPendingException(context); // or JS_ValueToInt32 exception crashes JS engine
     269             :                         if (!JSVAL_IS_OBJECT(OOJS_ARGV[i]))
     270             :                         {
     271             :                                 OOJSReportBadArguments(context, @"Mission", @"markSystem", MIN(argc, 1U), OOJS_ARGV, nil, @"numbers or objects");
     272             :                                 return NO;
     273             :                         }
     274             :                 }
     275             :         }
     276             : 
     277             :         for (i=0;i<argc;i++)
     278             :         {
     279             :                 if (JS_ValueToInt32(context, OOJS_ARGV[i], &dest)) 
     280             :                 {
     281             :                         OOStandardsDeprecated(@"Use of numbers for mission.markSystem is deprecated");
     282             :                         if (!OOEnforceStandards())
     283             :                         {
     284             :                                 [player addMissionDestinationMarker:[player defaultMarker:dest]];
     285             :                         }
     286             :                 }
     287             :                 else // must be object, from above
     288             :                 {
     289             :                         JS_ClearPendingException(context); // or JS_ValueToInt32 exception crashes JS engine
     290             :                         NSDictionary *marker = OOJSNativeObjectFromJSObject(context, JSVAL_TO_OBJECT(OOJS_ARGV[i]));
     291             :                         OOSystemID system = [marker oo_intForKey:@"system" defaultValue:-1];
     292             :                         if (system >= 0)
     293             :                         {
     294             :                                 [player addMissionDestinationMarker:marker];
     295             :                         }
     296             :                 }
     297             :         }
     298             :         OOJS_RETURN_VOID;
     299             :         
     300             :         OOJS_NATIVE_EXIT
     301             : }
     302             : 
     303             : 
     304             : // unmarkSystem(integer+)
     305           0 : static JSBool MissionUnmarkSystem(JSContext *context, uintN argc, jsval *vp)
     306             : {
     307             :         OOJS_NATIVE_ENTER(context)
     308             :         
     309             :         PlayerEntity            *player = OOPlayerForScripting();
     310             :         unsigned i;
     311             :         int dest;
     312             : 
     313             :         // two pass. Once to validate, once to apply if they validate
     314             :         for (i=0;i<argc;i++)
     315             :         {
     316             :                 if (!JS_ValueToInt32(context, OOJS_ARGV[i], &dest)) 
     317             :                 {
     318             :                         JS_ClearPendingException(context); // or JS_ValueToInt32 exception crashes JS engine
     319             :                         if (!JSVAL_IS_OBJECT(OOJS_ARGV[i]))
     320             :                         {
     321             :                                 OOJSReportBadArguments(context, @"Mission", @"unmarkSystem", MIN(argc, 1U), OOJS_ARGV, nil, @"numbers or objects");
     322             :                                 return NO;
     323             :                         }
     324             :                 }
     325             :         }
     326             : 
     327             :         BOOL result = YES;
     328             :         for (i=0;i<argc;i++)
     329             :         {
     330             :                 if (JS_ValueToInt32(context, OOJS_ARGV[i], &dest)) 
     331             :                 {
     332             :                         OOStandardsDeprecated(@"Use of numbers for mission.unmarkSystem is deprecated");
     333             :                         if (!OOEnforceStandards())
     334             :                         {
     335             :                                 if (![player removeMissionDestinationMarker:[player defaultMarker:dest]]) {
     336             :                                         result = NO;
     337             :                                 }
     338             :                         }
     339             :                 }
     340             :                 else // must be object, from above
     341             :                 {
     342             :                         JS_ClearPendingException(context); // or JS_ValueToInt32 exception crashes JS engine
     343             :                         NSDictionary *marker = OOJSNativeObjectFromJSObject(context, JSVAL_TO_OBJECT(OOJS_ARGV[i]));
     344             :                         OOSystemID system = [marker oo_intForKey:@"system" defaultValue:-1];
     345             :                         if (system >= 0)
     346             :                         {
     347             :                                 if (![player removeMissionDestinationMarker:marker]) {
     348             :                                         result = NO;
     349             :                                 }
     350             :                         }
     351             :                 }
     352             :         }
     353             :         
     354             :         OOJS_RETURN_BOOL(result);
     355             :         
     356             :         OOJS_NATIVE_EXIT
     357             : }
     358             : 
     359             : 
     360             : // addMessageText(text : String)
     361           0 : static JSBool MissionAddMessageText(JSContext *context, uintN argc, jsval *vp)
     362             : {
     363             :         OOJS_NATIVE_ENTER(context)
     364             :         
     365             :         PlayerEntity            *player = OOPlayerForScripting();
     366             :         NSString                        *text = nil;
     367             :         
     368             :         if (EXPECT_NOT(argc == 0))
     369             :         {
     370             :                 OOJS_RETURN_VOID;
     371             :         }
     372             :         
     373             :         // Found "FIXME: warning if no mission screen running.",,,
     374             :         // However: used routinely by the Constrictor mission in F7, without mission screens.
     375             :         text = OOStringFromJSValue(context, OOJS_ARGV[0]);
     376             :         [player addLiteralMissionText:text];
     377             :         
     378             :         OOJS_RETURN_VOID;
     379             :         
     380             :         OOJS_NATIVE_EXIT
     381             : }
     382             : 
     383             : 
     384             : // setInstructionsKey(instructionsKey: String [, missionKey : String])
     385           0 : static JSBool MissionSetInstructionsKey(JSContext *context, uintN argc, jsval *vp)
     386             : {
     387             :         return MissionSetInstructionsInternal(context, argc, vp, YES);
     388             : }
     389             : 
     390             : 
     391             : // setInstructions(instructions: String [, missionKey : String])
     392           0 : static JSBool MissionSetInstructions(JSContext *context, uintN argc, jsval *vp)
     393             : {
     394             :         return MissionSetInstructionsInternal(context, argc, vp, NO);
     395             : }
     396             : 
     397             : 
     398           0 : static JSBool MissionSetInstructionsInternal(JSContext *context, uintN argc, jsval *vp, BOOL isKey)
     399             : {
     400             :         OOJS_NATIVE_ENTER(context)
     401             :         
     402             :         PlayerEntity            *player = OOPlayerForScripting();
     403             :         NSString                        *text = nil;
     404             :         NSArray                         *texts = nil;
     405             :         NSString                        *missionKey = nil;
     406             :         
     407             :         if (EXPECT_NOT(argc == 0))
     408             :         {
     409             :                 OOJSReportWarning(context, @"Usage error: mission.%@() called with no arguments. Treating as Mission.%@(null). This call may fail in a future version of Oolite.", isKey ? @"setInstructionsKey" : @"setInstructions", isKey ? @"setInstructionsKey" : @"setInstructions");
     410             :         }
     411             :         else if (EXPECT_NOT(JSVAL_IS_VOID(OOJS_ARGV[0])))
     412             :         {
     413             :                 OOJSReportBadArguments(context, @"Mission", isKey ? @"setInstructionsKey" : @"setInstructions", 1, OOJS_ARGV, NULL, @"string or null");
     414             :                 return NO;
     415             :         }
     416             :         else if (!JSVAL_IS_NULL(OOJS_ARGV[0]) && JSVAL_IS_OBJECT(OOJS_ARGV[0]))
     417             :         {
     418             :                 texts = OOJSNativeObjectFromJSValue(context, OOJS_ARGV[0]);
     419             :         }
     420             :         else
     421             :         {
     422             :                 text = OOStringFromJSValue(context, OOJS_ARGV[0]);
     423             :         }
     424             :         
     425             :         if (argc > 1)
     426             :         {
     427             :                 missionKey = OOStringFromJSValueEvenIfNull(context, OOJS_ARGV[1]);
     428             :         }
     429             :         else
     430             :         {
     431             :                 missionKey = [[OOJSScript currentlyRunningScript] name];
     432             :         }
     433             :         
     434             :         if (text != nil)
     435             :         {
     436             :                 if (isKey)
     437             :                 {
     438             :                         [player setMissionDescription:text forMission:missionKey];
     439             :                 }
     440             :                 else
     441             :                 {
     442             :                         [player setMissionInstructions:text forMission:missionKey];
     443             :                 }
     444             :         }
     445             :         else if (texts != nil && !isKey)
     446             :         {
     447             :                 [player setMissionInstructionsList:texts forMission:missionKey];
     448             :         }
     449             :         else
     450             :         {
     451             :                 [player clearMissionDescriptionForMission:missionKey];
     452             :         }
     453             :         
     454             :         OOJS_RETURN_VOID;
     455             :         
     456             :         OOJS_NATIVE_EXIT
     457             : }
     458             : 
     459             : 
     460           0 : static NSDictionary *GetParameterDictionary(JSContext *context, JSObject *object, const char *key)
     461             : {
     462             :         jsval value = JSVAL_NULL;
     463             :         if (JS_GetProperty(context, object, key, &value))
     464             :         {
     465             :                 if (JSVAL_IS_OBJECT(value))
     466             :                 {
     467             :                         return OOJSNativeObjectFromJSObject(context, JSVAL_TO_OBJECT(value));
     468             :                 }
     469             :         }
     470             :         return nil;
     471             : }
     472             : 
     473             : 
     474           0 : static NSString *GetParameterString(JSContext *context, JSObject *object, const char *key)
     475             : {
     476             :         jsval value = JSVAL_NULL;
     477             :         if (JS_GetProperty(context, object, key, &value))
     478             :         {
     479             :                 return OOStringFromJSValue(context, value);
     480             :         }
     481             :         return nil;
     482             : }
     483             : 
     484             : 
     485           0 : static NSDictionary *GetParameterImageDescriptor(JSContext *context, JSObject *object, const char *key)
     486             : {
     487             :         jsval value = JSVAL_NULL;
     488             :         if (JS_GetProperty(context, object, key, &value))
     489             :         {
     490             :                 return [[UNIVERSE gui] textureDescriptorFromJSValue:value inContext:context callerDescription:@"mission.runScreen()"];
     491             :         }
     492             :         else
     493             :         {
     494             :                 return nil;
     495             :         }
     496             : }
     497             : 
     498             : 
     499             : // runScreen(params: dict, callBack:function) - if the callback function is null, emulate the old style runMissionScreen
     500           0 : static JSBool MissionRunScreen(JSContext *context, uintN argc, jsval *vp)
     501             : {
     502             :         OOJS_NATIVE_ENTER(context)
     503             :         
     504             :         PlayerEntity            *player = OOPlayerForScripting();
     505             :         jsval                           function = JSVAL_NULL;
     506             :         jsval                           value = JSVAL_NULL;
     507             :         JSObject                        *params = NULL;
     508             :         
     509             :         // No mission screens during intro.
     510             :         if ([player status] == STATUS_START_GAME)
     511             :         {
     512             :                 // (though no JS should be loaded at this stage, so this
     513             :                 // check may be obsolete - CIM)
     514             :                 OOJS_RETURN_BOOL(NO);
     515             :         }
     516             :         
     517             :         // Validate arguments.
     518             :         if (argc < 1 || !JS_ValueToObject(context, OOJS_ARGV[0], &params))
     519             :         {
     520             :                 OOJSReportBadArguments(context, @"mission", @"runScreen", MIN(argc, 1U), &OOJS_ARGV[0], nil, @"parameter object");
     521             :                 return NO;
     522             :         }
     523             :         
     524             :         if (argc > 1)  function = OOJS_ARGV[1];
     525             :         if (!JSVAL_IS_NULL(function) && !OOJSValueIsFunction(context, function))
     526             :         {
     527             :                 OOJSReportBadArguments(context, @"mission", @"runScreen", 1, &OOJS_ARGV[1], nil, @"function");
     528             :                 return NO;
     529             :         }
     530             :         
     531             :         // Not OOJS_BEGIN_FULL_NATIVE() - we use JSAPI while paused.
     532             :         OOJSPauseTimeLimiter();
     533             :         
     534             :         if (!JSVAL_IS_NULL(function))
     535             :         {
     536             : 
     537             :                 /* CIM 30/12/12: This following line causes problems in certain
     538             :                  * cases, but has to be kept for backward
     539             :                  * compatibility. Documenting the third argument of
     540             :                  * mission.runScreen will at least help people get around it in
     541             :                  * multi-world-script mission screens. (Though, since no-one has
     542             :                  * complained yet, perhaps I'm the only one who uses them?) */
     543             : 
     544             :                 sCallbackScript = [[[OOJSScript currentlyRunningScript] weakRefUnderlyingObject] retain];
     545             :                 if (argc > 2)
     546             :                 {
     547             :                         sCallbackThis = OOJS_ARGV[2];
     548             :                 }
     549             :                 else
     550             :                 {
     551             :                         sCallbackThis = OOJSValueFromNativeObject(context, sCallbackScript);
     552             :                 }
     553             :         }
     554             :         
     555             :         // Apply settings.
     556             :         if (JS_GetProperty(context, params, "title", &value) && !JSVAL_IS_VOID(value))
     557             :         {
     558             :                 [player setMissionTitle:OOStringFromJSValue(context, value)];
     559             :         }
     560             :         else
     561             :         {
     562             :                 NSString *titleKey = GetParameterString(context, params, "titleKey");
     563             :                 if (titleKey != nil)
     564             :                 {
     565             :                         NSString *message = [[UNIVERSE missiontext] oo_stringForKey:titleKey];
     566             :                         if (message != nil)
     567             :                         {
     568             :                                 [player setMissionTitle:OOExpand(message)];
     569             :                         }
     570             :                         else
     571             :                         {
     572             :                                 OOJSReportWarning(context, @"Mission.runScreen: titleKey '%@' has no entry in missiontext.plist.", titleKey);
     573             :                         }
     574             :                 }
     575             :         }
     576             :         
     577             :         [[OOMusicController     sharedController] setMissionMusic:GetParameterString(context, params, "music")];
     578             :         [player setMissionOverlayDescriptor:GetParameterImageDescriptor(context, params, "overlay")];
     579             :         [player setMissionBackgroundDescriptor:GetParameterImageDescriptor(context, params, "background")];
     580             :         [player setMissionBackgroundSpecial:GetParameterString(context, params, "backgroundSpecial")];
     581             : 
     582             :         if (JS_GetProperty(context, params, "customChartZoom", &value) && !JSVAL_IS_VOID(value))
     583             :         {
     584             :                 jsdouble zoom;
     585             :                 if (JS_ValueToNumber(context, value, &zoom))
     586             :                 {
     587             :                         if (zoom >= 1 && zoom <= CHART_MAX_ZOOM)
     588             :                         {
     589             :                                 [player setCustomChartZoom:zoom];
     590             :                         }
     591             :                         else 
     592             :                         {
     593             :                                 OOJSReportWarning(context, @"Mission.runScreen: invalid customChartZoom value specified.");
     594             :                                 [player setCustomChartZoom:1];
     595             :                         }
     596             :                 }
     597             :         }
     598             :         if (JS_GetProperty(context, params, "customChartCentre", &value) && !JSVAL_IS_VOID(value))
     599             :         {
     600             :                 Vector vValue;
     601             :                 if (JSValueToVector(context, value, &vValue))
     602             :                 {
     603             :                         NSPoint coords = { vValue.x, vValue.y };
     604             :                         [player setCustomChartCentre:coords];
     605             :                 }
     606             :                 else 
     607             :                 {
     608             :                         [player setCustomChartCentre:[player galaxy_coordinates]];
     609             :                         OOJSReportWarning(context, @"Mission.runScreen: invalid value for customChartCentre. Must be valid vector. Defaulting to current location.");
     610             :                 }
     611             :         }
     612             :         if (JS_GetProperty(context, params, "customChartCentreInLY", &value) && !JSVAL_IS_VOID(value))
     613             :         {
     614             :                 Vector vValue;
     615             :                 if (JSValueToVector(context, value, &vValue))
     616             :                 {
     617             :                         NSPoint coords = OOInternalCoordinatesFromGalactic(vValue);
     618             :                         [player setCustomChartCentre:coords];
     619             :                 }
     620             :                 else 
     621             :                 {
     622             :                         [player setCustomChartCentre:[player galaxy_coordinates]];
     623             :                         OOJSReportWarning(context, @"Mission.runScreen: invalid value for customChartCentreInLY. Must be valid vector. Defaulting to current location.");
     624             :                 }
     625             :         }
     626             : 
     627             :         [UNIVERSE removeDemoShips];     // remove any demoship or miniature planet that may be remaining from previous screens
     628             :         
     629             :         ShipEntity *demoShip = nil;
     630             :         if (JS_GetProperty(context, params, "model", &value) && !JSVAL_IS_VOID(value))
     631             :         {
     632             :                 if ([player status] == STATUS_IN_FLIGHT && JSVAL_IS_STRING(value))
     633             :                 {
     634             :                         OOJSReportWarning(context, @"Mission.runScreen: model cannot be displayed while in flight.");
     635             :                 }
     636             :                 else
     637             :                 {
     638             :                         NSString *role = OOStringFromJSValue(context, value);
     639             :                         
     640             :                         JSBool spinning = YES;
     641             :                         if (JS_GetProperty(context, params, "spinModel", &value) && !JSVAL_IS_VOID(value))
     642             :                         {
     643             :                                 JS_ValueToBoolean(context, value, &spinning);
     644             :                         }
     645             :                         
     646             :                 //      [player showShipModel:OOStringFromJSValue(context, value)];
     647             :                         demoShip = [UNIVERSE makeDemoShipWithRole:role spinning:spinning];
     648             :                 }
     649             :         }
     650             :         if (demoShip != nil)
     651             :         {
     652             :                 if (JS_GetProperty(context, params, "modelPersonality", &value) && !JSVAL_IS_VOID(value))
     653             :                 {
     654             :                         int personality = 0;
     655             :                         JS_ValueToInt32(context,value,&personality);
     656             :                         [demoShip setEntityPersonalityInt:personality];
     657             :                 }
     658             :                 jsval demoShipVal = [demoShip oo_jsValueInContext:context];
     659             :                 JS_SetProperty(context, sMissionObject, "displayModel", &demoShipVal);
     660             :         }
     661             :         else
     662             :         {
     663             :                 JS_DeleteProperty(context, sMissionObject, "displayModel");
     664             :         }
     665             : 
     666             :         JSBool allowInterrupt = NO;
     667             :         // force the allowInterrupt to be YES while in flight
     668             :         if ([player status] == STATUS_IN_FLIGHT) 
     669             :         {
     670             :                 allowInterrupt = YES;
     671             :         } 
     672             :         else
     673             :         {
     674             :                 if (JS_GetProperty(context, params, "allowInterrupt", &value) && !JSVAL_IS_VOID(value))
     675             :                 {
     676             :                         JS_ValueToBoolean(context, value, &allowInterrupt);
     677             :                 }
     678             :         }
     679             : 
     680             :         if (JS_GetProperty(context, params, "exitScreen", &value) && !JSVAL_IS_VOID(value))
     681             :         {
     682             :                 [player setMissionExitScreen:OOGUIScreenIDFromJSValue(context, value)];
     683             :         }
     684             :         else
     685             :         {
     686             :                 [player setMissionExitScreen:GUI_SCREEN_STATUS];
     687             :         }
     688             : 
     689             :         if (JS_GetProperty(context, params, "screenID", &value) && !JSVAL_IS_VOID(value))
     690             :         {
     691             :                 [player setMissionScreenID:OOStringFromJSValue(context, value)];
     692             :         }
     693             :         else
     694             :         {
     695             :                 [player clearMissionScreenID];
     696             :         }
     697             : 
     698             :         [player clearExtraMissionKeys];
     699             :         if (JS_GetProperty(context, params, "registerKeys", &value) && !JSVAL_IS_VOID(value))
     700             :         {
     701             :                 [player setExtraMissionKeys:GetParameterDictionary(context, params, "registerKeys")];
     702             :         }
     703             : 
     704             :         JSBool textEntry = NO;
     705             :         if (JS_GetProperty(context, params, "textEntry", &value) && !JSVAL_IS_VOID(value))
     706             :         {
     707             :                 JS_ValueToBoolean(context, value, &textEntry);
     708             :         }
     709             :         if (textEntry)
     710             :         {
     711             :                 [player setMissionChoiceByTextEntry:YES];
     712             :         }
     713             :         else
     714             :         {
     715             :                 [player setMissionChoiceByTextEntry:NO];
     716             :         }
     717             : 
     718             :         // Start the mission screen.
     719             :         sCallbackFunction = function;
     720             :         [player setGuiToMissionScreenWithCallback:!JSVAL_IS_NULL(sCallbackFunction)];
     721             : 
     722             :         // Apply more settings. (These must be done after starting the screen for legacy reasons.)
     723             :         if (allowInterrupt)
     724             :         {
     725             :                 [player allowMissionInterrupt];
     726             :         }
     727             :         NSString *message = GetParameterString(context, params, "message");
     728             :         if (message != nil)
     729             :         {
     730             :                 [player addLiteralMissionText:message];
     731             :         }
     732             :         else
     733             :         {
     734             :                 NSString *messageKey = GetParameterString(context, params, "messageKey");
     735             :                 if (messageKey != nil)  [player addMissionText:messageKey];
     736             :         }
     737             :         
     738             :         if (!textEntry)
     739             :         {
     740             :                 NSDictionary *choices = GetParameterDictionary(context, params, "choices");
     741             :                 if (choices == nil)
     742             :                 {
     743             :                         [player setMissionChoices:GetParameterString(context, params, "choicesKey")];
     744             :                 }
     745             :                 else 
     746             :                 {
     747             :                         [player setMissionChoicesDictionary:choices];           
     748             :                 }
     749             :         }
     750             : 
     751             :         NSString *firstKey = GetParameterString(context, params, "initialChoicesKey");
     752             :         if (firstKey != nil)
     753             :         {
     754             :                 OOGUIRow row = [[UNIVERSE gui] rowForKey:firstKey];
     755             :                 if (row != -1)
     756             :                 {
     757             :                         [[UNIVERSE gui] setSelectedRow:row];
     758             :                 }
     759             :         }
     760             :         
     761             :         // now clean up!
     762             :         [player setMissionOverlayDescriptor:nil];
     763             :         [player setMissionBackgroundDescriptor:nil];
     764             :         [player setMissionTitle:nil];
     765             :         [player setMissionMusic:nil];
     766             :         
     767             :         OOJSResumeTimeLimiter();
     768             :         
     769             :         OOJS_RETURN_BOOL(YES);
     770             :         
     771             :         OOJS_NATIVE_EXIT
     772             : }
     773             : 
     774             : 
     775           0 : static JSBool MissionRunShipLibrary(JSContext *context, uintN argc, jsval *vp)
     776             : {
     777             :         OOJS_NATIVE_ENTER(context)
     778             :         
     779             :         PlayerEntity    *player = OOPlayerForScripting();
     780             :         BOOL                    OK = YES;
     781             :         if ([player status] != STATUS_DOCKED)
     782             :         {
     783             :                 OOJSReportWarning(context, @"Mission.runShipLibrary: must be docked.");
     784             :                 OK = NO;
     785             :         }
     786             :         else
     787             :         {
     788             :                 [PLAYER setGuiToIntroFirstGo:NO];
     789             :         }
     790             :         
     791             :         OOJS_RETURN_BOOL(OK);
     792             :         
     793             :         OOJS_NATIVE_EXIT
     794             : }
     795             : 
     796             : 

Generated by: LCOV version 1.14