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