1 /*
2  * See Licensing and Copyright notice in naev.h
3  */
4 
5 /**
6  * @file land.c
7  *
8  * @brief Handles all the landing menus and actions.
9  */
10 
11 
12 #include "land.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 "land_outfits.h"
22 #include "land_shipyard.h"
23 #include "land_trade.h"
24 
25 #include "log.h"
26 #include "toolkit.h"
27 #include "dialogue.h"
28 #include "player.h"
29 #include "rng.h"
30 #include "music.h"
31 #include "economy.h"
32 #include "hook.h"
33 #include "mission.h"
34 #include "ntime.h"
35 #include "save.h"
36 #include "map.h"
37 #include "news.h"
38 #include "escort.h"
39 #include "event.h"
40 #include "conf.h"
41 #include "gui.h"
42 #include "equipment.h"
43 #include "npc.h"
44 #include "camera.h"
45 #include "menu.h"
46 #include "ndata.h"
47 #include "nlua.h"
48 #include "nluadef.h"
49 #include "nlua_tk.h"
50 
51 
52 /* global/main window */
53 #define LAND_WIDTH   800 /**< Land window width. */
54 #define LAND_HEIGHT  600 /**< Land window height. */
55 #define PORTRAIT_WIDTH 200
56 #define PORTRAIT_HEIGHT 150
57 
58 
59 /*
60  * we use visited flags to not duplicate missions generated
61  */
62 #define VISITED_LAND          (1<<0) /**< Player already landed. */
63 #define VISITED_COMMODITY     (1<<1) /**< Player already visited commodities. */
64 #define VISITED_BAR           (1<<2) /**< Player already visited bar. */
65 #define VISITED_OUTFITS       (1<<3) /**< Player already visited outfits. */
66 #define VISITED_SHIPYARD      (1<<4) /**< Player already visited shipyard. */
67 #define VISITED_EQUIPMENT     (1<<5) /**< Player already visited equipment. */
68 #define VISITED_MISSION       (1<<6) /**< Player already visited mission computer. */
69 #define visited(f)            (land_visited |= (f)) /**< Mark place is visited. */
70 #define has_visited(f)        (land_visited & (f)) /**< Check if player has visited. */
71 static unsigned int land_visited = 0; /**< Contains what the player visited. */
72 
73 /* Which tabs have been generated by their respective open functions. */
74 unsigned int land_generated = 0;
75 
76 /*
77  * land variables
78  */
79 int landed = 0; /**< Is player landed. */
80 int land_loaded = 0; /**< Finished loading? */
81 unsigned int land_wid = 0; /**< Land window ID, also used in gui.c */
82 static int land_regen = 0; /**< Whether or not regenning. */
83 static const char *land_windowNames[LAND_NUMWINDOWS] = {
84    "Landing Main",
85    "Spaceport Bar",
86    "Missions",
87    "Outfits",
88    "Shipyard",
89    "Equipment",
90    "Commodity"
91 };
92 static int land_windowsMap[LAND_NUMWINDOWS]; /**< Mapping of windows. */
93 static unsigned int *land_windows = NULL; /**< Landed window ids. */
94 Planet* land_planet = NULL; /**< Planet player landed at. */
95 static glTexture *gfx_exterior = NULL; /**< Exterior graphic of the landed planet. */
96 
97 /*
98  * mission computer stack
99  */
100 static Mission* mission_computer = NULL; /**< Missions at the computer. */
101 static int mission_ncomputer = 0; /**< Number of missions at the computer. */
102 
103 /*
104  * Bar stuff.
105  */
106 static glTexture *mission_portrait = NULL; /**< Mission portrait. */
107 
108 /*
109  * player stuff
110  */
111 static int last_window = 0; /**< Default window. */
112 
113 
114 /*
115  * Error handling.
116  */
117 static char errorlist[512];
118 static char errorreason[512];
119 static int errorappend;
120 static char *errorlist_ptr;
121 
122 
123 /*
124  * Rescue.
125  */
126 static nlua_env rescue_env = LUA_NOREF; /**< Rescue Lua env. */
127 static void land_stranded (void);
128 
129 
130 /*
131  * prototypes
132  */
133 static void land_createMainTab( unsigned int wid );
134 static void land_cleanupWindow( unsigned int wid, char *name );
135 static void land_changeTab( unsigned int wid, char *wgt, int old, int tab );
136 /* spaceport bar */
137 static void bar_getDim( int wid,
138       int *w, int *h, int *iw, int *ih, int *bw, int *bh );
139 static void bar_open( unsigned int wid );
140 static int bar_genList( unsigned int wid );
141 static void bar_update( unsigned int wid, char* str );
142 static void bar_close( unsigned int wid, char* str );
143 static void bar_approach( unsigned int wid, char* str );
144 static int news_load (void);
145 /* mission computer */
146 static void misn_open( unsigned int wid );
147 static void misn_close( unsigned int wid, char *name );
148 static void misn_accept( unsigned int wid, char* str );
149 static void misn_genList( unsigned int wid, int first );
150 static void misn_update( unsigned int wid, char* str );
151 
152 
153 /**
154  * @brief Queue a takeoff.
155  */
land_queueTakeoff(void)156 void land_queueTakeoff (void)
157 {
158    land_takeoff = 1;
159 }
160 
161 
162 /**
163  * @brief Check to see if finished loading.
164  */
land_doneLoading(void)165 int land_doneLoading (void)
166 {
167    if (landed && land_loaded)
168       return 1;
169    return 0;
170 }
171 
172 
173 /**
174  * @brief Makes sure it's sane to change ships in the equipment view.
175  *    @param shipname Ship being changed to.
176  */
can_swapEquipment(char * shipname)177 int can_swapEquipment( char* shipname )
178 {
179    int failure = 0;
180    char *loc = player_getLoc(shipname);
181    Pilot *newship;
182    newship = player_getShip(shipname);
183 
184    if (strcmp(shipname,player.p->name)==0) { /* Already onboard. */
185       land_errDialogueBuild( "You're already onboard the %s.", shipname );
186       failure = 1;
187    }
188    if (strcmp(loc,land_planet->name)) { /* Ship isn't here. */
189       dialogue_alert( "You must transport the ship to %s to be able to get in.",
190             land_planet->name );
191       failure = 1;
192    }
193    if (pilot_cargoUsed(player.p) > (pilot_cargoFree(newship) + pilot_cargoUsed(newship))) { /* Current ship has too much cargo. */
194       land_errDialogueBuild( "You have %d tons more cargo than the new ship can hold.",
195             pilot_cargoUsed(player.p) - pilot_cargoFree(newship), shipname );
196       failure = 1;
197    }
198    if (pilot_hasDeployed(player.p)) { /* Escorts are in space. */
199       land_errDialogueBuild( "You can't strand your fighters in space.");
200       failure = 1;
201    }
202    return !failure;
203 }
204 
205 
206 /**
207  * @brief Generates error dialogues used by several landing tabs.
208  *    @param name Name of the ship, outfit or commodity being acted upon.
209  *    @param type Type of action.
210  */
land_errDialogue(char * name,char * type)211 int land_errDialogue( char* name, char* type )
212 {
213    errorlist_ptr = NULL;
214    if (strcmp(type,"tradeShip")==0)
215       shipyard_canTrade( name );
216    else if (strcmp(type,"buyShip")==0)
217       shipyard_canBuy( name, land_planet );
218    else if (strcmp(type,"swapEquipment")==0)
219       can_swapEquipment( name );
220    else if (strcmp(type,"swap")==0)
221       can_swap( name );
222    else if (strcmp(type,"sellShip")==0)
223       can_sell( name );
224    else if (strcmp(type,"buyOutfit")==0)
225       outfit_canBuy( name, land_planet );
226    else if (strcmp(type,"sellOutfit")==0)
227       outfit_canSell( name );
228    else if (strcmp(type,"buyCommodity")==0)
229       commodity_canBuy( name );
230    else if (strcmp(type,"sellCommodity")==0)
231       commodity_canSell( name );
232    if (errorlist_ptr != NULL) {
233       dialogue_alert( "%s", errorlist );
234       return 1;
235    }
236    return 0;
237 }
238 
239 /**
240  * @brief Generates error dialogues used by several landing tabs.
241  *    @param fmt String with printf-like formatting
242  */
land_errDialogueBuild(const char * fmt,...)243 void land_errDialogueBuild( const char *fmt, ... )
244 {
245    va_list ap;
246 
247    if (fmt == NULL)
248       return;
249    else { /* get the message */
250       va_start(ap, fmt);
251       vsnprintf(errorreason, 512, fmt, ap);
252       va_end(ap);
253    }
254 
255    if (errorlist_ptr == NULL) /* Initialize on first run. */
256       errorappend = nsnprintf( errorlist, sizeof(errorlist), "%s", errorreason );
257    else /* Append newest error to the existing list. */
258       nsnprintf( &errorlist[errorappend],  sizeof(errorlist)-errorappend, "\n%s", errorreason );
259    errorlist_ptr = errorlist;
260 }
261 
262 
263 /**
264  * @brief Gets the dimensions of the spaceport bar window.
265  */
bar_getDim(int wid,int * w,int * h,int * iw,int * ih,int * bw,int * bh)266 static void bar_getDim( int wid,
267       int *w, int *h, int *iw, int *ih, int *bw, int *bh )
268 {
269    /* Get window dimensions. */
270    window_dimWindow( wid, w, h );
271 
272    /* Calculate dimensions of portraits. */
273    *iw = 300 + (*w - 800);
274    *ih = *h - 60;
275 
276    /* Calculate button dimensions. */
277    *bw = (*w - *iw - 80)/2;
278    *bh = LAND_BUTTON_HEIGHT;
279 }
280 /**
281  * @brief Opens the spaceport bar window.
282  */
bar_open(unsigned int wid)283 static void bar_open( unsigned int wid )
284 {
285    int w, h, iw, ih, bw, bh, dh, th;
286 
287    /* Mark as generated. */
288    land_tabGenerate(LAND_WINDOW_BAR);
289 
290    /* Set window functions. */
291    window_onClose( wid, bar_close );
292 
293    /* Get dimensions. */
294    bar_getDim( wid, &w, &h, &iw, &ih, &bw, &bh );
295    dh = gl_printHeightRaw( &gl_smallFont, w - iw - 60, land_planet->bar_description );
296 
297    /* Approach when pressing enter */
298    window_setAccept( wid, bar_approach );
299 
300    /* Buttons */
301    window_addButtonKey( wid, -20, 20,
302          bw, bh, "btnCloseBar",
303          "Take Off", land_buttonTakeoff, SDLK_t );
304    window_addButtonKey( wid, -20 - bw - 20, 20,
305          bw, bh, "btnApproach",
306          "Approach", bar_approach, SDLK_a );
307 
308    /* Bar description. */
309    window_addText( wid, iw + 40, -40,
310          w - iw - 60, dh, 0,
311          "txtDescription", &gl_smallFont, &cBlack,
312          land_planet->bar_description );
313 
314    /* Add portrait text. */
315    th = -40 - dh - 40;
316    window_addText( wid, iw + 40, th,
317          w - iw - 60, gl_defFont.h, 1,
318          "txtPortrait", &gl_defFont, &cDConsole, NULL );
319 
320    /* Add mission description text. */
321    th -= 20 + PORTRAIT_HEIGHT + 20 + 20;
322    window_addText( wid, iw + 60, th,
323          w - iw - 100, h + th - (2*bh+60), 0,
324          "txtMission", &gl_smallFont, &cBlack, NULL );
325 
326    /* Generate the mission list. */
327    bar_genList( wid );
328    /* Set default keyboard focuse to the list */
329    window_setFocus( wid , "iarMissions" );
330 }
331 
332 /**
333  * @brief Generates the mission list for the bar.
334  *
335  *    @param wid Window to create mission list for.
336  */
bar_genList(unsigned int wid)337 static int bar_genList( unsigned int wid )
338 {
339    glTexture **portraits;
340    char **names, *focused;
341    int w, h, iw, ih, bw, bh;
342    int n, pos;
343 
344    /* Sanity check. */
345    if (wid == 0)
346       return 0;
347 
348    /* Get dimensions. */
349    bar_getDim( wid, &w, &h, &iw, &ih, &bw, &bh );
350 
351    /* Save focus. */
352    focused = strdup(window_getFocus(wid));
353 
354    /* Destroy widget if already exists. */
355    if (widget_exists( wid, "iarMissions" )) {
356       /* Store position. */
357       pos = toolkit_getImageArrayPos( wid, "iarMissions" );
358 
359       window_destroyWidget( wid, "iarMissions" );
360    }
361    else
362       pos = -1;
363 
364    /* We sort just in case. */
365    npc_sort();
366 
367    /* Set up missions. */
368    if (mission_portrait == NULL)
369       mission_portrait = gl_newImage( PORTRAIT_GFX_PATH"news.png", 0 );
370    n = npc_getArraySize();
371    if (n <= 0) {
372       n            = 1;
373       portraits    = malloc(sizeof(glTexture*));
374       portraits[0] = mission_portrait;
375       names        = malloc(sizeof(char*));
376       names[0]     = strdup("News");
377    }
378    else {
379       n            = n+1;
380       portraits    = malloc( sizeof(glTexture*) * n );
381       portraits[0] = mission_portrait;
382       npc_getTextureArray( &portraits[1], n-1 );
383       names        = malloc( sizeof(char*) * n );
384       names[0]     = strdup("News");
385       npc_getNameArray( &names[1], n-1 );
386    }
387    window_addImageArray( wid, 20, -40,
388          iw, ih, "iarMissions", 100, 75,
389          portraits, names, n, bar_update, bar_approach );
390 
391    /* Restore position. */
392    toolkit_setImageArrayPos( wid, "iarMissions", pos );
393 
394    /* write the outfits stuff */
395    bar_update( wid, NULL );
396 
397    /* Restore focus. */
398    window_setFocus( wid, focused );
399    free(focused);
400 
401    return 0;
402 }
403 /**
404  * @brief Regenerates the bar list.
405  */
bar_regen(void)406 void bar_regen (void)
407 {
408    if (!landed)
409       return;
410    bar_genList( land_getWid(LAND_WINDOW_BAR) );
411 }
412 /**
413  * @brief Updates the missions in the spaceport bar.
414  *    @param wid Window to update the outfits in.
415  *    @param str Unused.
416  */
bar_update(unsigned int wid,char * str)417 static void bar_update( unsigned int wid, char* str )
418 {
419    (void) str;
420    int pos;
421    int w, h, iw, ih, bw, bh, dh;
422 
423    /* Get dimensions. */
424    bar_getDim( wid, &w, &h, &iw, &ih, &bw, &bh );
425    dh = gl_printHeightRaw( &gl_smallFont, w - iw - 60, land_planet->bar_description );
426 
427    /* Get array. */
428    pos = toolkit_getImageArrayPos( wid, "iarMissions" );
429 
430    /* See if is news. */
431    if (pos==0) { /* News selected. */
432       /* Destroy news widget if needed. */
433       if (widget_exists(wid, "cstNews"))
434          window_destroyWidget( wid, "cstNews" );
435 
436       /* Destroy portrait. */
437       if (widget_exists(wid, "imgPortrait"))
438          window_destroyWidget(wid, "imgPortrait");
439 
440       /* Disable button. */
441       window_disableButton( wid, "btnApproach" );
442 
443       /* Clear text. */
444       window_modifyText(  wid, "txtPortrait", NULL );
445       window_modifyText(  wid, "txtMission",  NULL );
446 
447       /* Create news. */
448       news_widget( wid, iw + 60, -40 - (40 + dh),
449             w - iw - 100, h - 40 - (dh+20) - 40 - bh - 20 );
450       return;
451    }
452 
453    /* Shift to ignore news now. */
454    pos--;
455 
456    /* Destroy news widget if needed. */
457    if (widget_exists(wid, "cstNews"))
458       window_destroyWidget( wid, "cstNews" );
459 
460    /* Create widgets if needed. */
461    if (!widget_exists(wid, "imgPortrait"))
462       window_addImage( wid, iw + 40 + (w-iw-60-PORTRAIT_WIDTH)/2,
463             -(40 + dh + 40 + gl_defFont.h + 20 + PORTRAIT_HEIGHT),
464             0, 0, "imgPortrait", NULL, 1 );
465 
466    /* Enable button. */
467    window_enableButton( wid, "btnApproach" );
468 
469    /* Set portrait. */
470    window_modifyText(  wid, "txtPortrait", npc_getName( pos ) );
471    window_modifyImage( wid, "imgPortrait", npc_getTexture( pos ), 0, 0 );
472 
473    /* Set mission description. */
474    window_modifyText(  wid, "txtMission", npc_getDesc( pos ));
475 }
476 /**
477  * @brief Closes the mission computer window.
478  *    @param wid Window to close.
479  *    @param name Unused.
480  */
bar_close(unsigned int wid,char * name)481 static void bar_close( unsigned int wid, char *name )
482 {
483    (void) wid;
484    (void) name;
485 
486    /* Must not be regenerating. */
487    if (land_regen) {
488       land_regen--;
489       return;
490    }
491 
492    if (mission_portrait != NULL)
493       gl_freeTexture(mission_portrait);
494    mission_portrait = NULL;
495 }
496 /**
497  * @brief Approaches guy in mission computer.
498  */
bar_approach(unsigned int wid,char * str)499 static void bar_approach( unsigned int wid, char *str )
500 {
501    (void) str;
502    int pos, n;
503 
504    /* Get position. */
505    pos = toolkit_getImageArrayPos( wid, "iarMissions" );
506 
507    /* Should never happen, but in case news is selected */
508    if (pos == 0)
509       return;
510 
511    /* Ignore news. */
512    pos--;
513 
514    n = npc_getArraySize();
515    npc_approach( pos );
516    bar_genList( wid ); /* Always just in case. */
517 
518    /* Focus the news if the number of NPCs has changed. */
519    if (n != npc_getArraySize())
520       toolkit_setImageArrayPos( wid, "iarMissions", 0 );
521 
522    /* Reset markers. */
523    mission_sysMark();
524 
525    /* Mission forced take off. */
526    if (land_takeoff)
527       takeoff(0);
528 }
529 /**
530  * @brief Loads the news.
531  *
532  * @return 0 on success.
533  */
news_load(void)534 static int news_load (void)
535 {
536    generate_news(faction_name(land_planet->faction));
537    return 0;
538 }
539 
540 
541 
542 /**
543  * @brief Opens the mission computer window.
544  */
misn_open(unsigned int wid)545 static void misn_open( unsigned int wid )
546 {
547    int w, h;
548    int y;
549 
550    /* Mark as generated. */
551    land_tabGenerate(LAND_WINDOW_MISSION);
552 
553    /* Get window dimensions. */
554    window_dimWindow( wid, &w, &h );
555 
556    /* Set window functions. */
557    window_onClose( wid, misn_close );
558 
559    /* buttons */
560    window_addButtonKey( wid, -20, 20,
561          LAND_BUTTON_WIDTH,LAND_BUTTON_HEIGHT, "btnCloseMission",
562          "Take Off", land_buttonTakeoff, SDLK_t );
563    window_addButtonKey( wid, -20, 40+LAND_BUTTON_HEIGHT,
564          LAND_BUTTON_WIDTH,LAND_BUTTON_HEIGHT, "btnAcceptMission",
565          "Accept Mission", misn_accept, SDLK_a );
566 
567    /* text */
568    y = -60;
569    window_addText( wid, w/2 + 10, y,
570          w/2 - 30, 40, 0,
571          "txtSDate", NULL, &cDConsole,
572          "Date:\n"
573          "Free Space:");
574    window_addText( wid, w/2 + 110, y,
575          w/2 - 90, 40, 0,
576          "txtDate", NULL, &cBlack, NULL );
577    y -= 2 * gl_defFont.h + 50;
578    window_addText( wid, w/2 + 10, y,
579          w/2 - 30, 20, 0,
580          "txtSReward", &gl_smallFont, &cDConsole, "Reward:" );
581    window_addText( wid, w/2 + 70, y,
582          w/2 - 90, 20, 0,
583          "txtReward", &gl_smallFont, &cBlack, NULL );
584    y -= 20;
585    window_addText( wid, w/2 + 10, y,
586          w/2 - 30, h/2-90, 0,
587          "txtDesc", &gl_smallFont, &cBlack, NULL );
588 
589    /* map */
590    map_show( wid, 20, 20,
591          w/2 - 30, h/2 - 35, 0.75 );
592 
593    misn_genList(wid, 1);
594    /* Set default keyboard focuse to the list */
595    window_setFocus( wid , "lstMission" );
596 }
597 /**
598  * @brief Closes the mission computer window.
599  *    @param wid Window to close.
600  *    @param name Unused.
601  */
misn_close(unsigned int wid,char * name)602 static void misn_close( unsigned int wid, char *name )
603 {
604    (void) wid;
605    (void) name;
606 
607    /* Remove computer markers just in case. */
608    space_clearComputerMarkers();
609 }
610 /**
611  * @brief Accepts the selected mission.
612  *    @param wid Window of the mission computer.
613  *    @param str Unused.
614  */
misn_accept(unsigned int wid,char * str)615 static void misn_accept( unsigned int wid, char* str )
616 {
617    (void) str;
618    char* misn_name;
619    Mission* misn;
620    int pos;
621    int i, ret;
622 
623    misn_name = toolkit_getList( wid, "lstMission" );
624 
625    /* Make sure you have missions. */
626    if (strcmp(misn_name,"No Missions")==0)
627       return;
628 
629    /* Make sure player can accept the mission. */
630    for (i=0; i<MISSION_MAX; i++)
631       if (player_missions[i]->data == NULL) break;
632    if (i >= MISSION_MAX) {
633       dialogue_alert("You have too many active missions.");
634       return;
635    }
636 
637    if (dialogue_YesNo("Accept Mission",
638          "Are you sure you want to accept this mission?")) {
639       pos = toolkit_getListPos( wid, "lstMission" );
640       misn = &mission_computer[pos];
641       ret = mission_accept( misn );
642       if ((ret==0) || (ret==2) || (ret==-1)) { /* success in accepting the mission */
643          if (ret==-1)
644             mission_cleanup( &mission_computer[pos] );
645          memmove( &mission_computer[pos], &mission_computer[pos+1],
646                sizeof(Mission) * (mission_ncomputer-pos-1) );
647          mission_ncomputer--;
648 
649          /* Regenerate list. */
650          misn_genList(wid, 0);
651          /* Add position persistancey after a mission has been accepted */
652          /* NOTE: toolkit_setListPos protects us from a bad position by clamping */
653          toolkit_setListPos( wid, "lstMission", pos-1 ); /*looks better without the -1, makes more sense with*/
654       }
655 
656       /* Reset markers. */
657       mission_sysMark();
658    }
659 }
660 /**
661  * @brief Generates the mission list.
662  *    @param wid Window to generate the mission list for.
663  *    @param first Is it the first time generated?
664  */
misn_genList(unsigned int wid,int first)665 static void misn_genList( unsigned int wid, int first )
666 {
667    int i,j;
668    char** misn_names, *focused;
669    int w,h;
670 
671    /* Save focus. */
672    focused = strdup(window_getFocus(wid));
673 
674    if (!first)
675       window_destroyWidget( wid, "lstMission" );
676 
677    /* Get window dimensions. */
678    window_dimWindow( wid, &w, &h );
679 
680    /* list */
681    j = 1; /* make sure we don't accidentally free the memory twice. */
682    misn_names = NULL;
683    if (mission_ncomputer > 0) { /* there are missions */
684       misn_names = malloc(sizeof(char*) * mission_ncomputer);
685       j = 0;
686       for (i=0; i<mission_ncomputer; i++)
687          if (mission_computer[i].title != NULL)
688             misn_names[j++] = strdup(mission_computer[i].title);
689    }
690    if ((misn_names==NULL) || (mission_ncomputer==0) || (j==0)) { /* no missions. */
691       if (j==0)
692          free(misn_names);
693       misn_names = malloc(sizeof(char*));
694       misn_names[0] = strdup("No Missions");
695       j = 1;
696    }
697    window_addList( wid, 20, -40,
698          w/2 - 30, h/2 - 35,
699          "lstMission", misn_names, j, 0, misn_update );
700 
701    /* Restore focus. */
702    window_setFocus( wid, focused );
703    free(focused);
704    /* duplicateed the save focus functionaility from the bar */
705 }
706 /**
707  * @brief Updates the mission list.
708  *    @param wid Window of the mission computer.
709  *    @param str Unused.
710  */
misn_update(unsigned int wid,char * str)711 static void misn_update( unsigned int wid, char* str )
712 {
713    (void) str;
714    char *active_misn;
715    Mission* misn;
716    char txt[256], *buf;
717 
718    /* Clear computer markers. */
719    space_clearComputerMarkers();
720 
721    /* Update date stuff. */
722    buf = ntime_pretty( 0, 2 );
723    nsnprintf( txt, sizeof(txt), "%s\n%d Tons", buf, player.p->cargo_free );
724    free(buf);
725    window_modifyText( wid, "txtDate", txt );
726 
727    active_misn = toolkit_getList( wid, "lstMission" );
728    if (strcmp(active_misn,"No Missions")==0) {
729       window_modifyText( wid, "txtReward", "None" );
730       window_modifyText( wid, "txtDesc",
731             "There are no missions available here." );
732       window_disableButton( wid, "btnAcceptMission" );
733       return;
734    }
735 
736    misn = &mission_computer[ toolkit_getListPos( wid, "lstMission" ) ];
737    mission_sysComputerMark( misn );
738    if (misn->markers != NULL)
739       map_center( system_getIndex( misn->markers[0].sys )->name );
740    window_modifyText( wid, "txtReward", misn->reward );
741    window_modifyText( wid, "txtDesc", misn->desc );
742    window_enableButton( wid, "btnAcceptMission" );
743 }
744 
745 
746 /**
747  * @brief Refuels the player's current ship, if possible.
748  */
land_refuel(void)749 void land_refuel (void)
750 {
751    unsigned int w;
752 
753    /* Full fuel. */
754    if (player.p->fuel >= player.p->fuel_max)
755       return;
756 
757    /* No refuel service. */
758    if (!planet_hasService(land_planet, PLANET_SERVICE_REFUEL))
759       return;
760 
761    player.p->fuel = player.p->fuel_max;
762 
763    w = land_getWid( LAND_WINDOW_EQUIPMENT );
764    if (w > 0)
765       equipment_updateShips( w, NULL ); /* Must update counter. */
766 }
767 
768 
769 /**
770  * @brief Buys a local system map.
771  */
spaceport_buyMap(unsigned int wid,char * str)772 static void spaceport_buyMap( unsigned int wid, char *str )
773 {
774    (void) wid;
775    (void) str;
776    Outfit *o;
777    unsigned int w;
778 
779    /* Make sure the map isn't already known, etc. */
780    if (land_errDialogue( LOCAL_MAP_NAME, "buyOutfit" ))
781       return;
782 
783    o = outfit_get( LOCAL_MAP_NAME );
784    if (o == NULL) {
785       WARN("Outfit '%s' does not exist!", LOCAL_MAP_NAME);
786       return;
787    }
788 
789    player_modCredits( -o->price );
790    player_addOutfit(o, 1);
791 
792    /* Disable the button. */
793    window_disableButtonSoft( land_windows[0], "btnMap" );
794 
795    /* Update map quantity in outfitter. */
796    w = land_getWid( LAND_WINDOW_OUTFITS );
797    if (w > 0)
798       outfits_regenList( w, NULL );
799 }
800 
801 
802 /**
803  * @brief Adds the "Buy Local Map" button if needed.
804  */
land_checkAddMap(void)805 void land_checkAddMap (void)
806 {
807    char buf[ECON_CRED_STRLEN], cred[ECON_CRED_STRLEN];
808    Outfit *o;
809 
810    /* Maps are only offered if the planet provides fuel. */
811    if (!planet_hasService(land_planet, PLANET_SERVICE_REFUEL))
812       return;
813 
814    o = outfit_get( LOCAL_MAP_NAME );
815    if (o == NULL) {
816       WARN("Outfit '%s' does not exist!", LOCAL_MAP_NAME);
817       return;
818    }
819 
820    /* Just enable button if it exists. */
821    if (widget_exists( land_windows[0], "btnMap" ))
822       window_enableButton( land_windows[0], "btnMap");
823    /* Else create it. */
824    else {
825       /* Refuel button. */
826       credits2str( cred, o->price, 2 );
827       nsnprintf( buf, sizeof(buf), "Buy Local Map (%s)", cred );
828       window_addButtonKey( land_windows[0], -20, 20 + (LAND_BUTTON_HEIGHT + 20),
829             LAND_BUTTON_WIDTH,LAND_BUTTON_HEIGHT, "btnMap",
830             buf, spaceport_buyMap, SDLK_b );
831    }
832 
833    /* Make sure player can click it. */
834    if (!outfit_canBuy(LOCAL_MAP_NAME, land_planet))
835       window_disableButtonSoft( land_windows[0], "btnMap" );
836 }
837 
838 
839 /**
840  * @brief Wrapper for takeoff mission button.
841  *
842  *    @param wid Window causing takeoff.
843  *    @param unused Unused.
844  */
land_buttonTakeoff(unsigned int wid,char * unused)845 void land_buttonTakeoff( unsigned int wid, char *unused )
846 {
847    (void) wid;
848    (void) unused;
849    /* We'll want the time delay. */
850    takeoff(1);
851 }
852 
853 
854 /**
855  * @brief Cleans up the land window.
856  *
857  *    @param wid Window closing.
858  *    @param name Unused.
859  */
land_cleanupWindow(unsigned int wid,char * name)860 static void land_cleanupWindow( unsigned int wid, char *name )
861 {
862    (void) wid;
863    (void) name;
864 
865    /* Must not be regenerating. */
866    if (land_regen) {
867       land_regen--;
868       return;
869    }
870 
871    /* Clean up possible stray graphic. */
872    if (gfx_exterior != NULL) {
873       gl_freeTexture( gfx_exterior );
874       gfx_exterior = NULL;
875    }
876 }
877 
878 
879 /**
880  * @brief Gets the WID of a window by type.
881  *
882  *    @param window Type of window to get wid (LAND_WINDOW_MAIN, ...).
883  *    @return 0 on error, otherwise the wid of the window.
884  */
land_getWid(int window)885 unsigned int land_getWid( int window )
886 {
887    if (land_windowsMap[window] == -1)
888       return 0;
889    return land_windows[ land_windowsMap[window] ];
890 }
891 
892 
893 /**
894  * @brief Recreates the land windows.
895  *
896  *    @param load Is loading game?
897  *    @param changetab Should it change to the last open tab?
898  */
land_genWindows(int load,int changetab)899 void land_genWindows( int load, int changetab )
900 {
901    int i, j;
902    const char *names[LAND_NUMWINDOWS];
903    int w, h;
904    Planet *p;
905    int regen;
906 
907    /* Destroy old window if exists. */
908    if (land_wid > 0) {
909       land_regen = 2; /* Mark we're regenning. */
910       window_destroy(land_wid);
911 
912       /* Mark tabs as not generated. */
913       land_generated = 0;
914    }
915    land_loaded = 0;
916 
917    /* Get planet. */
918    p     = land_planet;
919    regen = landed;
920 
921    /* Create window. */
922    if ((gl_screen.rw < 1024) || (gl_screen.rh < 768)) {
923       w = -1; /* Fullscreen. */
924       h = -1;
925    }
926    else {
927       w = 800 + 0.5 * (SCREEN_W - 800);
928       h = 600 + 0.5 * (SCREEN_H - 600);
929    }
930    land_wid = window_create( p->name, -1, -1, w, h );
931    window_onClose( land_wid, land_cleanupWindow );
932 
933    /* Set window map to invalid. */
934    for (i=0; i<LAND_NUMWINDOWS; i++)
935       land_windowsMap[i] = -1;
936 
937    /* See what is available. */
938    j = 0;
939    /* Main. */
940    land_windowsMap[LAND_WINDOW_MAIN] = j;
941    names[j++] = land_windowNames[LAND_WINDOW_MAIN];
942    /* Bar. */
943    if (planet_hasService(land_planet, PLANET_SERVICE_BAR)) {
944       land_windowsMap[LAND_WINDOW_BAR] = j;
945       names[j++] = land_windowNames[LAND_WINDOW_BAR];
946    }
947    /* Missions. */
948    if (planet_hasService(land_planet, PLANET_SERVICE_MISSIONS)) {
949       land_windowsMap[LAND_WINDOW_MISSION] = j;
950       names[j++] = land_windowNames[LAND_WINDOW_MISSION];
951    }
952    /* Outfits. */
953    if (planet_hasService(land_planet, PLANET_SERVICE_OUTFITS)) {
954       land_windowsMap[LAND_WINDOW_OUTFITS] = j;
955       names[j++] = land_windowNames[LAND_WINDOW_OUTFITS];
956    }
957    /* Shipyard. */
958    if (planet_hasService(land_planet, PLANET_SERVICE_SHIPYARD)) {
959       land_windowsMap[LAND_WINDOW_SHIPYARD] = j;
960       names[j++] = land_windowNames[LAND_WINDOW_SHIPYARD];
961    }
962    /* Equipment. */
963    if (planet_hasService(land_planet, PLANET_SERVICE_OUTFITS) ||
964          planet_hasService(land_planet, PLANET_SERVICE_SHIPYARD)) {
965       land_windowsMap[LAND_WINDOW_EQUIPMENT] = j;
966       names[j++] = land_windowNames[LAND_WINDOW_EQUIPMENT];
967    }
968    /* Commodity. */
969    if (planet_hasService(land_planet, PLANET_SERVICE_COMMODITY)) {
970       land_windowsMap[LAND_WINDOW_COMMODITY] = j;
971       names[j++] = land_windowNames[LAND_WINDOW_COMMODITY];
972    }
973 
974    /* Create tabbed window. */
975    land_windows = window_addTabbedWindow( land_wid, -1, -1, -1, -1, "tabLand", j, names, 0 );
976 
977    /*
978     * Order here is very important:
979     *
980     *  1) Create main tab - must have decent background.
981     *  2) Set landed, play music and run land hooks - so hooks run well.
982     *  3) Generate missions - so that campaigns are fluid.
983     *  4) Create other tabs - lists depend on NPC and missions.
984     */
985 
986    /* 1) Create main tab. */
987    land_createMainTab( land_getWid(LAND_WINDOW_MAIN) );
988 
989    /* Add local system map button. */
990    land_checkAddMap();
991 
992    /* 2) Set as landed and run hooks. */
993    if (!regen) {
994       landed = 1;
995       music_choose("land"); /* Must be before hooks in case hooks change music. */
996       if (!load) {
997          hooks_run("land");
998       }
999       events_trigger( EVENT_TRIGGER_LAND );
1000 
1001       /* 3) Generate computer and bar missions. */
1002       if (planet_hasService(land_planet, PLANET_SERVICE_MISSIONS))
1003          mission_computer = missions_genList( &mission_ncomputer,
1004                land_planet->faction, land_planet->name, cur_system->name,
1005                MIS_AVAIL_COMPUTER );
1006       if (planet_hasService(land_planet, PLANET_SERVICE_BAR))
1007          npc_generate(); /* Generate bar npc. */
1008    }
1009 
1010    /* 4) Create other tabs. */
1011 #define should_open(s, w) \
1012    (planet_hasService(land_planet, s) && (!land_tabGenerated(w)))
1013 
1014    /* Things get a bit hairy here. Hooks may have triggered a GUI reload via
1015     * e.g. player.swapShip, so the land tabs may have been generated already
1016     * and we need to check that before regenerating them.
1017     */
1018 
1019    /* Basic - bar + missions */
1020    if (should_open( PLANET_SERVICE_BAR, LAND_WINDOW_BAR ))
1021       bar_open( land_getWid(LAND_WINDOW_BAR) );
1022    if (should_open( PLANET_SERVICE_MISSIONS, LAND_WINDOW_MISSION ))
1023       misn_open( land_getWid(LAND_WINDOW_MISSION) );
1024    /* Outfits. */
1025    if (should_open( PLANET_SERVICE_OUTFITS, LAND_WINDOW_OUTFITS ))
1026       outfits_open( land_getWid(LAND_WINDOW_OUTFITS) );
1027    /* Shipyard. */
1028    if (should_open( PLANET_SERVICE_SHIPYARD, LAND_WINDOW_SHIPYARD ))
1029       shipyard_open( land_getWid(LAND_WINDOW_SHIPYARD) );
1030    /* Equipment. */
1031    if ((planet_hasService(land_planet, PLANET_SERVICE_OUTFITS) ||
1032          planet_hasService(land_planet, PLANET_SERVICE_SHIPYARD)) &&
1033          !land_tabGenerated( LAND_WINDOW_EQUIPMENT ))
1034       equipment_open( land_getWid(LAND_WINDOW_EQUIPMENT) );
1035    /* Commodity. */
1036    if (should_open( PLANET_SERVICE_COMMODITY, LAND_WINDOW_COMMODITY ))
1037       commodity_exchange_open( land_getWid(LAND_WINDOW_COMMODITY) );
1038 #undef should_open
1039 
1040    if (!regen) {
1041       /* Reset markers if needed. */
1042       mission_sysMark();
1043 
1044       /* Check land missions. */
1045       if (!has_visited(VISITED_LAND)) {
1046          missions_run(MIS_AVAIL_LAND, land_planet->faction,
1047                land_planet->name, cur_system->name);
1048          visited(VISITED_LAND);
1049       }
1050    }
1051 
1052    /* Go to last open tab. */
1053    window_tabWinOnChange( land_wid, "tabLand", land_changeTab );
1054    if (changetab && land_windowsMap[ last_window ] != -1)
1055       window_tabWinSetActive( land_wid, "tabLand", land_windowsMap[ last_window ] );
1056 
1057    /* Refresh the map button in case the player couldn't afford it prior to
1058     * mission payment.
1059     */
1060    land_checkAddMap();
1061 
1062    /* Refuel if necessary. */
1063    land_refuel();
1064 
1065    /* Finished loading. */
1066    land_loaded = 1;
1067 }
1068 
1069 
1070 /**
1071  * @brief Sets the land window tab.
1072  *
1073  *    @param Tab to set like LAND_WINDOW_COMMODITY.
1074  *    @return 0 on success.
1075  */
land_setWindow(int window)1076 int land_setWindow( int window )
1077 {
1078    if (land_windowsMap[ window ] < 0)
1079       return -1;
1080    window_tabWinSetActive( land_wid, "tabLand", land_windowsMap[window] );
1081    return 0;
1082 }
1083 
1084 
1085 /**
1086  * @brief Opens up all the land dialogue stuff.
1087  *    @param p Planet to open stuff for.
1088  *    @param load Whether or not loading the game.
1089  */
land(Planet * p,int load)1090 void land( Planet* p, int load )
1091 {
1092    /* Do not land twice. */
1093    if (landed)
1094       return;
1095 
1096    /* Resets the player's heat. */
1097    pilot_heatReset( player.p );
1098 
1099    /* Heal the player so GUI shows player at full everything. */
1100    pilot_healLanded( player.p );
1101 
1102    /* Stop player sounds. */
1103    player_soundStop();
1104 
1105    /* Load stuff */
1106    land_planet = p;
1107    gfx_exterior = gl_newImage( p->gfx_exterior, 0 );
1108 
1109    /* Generate the news. */
1110    if (planet_hasService(land_planet, PLANET_SERVICE_BAR))
1111       news_load();
1112 
1113    /* Clear the NPC. */
1114    npc_clear();
1115 
1116    /* Create all the windows. */
1117    land_genWindows( load, 0 );
1118 
1119    /* Hack so that load can run player.takeoff(). */
1120    if (load)
1121       hooks_run( "load" );
1122 
1123    /* Mission forced take off. */
1124    if (land_takeoff)
1125       takeoff(0);
1126 }
1127 
1128 
1129 /**
1130  * @brief Creates the main tab.
1131  *
1132  *    @param wid Window to create main tab.
1133  */
land_createMainTab(unsigned int wid)1134 static void land_createMainTab( unsigned int wid )
1135 {
1136    glTexture *logo;
1137    int offset;
1138    int w,h;
1139 
1140    /* Get window dimensions. */
1141    window_dimWindow( wid, &w, &h );
1142 
1143    /*
1144     * Faction logo.
1145     */
1146    offset = 20;
1147    if (land_planet->faction != -1) {
1148       logo = faction_logoSmall(land_planet->faction);
1149       if (logo != NULL) {
1150          window_addImage( wid, 440 + (w-460-logo->w)/2, -20,
1151                0, 0, "imgFaction", logo, 0 );
1152          offset = 84;
1153       }
1154    }
1155 
1156    /*
1157     * Pretty display.
1158     */
1159    window_addImage( wid, 20, -40, 0, 0, "imgPlanet", gfx_exterior, 1 );
1160    window_addText( wid, 440, -20-offset,
1161          w-460, h-20-offset-60-LAND_BUTTON_HEIGHT*2, 0,
1162          "txtPlanetDesc", &gl_smallFont, &cBlack, land_planet->description);
1163 
1164    /*
1165     * buttons
1166     */
1167    /* first column */
1168    window_addButtonKey( wid, -20, 20,
1169          LAND_BUTTON_WIDTH, LAND_BUTTON_HEIGHT, "btnTakeoff",
1170          "Take Off", land_buttonTakeoff, SDLK_t );
1171 
1172    /* Add "no refueling" notice if needed. */
1173    if (!planet_hasService(land_planet, PLANET_SERVICE_REFUEL)) {
1174       window_addText( land_windows[0], -20, 20 + (LAND_BUTTON_HEIGHT + 20) + 20,
1175                200, gl_defFont.h, 1, "txtRefuel",
1176                &gl_defFont, &cBlack, "No refueling services." );
1177    }
1178 }
1179 
1180 
1181 /**
1182  * @brief Saves the last place the player was.
1183  *
1184  *    @param wid Unused.
1185  *    @param wgt Unused.
1186  *    @param old Previously-active tab. (Unused)
1187  *    @param tab Tab changed to.
1188  */
land_changeTab(unsigned int wid,char * wgt,int old,int tab)1189 static void land_changeTab( unsigned int wid, char *wgt, int old, int tab )
1190 {
1191    int i;
1192    (void) wid;
1193    (void) wgt;
1194    (void) old;
1195 
1196    unsigned int w;
1197    const char *torun_hook;
1198    unsigned int to_visit;
1199 
1200    /* Sane defaults. */
1201    torun_hook = NULL;
1202    to_visit   = 0;
1203 
1204    /* Find what switched. */
1205    for (i=0; i<LAND_NUMWINDOWS; i++) {
1206       if (land_windowsMap[i] == tab) {
1207          last_window = i;
1208          w = land_getWid( i );
1209 
1210          /* Must regenerate outfits. */
1211          switch (i) {
1212             case LAND_WINDOW_MAIN:
1213                land_checkAddMap();
1214                break;
1215             case LAND_WINDOW_OUTFITS:
1216                outfits_update( w, NULL );
1217                to_visit   = VISITED_OUTFITS;
1218                torun_hook = "outfits";
1219                break;
1220             case LAND_WINDOW_SHIPYARD:
1221                shipyard_update( w, NULL );
1222                to_visit   = VISITED_SHIPYARD;
1223                torun_hook = "shipyard";
1224                break;
1225             case LAND_WINDOW_BAR:
1226                bar_update( w, NULL );
1227                to_visit   = VISITED_BAR;
1228                torun_hook = "bar";
1229                break;
1230             case LAND_WINDOW_MISSION:
1231                misn_update( w, NULL );
1232                to_visit   = VISITED_MISSION;
1233                torun_hook = "mission";
1234                break;
1235             case LAND_WINDOW_COMMODITY:
1236                commodity_update( w, NULL );
1237                to_visit   = VISITED_COMMODITY;
1238                torun_hook = "commodity";
1239                break;
1240             case LAND_WINDOW_EQUIPMENT:
1241                equipment_updateShips( w, NULL );
1242                equipment_updateOutfits( w, NULL );
1243                to_visit   = VISITED_EQUIPMENT;
1244                torun_hook = "equipment";
1245                break;
1246 
1247             default:
1248                break;
1249          }
1250 
1251          /* Clear markers if closing Mission Computer. */
1252          if (i != LAND_WINDOW_MISSION)
1253             space_clearComputerMarkers();
1254 
1255          break;
1256       }
1257    }
1258 
1259    /* Check land missions - always run hooks. */
1260    /*if ((to_visit != 0) && !has_visited(to_visit)) {*/
1261    {
1262       /* Run hooks, run after music in case hook wants to change music. */
1263       if (torun_hook != NULL)
1264          if (hooks_run( torun_hook ) > 0)
1265             bar_genList( land_getWid(LAND_WINDOW_BAR) );
1266 
1267       visited(to_visit);
1268 
1269       if (land_takeoff)
1270          takeoff(1);
1271    }
1272 }
1273 
1274 
1275 /**
1276  * @brief Makes the player take off if landed.
1277  *
1278  *    @param delay Whether or not to have time pass as if the player landed normally.
1279  */
takeoff(int delay)1280 void takeoff( int delay )
1281 {
1282    int h;
1283    char *nt;
1284    double a, r;
1285 
1286    if (!landed)
1287       return;
1288 
1289    /* Player's ship is not able to fly. */
1290    if (!player_canTakeoff()) {
1291       char message[512];
1292       pilot_reportSpaceworthy( player.p, message, sizeof(message) );
1293       dialogue_msg( "Ship not fit for flight", message );
1294 
1295       /* Check whether the player needs rescuing. */
1296       land_stranded();
1297 
1298       return;
1299    }
1300 
1301    /* Clear queued takeoff. */
1302    land_takeoff = 0;
1303 
1304    /* Refuel if needed. */
1305    land_refuel();
1306 
1307    /* In case we had paused messy sounds. */
1308    sound_stopAll();
1309 
1310    /* ze music */
1311    music_choose("takeoff");
1312 
1313    /* to randomize the takeoff a bit */
1314    a = RNGF() * 2. * M_PI;
1315    r = RNGF() * land_planet->radius;
1316 
1317    /* no longer authorized to land */
1318    player_rmFlag(PLAYER_LANDACK);
1319    pilot_rmFlag(player.p,PILOT_LANDING); /* No longer landing. */
1320 
1321    /* set player to another position with random facing direction and no vel */
1322    player_warp( land_planet->pos.x + r * cos(a), land_planet->pos.y + r * sin(a) );
1323    vect_pset( &player.p->solid->vel, 0., 0. );
1324    player.p->solid->dir = RNGF() * 2. * M_PI;
1325    cam_setTargetPilot( player.p->id, 0 );
1326 
1327    /* heal the player */
1328    pilot_healLanded( player.p );
1329 
1330    /* Clear planet target. Allows for easier autonav out of the system. */
1331    player_targetPlanetSet( -1 );
1332 
1333    /* initialize the new space */
1334    h = player.p->nav_hyperspace;
1335    space_init(NULL);
1336    player.p->nav_hyperspace = h;
1337 
1338    /* cleanup */
1339    if (save_all() < 0) /* must be before cleaning up planet */
1340       dialogue_alert( "Failed to save game! You should exit and check the log to see what happened and then file a bug report!" );
1341 
1342    /* time goes by, triggers hook before takeoff */
1343    if (delay)
1344       ntime_inc( ntime_create( 0, 1, 0 ) ); /* 1 STP */
1345    nt = ntime_pretty( 0, 2 );
1346    player_message("\epTaking off from %s on %s.", land_planet->name, nt);
1347    free(nt);
1348 
1349    /* Hooks and stuff. */
1350    land_cleanup(); /* Cleanup stuff */
1351    hooks_run("takeoff"); /* Must be run after cleanup since we don't want the
1352                             missions to think we are landed. */
1353    if (menu_isOpen(MENU_MAIN))
1354       return;
1355    player_addEscorts();
1356    hooks_run("enter");
1357    if (menu_isOpen(MENU_MAIN))
1358       return;
1359    events_trigger( EVENT_TRIGGER_ENTER );
1360    missions_run( MIS_AVAIL_SPACE, -1, NULL, NULL );
1361    if (menu_isOpen(MENU_MAIN))
1362       return;
1363    player.p->ptimer = PILOT_TAKEOFF_DELAY;
1364    pilot_setFlag( player.p, PILOT_TAKEOFF );
1365    pilot_setThrust( player.p, 0. );
1366    pilot_setTurn( player.p, 0. );
1367    }
1368 
1369 
1370 /**
1371  * @brief Runs the rescue script if players are stuck.
1372  */
land_stranded(void)1373 static void land_stranded (void)
1374 {
1375    char *buf;
1376    uint32_t bufsize;
1377    const char *file = "dat/rescue.lua";
1378 
1379    /* Nothing to do if there's no rescue script. */
1380    if (!ndata_exists(file))
1381       return;
1382 
1383    if (rescue_env == LUA_NOREF) {
1384       rescue_env = nlua_newEnv(1);
1385       nlua_loadStandard( rescue_env );
1386       nlua_loadTk( rescue_env );
1387 
1388       buf = ndata_read( file, &bufsize );
1389       if (nlua_dobufenv(rescue_env, buf, bufsize, file) != 0) {
1390          WARN("Error loading file: %s\n"
1391              "%s\n"
1392              "Most likely Lua file has improper syntax, please check",
1393                file, lua_tostring(naevL,-1));
1394          free(buf);
1395          return;
1396       }
1397       free(buf);
1398    }
1399 
1400    /* Run Lua. */
1401    nlua_getenv(rescue_env,"rescue");
1402    if (nlua_pcall(rescue_env, 0, 0)) { /* error has occurred */
1403       WARN("Rescue: 'rescue' : '%s'", lua_tostring(naevL,-1));
1404       lua_pop(naevL,1);
1405    }
1406 }
1407 
1408 
1409 /**
1410  * @brief Cleans up some land-related variables.
1411  */
land_cleanup(void)1412 void land_cleanup (void)
1413 {
1414    int i;
1415 
1416    /* Clean up default stuff. */
1417    land_regen     = 0;
1418    land_planet    = NULL;
1419    landed         = 0;
1420    land_visited   = 0;
1421    land_generated = 0;
1422 
1423    /* Destroy window. */
1424    if (land_wid > 0)
1425       window_destroy(land_wid);
1426    land_wid       = 0;
1427 
1428    /* Clean up possible stray graphic. */
1429    if (gfx_exterior != NULL)
1430       gl_freeTexture( gfx_exterior );
1431    gfx_exterior   = NULL;
1432 
1433    /* Clean up mission computer. */
1434    for (i=0; i<mission_ncomputer; i++)
1435       mission_cleanup( &mission_computer[i] );
1436    if (mission_computer != NULL)
1437       free(mission_computer);
1438    mission_computer  = NULL;
1439    mission_ncomputer = 0;
1440 
1441    /* Clean up bar missions. */
1442    npc_freeAll();
1443 
1444    /* Clean up rescue Lua. */
1445    if (rescue_env != LUA_NOREF) {
1446       nlua_freeEnv(rescue_env);
1447       rescue_env = LUA_NOREF;
1448    }
1449 }
1450 
1451 
1452 /**
1453  * @brief Exits all the landing stuff.
1454  */
land_exit(void)1455 void land_exit (void)
1456 {
1457    land_cleanup();
1458    equipment_cleanup();
1459    outfits_cleanup();
1460 }
1461 
1462 
1463