1 /*
2  * See Licensing and Copyright notice in naev.h
3  */
4 
5 /**
6  * @file nlua_misn.c
7  *
8  * @brief Handles the mission Lua bindings.
9  */
10 
11 
12 #include "nlua_misn.h"
13 
14 #include "naev.h"
15 
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include "nstring.h"
19 #include <math.h>
20 
21 #include <lua.h>
22 #include <lauxlib.h>
23 
24 #include "nlua.h"
25 #include "nlua_hook.h"
26 #include "nlua_player.h"
27 #include "nlua_tk.h"
28 #include "nlua_faction.h"
29 #include "nlua_system.h"
30 #include "nlua_tex.h"
31 #include "nlua_camera.h"
32 #include "nlua_music.h"
33 #include "nlua_bkg.h"
34 #include "nlua_tut.h"
35 #include "player.h"
36 #include "mission.h"
37 #include "log.h"
38 #include "rng.h"
39 #include "toolkit.h"
40 #include "land.h"
41 #include "nxml.h"
42 #include "nluadef.h"
43 #include "music.h"
44 #include "gui_osd.h"
45 #include "npc.h"
46 #include "array.h"
47 #include "ndata.h"
48 
49 
50 /**
51  * @brief Mission Lua bindings.
52  *
53  * An example would be:
54  * @code
55  * misn.setNPC( "Keer", "empire/unique/keer" )
56  * misn.setDesc( "You see here Commodore Keer." )
57  * @endcode
58  *
59  * @luamod misn
60  */
61 
62 
63 /*
64  * prototypes
65  */
66 
67 
68 /*
69  * libraries
70  */
71 /* Mission methods */
72 static int misn_setTitle( lua_State *L );
73 static int misn_setDesc( lua_State *L );
74 static int misn_setReward( lua_State *L );
75 static int misn_setNPC( lua_State *L );
76 static int misn_factions( lua_State *L );
77 static int misn_accept( lua_State *L );
78 static int misn_finish( lua_State *L );
79 static int misn_markerAdd( lua_State *L );
80 static int misn_markerMove( lua_State *L );
81 static int misn_markerRm( lua_State *L );
82 static int misn_cargoAdd( lua_State *L );
83 static int misn_cargoRm( lua_State *L );
84 static int misn_cargoJet( lua_State *L );
85 static int misn_osdCreate( lua_State *L );
86 static int misn_osdDestroy( lua_State *L );
87 static int misn_osdActive( lua_State *L );
88 static int misn_npcAdd( lua_State *L );
89 static int misn_npcRm( lua_State *L );
90 static int misn_claim( lua_State *L );
91 static const luaL_reg misn_methods[] = {
92    { "setTitle", misn_setTitle },
93    { "setDesc", misn_setDesc },
94    { "setReward", misn_setReward },
95    { "setNPC", misn_setNPC },
96    { "factions", misn_factions },
97    { "accept", misn_accept },
98    { "finish", misn_finish },
99    { "markerAdd", misn_markerAdd },
100    { "markerMove", misn_markerMove },
101    { "markerRm", misn_markerRm },
102    { "cargoAdd", misn_cargoAdd },
103    { "cargoRm", misn_cargoRm },
104    { "cargoJet", misn_cargoJet },
105    { "osdCreate", misn_osdCreate },
106    { "osdDestroy", misn_osdDestroy },
107    { "osdActive", misn_osdActive },
108    { "npcAdd", misn_npcAdd },
109    { "npcRm", misn_npcRm },
110    { "claim", misn_claim },
111    {0,0}
112 }; /**< Mission Lua methods. */
113 
114 
115 /**
116  * @brief Registers all the mission libraries.
117  *
118  *    @param L Lua state.
119  *    @return 0 on success.
120  */
misn_loadLibs(nlua_env env)121 int misn_loadLibs( nlua_env env )
122 {
123    nlua_loadStandard(env);
124    nlua_loadMisn(env);
125    nlua_loadHook(env);
126    nlua_loadCamera(env);
127    nlua_loadTex(env);
128    nlua_loadBackground(env);
129    nlua_loadMusic(env);
130    nlua_loadTk(env);
131    if (player_isTut())
132       nlua_loadTut(env);
133    return 0;
134 }
135 /*
136  * individual library loading
137  */
138 /**
139  * @brief Loads the mission Lua library.
140  *    @param L Lua state.
141  */
nlua_loadMisn(nlua_env env)142 int nlua_loadMisn( nlua_env env )
143 {
144    nlua_register(env, "misn", misn_methods, 0);
145    return 0;
146 }
147 
148 
149 /**
150  * @brief Tries to run a mission, but doesn't err if it fails.
151  *
152  *    @param misn Mission that owns the function.
153  *    @param func Name of the function to call.
154  *    @return -1 on error, 1 on misn.finish() call, 2 if mission got deleted
155  *            and 0 normally.
156  */
misn_tryRun(Mission * misn,const char * func)157 int misn_tryRun( Mission *misn, const char *func )
158 {
159    int ret;
160 
161    /* Get the function to run. */
162    misn_runStart( misn, func );
163    if (lua_isnil( naevL, -1 )) {
164       lua_pop(naevL,1);
165       return 0;
166    }
167    ret = misn_runFunc( misn, func, 0 );
168    return ret;
169 }
170 
171 
172 /**
173  * @brief Runs a mission function.
174  *
175  *    @param misn Mission that owns the function.
176  *    @param func Name of the function to call.
177  *    @return -1 on error, 1 on misn.finish() call, 2 if mission got deleted
178  *            and 0 normally.
179  */
misn_run(Mission * misn,const char * func)180 int misn_run( Mission *misn, const char *func )
181 {
182    int ret;
183 
184    /* Run the function. */
185    misn_runStart( misn, func );
186    ret = misn_runFunc( misn, func, 0 );
187    return ret;
188 }
189 
190 
191 /**
192  * @brief Gets the mission that's being currently run in Lua.
193  *
194  * This should ONLY be called below an nlua_pcall, so __NLUA_CURENV is set
195  */
misn_getFromLua(lua_State * L)196 Mission* misn_getFromLua( lua_State *L )
197 {
198    Mission *misn;
199 
200    nlua_getenv(__NLUA_CURENV, "__misn");
201    misn = (Mission*) lua_touserdata( L, -1 );
202    lua_pop( L, 1 );
203 
204    return misn;
205 }
206 
207 
208 /**
209  * @brief Sets up the mission to run misn_runFunc.
210  */
misn_runStart(Mission * misn,const char * func)211 void misn_runStart( Mission *misn, const char *func )
212 {
213    lua_pushlightuserdata( naevL, misn );
214    nlua_setenv( misn->env, "__misn" );
215 
216    /* Set the Lua state. */
217    nlua_getenv( misn->env, func );
218 }
219 
220 
221 /**
222  * @brief Runs a mission set up with misn_runStart.
223  *
224  *    @param misn Mission that owns the function.
225  *    @param func Name of the function to call.
226  *    @return -1 on error, 1 on misn.finish() call, 2 if mission got deleted
227  *            and 0 normally.
228  */
misn_runFunc(Mission * misn,const char * func,int nargs)229 int misn_runFunc( Mission *misn, const char *func, int nargs )
230 {
231    int i, ret;
232    const char* err;
233    int misn_delete;
234    Mission *cur_mission;
235    nlua_env env;
236 
237    env = misn->env;
238    ret = nlua_pcall(env, nargs, 0);
239 
240    /* The mission can change if accepted. */
241    nlua_getenv(env, "__misn");
242    cur_mission = (Mission*) lua_touserdata(naevL, -1);
243    lua_pop(naevL, 1);
244 
245    if (ret != 0) { /* error has occurred */
246       err = (lua_isstring(naevL,-1)) ? lua_tostring(naevL,-1) : NULL;
247       if ((err==NULL) || (strcmp(err,NLUA_DONE)!=0)) {
248          WARN("Mission '%s' -> '%s': %s",
249                cur_mission->data->name, func, (err) ? err : "unknown error");
250          ret = -1;
251       }
252       else
253          ret = 1;
254       lua_pop(naevL,1);
255    }
256 
257    /* Get delete. */
258    nlua_getenv(env, "__misn_delete");
259    misn_delete = lua_toboolean(naevL,-1);
260    lua_pop(naevL,1);
261 
262    /* mission is finished */
263    if (misn_delete) {
264       ret = 2;
265       mission_cleanup( cur_mission );
266       for (i=0; i<MISSION_MAX; i++) {
267          if (cur_mission != player_missions[i])
268             continue;
269 
270          mission_shift(i);
271          break;
272       }
273    }
274 
275    return ret;
276 }
277 
278 
279 /**
280  * @brief Sets the current mission title.
281  *
282  *    @luatparam string title Title to use for mission.
283  * @luafunc setTitle( title )
284  */
misn_setTitle(lua_State * L)285 static int misn_setTitle( lua_State *L )
286 {
287    const char *str;
288    Mission *cur_mission;
289 
290    str = luaL_checkstring(L,1);
291 
292    cur_mission = misn_getFromLua(L);
293    if (cur_mission->title) /* cleanup old title */
294       free(cur_mission->title);
295    cur_mission->title = strdup(str);
296 
297    return 0;
298 }
299 /**
300  * @brief Sets the current mission description.
301  *
302  * Also sets the mission OSD unless you explicitly force an OSD, however you
303  *  can't specify bullet points or other fancy things like with the real OSD.
304  *
305  *    @luatparam string desc Description to use for mission.
306  * @luafunc setDesc( desc )
307  */
misn_setDesc(lua_State * L)308 static int misn_setDesc( lua_State *L )
309 {
310    const char *str;
311    Mission *cur_mission;
312 
313    str = luaL_checkstring(L,1);
314 
315    cur_mission = misn_getFromLua(L);
316    if (cur_mission->desc) /* cleanup old description */
317       free(cur_mission->desc);
318    cur_mission->desc = strdup(str);
319 
320    return 0;
321 }
322 /**
323  * @brief Sets the current mission reward description.
324  *
325  *    @luatparam string reward Description of the reward to use.
326  * @luafunc setReward( reward )
327  */
misn_setReward(lua_State * L)328 static int misn_setReward( lua_State *L )
329 {
330    const char *str;
331    Mission *cur_mission;
332 
333    str = luaL_checkstring(L,1);
334 
335    cur_mission = misn_getFromLua(L);
336    if (cur_mission->reward) /* cleanup old reward */
337       free(cur_mission->reward);
338    cur_mission->reward = strdup(str);
339    return 0;
340 }
341 
342 /**
343  * @brief Adds a new marker.
344  *
345  * @usage my_marker = misn.markerAdd( system.get("Gamma Polaris"), "low" )
346  *
347  * Valid marker types are:<br/>
348  *  - "plot": Important plot marker.<br/>
349  *  - "high": High importance mission marker (lower than plot).<br/>
350  *  - "low": Low importance mission marker (lower than high).<br/>
351  *  - "computer": Mission computer marker.<br/>
352  *
353  *    @luatparam System sys System to mark.
354  *    @luatparam string type Colouring scheme to use.
355  *    @luatreturn number A marker ID to be used with markerMove and markerRm.
356  * @luafunc markerAdd( sys, type )
357  */
misn_markerAdd(lua_State * L)358 static int misn_markerAdd( lua_State *L )
359 {
360    int id;
361    LuaSystem sys;
362    const char *stype;
363    SysMarker type;
364    Mission *cur_mission;
365 
366    /* Check parameters. */
367    sys   = luaL_checksystem( L, 1 );
368    stype = luaL_checkstring( L, 2 );
369 
370    /* Handle types. */
371    if (strcmp(stype, "computer")==0)
372       type = SYSMARKER_COMPUTER;
373    else if (strcmp(stype, "low")==0)
374       type = SYSMARKER_LOW;
375    else if (strcmp(stype, "high")==0)
376       type = SYSMARKER_HIGH;
377    else if (strcmp(stype, "plot")==0)
378       type = SYSMARKER_PLOT;
379    else {
380       NLUA_ERROR(L, "Unknown marker type: %s", stype);
381       return 0;
382    }
383 
384    cur_mission = misn_getFromLua(L);
385 
386    /* Add the marker. */
387    id = mission_addMarker( cur_mission, -1, sys, type );
388 
389    /* Update system markers. */
390    mission_sysMark();
391 
392    /* Return the ID. */
393    lua_pushnumber( L, id );
394    return 1;
395 }
396 
397 /**
398  * @brief Moves a marker to a new system.
399  *
400  * @usage misn.markerMove( my_marker, system.get("Delta Pavonis") )
401  *
402  *    @luatparam number id ID of the mission marker to move.
403  *    @luatparam System sys System to move the marker to.
404  * @luafunc markerMove( id, sys )
405  */
misn_markerMove(lua_State * L)406 static int misn_markerMove( lua_State *L )
407 {
408    int id;
409    LuaSystem sys;
410    MissionMarker *marker;
411    int i, n;
412    Mission *cur_mission;
413 
414    /* Handle parameters. */
415    id    = luaL_checkinteger( L, 1 );
416    sys   = luaL_checksystem( L, 2 );
417 
418    cur_mission = misn_getFromLua(L);
419 
420    /* Mission must have markers. */
421    if (cur_mission->markers == NULL) {
422       NLUA_ERROR( L, "Mission has no markers set!" );
423       return 0;
424    }
425 
426    /* Check id. */
427    marker = NULL;
428    n = array_size( cur_mission->markers );
429    for (i=0; i<n; i++) {
430       if (id == cur_mission->markers[i].id) {
431          marker = &cur_mission->markers[i];
432          break;
433       }
434    }
435    if (marker == NULL) {
436       NLUA_ERROR( L, "Mission does not have a marker with id '%d'", id );
437       return 0;
438    }
439 
440    /* Update system. */
441    marker->sys = sys;
442 
443    /* Update system markers. */
444    mission_sysMark();
445    return 0;
446 }
447 
448 /**
449  * @brief Removes a mission system marker.
450  *
451  * @usage misn.markerRm( my_marker )
452  *
453  *    @luatparam number id ID of the marker to remove.
454  * @luafunc markerRm( id )
455  */
misn_markerRm(lua_State * L)456 static int misn_markerRm( lua_State *L )
457 {
458    int id;
459    int i, n;
460    MissionMarker *marker;
461    Mission *cur_mission;
462 
463    /* Handle parameters. */
464    id    = luaL_checkinteger( L, 1 );
465 
466    cur_mission = misn_getFromLua(L);
467 
468    /* Mission must have markers. */
469    if (cur_mission->markers == NULL) {
470       /* Already removed. */
471       return 0;
472    }
473 
474    /* Check id. */
475    marker = NULL;
476    n = array_size( cur_mission->markers );
477    for (i=0; i<n; i++) {
478       if (id == cur_mission->markers[i].id) {
479          marker = &cur_mission->markers[i];
480          break;
481       }
482    }
483    if (marker == NULL) {
484       /* Already removed. */
485       return 0;
486    }
487 
488    /* Remove the marker. */
489    array_erase( &cur_mission->markers, marker, &marker[1] );
490 
491    /* Update system markers. */
492    mission_sysMark();
493    return 0;
494 }
495 
496 
497 /**
498  * @brief Sets the current mission NPC.
499  *
500  * This is used in bar missions where you talk to a person. The portraits are
501  *  the ones found in GFX_PATH/portraits without the png extension. So for
502  *  GFX_PATH/portraits/none.png you would just use "none".
503  *
504  * @usage misn.setNPC( "Invisible Man", "none" )
505  *
506  *    @luatparam string name Name of the NPC.
507  *    @luatparam string portrait Name of the portrait to use for the NPC.
508  * @luafunc setNPC( name, portrait )
509  */
misn_setNPC(lua_State * L)510 static int misn_setNPC( lua_State *L )
511 {
512    char buf[PATH_MAX];
513    const char *name, *str;
514    Mission *cur_mission;
515 
516    cur_mission = misn_getFromLua(L);
517 
518    /* Free if portrait is already set. */
519    if (cur_mission->portrait != NULL) {
520       gl_freeTexture(cur_mission->portrait);
521       cur_mission->portrait = NULL;
522    }
523 
524    /* Free NPC name. */
525    if (cur_mission->npc != NULL) {
526       free(cur_mission->npc);
527       cur_mission->npc = NULL;
528    }
529 
530    /* For no parameters just leave having freed NPC. */
531    if (lua_gettop(L) == 0)
532       return 0;
533 
534    /* Get parameters. */
535    name = luaL_checkstring(L,1);
536    str  = luaL_checkstring(L,2);
537 
538    /* Set NPC name. */
539    cur_mission->npc = strdup(name);
540 
541    /* Set portrait. */
542    nsnprintf( buf, PATH_MAX, GFX_PATH"portraits/%s.png", str );
543    cur_mission->portrait = gl_newImage( buf, 0 );
544 
545    return 0;
546 }
547 
548 
549 /**
550  * @brief Gets the factions the mission is available for.
551  *
552  * @usage f = misn.factions()
553  *    @luatreturn {Faction,...} A table containing the factions for whom the mission is available.
554  * @luafunc factions()
555  */
misn_factions(lua_State * L)556 static int misn_factions( lua_State *L )
557 {
558    int i;
559    MissionData *dat;
560    LuaFaction f;
561    Mission *cur_mission;
562 
563    cur_mission = misn_getFromLua(L);
564    dat = cur_mission->data;
565 
566    /* we'll push all the factions in table form */
567    lua_newtable(L);
568    for (i=0; i<dat->avail.nfactions; i++) {
569       lua_pushnumber(L,i+1); /* index, starts with 1 */
570       f = dat->avail.factions[i];
571       lua_pushfaction(L, f); /* value */
572       lua_rawset(L,-3); /* store the value in the table */
573    }
574    return 1;
575 }
576 /**
577  * @brief Attempts to accept the mission.
578  *
579  * @usage if not misn.accept() then return end
580  *    @luatreturn boolean true if mission was properly accepted.
581  * @luafunc accept()
582  */
misn_accept(lua_State * L)583 static int misn_accept( lua_State *L )
584 {
585    int i, ret;
586    Mission *cur_mission;
587 
588    ret = 0;
589 
590    /* find last mission */
591    for (i=0; i<MISSION_MAX; i++)
592       if (player_missions[i]->data == NULL)
593          break;
594 
595    cur_mission = misn_getFromLua(L);
596 
597    /* no missions left */
598    if (cur_mission->accepted)
599       NLUA_ERROR(L, "Mission already accepted!");
600    else if (i>=MISSION_MAX)
601       ret = 1;
602    else { /* copy it over */
603       *player_missions[i] = *cur_mission;
604       memset( cur_mission, 0, sizeof(Mission) );
605       cur_mission = player_missions[i];
606       cur_mission->accepted = 1; /* Mark as accepted. */
607 
608       /* Need to change pointer. */
609       lua_pushlightuserdata(L,cur_mission);
610       nlua_setenv(cur_mission->env, "__misn");
611    }
612 
613    lua_pushboolean(L,!ret); /* we'll convert C style return to Lua */
614    return 1;
615 }
616 /**
617  * @brief Finishes the mission.
618  *
619  *    @luatparam[opt] boolean properly If true and the mission is unique it marks the mission
620  *                     as completed.  If false it deletes the mission but
621  *                     doesn't mark it as completed.  If the parameter isn't
622  *                     passed it just ends the mission (without removing it
623  *                     from the player's list of active missions).
624  * @luafunc finish( properly )
625  */
misn_finish(lua_State * L)626 static int misn_finish( lua_State *L )
627 {
628    int b;
629    Mission *cur_mission;
630 
631    if (lua_isboolean(L,1))
632       b = lua_toboolean(L,1);
633    else {
634       lua_pushstring(L, NLUA_DONE);
635       lua_error(L); /* THERE IS NO RETURN */
636       return 0;
637    }
638 
639    cur_mission = misn_getFromLua(L);
640 
641    lua_pushboolean( L, 1 );
642    nlua_setenv(cur_mission->env, "__misn_delete");
643 
644    if (b && mis_isFlag(cur_mission->data,MISSION_UNIQUE))
645       player_missionFinished( mission_getID( cur_mission->data->name ) );
646 
647    lua_pushstring(L, NLUA_DONE);
648    lua_error(L); /* shouldn't return */
649 
650    return 0;
651 }
652 
653 
654 /**
655  * @brief Adds some mission cargo to the player.  He cannot sell it nor get rid of it
656  *  unless he abandons the mission in which case it'll get eliminated.
657  *
658  *    @luatparam string cargo Name of the cargo to add. This must match a cargo name defined in commodity.xml.
659  *    @luatparam number quantity Quantity of cargo to add.
660  *    @luatreturn number The id of the cargo which can be used in cargoRm.
661  * @luafunc cargoAdd( cargo, quantity )
662  */
misn_cargoAdd(lua_State * L)663 static int misn_cargoAdd( lua_State *L )
664 {
665    const char *cname;
666    Commodity *cargo;
667    int quantity, ret;
668    Mission *cur_mission;
669 
670    /* Parameters. */
671    cname    = luaL_checkstring(L,1);
672    quantity = luaL_checkint(L,2);
673    cargo = commodity_get( cname );
674 
675    /* Check if the cargo exists. */
676    if(cargo == NULL) {
677       NLUA_ERROR(L, "Cargo '%s' not found.", cname);
678       return 0;
679    }
680 
681    cur_mission = misn_getFromLua(L);
682 
683    /* First try to add the cargo. */
684    ret = pilot_addMissionCargo( player.p, cargo, quantity );
685    mission_linkCargo( cur_mission, ret );
686 
687    lua_pushnumber(L, ret);
688    return 1;
689 }
690 /**
691  * @brief Removes the mission cargo.
692  *
693  *    @luatparam number cargoid Identifier of the mission cargo.
694  *    @luatreturn boolean true on success.
695  * @luafunc cargoRm( cargoid )
696  */
misn_cargoRm(lua_State * L)697 static int misn_cargoRm( lua_State *L )
698 {
699    int ret;
700    unsigned int id;
701    Mission *cur_mission;
702 
703    id = luaL_checklong(L,1);
704 
705    /* First try to remove the cargo from player. */
706    if (pilot_rmMissionCargo( player.p, id, 0 ) != 0) {
707       lua_pushboolean(L,0);
708       return 1;
709    }
710 
711    cur_mission = misn_getFromLua(L);
712 
713    /* Now unlink the mission cargo if it was successful. */
714    ret = mission_unlinkCargo( cur_mission, id );
715 
716    lua_pushboolean(L,!ret);
717    return 1;
718 }
719 /**
720  * @brief Jettisons the mission cargo.
721  *
722  *    @luatparam number cargoid ID of the cargo to jettison.
723  *    @luatreturn boolean true on success.
724  * @luafunc cargoJet( cargoid )
725  */
misn_cargoJet(lua_State * L)726 static int misn_cargoJet( lua_State *L )
727 {
728    int ret;
729    unsigned int id;
730    Mission *cur_mission;
731 
732    id = luaL_checklong(L,1);
733 
734    /* First try to remove the cargo from player. */
735    if (pilot_rmMissionCargo( player.p, id, 1 ) != 0) {
736       lua_pushboolean(L,0);
737       return 1;
738    }
739 
740    cur_mission = misn_getFromLua(L);
741 
742    /* Now unlink the mission cargo if it was successful. */
743    ret = mission_unlinkCargo( cur_mission, id );
744 
745    lua_pushboolean(L,!ret);
746    return 1;
747 }
748 
749 
750 /**
751  * @brief Creates a mission OSD.
752  *
753  * @note You can index elements by using '\t' as first character of an element.
754  *
755  * @usage misn.osdCreate( "My OSD", {"Element 1", "Element 2"})
756  *
757  *    @luatparam string title Title to give the OSD.
758  *    @luatparam {string,...} list List of elements to put in the OSD.
759  * @luafunc osdCreate( title, list )
760  */
misn_osdCreate(lua_State * L)761 static int misn_osdCreate( lua_State *L )
762 {
763    const char *title;
764    int nitems;
765    char **items;
766    int i;
767    Mission *cur_mission;
768 
769    cur_mission = misn_getFromLua(L);
770 
771    /* Must be accepted. */
772    if (!cur_mission->accepted) {
773       WARN("Can't create an OSD on an unaccepted mission!");
774       return 0;
775    }
776 
777    /* Check parameters. */
778    title  = luaL_checkstring(L,1);
779    luaL_checktype(L,2,LUA_TTABLE);
780    nitems = lua_objlen(L,2);
781 
782    /* Destroy OSD if already exists. */
783    if (cur_mission->osd != 0) {
784       osd_destroy( cur_mission->osd );
785       cur_mission->osd = 0;
786    }
787 
788    /* Allocate items. */
789    items = calloc( nitems, sizeof(char *) );
790 
791    /* Get items. */
792    for (i=0; i<nitems; i++) {
793       lua_pushnumber(L,i+1);
794       lua_gettable(L,2);
795       if (!lua_isstring(L,-1)) {
796          free(items);
797          luaL_typerror(L, -1, "string");
798          return 0;
799       }
800       items[i] = strdup( lua_tostring(L, -1) );
801       lua_pop(L,1);
802    }
803 
804    /* Create OSD. */
805    cur_mission->osd = osd_create( title, nitems, (const char**) items,
806          cur_mission->data->avail.priority );
807    cur_mission->osd_set = 1; /* OSD was explicitly set. */
808 
809    /* Free items. */
810    for (i=0; i<nitems; i++)
811       free(items[i]);
812    free(items);
813 
814    return 0;
815 }
816 
817 
818 /**
819  * @brief Destroys the mission OSD.
820  *
821  * @luafunc osdDestroy()
822  */
misn_osdDestroy(lua_State * L)823 static int misn_osdDestroy( lua_State *L )
824 {
825    Mission *cur_mission;
826    cur_mission = misn_getFromLua(L);
827 
828    if (cur_mission->osd != 0) {
829       osd_destroy( cur_mission->osd );
830       cur_mission->osd = 0;
831    }
832 
833    return 0;
834 }
835 
836 
837 /**
838  * @brief Sets active in mission OSD.
839  *
840  * @note Uses Lua indexes, so 1 is first member, 2 is second and so on.
841  *
842  *    @luatparam number n Element of the OSD to make active.
843  * @luafunc osdActive( n )
844  */
misn_osdActive(lua_State * L)845 static int misn_osdActive( lua_State *L )
846 {
847    int n;
848    Mission *cur_mission;
849 
850    n = luaL_checkint(L,1);
851    n = n-1; /* Convert to C index. */
852 
853    cur_mission = misn_getFromLua(L);
854 
855    if (cur_mission->osd != 0)
856       osd_active( cur_mission->osd, n );
857 
858    return 0;
859 }
860 
861 
862 /**
863  * @brief Adds an NPC.
864  *
865  * @note Do not use this at all in the "create" function. Use setNPC, setDesc and the "accept" function instead.
866  *
867  * @usage npc_id = misn.npcAdd( "my_func", "Mr. Test", "none", "A test." ) -- Creates an NPC.
868  *
869  *    @luatparam string func Name of the function to run when approaching, gets passed the npc_id when called.
870  *    @luatparam string name Name of the NPC
871  *    @luatparam string portrait Portrait to use for the NPC (from GFX_PATH/portraits*.png).
872  *    @luatparam string desc Description associated to the NPC.
873  *    @luatparam[opt=5] number priority Optional priority argument (highest is 0, lowest is 10).
874  *    @luatreturn number The ID of the NPC to pass to npcRm.
875  * @luafunc npcAdd( func, name, portrait, desc, priority )
876  */
misn_npcAdd(lua_State * L)877 static int misn_npcAdd( lua_State *L )
878 {
879    unsigned int id;
880    int priority;
881    const char *func, *name, *gfx, *desc;
882    char portrait[PATH_MAX];
883    Mission *cur_mission;
884 
885    /* Handle parameters. */
886    func = luaL_checkstring(L, 1);
887    name = luaL_checkstring(L, 2);
888    gfx  = luaL_checkstring(L, 3);
889    desc = luaL_checkstring(L, 4);
890 
891    /* Optional priority. */
892    if (lua_gettop(L) > 4)
893       priority = luaL_checkint( L, 5 );
894    else
895       priority = 5;
896 
897    /* Set path. */
898    nsnprintf( portrait, PATH_MAX, GFX_PATH"portraits/%s.png", gfx );
899 
900    cur_mission = misn_getFromLua(L);
901 
902    /* Add npc. */
903    id = npc_add_mission( cur_mission, func, name, priority, portrait, desc );
904 
905    /* Return ID. */
906    if (id > 0) {
907       lua_pushnumber( L, id );
908       return 1;
909    }
910    return 0;
911 }
912 
913 
914 /**
915  * @brief Removes an NPC.
916  *
917  * @usage misn.npcRm( npc_id )
918  *
919  *    @luatparam number id ID of the NPC to remove.
920  * @luafunc npcRm( id )
921  */
misn_npcRm(lua_State * L)922 static int misn_npcRm( lua_State *L )
923 {
924    unsigned int id;
925    int ret;
926    Mission *cur_mission;
927 
928    id = luaL_checklong(L, 1);
929    cur_mission = misn_getFromLua(L);
930    ret = npc_rm_mission( id, cur_mission );
931 
932    if (ret != 0)
933       NLUA_ERROR(L, "Invalid NPC ID!");
934    return 0;
935 }
936 
937 
938 /**
939  * @brief Tries to claim systems or strings.
940  *
941  * Claiming systems and strings is a way to avoid mission collisions preemptively.
942  *
943  * Note it does not actually perform the claim if it fails to claim. It also
944  *  does not work more than once.
945  *
946  * @usage if not misn.claim( { system.get("Gamma Polaris") } ) then misn.finish( false ) end
947  * @usage if not misn.claim( system.get("Gamma Polaris") ) then misn.finish( false ) end
948  * @usage if not misn.claim( 'some_string' ) then misn.finish( false ) end
949  * @usage if not misn.claim( { system.get("Gamma Polaris"), 'some_string' } ) then misn.finish( false ) end
950  *
951  *    @luatparam System|String|{System,String...} params Table of systems/strings to claim or a single system/string.
952  *    @luatreturn boolean true if was able to claim, false otherwise.
953  * @luafunc claim( params )
954  */
misn_claim(lua_State * L)955 static int misn_claim( lua_State *L )
956 {
957    Claim_t *claim;
958    Mission *cur_mission;
959 
960    /* Get mission. */
961    cur_mission = misn_getFromLua(L);
962 
963    /* Check to see if already claimed. */
964    if (cur_mission->claims != NULL) {
965       NLUA_ERROR(L, "Mission trying to claim but already has.");
966       return 0;
967    }
968 
969    /* Create the claim. */
970    claim = claim_create();
971 
972    if (lua_istable(L,1)) {
973       /* Iterate over table. */
974       lua_pushnil(L);
975       while (lua_next(L, 1) != 0) {
976          if (lua_issystem(L,-1))
977             claim_addSys( claim, lua_tosystem( L, -1 ) );
978          else if (lua_isstring(L,-1))
979             claim_addStr( claim, lua_tostring( L, -1 ) );
980          lua_pop(L,1);
981       }
982    }
983    else if (lua_issystem(L, 1))
984       claim_addSys( claim, lua_tosystem( L, 1 ) );
985    else if (lua_isstring(L, 1))
986       claim_addStr( claim, lua_tostring( L, 1 ) );
987    else
988       NLUA_INVALID_PARAMETER(L);
989 
990    /* Test claim. */
991    if (claim_test( claim )) {
992       claim_destroy( claim );
993       lua_pushboolean(L,0);
994       return 1;
995    }
996 
997    /* Set the claim. */
998    cur_mission->claims = claim;
999    claim_activate( claim );
1000    lua_pushboolean(L,1);
1001    return 1;
1002 }
1003 
1004 
1005 
1006