naev 0.11.5
land.c
Go to the documentation of this file.
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
10#include <math.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include "physfs.h"
14
15#include "naev.h"
18#include "land.h"
19
20#include "array.h"
21#include "camera.h"
22#include "conf.h"
23#include "dialogue.h"
24#include "economy.h"
25#include "equipment.h"
26#include "escort.h"
27#include "event.h"
28#include "gui.h"
29#include "gui_omsg.h"
30#include "hook.h"
31#include "land_outfits.h"
32#include "land_shipyard.h"
33#include "land_trade.h"
34#include "log.h"
35#include "map.h"
36#include "menu.h"
37#include "mission.h"
38#include "music.h"
39#include "ndata.h"
40#include "news.h"
41#include "nlua.h"
42#include "nlua_tk.h"
43#include "nluadef.h"
44#include "npc.h"
45#include "nstring.h"
46#include "ntime.h"
47#include "player.h"
48#include "player_fleet.h"
49#include "rng.h"
50#include "render.h"
51#include "save.h"
52#include "shiplog.h"
53#include "toolkit.h"
54
55/*
56 * we use visited flags to not duplicate missions generated
57 */
58#define VISITED_LAND (1<<0)
59#define VISITED_COMMODITY (1<<1)
60#define VISITED_BAR (1<<2)
61#define VISITED_OUTFITS (1<<3)
62#define VISITED_SHIPYARD (1<<4)
63#define VISITED_EQUIPMENT (1<<5)
64#define VISITED_MISSION (1<<6)
65#define visited(f) (land_visited |= (f))
66#define has_visited(f) (land_visited & (f))
67static unsigned int land_visited = 0;
69/* Which tabs have been generated by their respective open functions. */
70unsigned int land_generated = 0;
71
72/*
73 * land variables
74 */
75int landed = 0;
76int land_loaded = 0;
77static int land_takeoff = 0;
78static int land_takeoff_nosave = 0;
79unsigned int land_wid = 0;
80static int land_regen = 0;
81static int land_windowsMap[LAND_NUMWINDOWS];
82static unsigned int *land_windows = NULL;
83Spob* land_spob = NULL;
84static glTexture *gfx_exterior = NULL;
86/*
87 * mission computer stack
88 */
89static Mission* mission_computer = NULL;
90static int mission_ncomputer = 0;
92/*
93 * Bar stuff.
94 */
97/*
98 * player stuff
99 */
100static int last_window = 0;
102/*
103 * Error handling.
104 */
105static char errorlist[STRMAX_SHORT];
106static char errorreason[STRMAX_SHORT];
107static int errorappend;
108static char *errorlist_ptr;
109
110/*
111 * Rescue.
112 */
113static nlua_env rescue_env = LUA_NOREF;
114static void land_stranded (void);
115
116/*
117 * prototypes
118 */
119static int land_gc( void *unused );
120static int land_hasLocalMap (void);
121static void land_createMainTab( unsigned int wid );
122static void land_setupTabs (void);
123static void land_cleanupWindow( unsigned int wid, const char *name );
124static void land_changeTab( unsigned int wid, const char *wgt, int old, int tab );
125/* spaceport bar */
126static void bar_getDim( int wid, int *w, int *h, int *iw, int *ih, int *bw, int *bh );
127static void bar_open( unsigned int wid );
128static int bar_genList( unsigned int wid );
129static void bar_update( unsigned int wid, const char *str );
130static void bar_close( unsigned int wid, const char *str );
131static void bar_approach( unsigned int wid, const char *str );
132static int news_load (void);
133/* mission computer */
134static void misn_open( unsigned int wid );
135static void misn_autonav( unsigned int wid, const char *str );
136static void misn_accept( unsigned int wid, const char *str );
137static void misn_genList( unsigned int wid, int first );
138static void misn_update( unsigned int wid, const char *str );
139
144{
145 land_takeoff = 1;
146 land_takeoff_nosave = player_isFlag(PLAYER_NOSAVE);
147}
148
149void land_needsTakeoff( int delay )
150{
151 if (land_takeoff)
153}
154
155/* Maps are only offered if the spob provides fuel. */
156static int land_hasLocalMap (void)
157{
158 if (!spob_hasService( land_spob, SPOB_SERVICE_REFUEL ))
159 return 0;
160 return 1;
161}
162
166int land_canSave (void)
167{
168 /* Overrided case. */
169 if (player_isFlag( PLAYER_NOSAVE ))
170 return 0;
171
172 /* If the current landed planet is refuelable, no need to check if can land. */
173 if ((land_spob!=NULL) && spob_hasService(land_spob,SPOB_SERVICE_REFUEL))
174 return 1;
175
176 /* For other places we'll have to see if can land. */
177 for (int i=0; i<array_size(cur_system->spobs); i++) {
178 Spob *p = cur_system->spobs[i];
179 spob_updateLand( p );
180 if (spob_hasService(p,SPOB_SERVICE_REFUEL) && p->can_land)
181 return 1;
182 }
183 return 0;
184}
185
190{
191 if (landed && land_loaded)
192 return 1;
193 return 0;
194}
195
199void land_errClear (void)
200{
201 errorlist_ptr = NULL; /* Clear errors. */
202}
203
208void land_errDialogueBuild( const char *fmt, ... )
209{
210 va_list ap;
211
212 if (fmt == NULL)
213 return;
214 va_start(ap, fmt);
215 vsnprintf(errorreason, sizeof(errorreason), fmt, ap);
216 va_end(ap);
217
218 if (errorlist_ptr == NULL) /* Initialize on first run. */
219 errorappend = scnprintf( errorlist, sizeof(errorlist), "%s", errorreason );
220 else /* Append newest error to the existing list. */
221 scnprintf( &errorlist[errorappend], sizeof(errorlist)-errorappend, "\n%s", errorreason );
222 errorlist_ptr = errorlist;
223}
224
229{
230 if (errorlist_ptr != NULL) {
231 dialogue_alert( "%s", errorlist );
232 return 1;
233 }
234 return 0;
235}
236
240static void bar_getDim( int wid,
241 int *w, int *h, int *iw, int *ih, int *bw, int *bh )
242{
243 /* Get window dimensions. */
244 window_dimWindow( wid, w, h );
245
246 /* Calculate dimensions of portraits. */
247 *iw = 704 + (*w - LAND_WIDTH);
248 *ih = *h - 60;
249
250 /* Calculate button dimensions. */
251 *bw = (*w - *iw - 80)/2;
252 *bh = LAND_BUTTON_HEIGHT;
253}
257static void bar_open( unsigned int wid )
258{
259 int w, h, iw, ih, bw, bh, dh, th;
260 const char *desc;
261
262 /* Mark as generated. */
263 land_tabGenerate(LAND_WINDOW_BAR);
264
265 /* Set window functions. */
267
268 /* Get dimensions. */
269 desc = (land_spob->bar_description!=NULL) ? _(land_spob->bar_description) : "(NULL)";
270 bar_getDim( wid, &w, &h, &iw, &ih, &bw, &bh );
271 dh = gl_printHeightRaw( &gl_defFont, w - iw - 60, desc );
272
273 /* Approach when pressing enter */
275
276 /* Buttons */
277 window_addButtonKey( wid, -20, 20,
278 bw, bh, "btnCloseBar",
279 _("Take Off"), land_buttonTakeoff, SDLK_t );
280 window_addButtonKey( wid, -20 - bw - 20, 20,
281 bw, bh, "btnApproach",
282 p_("bar", "Approach"), bar_approach, SDLK_a );
283
284 /* Bar description. */
285 window_addText( wid, iw + 40, -40, w - iw - 60, dh, 0,
286 "txtDescription", &gl_defFont, NULL, desc );
287
288 /* Add portrait text. */
289 th = -40 - dh - 40;
290 window_addText( wid, iw + 40, th,
291 w - iw - 60, gl_defFont.h, 1,
292 "txtPortrait", &gl_defFont, NULL, NULL );
293
294 /* Add mission description text. */
295 th -= 20 + PORTRAIT_HEIGHT + 20 + 20;
296 window_addText( wid, iw + 60, th,
297 w - iw - 100, h + th - (2*bh+60), 0,
298 "txtMission", &gl_defFont, NULL, NULL );
299
300 /* Generate the mission list. */
301 bar_genList( wid );
302}
303
309static int bar_genList( unsigned int wid )
310{
311 ImageArrayCell *portraits;
312 int w, h, iw, ih, bw, bh;
313 int n, pos;
314
315 /* Validity check. */
316 if (wid == 0)
317 return 0;
318
319 /* Get dimensions. */
320 bar_getDim( wid, &w, &h, &iw, &ih, &bw, &bh );
321
322 /* Destroy widget if already exists. */
323 if (widget_exists( wid, "iarMissions" )) {
324 /* Store position. */
325 pos = toolkit_getImageArrayPos( wid, "iarMissions" );
326
327 window_destroyWidget( wid, "iarMissions" );
328 }
329 else
330 pos = -1;
331
332 /* We sort just in case. */
333 npc_sort();
334
335 /* Set up missions. */
336 if (mission_portrait == NULL)
337 mission_portrait = gl_newImage( PORTRAIT_GFX_PATH"news.webp", 0 );
338 n = npc_getArraySize();
339 if (n <= 0) {
340 n = 1;
341 portraits = calloc(1, sizeof(ImageArrayCell));
342 portraits[0].image = gl_dupTexture(mission_portrait);
343 portraits[0].caption = strdup(_("News"));
344 }
345 else {
346 n = n+1;
347 portraits = calloc(n, sizeof(ImageArrayCell));
348 portraits[0].image = gl_dupTexture(mission_portrait);
349 portraits[0].caption = strdup(_("News"));
350 for (int i=0; i<npc_getArraySize(); i++) {
351 ImageArrayCell *p = &portraits[i+1];
352 const glTexture *bg = npc_getBackground(i);
353 p->caption = strdup( npc_getName(i) );
354 if (bg!=NULL) {
355 p->image = gl_dupTexture( bg );
356 p->layers = gl_addTexArray( p->layers, gl_dupTexture( npc_getTexture(i) ) );
357 }
358 else
359 p->image = gl_dupTexture( npc_getTexture(i) );
360 if (npc_isImportant(i))
361 p->layers = gl_addTexArray( p->layers, gl_newImage( OVERLAY_GFX_PATH"portrait_exclamation.webp", 0 ) );
362 }
363 }
364 window_addImageArray( wid, 20, -40,
365 iw, ih, "iarMissions", 128, 96,
366 portraits, n, bar_update, bar_approach, bar_approach );
367
368 /* Restore position. */
369 toolkit_setImageArrayPos( wid, "iarMissions", pos );
370
371 /* write the outfits stuff */
372 bar_update( wid, NULL );
373
374 /* Set default keyboard focus. */
375 window_setFocus( wid, "iarMissions" );
376
377 return 0;
378}
382void bar_regen (void)
383{
384 if (!landed)
385 return;
386 if (!land_loaded)
387 return;
388 bar_genList( land_getWid(LAND_WINDOW_BAR) );
389}
395static void bar_update( unsigned int wid, const char *str )
396{
397 (void) str;
398 int pos;
399 int w, h, iw, ih, bw, bh, dh;
400
401 /* Get dimensions. */
402 bar_getDim( wid, &w, &h, &iw, &ih, &bw, &bh );
403 dh = gl_printHeightRaw( &gl_defFont, w - iw - 60, _(land_spob->bar_description) );
404
405 /* Get array. */
406 pos = toolkit_getImageArrayPos( wid, "iarMissions" );
407
408 /* See if is news. */
409 if (pos==0) { /* News selected. */
410 /* Destroy news widget if needed. */
411 if (widget_exists(wid, "cstNews"))
412 window_destroyWidget( wid, "cstNews" );
413
414 /* Destroy portrait. */
415 if (widget_exists(wid, "imgPortrait"))
416 window_destroyWidget(wid, "imgPortrait");
417 if (widget_exists(wid, "imgPortraitBG"))
418 window_destroyWidget(wid, "imgPortraitBG");
419
420 /* Disable button. */
421 window_disableButton( wid, "btnApproach" );
422
423 /* Clear text. */
424 window_modifyText( wid, "txtPortrait", NULL );
425 window_modifyText( wid, "txtMission", NULL );
426
427 /* Create news. */
428 news_widget( wid, iw + 60, -40 - (40 + dh),
429 w - iw - 100, h - 40 - (dh+20) - 40 - bh - 20 );
430 return;
431 }
432
433 /* Shift to ignore news now. */
434 pos--;
435
436 /* Destroy news widget if needed. */
437 if (widget_exists(wid, "cstNews"))
438 window_destroyWidget( wid, "cstNews" );
439
440 /* Create widgets if needed. */
441 if (!widget_exists(wid, "imgPortraitBG")) /* Must be first */
442 window_addImage( wid, iw + 40 + (w-iw-60-PORTRAIT_WIDTH)/2,
443 -(40 + dh + 40 + gl_defFont.h + 20 + PORTRAIT_HEIGHT),
444 0, 0, "imgPortraitBG", NULL, 1 );
445 if (!widget_exists(wid, "imgPortrait"))
446 window_addImage( wid, iw + 40 + (w-iw-60-PORTRAIT_WIDTH)/2,
447 -(40 + dh + 40 + gl_defFont.h + 20 + PORTRAIT_HEIGHT),
448 0, 0, "imgPortrait", NULL, 1 );
449
450 /* Enable button. */
451 window_enableButton( wid, "btnApproach" );
452
453 /* Set portrait. */
454 window_modifyText( wid, "txtPortrait", npc_getName( pos ) );
455 window_modifyImage( wid, "imgPortrait", npc_getTexture( pos ),
456 PORTRAIT_WIDTH, PORTRAIT_HEIGHT );
457 window_modifyImage( wid, "imgPortraitBG", npc_getBackground( pos ),
458 PORTRAIT_WIDTH, PORTRAIT_HEIGHT );
459
460 /* Set mission description. */
461 window_modifyText( wid, "txtMission", npc_getDesc( pos ));
462}
468static void bar_close( unsigned int wid, const char *name )
469{
470 (void) wid;
471 (void) name;
472
473 /* Must not be regenerating. */
474 if (land_regen) {
475 land_regen--;
476 return;
477 }
478
480 mission_portrait = NULL;
481}
485static void bar_approach( unsigned int wid, const char *str )
486{
487 (void) str;
488 int pos, n;
489
490 /* Get position. */
491 pos = toolkit_getImageArrayPos( wid, "iarMissions" );
492
493 /* Should never happen, but in case news is selected */
494 if (pos == 0)
495 return;
496
497 /* Ignore news. */
498 pos--;
499
500 n = npc_getArraySize();
501 npc_approach( pos );
502 /* This check is necessary if the player quits the game in the middle of an NPC approach. */
503 if (land_spob==NULL)
504 return;
505 bar_genList( wid ); /* Always just in case. */
506
507 /* Focus the news if the number of NPCs has changed. */
508 if (n != npc_getArraySize())
509 toolkit_setImageArrayPos( wid, "iarMissions", 0 );
510
511 /* Reset markers. */
513
514 /* Mission forced take off. */
515 land_needsTakeoff( 0 );
516}
522static int news_load (void)
523{
525 return 0;
526}
527
528
532static void misn_open( unsigned int wid )
533{
534 int w,h, y;
535
536 /* Mark as generated. */
537 land_tabGenerate(LAND_WINDOW_MISSION);
538
539 /* Get window dimensions. */
540 window_dimWindow( wid, &w, &h );
541
542 /* buttons */
543 window_addButtonKey( wid, -20, 20,
544 LAND_BUTTON_WIDTH,LAND_BUTTON_HEIGHT, "btnCloseMission",
545 _("Take Off"), land_buttonTakeoff, SDLK_t );
546 window_addButtonKey( wid, -20, 40+LAND_BUTTON_HEIGHT,
547 LAND_BUTTON_WIDTH,LAND_BUTTON_HEIGHT, "btnAcceptMission",
548 _("Accept Mission"), misn_accept, SDLK_a );
549 window_addButtonKey( wid, -20, 60+2*LAND_BUTTON_HEIGHT,
550 LAND_BUTTON_WIDTH,LAND_BUTTON_HEIGHT, "btnAutonavMission",
551 _("Autonav"), misn_autonav, SDLK_n );
552
553 /* text */
554 y = -60;
555 window_addText( wid, w/2 + 10, y,
556 w/2 - 30, 40, 0,
557 "txtSDate", NULL, &cFontGrey,
558 _("Date:\n"
559 "Free Space:"));
560 window_addText( wid, w/2 + 110, y,
561 w/2 - 130, 40, 0,
562 "txtDate", NULL, NULL, NULL );
563 y -= 2 * gl_defFont.h + 30;
564 window_addText( wid, w/2 + 10, y,
565 w/2 - 30, 50, 0,
566 "txtHeader", &gl_defFont, NULL, NULL );
567 y -= 50;
568 window_addText( wid, w/2 + 10, y,
569 w/2 - 30, y - 40 + h - 2*LAND_BUTTON_HEIGHT, 0,
570 "txtDesc", &gl_defFont, NULL, NULL );
571
572 /* map */
573 map_show( wid, 20, 20, w/2 - 30, h/2 - 35, 0.75, 0., 0. );
574
575 misn_genList(wid, 1);
576 space_clearComputerMarkers(); /* Don't want markers at the beginning. */
577}
583static void misn_autonav( unsigned int wid, const char *str )
584{
585 Mission* misn;
586 const StarSystem *sys;
587 (void) str;
588
589 /* Makes sure current mission has system */
590 misn = &mission_computer[ toolkit_getListPos( wid, "lstMission" ) ];
591 sys = mission_sysComputerMark( misn );
592 if (sys==NULL)
593 return;
594
595 /* Select mission's target system */
596 map_select( sys,0 );
597
598 /* Autonav to target system */
601}
607static void misn_accept( unsigned int wid, const char *str )
608{
609 (void) str;
610 const char *misn_name = toolkit_getList( wid, "lstMission" );
611
612 /* Make sure you have missions. */
613 if (strcmp(misn_name,_("No Missions"))==0)
614 return;
615
616 if (dialogue_YesNo( _("Accept Mission"),
617 _("Are you sure you want to accept this mission?"))) {
618 int changed = 0;
619 int pos = toolkit_getListPos( wid, "lstMission" );
620 Mission *misn = &mission_computer[pos];
621 int ret = mission_accept( misn );
622 if (ret==-1) { /* Errored out. */
624 changed = 1;
625 }
626 if ((ret==2) || (ret==3)) /* Deleted or accepted. */
627 changed = 1;
628
629 if (changed) {
630 memmove( &mission_computer[pos], &mission_computer[pos+1],
631 sizeof(Mission) * (mission_ncomputer-pos-1) );
633
634 /* Regenerate list. */
635 misn_genList(wid, 0);
636 /* Add position persistancey after a mission has been accepted */
637 /* NOTE: toolkit_setListPos protects us from a bad position by clamping */
638 toolkit_setListPos( wid, "lstMission", pos-1 ); /*looks better without the -1, makes more sense with*/
639 }
640
641 /* Reset markers. */
643 }
644}
650static void misn_genList( unsigned int wid, int first )
651{
652 char** misn_names;
653 int j, w,h;
654
655 if (!first)
656 window_destroyWidget( wid, "lstMission" );
657
658 /* Get window dimensions. */
659 window_dimWindow( wid, &w, &h );
660
661 /* list */
662 j = 1; /* make sure we don't accidentally free the memory twice. */
663 misn_names = NULL;
664 if (mission_ncomputer > 0) { /* there are missions */
665 misn_names = malloc(sizeof(char*) * mission_ncomputer);
666 j = 0;
667 for (int i=0; i<mission_ncomputer; i++)
668 if (mission_computer[i].title != NULL)
669 misn_names[j++] = strdup(mission_computer[i].title);
670 }
671 if ((misn_names==NULL) || (mission_ncomputer==0) || (j==0)) { /* no missions. */
672 if (j==0)
673 free(misn_names);
674 misn_names = malloc(sizeof(char*));
675 misn_names[0] = strdup(_("No Missions"));
676 j = 1;
677 }
678 window_addList( wid, 20, -40,
679 w/2 - 30, h/2 - 35,
680 "lstMission", misn_names, j, 0, misn_update, misn_accept );
681
682 /* Set default keyboard focus. */
683 window_setFocus( wid, "lstMission" );
684}
690static void misn_update( unsigned int wid, const char *str )
691{
692 (void) str;
693 const char *active_misn;
694 Mission* misn;
695 const StarSystem *sys;
696 char txt[STRMAX_SHORT], *buf;
697
698 /* Clear computer markers. */
700
701 /* Update date stuff. */
702 buf = ntime_pretty( 0, 2 );
703 snprintf( txt, sizeof(txt), n_(
704 "%s\n%d Tonne", "%s\n%d Tonnes", player.p->cargo_free),
705 buf, player.p->cargo_free );
706 free(buf);
707 window_modifyText( wid, "txtDate", txt );
708
709 active_misn = toolkit_getList( wid, "lstMission" );
710 if (strcmp(active_misn,_("No Missions"))==0) {
711 window_modifyText( wid, "txtHeader", NULL );
712 window_modifyText( wid, "txtDesc",
713 _("There are no missions available here.") );
714 window_disableButton( wid, "btnAcceptMission" );
715 window_disableButton( wid, "btnAutonavMission" );
716 return;
717 }
718
719 misn = &mission_computer[ toolkit_getListPos( wid, "lstMission" ) ];
720 sys = mission_sysComputerMark( misn );
721 if (sys!=NULL)
722 map_center( wid, sys->name );
723 snprintf( txt, sizeof(txt), _("%s\n#nReward:#0 %s"), misn->title, misn->reward );
724 window_modifyText( wid, "txtHeader", txt );
725 window_modifyText( wid, "txtDesc", misn->desc );
726 window_enableButton( wid, "btnAcceptMission" );
727 window_enableButton( wid, "btnAutonavMission" );
728}
729
733void land_refuel (void)
734{
735 unsigned int w;
736
737 /* Full fuel. */
738 if (player.p->fuel >= player.p->fuel_max)
739 return;
740
741 /* No refuel service. */
742 if (!spob_hasService(land_spob, SPOB_SERVICE_REFUEL))
743 return;
744
746
747 w = land_getWid( LAND_WINDOW_EQUIPMENT );
748 if (w > 0)
749 equipment_updateShips( w, NULL ); /* Must update counter. */
750}
751
755static void spaceport_buyMap( unsigned int wid, const char *str )
756{
757 (void) wid;
758 (void) str;
759 const Outfit *o = outfit_get( LOCAL_MAP_NAME );
760 unsigned int w;
761
762 if (o == NULL) {
763 WARN( _("Outfit '%s' does not exist!"), LOCAL_MAP_NAME);
764 return;
765 }
766
767 /* Make sure the map isn't already known, etc. */
768 if (!outfit_canBuy( o, -1 )) {
770 return;
771 }
772
774 player_addOutfit(o, 1);
775
776 /* Disable the button. */
777 window_disableButtonSoft( land_windows[0], "btnMap" );
778
779 /* Update map quantity in outfitter. */
780 w = land_getWid( LAND_WINDOW_OUTFITS );
781 if (w > 0)
782 outfits_regenList( w, NULL );
783
784 /* Update main tab. */
786}
787
792{
793 char buf[STRMAX], cred[ECON_CRED_STRLEN], tons[STRMAX_SHORT];
794 size_t l = 0;
795 const Outfit *o;
796
797 /* Update credits. */
798 tonnes2str( tons, player.p->cargo_free );
799 credits2str( cred, player.p->credits, 2 );
800 l += scnprintf( &buf[l], sizeof(buf)-l, _("%s (%s system)"), spob_name(land_spob), _(cur_system->name) );
801 l += scnprintf( &buf[l], sizeof(buf)-l, "\n" );
802 l += scnprintf( &buf[l], sizeof(buf)-l, _("%s (%s-class)"), spob_getClassName(land_spob->class), _(land_spob->class) );
803 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s",
805 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", space_populationStr( land_spob ) );
806 l += scnprintf( &buf[l], sizeof(buf)-l, "\n\n%s", tons );
807 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", cred );
808 /* Show tags. */
809 if (conf.devmode) {
810 l += scnprintf( &buf[l], sizeof(buf)-l, "\n" );
811 for (int i=0; i<array_size(land_spob->tags); i++)
812 l += scnprintf( &buf[l], sizeof(buf)-l, "%s%s", ((i>0) ? ", " : ""), land_spob->tags[i] );
813 }
814
815 window_modifyText( land_windows[0], "txtDInfo", buf );
816
817 /* Make sure maps are available. */
818 if (!land_hasLocalMap())
819 return;
820
821 o = outfit_get( LOCAL_MAP_NAME );
822 if (o == NULL) {
823 WARN( _("Outfit '%s' does not exist!"), LOCAL_MAP_NAME);
824 return;
825 }
826
827 /* Just enable button if it exists. */
828 if (widget_exists( land_windows[0], "btnMap" ))
829 window_enableButton( land_windows[0], "btnMap");
830 /* Else create it. */
831 else {
832 /* Buy local map button. */
833 credits2str( cred, o->price, 0 );
834 snprintf( buf, sizeof(buf), _("Buy Local Map (%s)"), cred );
835 window_addButtonKey( land_windows[0], -20, 20 + (LAND_BUTTON_HEIGHT + 20),
836 LAND_BUTTON_WIDTH, LAND_BUTTON_HEIGHT, "btnMap",
837 buf, spaceport_buyMap, SDLK_b );
838 }
839
840 /* Make sure player can click it. */
841 if (!outfit_canBuy( o, -1 ))
842 window_disableButtonSoft( land_windows[0], "btnMap" );
843}
844
851void land_buttonTakeoff( unsigned int wid, const char *unused )
852{
853 (void) wid;
854 (void) unused;
855 /* We'll want the time delay. */
856 takeoff( 1, player_isFlag(PLAYER_NOSAVE) );
857}
858
865static void land_cleanupWindow( unsigned int wid, const char *name )
866{
867 (void) wid;
868 (void) name;
869
870 /* Must not be regenerating. */
871 if (land_regen) {
872 land_regen--;
873 return;
874 }
875
876 /* Clean up possible stray graphic. */
877 if (gfx_exterior != NULL) {
879 gfx_exterior = NULL;
880 }
881}
882
889unsigned int land_getWid( int window )
890{
891 if (land_windowsMap[window] == -1)
892 return 0;
893 return land_windows[ land_windowsMap[window] ];
894}
895
899static void land_setupTabs (void)
900{
901 int j;
902 const char *names[LAND_NUMWINDOWS];
903
904 /* Destroy if exists. */
905 if (widget_exists( land_wid, "tabLand" ))
906 window_destroyWidget( land_wid, "tabLand" );
907
908 /* Set window map to invalid. */
909 for (int i=0; i<LAND_NUMWINDOWS; i++)
910 land_windowsMap[i] = -1;
911
912 /* See what is available. */
913 j = 0;
914 /* Main. */
915 land_windowsMap[LAND_WINDOW_MAIN] = j;
916 names[j++] = _("Landing Main");
917 /* Bar. */
918 if (spob_hasService(land_spob, SPOB_SERVICE_BAR)) {
919 land_windowsMap[LAND_WINDOW_BAR] = j;
920 names[j++] = _("Spaceport Bar");
921 }
922 /* Missions. */
923 if (spob_hasService(land_spob, SPOB_SERVICE_MISSIONS)) {
924 land_windowsMap[LAND_WINDOW_MISSION] = j;
925 names[j++] = _("Missions");
926 }
927 /* Outfits. */
928 if (spob_hasService(land_spob, SPOB_SERVICE_OUTFITS)) {
929 land_windowsMap[LAND_WINDOW_OUTFITS] = j;
930 names[j++] = _("Outfits");
931 }
932 /* Shipyard. */
933 if (spob_hasService(land_spob, SPOB_SERVICE_SHIPYARD)) {
934 land_windowsMap[LAND_WINDOW_SHIPYARD] = j;
935 names[j++] = _("Shipyard");
936 }
937 /* Equipment. */
938 if (spob_hasService(land_spob, SPOB_SERVICE_OUTFITS) ||
939 spob_hasService(land_spob, SPOB_SERVICE_SHIPYARD)) {
940 land_windowsMap[LAND_WINDOW_EQUIPMENT] = j;
941 names[j++] = p_("service", "Equipment");
942 }
943 /* Commodity. */
944 if (spob_hasService(land_spob, SPOB_SERVICE_COMMODITY)) {
945 land_windowsMap[LAND_WINDOW_COMMODITY] = j;
946 names[j++] = _("Commodity");
947 }
948
949 land_windows = window_addTabbedWindow( land_wid, -1, -1, -1, -1, "tabLand", j, names, 0 );
950}
951
957void land_genWindows( int load )
958{
959 int w, h;
960 Spob *p;
961 int regen;
962 unsigned int pntservices;
963
964 /* Destroy old window if exists. */
965 if (land_wid > 0) {
966 land_regen = 2; /* Mark we're regenning. */
968
969 /* Mark tabs as not generated. */
970 land_generated = 0;
971 }
972 land_loaded = 0;
973
974 /* Get spob. */
975 p = land_spob;
976 regen = landed;
977 pntservices = p->services;
978
979 /* Create window. */
980 if (SCREEN_W < LAND_WIDTH || SCREEN_H < LAND_HEIGHT) {
981 w = -1; /* Fullscreen. */
982 h = -1;
983 }
984 else {
985 w = LAND_WIDTH + 0.5 * (SCREEN_W - LAND_WIDTH);
986 h = LAND_HEIGHT + 0.5 * (SCREEN_H - LAND_HEIGHT);
987 }
988 land_wid = window_create( "wdwLand", spob_name(p), -1, -1, w, h );
990
991 /* Create tabbed window. */
993
994 /*
995 * Order here is very important:
996 *
997 * 1) Create main tab - must have decent background.
998 * 2) Set landed, play music and run land hooks - so hooks run well.
999 * 3) Generate missions - so that campaigns are fluid.
1000 * 4) Create other tabs - lists depend on NPC and missions.
1001 */
1002 /* 1) Create main tab. */
1003 land_createMainTab( land_getWid(LAND_WINDOW_MAIN) );
1004
1005 /* Add local system map button. */
1007
1008 /* 2) Set as landed and run hooks. */
1009 if (!regen) {
1010 landed = 1;
1011 music_choose("land"); /* Must be before hooks in case hooks change music. */
1012
1013 /* We don't run the "land" hook when loading. If you want to have it do stuff when loading, use the "load" hook.
1014 * Note that you can use the same function for both hooks. */
1015 if (!load)
1016 hooks_run("land");
1017 else
1018 hooks_run("load"); /* Should be run before generating missions, so if the load hook cancels a mission, it can reappear. */
1019 events_trigger( EVENT_TRIGGER_LAND );
1020
1021 /* An event, hook or the likes made Naev quit. */
1022 if (naev_isQuit())
1023 return;
1024
1025 /* Make sure services didn't change or we have to do the tab window. */
1026 if (land_spob->services != pntservices) {
1028 land_createMainTab( land_getWid(LAND_WINDOW_MAIN) );
1030 }
1031
1032 /* 3) Generate computer and bar missions. */
1033 /* Generate bar missions first for claims. */
1034 if (spob_hasService(land_spob, SPOB_SERVICE_BAR))
1035 npc_generateMissions(); /* Generate bar npc. */
1036 if (spob_hasService(land_spob, SPOB_SERVICE_MISSIONS))
1039 MIS_AVAIL_COMPUTER );
1040 }
1041
1042 /* 4) Create other tabs. */
1043#define should_open(s, w) \
1044 (spob_hasService(land_spob, s) && (!land_tabGenerated(w)))
1045
1046 /* Things get a bit hairy here. Hooks may have triggered a GUI reload via
1047 * e.g. player.swapShip, so the land tabs may have been generated already
1048 * and we need to check that before regenerating them.
1049 */
1050
1051 /* Basic - bar + missions */
1052 if (should_open( SPOB_SERVICE_BAR, LAND_WINDOW_BAR ))
1053 bar_open( land_getWid(LAND_WINDOW_BAR) );
1054 if (should_open( SPOB_SERVICE_MISSIONS, LAND_WINDOW_MISSION ))
1055 misn_open( land_getWid(LAND_WINDOW_MISSION) );
1056 /* Outfits. */
1057 if (should_open( SPOB_SERVICE_OUTFITS, LAND_WINDOW_OUTFITS ))
1058 outfits_open( land_getWid(LAND_WINDOW_OUTFITS), NULL, spob_hasService(land_spob, SPOB_SERVICE_BLACKMARKET) );
1059 /* Shipyard. */
1060 if (should_open( SPOB_SERVICE_SHIPYARD, LAND_WINDOW_SHIPYARD ))
1061 shipyard_open( land_getWid(LAND_WINDOW_SHIPYARD) );
1062 /* Equipment. */
1063 if ((spob_hasService(land_spob, SPOB_SERVICE_OUTFITS) ||
1064 spob_hasService(land_spob, SPOB_SERVICE_SHIPYARD)) &&
1065 !land_tabGenerated( LAND_WINDOW_EQUIPMENT ))
1066 equipment_open( land_getWid(LAND_WINDOW_EQUIPMENT) );
1067 /* Commodity. */
1068 if (should_open( SPOB_SERVICE_COMMODITY, LAND_WINDOW_COMMODITY ))
1069 commodity_exchange_open( land_getWid(LAND_WINDOW_COMMODITY) );
1070#undef should_open
1071
1072 if (!regen) {
1073 /* Reset markers if needed. */
1075
1076 /* Check land missions. */
1077 if (!has_visited(VISITED_LAND)) {
1078 missions_run(MIS_AVAIL_LAND, land_spob->presence.faction,
1081 }
1082 }
1083
1084 /* Go to last open tab. */
1085 window_tabWinOnChange( land_wid, "tabLand", land_changeTab );
1086 if (!land_takeoff && land_windowsMap[ last_window ] != -1)
1087 window_tabWinSetActive( land_wid, "tabLand", land_windowsMap[ last_window ] );
1088
1089 /* Refresh the map button in case the player couldn't afford it prior to
1090 * mission payment. */
1092
1093 /* Refuel if necessary. */
1094 land_refuel();
1095
1096 /* Finished loading. */
1097 land_loaded = 1;
1098
1099 /* Necessary if player.land() was run in an abort() function. */
1100 if (!load)
1102}
1103
1110int land_setWindow( int window )
1111{
1112 if (land_windowsMap[ window ] < 0)
1113 return -1;
1114 last_window = window;
1115 window_tabWinSetActive( land_wid, "tabLand", land_windowsMap[window] );
1116 return 0;
1117}
1118
1124void land( Spob* p, int load )
1125{
1126 /* Do not land twice. */
1127 if (landed)
1128 return;
1129
1130 /* Incrcement times player landed. */
1131 if (!load) {
1134 }
1135
1136 /* Clear some unnecessary flags. */
1137 pilot_rmFlag( player.p, PILOT_COOLDOWN_BRAKE);
1138 pilot_rmFlag( player.p, PILOT_COOLDOWN );
1139
1140 /* Resets the player's heat. */
1142
1143 /* Heal the player so GUI shows player at full everything. */
1145
1146 player_addEscorts(); /* TODO only regenerate fleet if planet has a shipyard */
1147
1148 /* Stop player sounds. */
1150
1151 /* Clear message stuff. */
1152 free( player.p->comm_msg );
1153 player.p->comm_msg = NULL;
1154
1155 /* Clear some target stuff. */
1156 player.p->nav_spob = -1;
1157 gui_setNav();
1158
1159 /* Load stuff */
1160 land_spob = p;
1161 gfx_exterior = gl_newImage( p->gfx_exterior, 0 );
1162
1163 /* Run outfits as necessary. */
1165
1166 /* Generate the news. */
1167 if (spob_hasService(land_spob, SPOB_SERVICE_BAR))
1168 news_load();
1169
1170 /* Average economy prices that player has seen */
1171 economy_averageSeenPrices( p );
1172
1173 /* Clear the NPC. */
1174 npc_clear();
1175
1176 /* Create all the windows. */
1177 land_genWindows( load );
1178
1179 /* Just in case? */
1180 bar_regen();
1181
1182 /* Do a lua collection pass. Run in a hook since land can be called indirectly from Lua. */
1183 hook_addFunc( land_gc, NULL, "safe" );
1184
1185 /* Mission forced take off. */
1186 land_needsTakeoff( 0 );
1187}
1188
1192static int land_gc( void *unused )
1193{
1194 (void) unused;
1195 lua_gc( naevL, LUA_GCCOLLECT, 0 );
1196 return 0;
1197}
1198
1204static void land_createMainTab( unsigned int wid )
1205{
1206 int offset;
1207 int w, h, y, th;
1208 char buf[STRMAX_SHORT];
1209 size_t l = 0;
1210
1211 /* Get window dimensions. */
1212 window_dimWindow( wid, &w, &h );
1213
1214 /*
1215 * Faction logo.
1216 */
1217 offset = 20;
1218 if (land_spob->presence.faction != -1) {
1220 if (logo != NULL) {
1221 int logow = logo->w * (double)FACTION_LOGO_SM / MAX( logo->w, logo->h );
1222 int logoh = logo->h * (double)FACTION_LOGO_SM / MAX( logo->w, logo->h );
1223 window_addImage( wid, 440 + (w-460-logow)/2, -20,
1224 logow, logoh, "imgFaction", logo, 0 );
1225 offset += FACTION_LOGO_SM;
1226 }
1227 }
1228
1229 /*
1230 * Pretty display.
1231 */
1232 window_addImage( wid, 20, -40, 400, 400, "imgSpob", gfx_exterior, 1 );
1233 if (land_spob->description != NULL)
1234 window_addText( wid, 440, -20-offset,
1235 w-460, h-20-offset-60-LAND_BUTTON_HEIGHT*2, 0,
1236 "txtSpobDesc", &gl_defFont, NULL, _(land_spob->description) );
1237
1238 /* Player stats. */
1239 l += scnprintf( &buf[l], sizeof(buf)-l, "#n%s", _("Stationed at:") );
1240 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("Class:") );
1241 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("Faction:") );
1242 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("Population:") );
1243 l += scnprintf( &buf[l], sizeof(buf)-l, "\n\n%s", _("Free Space:") );
1244 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("Money:") );
1245 if (conf.devmode)
1246 l += scnprintf( &buf[l], sizeof(buf)-l, "\n%s", _("Tags:") );
1247 th = gl_printHeightRaw( &gl_defFont, 200, buf );
1248 window_addText( wid, 20, 20, 200, th,
1249 0, "txtSInfo", &gl_defFont, NULL, buf );
1250 window_addText( wid, 20+120, 20, w - 20 - (20+200) - LAND_BUTTON_WIDTH,
1251 th, 0, "txtDInfo", &gl_defFont, NULL, NULL );
1252
1253 /*
1254 * buttons
1255 */
1256 /* first column */
1257 window_addButtonKey( wid, -20, 20,
1258 LAND_BUTTON_WIDTH, LAND_BUTTON_HEIGHT, "btnTakeoff",
1259 _("Take Off"), land_buttonTakeoff, SDLK_t );
1260
1261 /* Additional notices if necessary. */
1262 l = 0;
1263 buf[0] = '\0';
1264 y = 20 + (LAND_BUTTON_HEIGHT + 20) + 20;
1265 if (land_hasLocalMap())
1266 y += LAND_BUTTON_HEIGHT + 20;
1267 /* Add "no refueling" notice if needed. */
1268 if (!spob_hasService(land_spob, SPOB_SERVICE_REFUEL))
1269 l += scnprintf( &buf[l], sizeof(buf)-l, _("No refueling services.") );
1270 if (!land_canSave()) {
1271 if (l > 0)
1272 l += scnprintf( &buf[l], sizeof(buf)-l, "\n" );
1273 l += scnprintf( &buf[l], sizeof(buf)-l, "#r%s#0", _("Game will not be saved.") );
1274 }
1275 if (l>0) {
1276 th = gl_printHeightRaw( &gl_defFont, 200, buf );
1277 window_addText( land_windows[0], -20, y, 200, th, 0,
1278 "txtPlayer", &gl_defFont, NULL, buf );
1279 }
1280}
1281
1290static void land_changeTab( unsigned int wid, const char *wgt, int old, int tab )
1291{
1292 (void) wid;
1293 (void) wgt;
1294 (void) old;
1295 unsigned int w;
1296 /* Safe defaults. */
1297 const char *torun_hook = NULL;
1298 unsigned int to_visit = 0;
1299
1300 /* Clear markers when not open. */
1301 if (last_window == LAND_WINDOW_MISSION)
1303
1304 /* Find what switched. */
1305 for (int i=0; i<LAND_NUMWINDOWS; i++) {
1306 if (land_windowsMap[i] != tab)
1307 continue;
1308 last_window = i;
1309 w = land_getWid( i );
1310
1311 /* Must regenerate outfits. */
1312 switch (i) {
1313 case LAND_WINDOW_MAIN:
1315 break;
1316 case LAND_WINDOW_OUTFITS:
1317 outfits_update( w, NULL );
1318 to_visit = VISITED_OUTFITS;
1319 torun_hook = "outfits";
1320 break;
1321 case LAND_WINDOW_SHIPYARD:
1322 shipyard_update( w, NULL );
1323 to_visit = VISITED_SHIPYARD;
1324 torun_hook = "shipyard";
1325 break;
1326 case LAND_WINDOW_BAR:
1327 bar_update( w, NULL );
1328 to_visit = VISITED_BAR;
1329 torun_hook = "bar";
1330 break;
1331 case LAND_WINDOW_MISSION:
1332 misn_update( w, NULL );
1333 to_visit = VISITED_MISSION;
1334 torun_hook = "mission";
1335 break;
1336 case LAND_WINDOW_COMMODITY:
1337 commodity_update( w, NULL );
1338 to_visit = VISITED_COMMODITY;
1339 torun_hook = "commodity";
1340 break;
1341 case LAND_WINDOW_EQUIPMENT:
1342 equipment_updateShips( w, NULL );
1343 equipment_updateOutfits( w, NULL );
1344 to_visit = VISITED_EQUIPMENT;
1345 torun_hook = "equipment";
1346 break;
1347
1348 default:
1349 break;
1350 }
1351
1352 /* Clear markers if closing Mission Computer. */
1353 if (i != LAND_WINDOW_MISSION)
1355
1356 break;
1357 }
1358
1359 /* Check land missions - always run hooks. */
1360 /*if ((to_visit != 0) && !has_visited(to_visit)) {*/
1361 {
1362 /* Run hooks, run after music in case hook wants to change music. */
1363 if (torun_hook != NULL)
1364 if (hooks_run( torun_hook ) > 0)
1365 bar_genList( land_getWid(LAND_WINDOW_BAR) );
1366
1367 visited(to_visit);
1368
1369 if (land_loaded)
1370 land_needsTakeoff( 1 );
1371 }
1372}
1373
1380void takeoff( int delay, int nosave )
1381{
1382 int h;
1383 char *nt;
1384 double a, r;
1385
1386 if (!landed)
1387 return;
1388
1389 /* Check to see if player fleet is ok. */
1390 if (player.fleet_capacity > 0) {
1391 char badfleet_ships[STRMAX_SHORT];
1392 int l = 0;
1393 int badfleet = 0;
1394 int nships = 0;
1395 const PlayerShip_t *pships = player_getShipStack();
1396
1397 /* Check to see if player's fleet is OK and count ships. */
1398 pfleet_update();
1399 badfleet_ships[0] = '\0';
1400 for (int i=0; i<array_size(pships); i++) {
1401 const PlayerShip_t *pe = &pships[i];
1402 if (!pe->deployed)
1403 continue;
1404 if (!pilot_isSpaceworthy(pe->p)) {
1405 badfleet = 1;
1406 l += scnprintf( &badfleet_ships[l], sizeof(badfleet_ships)-l, "\n%s", pe->p->name );
1407 }
1408 nships++;
1409 }
1410 /* Only care if the player has a fleet deployed. */
1411 if (nships > 0) {
1413 if (!spob_hasService(land_spob, SPOB_SERVICE_SHIPYARD)) {
1414 land_stranded(); /* Needs rescuing. */
1415 return;
1416 }
1417 else {
1418 dialogue_msgRaw( _("Fleet not fit for flight"), _("You lack the fleet capacity to take off with all selected ships.") );
1419 return;
1420 }
1421 }
1422 if (badfleet) {
1423 if (!dialogue_YesNo( _("Fleet not fit for flight"), "%s\n%s", _("The following ships in your fleet are not space worthy, are you sure you want to take off without them?"), badfleet_ships ))
1424 return;
1425 }
1426 }
1427 }
1428
1429 /* Player's ship is not able to fly. */
1431 char message[STRMAX_SHORT];
1432 pilot_reportSpaceworthy( player.p, message, sizeof(message) );
1433 dialogue_msgRaw( _("Ship not fit for flight"), message );
1434
1435 /* Check whether the player needs rescuing. */
1436 land_stranded();
1437
1438 return;
1439 }
1440
1441 /* Clear queued takeoff. */
1442 land_takeoff = 0;
1444
1445 /* Refuel if needed. */
1446 land_refuel();
1447
1448 /* In case we had paused messy sounds. */
1449 sound_stopAll();
1450
1451 /* ze music */
1452 music_choose("takeoff");
1453
1454 /* to randomize the takeoff a bit */
1455 a = RNGF() * 2. * M_PI;
1456 r = RNGF() * land_spob->radius;
1457
1458 /* no longer authorized to land */
1459 player_rmFlag(PLAYER_LANDACK);
1460 pilot_rmFlag(player.p,PILOT_LANDING); /* No longer landing. */
1461
1462 /* set player to another position with random facing direction and no vel */
1463 player_warp( land_spob->pos.x + r * cos(a), land_spob->pos.y + r * sin(a) );
1464 vec2_pset( &player.p->solid.vel, 0., 0. );
1465 player.p->solid.dir = RNGF() * 2. * M_PI;
1467
1468 /* Clear spob target. Allows for easier autonav out of the system. */
1470
1471 /* Clear pilots other than player. */
1472 pilots_clean(1);
1473
1474 /* Clear omsg. */
1475 omsg_cleanup();
1476
1477 /* initialize the new space */
1478 h = player.p->nav_hyperspace;
1479 space_init( NULL, 1 );
1480 player.p->nav_hyperspace = h;
1481
1482 /* Only save when the player shouldn't get stranded. */
1483 if (!nosave && land_canSave() && (save_all() < 0)) /* must be before cleaning up spob */
1484 dialogue_alert( _("Failed to save game! You should exit and check the log to see what happened and then file a bug report!") );
1485
1486 /* time goes by, triggers hook before takeoff */
1487 if (delay) {
1488 /* TODO should this depend on something else? */
1489 int stu = (int)(NT_PERIOD_SECONDS * player.p->stats.land_delay);
1490 ntime_inc( ntime_create( 0, 0, stu ) );
1491 }
1492 nt = ntime_pretty( 0, 2 );
1493 player_message( _("#oTaking off from %s on %s."), spob_name(land_spob), nt);
1494 free(nt);
1495
1496 /* Hooks and stuff. */
1497 land_cleanup(); /* Cleanup stuff */
1498 hooks_run("takeoff"); /* Must be run after cleanup since we don't want the
1499 missions to think we are landed. */
1501 return;
1502
1503 /* Add escorts and heal up. */
1504 player_addEscorts(); /* TODO only regenerate fleet if planet has a shipyard */
1507
1508 hooks_run("enter");
1510 return;
1511 events_trigger( EVENT_TRIGGER_ENTER );
1512 missions_run( MIS_AVAIL_ENTER, -1, NULL, NULL );
1514 return;
1515
1516 /* Clear effects of all surviving pilots. */
1517 Pilot*const* plts = pilot_getAll();
1518 for (int i=0; i<array_size(plts); i++) {
1519 Pilot *p = plts[i];
1520 if (pilot_isFlag(p,PILOT_DELETE))
1521 continue;
1522
1523 effect_clear( &p->effects );
1524 pilot_calcStats( p );
1525
1526 /* Update lua stuff. */
1528
1529 /* Normal pilots stop here. */
1530 if (!pilot_isWithPlayer( p ))
1531 continue;
1532
1534
1535 /* Set take off stuff. */
1536 p->landing_delay = PILOT_TAKEOFF_DELAY * player_dt_default();
1537 p->ptimer = p->landing_delay;
1538 pilot_setFlag( p, PILOT_TAKEOFF );
1539 pilot_setAccel( p, 0. );
1540 pilot_setTurn( p, 0. );
1541 }
1542
1543 /* Reset speed */
1545
1546 /* Landing is a special case where the player's gear can change and trigger
1547 * all sorts of things. We have to refresh the GUI to reflect those changes.
1548 * This is particular important for Lua-side mechanics such as flow. */
1549 gui_setSystem();
1550}
1551
1555static void land_stranded (void)
1556{
1557 /* Nothing to do if there's no rescue script. */
1558 if (!PHYSFS_exists(RESCUE_PATH))
1559 return;
1560
1561 if (rescue_env == LUA_NOREF) {
1562 char *buf;
1563 size_t bufsize;
1564
1565 rescue_env = nlua_newEnv();
1568
1569 buf = ndata_read( RESCUE_PATH, &bufsize );
1570 if (buf == NULL) {
1571 WARN( _("File '%s' not found!"), RESCUE_PATH );
1572 return;
1573 }
1574 if (nlua_dobufenv(rescue_env, buf, bufsize, RESCUE_PATH) != 0) {
1575 WARN( _("Error loading file: %s\n"
1576 "%s\n"
1577 "Most likely Lua file has improper syntax, please check"),
1578 RESCUE_PATH, lua_tostring(naevL,-1));
1579 free(buf);
1580 return;
1581 }
1582 free(buf);
1583 }
1584
1585 /* Run Lua. */
1586 nlua_getenv(naevL,rescue_env,"rescue");
1587 if (nlua_pcall(rescue_env, 0, 0)) { /* error has occurred */
1588 WARN( _("Rescue: 'rescue' : '%s'"), lua_tostring(naevL,-1));
1589 lua_pop(naevL,1);
1590 }
1591}
1592
1596void land_cleanup (void)
1597{
1598 /* Clean up default stuff. */
1599 land_regen = 0;
1600 land_spob = NULL;
1601 landed = 0;
1602 land_visited = 0;
1603 land_generated = 0;
1604
1605 /* Destroy window. */
1606 if (land_wid > 0)
1608 land_wid = 0;
1609
1610 /* Clean up possible stray graphic. */
1611 if (gfx_exterior != NULL)
1613 gfx_exterior = NULL;
1614
1615 /* Remove computer markers just in case. */
1617
1618 /* Clean up mission computer. */
1619 for (int i=0; i<mission_ncomputer; i++)
1621 free(mission_computer);
1622 mission_computer = NULL;
1624
1625 /* Clean up bar missions. */
1626 npc_clear();
1627
1628 /* Clean up shipyard. */
1630
1631 /* Clean up rescue Lua. */
1632 nlua_freeEnv(rescue_env);
1633 rescue_env = LUA_NOREF;
1634
1635 /* Deselect stuff. */
1636 equipment_slotDeselect( NULL );
1637}
1638
1642void land_exit (void)
1643{
1644 land_cleanup();
1647 commodity_exchange_cleanup();
1648}
Provides macros to work with dynamic arrays.
static ALWAYS_INLINE int array_size(const void *array)
Returns number of elements in the array.
Definition array.h:168
void cam_setTargetPilot(unsigned int follow, int soft_over)
Sets the target to follow.
Definition camera.c:145
void credits2str(char *str, credits_t credits, int decimals)
Converts credits to a usable string for displaying.
Definition commodity.c:59
void tonnes2str(char *str, int tonnes)
Converts tonnes to a usable string for displaying.
Definition commodity.c:108
void dialogue_alert(const char *fmt,...)
Displays an alert popup with only an ok button and a message.
Definition dialogue.c:132
void dialogue_msgRaw(const char *caption, const char *msg)
Opens a dialogue window with an ok button and a fixed message.
Definition dialogue.c:271
int dialogue_YesNo(const char *caption, const char *fmt,...)
Runs a dialogue with both yes and no options.
Definition dialogue.c:352
void effect_clear(Effect **efxlist)
Clears an effect list, removing all active effects.
Definition effect.c:492
void equipment_slotDeselect(CstSlotWidget *wgt)
Deselects equipment stuff.
Definition equipment.c:2542
void equipment_cleanup(void)
Cleans up after the equipment stuff.
Definition equipment.c:2529
void equipment_updateOutfits(unsigned int wid, const char *str)
Updates the player's outfit list.
Definition equipment.c:2041
void equipment_updateShips(unsigned int wid, const char *str)
Updates the player's ship window.
Definition equipment.c:1801
void equipment_open(unsigned int wid)
Opens the player's equipment window.
Definition equipment.c:299
void events_trigger(EventTrigger_t trigger)
Runs all the events matching a trigger.
Definition event.c:319
const glTexture * faction_logo(int f)
Gets the faction's logo (ideally 256x256).
Definition faction.c:453
const char * faction_name(int f)
Gets a factions "real" (internal) name.
Definition faction.c:306
int gl_printHeightRaw(const glFont *ft_font, const int width, const char *text)
Gets the height of a non-formatted string.
Definition font.c:1027
glFont gl_defFont
Definition font.c:153
void gui_setSystem(void)
Player just changed their system.
Definition gui.c:1799
void gui_setNav(void)
Player just changed their nav computer target.
Definition gui.c:1775
void player_message(const char *fmt,...)
Adds a mesg to the queue to be displayed on screen.
Definition gui.c:335
int hooks_run(const char *stack)
Runs all the hooks of stack.
Definition hook.c:999
unsigned int hook_addFunc(int(*func)(void *), void *data, const char *stack)
Adds a function hook to be run.
Definition hook.c:594
void bar_regen(void)
Regenerates the bar list.
Definition land.c:382
static void land_changeTab(unsigned int wid, const char *wgt, int old, int tab)
Saves the last place the player was.
Definition land.c:1290
void land_queueTakeoff(void)
Queue a takeoff.
Definition land.c:143
static int land_takeoff_nosave
Definition land.c:78
static int land_windowsMap[LAND_NUMWINDOWS]
Definition land.c:81
static int last_window
Definition land.c:100
#define visited(f)
Definition land.c:65
void takeoff(int delay, int nosave)
Makes the player take off if landed.
Definition land.c:1380
static void misn_autonav(unsigned int wid, const char *str)
Autonav to selected mission.
Definition land.c:583
static void land_cleanupWindow(unsigned int wid, const char *name)
Cleans up the land window.
Definition land.c:865
static void bar_close(unsigned int wid, const char *str)
Closes the mission computer window.
Definition land.c:468
#define VISITED_EQUIPMENT
Definition land.c:63
unsigned int land_wid
Definition land.c:79
static unsigned int * land_windows
Definition land.c:82
static void bar_update(unsigned int wid, const char *str)
Updates the missions in the spaceport bar.
Definition land.c:395
static int mission_ncomputer
Definition land.c:90
#define VISITED_MISSION
Definition land.c:64
int land_setWindow(int window)
Sets the land window tab.
Definition land.c:1110
static void bar_approach(unsigned int wid, const char *str)
Approaches guy in mission computer.
Definition land.c:485
unsigned int land_getWid(int window)
Gets the WID of a window by type.
Definition land.c:889
static void land_stranded(void)
Runs the rescue script if players are stuck.
Definition land.c:1555
static int land_regen
Definition land.c:80
static void spaceport_buyMap(unsigned int wid, const char *str)
Buys a local system map.
Definition land.c:755
#define VISITED_COMMODITY
Definition land.c:59
#define VISITED_LAND
Definition land.c:58
int land_loaded
Definition land.c:76
static void misn_open(unsigned int wid)
Opens the mission computer window.
Definition land.c:532
void land_cleanup(void)
Cleans up some land-related variables.
Definition land.c:1596
static Mission * mission_computer
Definition land.c:89
#define VISITED_BAR
Definition land.c:60
int landed
Definition land.c:75
int land_doneLoading(void)
Check to see if finished loading.
Definition land.c:189
static int land_takeoff
Definition land.c:77
void land(Spob *p, int load)
Opens up all the land dialogue stuff.
Definition land.c:1124
static int bar_genList(unsigned int wid)
Generates the mission list for the bar.
Definition land.c:309
void land_errDialogueBuild(const char *fmt,...)
Generates error dialogues used by several landing tabs.
Definition land.c:208
static int news_load(void)
Loads the news.
Definition land.c:522
void land_exit(void)
Exits all the landing stuff.
Definition land.c:1642
static void bar_getDim(int wid, int *w, int *h, int *iw, int *ih, int *bw, int *bh)
Gets the dimensions of the spaceport bar window.
Definition land.c:240
void land_genWindows(int load)
Recreates the land windows.
Definition land.c:957
void land_updateMainTab(void)
Adds the "Buy Local Map" button if needed and updates info.
Definition land.c:791
static unsigned int land_visited
Definition land.c:67
Spob * land_spob
Definition land.c:83
static void bar_open(unsigned int wid)
Opens the spaceport bar window.
Definition land.c:257
void land_errClear(void)
Clear error dialogues.
Definition land.c:199
int land_canSave(void)
Whether or not the player can save.
Definition land.c:166
static glTexture * mission_portrait
Definition land.c:95
static void land_setupTabs(void)
Sets up the tabs for the window.
Definition land.c:899
#define VISITED_SHIPYARD
Definition land.c:62
void land_buttonTakeoff(unsigned int wid, const char *unused)
Wrapper for takeoff mission button.
Definition land.c:851
void land_refuel(void)
Refuels the player's current ship, if possible.
Definition land.c:733
#define VISITED_OUTFITS
Definition land.c:61
static glTexture * gfx_exterior
Definition land.c:84
static void misn_update(unsigned int wid, const char *str)
Updates the mission list.
Definition land.c:690
int land_errDisplay(void)
Displays an error if applicable.
Definition land.c:228
#define has_visited(f)
Definition land.c:66
static int land_gc(void *unused)
Runs Lua garbage collection.
Definition land.c:1192
static void misn_accept(unsigned int wid, const char *str)
Accepts the selected mission.
Definition land.c:607
static void land_createMainTab(unsigned int wid)
Creates the main tab.
Definition land.c:1204
static void misn_genList(unsigned int wid, int first)
Generates the mission list.
Definition land.c:650
static nlua_env rescue_env
Definition land.c:113
void outfits_regenList(unsigned int wid, const char *str)
Regenerates the outfit list.
int outfit_canBuy(const Outfit *outfit, int wid)
Checks to see if the player can buy the outfit.
void outfits_cleanup(void)
Cleans up outfit globals.
void outfits_open(unsigned int wid, const Outfit **outfits, int blackmarket)
Opens the outfit exchange center window.
void outfits_update(unsigned int wid, const char *str)
Updates the outfits in the outfit window.
void shipyard_open(unsigned int wid)
Opens the shipyard window.
void shipyard_cleanup(void)
Cleans up shipyard data.
void shipyard_update(unsigned int wid, const char *str)
Updates the ships in the shipyard window.
void commodity_exchange_open(unsigned int wid)
Opens the local market window.
Definition land_trade.c:66
void commodity_update(unsigned int wid, const char *str)
Updates the commodity window.
Definition land_trade.c:208
Handles the important game menus.
#define MENU_MAIN
Definition menu.h:9
#define menu_isOpen(f)
Definition menu.h:16
int mission_accept(Mission *mission)
Small wrapper for misn_run.
Definition mission.c:206
Mission * missions_genList(int *n, int faction, const Spob *pnt, const StarSystem *sys, MissionAvailability loc)
Generates a mission list. This runs create() so won't work with all missions.
Definition mission.c:914
void mission_cleanup(Mission *misn)
Cleans up a mission.
Definition mission.c:739
const StarSystem * mission_sysComputerMark(const Mission *misn)
Marks the system of the computer mission to reflect where it will head to.
Definition mission.c:603
void mission_sysMark(void)
Marks all active systems that need marking.
Definition mission.c:578
void missions_run(MissionAvailability loc, int faction, const Spob *pnt, const StarSystem *sys)
Runs missions matching location, all Lua side and one-shot.
Definition mission.c:321
int music_choose(const char *situation)
Actually runs the music stuff, based on situation.
Definition music.c:412
int naev_isQuit(void)
Get if Naev is trying to quit.
Definition naev.c:158
Header file with generic functions and naev-specifics.
#define MAX(x, y)
Definition naev.h:39
void * ndata_read(const char *path, size_t *filesize)
Reads a file from the ndata (will be NUL terminated).
Definition ndata.c:154
int * generate_news(int faction)
Generates news from newslist from specific faction AND Generic news.
Definition news.c:209
void news_widget(unsigned int wid, int x, int y, int w, int h)
Creates a news widget.
Definition news.c:277
int nlua_loadStandard(nlua_env env)
Loads the standard Naev Lua API.
Definition nlua.c:798
int nlua_loadTk(nlua_env env)
Loads the Toolkit Lua library.
Definition nlua_tk.c:93
const char * npc_getDesc(int i)
Gets the NPC description.
Definition npc.c:563
void npc_generateMissions(void)
Generates the bar missions.
Definition npc.c:365
glTexture * npc_getTexture(int i)
Get the texture of an NPC.
Definition npc.c:551
int npc_approach(int i)
Approaches the NPC.
Definition npc.c:622
void npc_clear(void)
Cleans up the spaceport bar NPC.
Definition npc.c:470
int npc_getArraySize(void)
Get the size of the npc array.
Definition npc.c:496
glTexture * npc_getBackground(int i)
Get the background of an NPC.
Definition npc.c:516
int npc_isImportant(int i)
Checks to see if the NPC is important or not.
Definition npc.c:575
const char * npc_getName(int i)
Get the name of an NPC.
Definition npc.c:504
void npc_sort(void)
Sorts the NPCs.
Definition npc.c:356
int scnprintf(char *text, size_t maxlen, const char *fmt,...)
Like snprintf(), but returns the number of characters ACTUALLY "printed" into the buffer....
Definition nstring.c:99
ntime_t ntime_create(int scu, int stp, int stu)
Creates a time structure.
Definition ntime.c:94
char * ntime_pretty(ntime_t t, int d)
Gets the time in a pretty human readable format.
Definition ntime.c:173
void ntime_inc(ntime_t t)
Sets the time relatively.
Definition ntime.c:236
glTexture * gl_dupTexture(const glTexture *texture)
Duplicates a texture.
Definition opengl_tex.c:917
glTexture ** gl_addTexArray(glTexture **tex, glTexture *t)
Adds an element to a texture array.
glTexture * gl_newImage(const char *path, const unsigned int flags)
Loads an image as a texture.
Definition opengl_tex.c:675
void gl_freeTexture(glTexture *texture)
Frees a texture.
Definition opengl_tex.c:862
const Outfit * outfit_get(const char *name)
Gets an outfit by name.
Definition outfit.c:166
void pilots_clean(int persist)
Cleans up the pilot stack - leaves the player.
Definition pilot.c:3696
void pilot_setAccel(Pilot *p, double accel)
Sets the pilot's accel.
Definition pilot.c:659
void pilot_setTurn(Pilot *p, double turn)
Sets the pilot's turn.
Definition pilot.c:667
Pilot *const * pilot_getAll(void)
Gets the pilot stack.
Definition pilot.c:94
void pilot_heatReset(Pilot *p)
Resets a pilot's heat.
Definition pilot_heat.c:101
void pilot_healLanded(Pilot *pilot)
Cures the pilot as if he was landed.
void pilot_outfitLOntakeoff(Pilot *pilot)
Runs Lua outfits when pilot takes off from a spob.
void pilot_calcStats(Pilot *pilot)
Recalculates the pilot's stats based on his outfits.
int pilot_reportSpaceworthy(const Pilot *p, char *buf, int bufSize)
Pilot safety report - makes sure stats are safe.
void pilot_outfitLOnland(Pilot *pilot)
Runs Lua outfits when pilot lands on a spob.
int pilot_isSpaceworthy(const Pilot *p)
Pilot safety check - makes sure stats are safe.
void pilot_outfitLInitAll(Pilot *pilot)
Runs the pilot's Lua outfits init script.
int player_addOutfit(const Outfit *o, int quantity)
Adds an outfit to the player outfit stack.
Definition player.c:2828
void player_warp(double x, double y)
Warps the player to the new position.
Definition player.c:935
const PlayerShip_t * player_getShipStack(void)
Gets the array (array.h) of the player's ships.
Definition player.c:2644
void player_hyperspacePreempt(int preempt)
Enables or disables jump points preempting spobs in autoface and target clearing.
Definition player.c:1893
double player_dt_default(void)
Returns the player's total default time delta based on time dilation stuff.
Definition player.c:1913
int player_addEscorts(void)
Adds the player's escorts.
Definition player.c:3117
void player_soundStop(void)
Stops playing player sounds.
Definition player.c:894
credits_t player_modCredits(credits_t amount)
Modifies the amount of credits the player has.
Definition player.c:975
void player_targetSpobSet(int id)
Sets the player's target spob.
Definition player.c:1485
Player_t player
Definition player.c:74
void player_autonavResetSpeed(void)
Resets the game speed.
void player_autonavStart(void)
Starts autonav.
void pfleet_update(void)
Updates the used fleet capacity of the player.
int save_all(void)
Saves the current game.
Definition save.c:94
void sound_stopAll(void)
Stops all the playing voices.
Definition sound.c:1044
void space_init(const char *sysname, int do_simulate)
Initializes the system.
Definition space.c:1549
StarSystem * cur_system
Definition space.c:106
void spob_updateLand(Spob *p)
Updates the land possibilities of a spob.
Definition space.c:1943
const char * spob_name(const Spob *p)
Gets the translated name of a spob.
Definition space.c:1752
const char * spob_getClassName(const char *class)
Gets the long class name for a spob.
Definition space.c:215
const char * space_populationStr(const Spob *spb)
Gets the population in an approximated string. Note this function changes the string value each call,...
Definition space.c:4375
void space_clearComputerMarkers(void)
Clears all the system computer markers.
Definition space.c:3716
Represents an active mission.
Definition mission.h:81
char * reward
Definition mission.h:88
char * desc
Definition mission.h:87
char * title
Definition mission.h:86
A ship outfit, depends radically on the type.
Definition outfit.h:328
credits_t price
Definition outfit.h:347
The representation of an in-game pilot.
Definition pilot.h:217
ShipStats stats
Definition pilot.h:294
unsigned int id
Definition pilot.h:218
credits_t credits
Definition pilot.h:325
int nav_hyperspace
Definition pilot.h:345
double fuel_max
Definition pilot.h:259
Solid solid
Definition pilot.h:227
double fuel
Definition pilot.h:260
char * name
Definition pilot.h:219
int cargo_free
Definition pilot.h:327
int nav_spob
Definition pilot.h:344
Effect * effects
Definition pilot.h:297
char * comm_msg
Definition pilot.h:364
int devmode
Definition conf.h:157
Player ship.
Definition player.h:73
int deployed
Definition player.h:80
unsigned int landed_times
Definition player.h:92
Pilot * p
Definition player.h:74
Pilot * p
Definition player.h:101
PlayerShip_t ps
Definition player.h:102
int fleet_used
Definition player.h:125
int fleet_capacity
Definition player.h:126
unsigned int landed_times
Definition player.h:138
double land_delay
Definition shipstats.h:237
vec2 vel
Definition physics.h:48
double dir
Definition physics.h:46
int faction
Definition space.h:67
Represents a Space Object (SPOB), including and not limited to planets, stations, wormholes,...
Definition space.h:89
unsigned int services
Definition space.h:115
double radius
Definition space.h:95
char * bar_description
Definition space.h:114
char * description
Definition space.h:113
char * class
Definition space.h:100
char ** tags
Definition space.h:130
vec2 pos
Definition space.h:94
SpobPresence presence
Definition space.h:104
int h
Definition font.h:18
Abstraction for rendering sprite sheets.
Definition opengl_tex.h:36
double w
Definition opengl_tex.h:40
double h
Definition opengl_tex.h:41
double y
Definition vec2.h:34
double x
Definition vec2.h:33
unsigned int window_create(const char *name, const char *displayname, const int x, const int y, const int w, const int h)
Creates a window.
Definition toolkit.c:691
void window_setFocus(unsigned int wid, const char *wgtname)
Sets the focused widget in a window.
Definition toolkit.c:2471
void window_setAccept(unsigned int wid, void(*accept)(unsigned int, const char *))
Sets the default accept function of the window.
Definition toolkit.c:847
void window_dimWindow(unsigned int wid, int *w, int *h)
Gets the dimensions of a window.
Definition toolkit.c:371
void window_onClose(unsigned int wid, void(*fptr)(unsigned int, const char *))
Sets the default close function of the window.
Definition toolkit.c:826
void window_destroyWidget(unsigned int wid, const char *wgtname)
Destroys a widget in a window.
Definition toolkit.c:1165
void window_lower(unsigned int wid)
Lowers a window (causes all other windows to appear above it).
Definition toolkit.c:2560
int widget_exists(unsigned int wid, const char *wgtname)
Checks to see if a widget exists.
Definition toolkit.c:1142
void window_destroy(unsigned int wid)
Kills the window.
Definition toolkit.c:1037