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