naev 0.11.5
load.c
Go to the documentation of this file.
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
11#include "physfs.h"
12
13#include "naev.h"
16#include "load.h"
17
18#include "array.h"
19#include "dialogue.h"
20#include "economy.h"
21#include "event.h"
22#include "faction.h"
23#include "difficulty.h"
24#include "gui.h"
25#include "hook.h"
26#include "land.h"
27#include "log.h"
28#include "menu.h"
29#include "mission.h"
30#include "news.h"
31#include "ndata.h"
32#include "nlua_var.h"
33#include "nstring.h"
34#include "nxml.h"
35#include "outfit.h"
36#include "player.h"
37#include "plugin.h"
38#include "render.h"
39#include "save.h"
40#include "shiplog.h"
41#include "start.h"
42#include "space.h"
43#include "toolkit.h"
44#include "unidiff.h"
45
46#define LOAD_WIDTH 600
47#define LOAD_HEIGHT 530
49#define BUTTON_WIDTH 120
50#define BUTTON_HEIGHT 30
52typedef struct player_saves_s {
53 char *name;
54 nsave_t *saves;
56
57static player_saves_t *load_saves = NULL;
59static int old_saves_detected = 0, player_warned = 0;
60static char *selected_player = NULL;
61extern int save_loaded;
63/*
64 * Prototypes.
65 */
66/* externs */
67/* player.c */
68extern Spob* player_load( xmlNodePtr parent );
69/* event.c */
70extern int events_loadActive( xmlNodePtr parent );
71/* news.c */
72extern int news_loadArticles( xmlNodePtr parent );
73/* nlua_var.c */
74extern int var_load( xmlNodePtr parent );
75/* faction.c */
76extern int pfaction_load( xmlNodePtr parent );
77/* hook.c */
78extern int hook_load( xmlNodePtr parent );
79/* space.c */
80extern int space_sysLoad( xmlNodePtr parent );
81/* economy.c */
82extern int economy_sysLoad( xmlNodePtr parent );
83/* unidiff.c */
84extern int diff_load( xmlNodePtr parent );
85/* static */
86static void load_menu_update( unsigned int wid, const char *str );
87static void load_menu_close( unsigned int wdw, const char *str );
88static void load_menu_load( unsigned int wdw, const char *str );
89static void load_menu_delete( unsigned int wdw, const char *str );
90static void load_menu_snapshots( unsigned int wdw, const char *str );
91static void load_snapshot_menu_update( unsigned int wid, const char *str );
92static void load_snapshot_menu_close( unsigned int wdw, const char *str );
93static void load_snapshot_menu_onClose( unsigned int wid, const char *str );
94static void load_snapshot_menu_load( unsigned int wdw, const char *str );
95static void load_snapshot_menu_delete( unsigned int wdw, const char *str );
96static void load_snapshot_menu_save( unsigned int wdw, const char *str );
97static void display_save_info( unsigned int wid, const nsave_t *ns );
98static void move_old_save( const char *path, const char *fname, const char *ext, const char *new_name );
99static int load_load( nsave_t *save, const char *path );
100static int load_game( const nsave_t *ns );
101static int load_gameInternal( const char* file, const char* version );
102static int load_gameInternalHook( void *data );
103static int load_enumerateCallback( void* data, const char* origdir, const char* fname );
104static int load_enumerateCallbackPlayer( void* data, const char* origdir, const char* fname );
105static int load_compatibilityTest( const nsave_t *ns );
106static const char* load_compatibilityString( const nsave_t *ns );
107static SaveCompatibility load_compatibility( const nsave_t *ns );
108static int load_sortComparePlayers( const void *p1, const void *p2 );
109static int load_sortCompare( const void *p1, const void *p2 );
110static xmlDocPtr load_xml_parsePhysFS( const char* filename );
111
118static int load_load( nsave_t *save, const char *path )
119{
120 xmlDocPtr doc;
121 xmlNodePtr root, parent, node, cur;
122 int cycles, periods, seconds;
123
124 memset( save, 0, sizeof(nsave_t) );
125
126 /* Load the XML. */
127 doc = load_xml_parsePhysFS( path );
128 if (doc == NULL) {
129 WARN( _("Unable to parse save path '%s'."), path);
130 return -1;
131 }
132 root = doc->xmlChildrenNode; /* base node */
133 if (root == NULL) {
134 WARN( _("Unable to get child node of save '%s'."), path);
135 xmlFreeDoc(doc);
136 return -1;
137 }
138
139 /* Save path. */
140 save->path = strdup(path);
141
142 /* Iterate inside the naev_save. */
143 parent = root->xmlChildrenNode;
144 do {
145 xml_onlyNodes(parent);
146
147 /* Info. */
148 if (xml_isNode(parent, "version")) {
149 node = parent->xmlChildrenNode;
150 do {
151 xmlr_strd(node, "naev", save->version);
152 xmlr_strd(node, "data", save->data);
153 } while (xml_nextNode(node));
154 continue;
155 }
156
157 else if (xml_isNode(parent, "player")) {
158 /* Get name. */
159 xmlr_attr_strd(parent, "name", save->player_name);
160 /* Parse rest. */
161 node = parent->xmlChildrenNode;
162 do {
163 xml_onlyNodes(node);
164
165 /* Player info. */
166 xmlr_strd(node, "location", save->spob);
167 xmlr_ulong(node, "credits", save->credits);
168 xmlr_strd(node, "chapter", save->chapter);
169 xmlr_strd(node, "difficulty", save->difficulty);
170
171 /* Time. */
172 if (xml_isNode(node, "time")) {
173 cur = node->xmlChildrenNode;
174 cycles = periods = seconds = 0;
175 do {
176 xmlr_int(cur, "SCU", cycles);
177 xmlr_int(cur, "STP", periods);
178 xmlr_int(cur, "STU", seconds);
179 } while (xml_nextNode(cur));
180 save->date = ntime_create( cycles, periods, seconds );
181 continue;
182 }
183
184 /* Ship info. */
185 if (xml_isNode(node, "ship")) {
186 xmlr_attr_strd(node, "name", save->shipname);
187 xmlr_attr_strd(node, "model", save->shipmodel);
188 continue;
189 }
190 } while (xml_nextNode(node));
191 continue;
192 }
193 else if (xml_isNode(parent, "plugins")) {
194 save->plugins = array_create( char* );
195 /* Parse rest. */
196 node = parent->xmlChildrenNode;
197 do {
198 xml_onlyNodes(node);
199
200 if (xml_isNode(node, "plugin")) {
201 const char *name = xml_get(node);
202 if (name != NULL)
203 array_push_back( &save->plugins, strdup(name) );
204 else
205 WARN(_("Save '%s' has unnamed plugin node!"), path);
206 }
207 } while (xml_nextNode(node));
208 continue;
209 }
210 } while (xml_nextNode(parent));
211
212 /* Defaults. */
213 if (save->chapter==NULL)
214 save->chapter = strdup( start_chapter() );
215
216 save->compatible = load_compatibility( save );
217
218 /* Clean up. */
219 xmlFreeDoc(doc);
220
221 return 0;
222}
223
227int load_refresh (void)
228{
229 if (load_saves != NULL)
230 load_free();
231
232 /* load the saves */
234 PHYSFS_enumerate( "saves", load_enumerateCallback, NULL );
236
237 return 0;
238}
239
240static int load_enumerateCallbackPlayer( void* data, const char* origdir, const char* fname )
241{
242 char *path;
243 const char *fmt;
244 size_t dir_len;
245 PHYSFS_Stat stat;
246
247 dir_len = strlen( origdir );
248
249 fmt = dir_len && origdir[dir_len-1]=='/' ? "%s%s" : "%s/%s";
250 SDL_asprintf( &path, fmt, origdir, fname );
251 if (!PHYSFS_stat( path, &stat ))
252 WARN( _("PhysicsFS: Cannot stat %s: %s"), path,
253 _(PHYSFS_getErrorByCode( PHYSFS_getLastErrorCode() ) ) );
254 /* TODO remove this sometime in the future. Maybe 0.12.0 or 0.13.0? */
255 else if (stat.filetype == PHYSFS_FILETYPE_REGULAR) {
256 player_saves_t *ps = (player_saves_t*) data;
257 nsave_t ns;
258 int ret = load_load( &ns, path );
259 if (ret == 0) {
260 ns.save_name = strdup( fname );
261 ns.save_name[ strlen(ns.save_name)-3 ] = '\0';
262 ns.modtime = stat.modtime;
263 array_push_back( &ps->saves, ns );
264 if (ps->name == NULL)
265 ps->name = strdup( ns.player_name );
266 }
267 }
268
269 free( path );
270 return PHYSFS_ENUM_OK;
271}
272
276static int load_enumerateCallback( void* data, const char* origdir, const char* fname )
277{
278 (void) data;
279 char *path, *backup_path;
280 const char *fmt;
281 size_t dir_len, name_len;
282 PHYSFS_Stat stat;
283
284 dir_len = strlen( origdir );
285 name_len = strlen( fname );
286
287 fmt = dir_len && origdir[dir_len-1]=='/' ? "%s%s" : "%s/%s";
288 SDL_asprintf( &path, fmt, origdir, fname );
289 if (!PHYSFS_stat( path, &stat ))
290 WARN( _("PhysicsFS: Cannot stat %s: %s"), path,
291 _(PHYSFS_getErrorByCode( PHYSFS_getLastErrorCode() ) ) );
292 /* TODO remove this sometime in the future. Maybe 0.12.0 or 0.13.0? */
293 else if (stat.filetype == PHYSFS_FILETYPE_REGULAR) {
294 if ((name_len < 4 || strcmp( &fname[name_len-3], ".ns" )) && (name_len < 11 || strcmp( &fname[name_len-10], ".ns.backup" ))) {
295 free( path );
296 return PHYSFS_ENUM_OK;
297 }
298 if (!PHYSFS_exists( "saves-pre-0.10.0" ))
299 PHYSFS_mkdir( "saves-pre-0.10.0" );
300 SDL_asprintf( &backup_path, "saves-pre-0.10.0/%s", fname );
301 if (!ndata_copyIfExists( path, backup_path ))
302 old_saves_detected = 1;
303 free( backup_path );
304 move_old_save( path, fname, ".ns", "autosave.ns" );
305 move_old_save( path, fname, ".ns.backup", "backup.ns" );
306 }
307 else if (stat.filetype == PHYSFS_FILETYPE_DIRECTORY) {
308 player_saves_t psave;
309 psave.name = NULL;
310 psave.saves = array_create( nsave_t );
311 PHYSFS_enumerate( path, load_enumerateCallbackPlayer, &psave );
312 if (psave.name!=NULL) {
313 qsort( psave.saves, array_size(psave.saves), sizeof(nsave_t), load_sortCompare );
314 array_push_back( &load_saves, psave );
315 }
316 else
317 array_free( psave.saves );
318 }
319
320 free( path );
321 return PHYSFS_ENUM_OK;
322}
323
324static int load_compatibilityTest( const nsave_t *ns )
325{
326 char buf[STRMAX], buf2[STRMAX];
327 const plugin_t *plugins = plugin_list();
328 int l;
329
330 switch (ns->compatible) {
331 case SAVE_COMPATIBILITY_NAEV_VERSION:
332 if (!dialogue_YesNo( _("Save game version mismatch"),
333 _("Save game '%s' version does not match Naev version:\n"
334 " Save version: #r%s#0\n"
335 " Naev version: %s\n"
336 "Are you sure you want to load this game? It may lose data."),
337 ns->player_name, ns->version, naev_version( 0 ) ))
338 return -1;
339 break;
340
341 case SAVE_COMPATIBILITY_PLUGINS:
342 buf[0] = '\0';
343 l = 0;
344 for (int i=0; i<array_size(ns->plugins); i++)
345 l += scnprintf( &buf[l], sizeof(buf)-l, "%s%s", (l>0)?p_("plugins", ", "):"#r", ns->plugins[i] );
346 l += scnprintf( &buf[l], sizeof(buf)-l, "#0" );
347 buf2[0] = '\0';
348 l = 0;
349 for (int i=0; i<array_size(plugins); i++)
350 l += scnprintf( &buf2[l], sizeof(buf2)-l, "%s%s", (l>0)?p_("plugins", ", "):"", plugin_name(&plugins[i]) );
351 if (!dialogue_YesNo( _("Save game plugin mismatch"),
352 _("Save game '%s' plugins do not match loaded plugins:\n"
353 " Save plugins: %s\n"
354 " Naev plugins: %s\n"
355 "Are you sure you want to load this game? It may lose data."),
356 ns->player_name, buf, buf2 ) )
357 return -1;
358 break;
359
360 case SAVE_COMPATIBILITY_OK:
361 break;
362 }
363
364 return 0;
365}
366
367static const char* load_compatibilityString( const nsave_t *ns )
368{
369 switch (ns->compatible) {
370 case SAVE_COMPATIBILITY_NAEV_VERSION:
371 return _("version mismatch");
372
373 case SAVE_COMPATIBILITY_PLUGINS:
374 return _("plugins mismatch");
375
376 case SAVE_COMPATIBILITY_OK:
377 return _("compatible");
378 }
379 return NULL;
380}
381
385static SaveCompatibility load_compatibility( const nsave_t *ns )
386{
387 int diff = naev_versionCompare( ns->version );
388 const plugin_t *plugins = plugin_list();
389
390 if (ABS(diff) >= 2)
391 return SAVE_COMPATIBILITY_NAEV_VERSION;
392
393 for (int i=0; i<array_size(ns->plugins); i++) {
394 int found = 0;
395 for (int j=0; j<array_size(plugins); j++) {
396 if (strcmp( ns->plugins[i], plugin_name(&plugins[j]) )==0) {
397 found = 1;
398 break;
399 }
400 }
401 if (!found)
402 return SAVE_COMPATIBILITY_PLUGINS;
403 }
404
405 return SAVE_COMPATIBILITY_OK;
406}
407
411static int load_sortComparePlayers( const void *p1, const void *p2 )
412{
413 const player_saves_t *ps1, *ps2;
414 ps1 = (const player_saves_t*) p1;
415 ps2 = (const player_saves_t*) p2;
416 return load_sortCompare( &ps1->saves[0], &ps2->saves[0] );
417}
418
422static int load_sortCompare( const void *p1, const void *p2 )
423{
424 const nsave_t *ns1, *ns2;
425 ns1 = (const nsave_t*) p1;
426 ns2 = (const nsave_t*) p2;
427
428 /* Sort by compatibility first. */
429 if (!ns1->compatible && ns2->compatible)
430 return -1;
431 else if (ns1->compatible && !ns2->compatible)
432 return +1;
433
434 /* Search by file modification date. */
435 if (ns1->modtime > ns2->modtime)
436 return -1;
437 else if (ns1->modtime < ns2->modtime)
438 return +1;
439
440 /* Finally sort by name. */
441 return strcmp( ns1->save_name, ns2->save_name );
442}
443
447void load_free (void)
448{
449 for (int i=0; i<array_size(load_saves); i++) {
450 player_saves_t *ps = &load_saves[i];
451 free( ps->name );
452 for (int j=0; j<array_size(ps->saves); j++) {
453 nsave_t *ns = &ps->saves[j];
454 for (int k=0; k<array_size(ns->plugins); k++)
455 free( ns->plugins[k] );
456 array_free( ns->plugins );
457 free(ns->save_name);
458 free(ns->player_name);
459 free(ns->path);
460 free(ns->version);
461 free(ns->data);
462 free(ns->spob);
463 free(ns->chapter);
464 free(ns->difficulty);
465 free(ns->shipname);
466 free(ns->shipmodel);
467 }
468 array_free( ps->saves );
469 }
471 load_saves = NULL;
472}
473
477const nsave_t *load_getList( const char *name )
478{
480 return NULL;
481 if (name==NULL)
482 return load_saves[0].saves;
483 for (int i=0; i<array_size(load_saves); i++)
484 if (strcmp(load_saves[i].name,name)==0)
485 return load_saves[i].saves;
486 return NULL;
487}
488
493{
494 unsigned int wid;
495 char **names;
496 int n;
497 int pos = 0;
498
499 /* window */
500 wid = window_create( "wdwLoadGameMenu", _("Load Pilot"), -1, -1, LOAD_WIDTH, LOAD_HEIGHT );
503
504 load_refresh();
505
506 n = array_size( load_saves );
507 if (n > 0) {
508 names = malloc( sizeof(char*)*n );
509 for (int i=0; i<n; i++) {
510 nsave_t *ns = &load_saves[i].saves[0];
511 if (ns->compatible) {
512 char buf[STRMAX_SHORT];
513 scnprintf( buf, sizeof(buf), _("%s (#r%s#0)"),
514 ns->player_name, load_compatibilityString( ns ) );
515 names[i] = strdup( buf );
516 }
517 else
518 names[i] = strdup( ns->player_name );
519 if (selected_player != NULL && !strcmp( names[i], selected_player ))
520 pos = i;
521 }
522 }
523 /* case there are no players */
524 else {
525 names = malloc(sizeof(char*));
526 names[0] = strdup(_("None"));
527 n = 1;
528 }
529
530 /* Player text. */
531 window_addText( wid, -20, -40, BUTTON_WIDTH*2+20, LOAD_HEIGHT-40-20-2*(BUTTON_HEIGHT+20),
532 0, "txtPilot", &gl_smallFont, NULL, NULL );
533
534 window_addList( wid, 20, -40,
536 "lstNames", names, n, pos, load_menu_update, load_menu_load );
537
538 /* Buttons */
539 window_addButtonKey( wid, -20, 20, BUTTON_WIDTH, BUTTON_HEIGHT,
540 "btnBack", _("Back"), load_menu_close, SDLK_b );
541 window_addButtonKey( wid, -20-BUTTON_WIDTH-20, 20 + BUTTON_HEIGHT+15, BUTTON_WIDTH, BUTTON_HEIGHT,
542 "btnSnapshots", _("Snapshots"), load_menu_snapshots, SDLK_s );
543 window_addButtonKey( wid, -20, 20 + BUTTON_HEIGHT+15, BUTTON_WIDTH, BUTTON_HEIGHT,
544 "btnLoad", _("Load"), load_menu_load, SDLK_l );
545 window_addButton( wid, 20, 20, BUTTON_WIDTH, BUTTON_HEIGHT,
546 "btnDelete", _("Delete"), load_menu_delete );
547
548 if (old_saves_detected && !player_warned) {
549 char buf[STRMAX_SHORT];
550 snprintf( buf, sizeof(buf), "%s%s", PHYSFS_getRealDir("saves-pre-0.10.0"), "saves-pre-0.10.0" );
551 dialogue_alert( _("Naev has detected saves in pre-0.10.0 format, and has automatically migrated them to the new format. Old saves have been backed up at '%s'."), buf );
552 player_warned = 1;
553 }
554}
555
556static void load_snapshot_menu_onClose( unsigned int wid, const char *str )
557{
558 (void) str;
559 free( window_getData( wid ) );
560}
561
567void load_loadSnapshotMenu( const char *name, int disablesave )
568{
569 unsigned int wid;
570 char **names;
571 player_saves_t *ps;
572 int n;
573 char *t;
574 int *data;
575
576 ps = NULL;
577 for (int i=0; i<array_size(load_saves); i++) {
578 if (strcmp(load_saves[i].name, name)==0) {
579 ps = &load_saves[i];
580 break;
581 }
582 }
583 if (ps==NULL) {
584 WARN(_("Player '%s' not found in list of saves!"),name);
585 return;
586 }
587 load_player = ps;
588
589 t = strdup( name );
590 free( selected_player );
591 selected_player = t;
592
593 /* window */
594 wid = window_create( "wdwLoadSnapshotMenu", _("Load Snapshot"), -1, -1, LOAD_WIDTH, LOAD_HEIGHT );
597
598 data = malloc( sizeof( int ) );
599 *data = disablesave;
600 window_setData( wid, data );
601 window_onClose( wid, load_snapshot_menu_onClose );
602
603 /* load the saves */
604 n = array_size( ps->saves );
605 if (n > 0) {
606 names = malloc( sizeof(char*)*n );
607 for (int i=0; i<n; i++) {
608 nsave_t *ns = &ps->saves[i];
609 if (ns->compatible) {
610 char buf[STRMAX_SHORT];
611 scnprintf( buf, sizeof(buf), _("%s (#r%s#0)"),
612 ns->save_name, load_compatibilityString( ns ) );
613 names[i] = strdup( buf );
614 }
615 else
616 names[i] = strdup( ns->save_name );
617 }
618 }
619 /* case there are no files */
620 else {
621 names = malloc(sizeof(char*));
622 names[0] = strdup(_("None"));
623 n = 1;
624 }
625
626 /* Player text. */
627 window_addText( wid, -20, -40, BUTTON_WIDTH*2+20, LOAD_HEIGHT-40-20-2*(BUTTON_HEIGHT+20),
628 0, "txtPilot", &gl_smallFont, NULL, NULL );
629
630 window_addList( wid, 20, -40,
632 "lstSaves", names, n, 0, load_snapshot_menu_update, load_snapshot_menu_load );
633
634 /* Buttons */
635 window_addButtonKey( wid, -20, 20, BUTTON_WIDTH, BUTTON_HEIGHT,
636 "btnBack", _("Back"), load_snapshot_menu_close, SDLK_b );
637 window_addButtonKey( wid, -20-BUTTON_WIDTH-20, 20 + BUTTON_HEIGHT+15, BUTTON_WIDTH, BUTTON_HEIGHT,
638 "btnSave", _("Save As"), load_snapshot_menu_save, SDLK_s );
639 window_addButtonKey( wid, -20, 20 + BUTTON_HEIGHT+15, BUTTON_WIDTH, BUTTON_HEIGHT,
640 "btnLoad", _("Load"), load_snapshot_menu_load, SDLK_l );
641 window_addButton( wid, 20, 20, BUTTON_WIDTH, BUTTON_HEIGHT,
642 "btnDelete", _("Delete"), load_snapshot_menu_delete );
643
644 if (disablesave || window_exists( "wdwLoadGameMenu" ))
645 window_disableButton( wid, "btnSave" );
646 else {
647 int can_save = landed && !player_isFlag(PLAYER_NOSAVE);
648 if (!can_save)
649 window_disableButton( wid, "btnSave" );
650 }
651}
652
658static void load_menu_snapshots( unsigned int wdw, const char *str )
659{
660 (void) str;
661 int pos;
662
663 pos = toolkit_getListPos( wdw, "lstNames" );
664 if (array_size(load_saves) <= 0)
665 return;
666 load_loadSnapshotMenu( load_saves[pos].name, 1 );
667}
668
674static void load_snapshot_menu_save( unsigned int wdw, const char *str )
675{
676 char *save_name = dialogue_input( _("Save game"), 1, 60, _("Please give the new snapshot a name:") );
677 if (save_name == NULL)
678 return;
679 char path[PATH_MAX];
680 snprintf(path, sizeof(path), "saves/%s/%s.ns", player.name, save_name);
681 if (PHYSFS_exists( path )) {
682 int r = dialogue_YesNo(_("Overwrite"),
683 _("You already have a snapshot named '%s'. Overwrite?"), save_name);
684 if (r==0) {
685 load_snapshot_menu_save( wdw, str );
686 free( save_name );
687 return;
688 }
689 }
690 if (save_all_with_name(save_name) < 0)
691 dialogue_alert( _("Failed to save the game! You should exit and check the log to see what happened and then file a bug report!") );
692 else {
693 load_refresh();
694 int disablesave = * (int *) window_getData( wdw );
695 load_snapshot_menu_close( wdw, str );
696 load_loadSnapshotMenu( player.name, disablesave );
697 }
698 free( save_name );
699}
700
706static void load_menu_close( unsigned int wdw, const char *str )
707{
708 (void)str;
709 window_destroy( wdw );
710}
711
717static void load_snapshot_menu_close( unsigned int wdw, const char *str )
718{
719 (void)str;
720 window_destroy( wdw );
721}
722
728static void display_save_info( unsigned int wid, const nsave_t *ns )
729{
730 char buf[STRMAX_SHORT], credits[ECON_CRED_STRLEN], date[64], difficulty[STRMAX_SHORT];
731 size_t l = 0;
732
733 if (ns->difficulty == NULL) {
734 const Difficulty *d = difficulty_cur();
735 snprintf( difficulty, sizeof(difficulty), _("%s (options)"), _(d->name) );
736 }
737 else
738 snprintf( difficulty, sizeof(difficulty), _("%s (this save)"), _(ns->difficulty) );
739
740 credits2str( credits, ns->credits, 2 );
741 ntime_prettyBuf( date, sizeof(date), ns->date, 2 );
742 l += scnprintf( &buf[l], sizeof(buf)-l, "#n%s", _("Name:") );
743 l += scnprintf( &buf[l], sizeof(buf)-l, "\n#0 %s", ns->player_name );
744 l += scnprintf( &buf[l], sizeof(buf)-l, "\n#n%s", _("Version:") );
745 if (ns->compatible == SAVE_COMPATIBILITY_NAEV_VERSION)
746 l += scnprintf( &buf[l], sizeof(buf)-l, "\n #r%s#0", ns->version );
747 else
748 l += scnprintf( &buf[l], sizeof(buf)-l, "\n#0 %s", ns->version );
749 l += scnprintf( &buf[l], sizeof(buf)-l, "\n#n%s", _("Difficulty:") );
750 l += scnprintf( &buf[l], sizeof(buf)-l, "\n#0 %s", difficulty );
751 l += scnprintf( &buf[l], sizeof(buf)-l, "\n#n%s", _("Date:") );
752 l += scnprintf( &buf[l], sizeof(buf)-l, "\n#0 %s", date );
753 l += scnprintf( &buf[l], sizeof(buf)-l, "\n#n%s", _("Chapter:") );
754 l += scnprintf( &buf[l], sizeof(buf)-l, "\n#0 %s", ns->chapter );
755 l += scnprintf( &buf[l], sizeof(buf)-l, "\n#n%s", _("Space Object:") );
756 l += scnprintf( &buf[l], sizeof(buf)-l, "\n#0 %s", _(ns->spob) );
757 l += scnprintf( &buf[l], sizeof(buf)-l, "\n#n%s", _("Credits:") );
758 l += scnprintf( &buf[l], sizeof(buf)-l, "\n#0 %s", credits );
759 l += scnprintf( &buf[l], sizeof(buf)-l, "\n#n%s", _("Ship Name:") );
760 l += scnprintf( &buf[l], sizeof(buf)-l, "\n#0 %s", ns->shipname );
761 l += scnprintf( &buf[l], sizeof(buf)-l, "\n#n%s", _("Ship Model:") );
762 /*l +=*/ scnprintf( &buf[l], sizeof(buf)-l, "\n#0 %s", _(ns->shipmodel) );
763 window_modifyText( wid, "txtPilot", buf );
764}
765
773static void move_old_save( const char *path, const char *fname, const char *ext, const char *new_name )
774{
775 size_t name_len = strlen(fname);
776 size_t ext_len = strlen(ext);
777 if (name_len >= ext_len + 1 && !strcmp( &fname[name_len - ext_len], ext )) {
778 char *dirname = strdup( fname );
779 dirname[name_len - ext_len] = '\0';
780 char *new_path;
781 SDL_asprintf( &new_path, "saves/%s", dirname );
782 if (!PHYSFS_exists( new_path ))
783 PHYSFS_mkdir( new_path );
784 free( new_path );
785 SDL_asprintf( &new_path, "saves/%s/%s", dirname, new_name );
786 /* If it's going to overwrite a file, try to back it up. */
787 if (PHYSFS_exists( new_path )) {
788 int tries = 0;
789 char *bkp_path;
790 SDL_asprintf( &bkp_path, "%s.bkp", new_path );
791 while (PHYSFS_exists(bkp_path) && (tries++ < 10)) {
792 char *bkp_bkp_path;
793 SDL_asprintf( &bkp_bkp_path, "%s.bkp", bkp_path );
794 free( bkp_path );
795 bkp_path = bkp_bkp_path;
796 }
797 ndata_copyIfExists( new_path, bkp_path );
798 free( bkp_path );
799 }
800 /* Copy over the old file. */
801 if (!ndata_copyIfExists( path, new_path ))
802 if (!PHYSFS_delete( path ))
803 dialogue_alert( _("Unable to delete %s"), path );
804 free( new_path );
805 free( dirname );
806 }
807}
808
814static void load_menu_update( unsigned int wid, const char *str )
815{
816 (void) str;
817 int pos;
818 const nsave_t *ns;
819
820 /* Make sure list is ok. */
821 if (array_size( load_saves ) <= 0)
822 return;
823
824 /* Get position. */
825 pos = toolkit_getListPos( wid, "lstNames" );
826
827 ns = &load_saves[pos].saves[0];
828 if (selected_player != NULL)
829 free( selected_player );
830 selected_player = strdup( load_saves[pos].name );
831
832 display_save_info( wid, ns );
833}
834
840static void load_snapshot_menu_update( unsigned int wid, const char *str )
841{
842 (void) str;
843 int pos;
844 nsave_t *ns;
845
846 /* Make sure list is ok. */
847 if (array_size( load_player->saves ) <= 0)
848 return;
849
850 /* Get position. */
851 pos = toolkit_getListPos( wid, "lstSaves" );
852 ns = &load_player->saves[pos];
853
854 display_save_info( wid, ns );
855}
856
862static void load_menu_load( unsigned int wdw, const char *str )
863{
864 (void) str;
865 int pos;
866 unsigned int wid;
867 nsave_t *ns;
868
869 wid = window_get( "wdwLoadGameMenu" );
870 pos = toolkit_getListPos( wid, "lstNames" );
871
872 if (array_size(load_saves) <= 0)
873 return;
874
875 ns = &load_saves[pos].saves[0];
876
877 /* Check version. */
878 if (load_compatibilityTest( ns ))
879 return;
880
881 /* Close menus before loading for proper rendering. */
882 load_menu_close(wdw, NULL);
883
884 /* Close the main menu. */
885 menu_main_close();
886
887 /* Try to load the game. */
888 if (load_game( ns )) {
889 /* Failed so reopen both. */
890 menu_main();
892 }
893}
894
900static void load_snapshot_menu_load( unsigned int wdw, const char *str )
901{
902 (void) str;
903 int wid, pos;
904
905 wid = window_get( "wdwLoadSnapshotMenu" );
906
907 if (array_size( load_player->saves ) <= 0)
908 return;
909
910 pos = toolkit_getListPos( wid, "lstSaves" );
911
912 /* Check version. */
913 if (load_compatibilityTest( &load_player->saves[pos] ))
914 return;
915
916 /* Close menus before loading for proper rendering. */
917 load_snapshot_menu_close(wdw, NULL);
918
919 if (window_exists( "wdwLoadGameMenu" )) {
920 /* Close the main and the load menu. */
921 load_menu_close( window_get( "wdwLoadGameMenu" ), NULL );
922 menu_main_close();
923 }
924 else
925 menu_small_close();
926
927 /* Try to load the game. */
928 if (load_game( &load_player->saves[pos] )) {
929 /* Failed so reopen both. */
930 /* TODO how to handle failure here? It can happen at many different points now. */
931 /*menu_main();
932 load_loadGameMenu();*/
933 }
934}
935
936static void load_menu_delete( unsigned int wdw, const char *str )
937{
938 unsigned int wid;
939 int n, pos;
940 char path[PATH_MAX];
941
942 wid = window_get( "wdwLoadGameMenu" );
943 pos = toolkit_getListPos( wid, "lstNames" );
944
945 if (array_size(load_saves) <= 0)
946 return;
947
948 if (dialogue_YesNo( _("Permanently Delete?"),
949 _("Are you sure you want to permanently delete the character '%s'?\n#rThis is an undoable action!#0"), load_saves[pos].name) == 0)
950 return;
951
952 /* Remove it. */
953 n = array_size( load_saves[pos].saves );
954 for (int i = 0; i < n; i++)
955 if (!PHYSFS_delete( load_saves[pos].saves[i].path ))
956 dialogue_alert( _("Unable to delete %s"), load_saves[pos].saves[i].path );
957 snprintf(path, sizeof(path), "saves/%s", load_saves[pos].name);
958 if (!PHYSFS_delete( path ))
959 dialogue_alert( _("Unable to delete '%s' directory"), load_saves[pos].name );
960
961 load_refresh();
962
963 /* need to reload the menu */
964 load_menu_close( wdw, str );
966}
967
973static void load_snapshot_menu_delete( unsigned int wdw, const char *str )
974{
975 unsigned int wid;
976 int pos, last_save;
977
978 wid = window_get( "wdwLoadSnapshotMenu" );
979
980 if (array_size(load_player->saves) <= 0)
981 return;
982
983 pos = toolkit_getListPos( wid, "lstSaves" );
984
985 if (dialogue_YesNo( _("Permanently Delete?"),
986 _("Are you sure you want to permanently delete the snapshot '%s'?\n#rThis is an undoable action!#0"), load_player->saves[pos].save_name) == 0)
987 return;
988
989 /* Remove it. */
990 if (!PHYSFS_delete( load_player->saves[pos].path ))
991 dialogue_alert( _("Unable to delete %s"), load_player->saves[pos].path );
992 last_save = (array_size(load_player->saves) <= 1);
993
994 /* Delete directory if all are gone. */
995 if (last_save) {
996 char path[PATH_MAX];
997 snprintf(path, sizeof(path), "saves/%s", load_player->name);
998 if (!PHYSFS_delete( path ))
999 dialogue_alert( _("Unable to delete '%s' directory"), load_player->name );
1000 }
1001
1002 load_refresh();
1003
1004 /* need to reload the menu */
1005 int disablesave = * (int *) window_getData( wdw );
1006 load_snapshot_menu_close( wdw, str );
1007 if (window_exists( "wdwLoadGameMenu" )) {
1008 wid = window_get( "wdwLoadGameMenu" );
1009 load_menu_close( wid, str );
1011 }
1012 if (!last_save)
1013 load_loadSnapshotMenu( selected_player, disablesave );
1014}
1015
1016static void load_compatSlots (void)
1017{
1018 /* Vars for loading old saves. */
1019 char **sships;
1020 glTexture **tships;
1021 int nships;
1022 Pilot *ship;
1023
1024 nships = player_nships();
1025 sships = malloc(nships * sizeof(char*));
1026 tships = malloc(nships * sizeof(glTexture*));
1027 nships = player_ships( sships, tships );
1028 ship = player.p;
1029 for (int i=-1; i<nships; i++) {
1030 if (i >= 0)
1031 ship = player_getShip( sships[i] );
1032 /* Remove all outfits. */
1033 for (int j=0; j<array_size(ship->outfits); j++) {
1034 ShipOutfitSlot *sslot;
1035
1036 if (ship->outfits[j]->outfit != NULL) {
1037 player_addOutfit( ship->outfits[j]->outfit, 1 );
1038 pilot_rmOutfitRaw( ship, ship->outfits[j] );
1039 }
1040
1041 /* Add default outfit. */
1042 sslot = ship->outfits[j]->sslot;
1043 if (sslot->data != NULL)
1044 pilot_addOutfitRaw( ship, sslot->data, ship->outfits[j] );
1045 }
1046
1047 pilot_calcStats( ship );
1048 }
1049
1050 /* Clean up. */
1051 for (int i=0; i<nships; i++)
1052 free(sships[i]);
1053 free(sships);
1054 free(tships);
1055}
1056
1063int load_gameDiff( const char* file )
1064{
1065 xmlNodePtr node;
1066 xmlDocPtr doc;
1067
1068 /* Make sure it exists. */
1069 if (!PHYSFS_exists( file )) {
1070 dialogue_alert( _("Saved game file seems to have been deleted.") );
1071 return -1;
1072 }
1073
1074 /* Load the XML. */
1075 doc = load_xml_parsePhysFS( file );
1076 if (doc == NULL)
1077 goto err;
1078 node = doc->xmlChildrenNode; /* base node */
1079 if (node == NULL)
1080 goto err_doc;
1081
1082 /* Diffs should be cleared automatically first. */
1083 diff_load(node);
1084
1085 /* Free. */
1086 xmlFreeDoc(doc);
1087
1088 return 0;
1089
1090err_doc:
1091 xmlFreeDoc(doc);
1092err:
1093 WARN( _("Saved game '%s' invalid!"), file);
1094 return -1;
1095}
1096
1103int load_gameFile( const char *file )
1104{
1105 return load_gameInternal( file, naev_version(0) );
1106}
1107
1114static int load_game( const nsave_t *ns )
1115{
1116 return load_gameInternal( ns->path, ns->version );
1117}
1118
1126static int load_gameInternal( const char* file, const char* version )
1127{
1128 const char** data;
1129
1130 /* Make sure it exists. */
1131 if (!PHYSFS_exists( file )) {
1132 dialogue_alert( _("Saved game file seems to have been deleted.") );
1133 return -1;
1134 }
1135
1136 /* Some global cleaning has to be done here. */
1138 hook_clear();
1139
1140 data = malloc( sizeof(const char*) * 2 );
1141 data[0] = file;
1142 data[1] = version;
1143 /* If the player isn't loaded, hooks aren't run so we can just go right away. */
1144 if ((player.p == NULL) || player_isFlag(PLAYER_DESTROYED)) /* same condition in hook.c */
1145 return load_gameInternalHook( data );
1146 else {
1147 /* Break out of potential inner loops. */
1148 SDL_Event event;
1149 SDL_memset( &event, 0, sizeof(event) );
1150 event.type = SDL_LOOPDONE;
1151 SDL_PushEvent( &event );
1152
1153 /* Delay one frame. */
1154 hook_addFunc( load_gameInternalHook, data, "safe" );
1155 }
1156 return 0;
1157}
1158
1162static int load_gameInternalHook( void *data )
1163{
1164 xmlNodePtr node;
1165 xmlDocPtr doc;
1166 Spob *pnt;
1167 int misn_failed = 0, evt_failed = 0;
1168 const char **sdata = data;
1169 const char *file = sdata[0];
1170 const char *version = sdata[1];
1171 int version_diff = (version!=NULL) ? naev_versionCompare(version) : 0;
1172 free(data);
1173
1174 /* Load the XML. */
1175 doc = load_xml_parsePhysFS( file );
1176 if (doc == NULL)
1177 goto err;
1178 node = doc->xmlChildrenNode; /* base node */
1179 if (node == NULL)
1180 goto err_doc;
1181
1182 /* Clean up possible stuff that should be cleaned. */
1185 render_postprocessCleanup();
1186
1187 /* Welcome message - must be before space_init. */
1188 player_message( _("#gWelcome to %s!"), APPNAME );
1189 player_message( "#g v%s", naev_version(0) );
1190
1191 /* Now begin to load. */
1192 diff_load(node); /* Must load first to work properly. */
1194 missions_loadCommodity(node); /* Must be loaded before player. */
1195 pfaction_load(node); /* Must be loaded before player so the messages show up properly. */
1196 pnt = player_load(node);
1197 player.loaded_version = strdup( (version!=NULL) ? version : naev_version(0) );
1198
1199 /* Sanitize for new version. */
1200 if (version_diff <= -2) {
1201 WARN( _("Old version detected. Sanitizing ships for slots") );
1202 load_compatSlots();
1203 }
1204
1205 /* Load more stuff. */
1206 space_sysLoad(node);
1207 var_load(node);
1208 misn_failed = missions_loadActive(node);
1209 evt_failed = events_loadActive(node);
1210 news_loadArticles( node );
1211 hook_load(node);
1212
1213 /* Initialize the economy. */
1214 economy_init();
1215 economy_sysLoad(node);
1216
1217 /* Initialise the ship log */
1218 shiplog_new();
1219 shiplog_load(node);
1220
1221 /* Check validity. */
1223
1224 /* Run the load event trigger. */
1225 events_trigger( EVENT_TRIGGER_LOAD );
1226
1227 /* Create escorts in space. */
1229
1230 /* Load the GUI. */
1231 if (gui_load( gui_pick() ))
1232 gui_load( start_gui() ); /* Failed so use fallback... */
1233
1234 /* Land the player. */
1235 land( pnt, 1 );
1236
1237 /* Sanitize the GUI. */
1238 gui_setCargo();
1239 gui_setShip();
1240
1241 xmlFreeDoc(doc);
1242
1243 if (misn_failed || evt_failed) {
1244 char buf[STRMAX];
1245 unsigned int l = 0;
1246 const char **misn_failed_str = mission_loadFailed();
1247 l += scnprintf( &buf[l], sizeof(buf)-l, _("Saved game '%s' failed to load some missions/events properly!"), file);
1248 if (misn_failed) {
1249 l += scnprintf( &buf[l], sizeof(buf)-l, _("\nIn particular, the following missions have failed to load and been removed:"));
1250 for (int i=0; i<array_size(misn_failed_str); i++)
1251 l += scnprintf( &buf[l], sizeof(buf)-l, _("\n #r%s#0"), misn_failed_str[i]);
1252 }
1253 /*l +=*/ scnprintf( &buf[l], sizeof(buf)-l, _("\nNote that, in general, you should be able to find the missions/events again and start them without penalty."));
1254 dialogue_alertRaw( buf );
1255 }
1256
1257 /* Set loaded. */
1258 save_loaded = 1;
1259
1260 return 0;
1261
1262err_doc:
1263 xmlFreeDoc(doc);
1264err:
1265 dialogue_alert( _("Saved game '%s' invalid!"), file);
1266 menu_main();
1267 return -1;
1268}
1269
1273static xmlDocPtr load_xml_parsePhysFS( const char* filename )
1274{
1275 char buf[PATH_MAX];
1276 snprintf( buf, sizeof(buf), "%s/%s", PHYSFS_getWriteDir(), filename );
1277 return xmlParseFile( buf );
1278}
Provides macros to work with dynamic arrays.
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
Definition array.h:158
static ALWAYS_INLINE int array_size(const void *array)
Returns number of elements in the array.
Definition array.h:168
#define array_push_back(ptr_array, element)
Adds a new element at the end of the array.
Definition array.h:129
#define array_create(basic_type)
Creates a new dynamic array of ‘basic_type’.
Definition array.h:93
void credits2str(char *str, credits_t credits, int decimals)
Converts credits to a usable string for displaying.
Definition commodity.c:59
void dialogue_alert(const char *fmt,...)
Displays an alert popup with only an ok button and a message.
Definition dialogue.c:132
char * dialogue_input(const char *title, int min, int max, const char *fmt,...)
Creates a dialogue that allows the player to write a message.
Definition dialogue.c:441
void dialogue_alertRaw(const char *msg)
Displays an alert popup with only an ok button and a message.
Definition dialogue.c:151
int dialogue_YesNo(const char *caption, const char *fmt,...)
Runs a dialogue with both yes and no options.
Definition dialogue.c:352
int economy_init(void)
Initializes the economy.
Definition economy.c:449
void event_checkValidity(void)
Checks the event validity and cleans up after them.
Definition event.c:792
void events_trigger(EventTrigger_t trigger)
Runs all the events matching a trigger.
Definition event.c:319
glFont gl_smallFont
Definition font.c:154
const char * gui_pick(void)
Determines which GUI should be used.
Definition gui.c:1844
int gui_load(const char *name)
Attempts to load the actual GUI.
Definition gui.c:1876
void gui_setShip(void)
Player just upgraded their ship or modified it.
Definition gui.c:1791
void player_message(const char *fmt,...)
Adds a mesg to the queue to be displayed on screen.
Definition gui.c:335
void gui_setCargo(void)
Player just changed their cargo.
Definition gui.c:1767
void hook_clear(void)
Clears the hooks.
Definition hook.c:1136
unsigned int hook_addFunc(int(*func)(void *), void *data, const char *stack)
Adds a function hook to be run.
Definition hook.c:594
int landed
Definition land.c:75
void land(Spob *p, int load)
Opens up all the land dialogue stuff.
Definition land.c:1124
#define LOAD_WIDTH
Definition load.c:46
static void load_menu_update(unsigned int wid, const char *str)
Updates the load menu.
Definition load.c:814
int news_loadArticles(xmlNodePtr parent)
Loads the player's active articles from a save, initilizes news.
Definition news.c:488
static void load_menu_close(unsigned int wdw, const char *str)
Closes the load game menu.
Definition load.c:706
static void load_menu_load(unsigned int wdw, const char *str)
Loads a new game.
Definition load.c:862
#define LOAD_HEIGHT
Definition load.c:47
int space_sysLoad(xmlNodePtr parent)
Loads player's space properties from an XML node.
Definition space.c:3938
static int load_gameInternal(const char *file, const char *version)
Actually loads a new game.
Definition load.c:1126
int diff_load(xmlNodePtr parent)
Loads the diffs.
Definition unidiff.c:1797
int events_loadActive(xmlNodePtr parent)
Loads the player's active events from a save.
Definition event.c:854
static int load_gameInternalHook(void *data)
Loads a game. Meant to be run in a function hook.
Definition load.c:1162
int economy_sysLoad(xmlNodePtr parent)
Loads player's economy properties from an XML node.
Definition economy.c:1001
int hook_load(xmlNodePtr parent)
Loads hooks for a player.
Definition hook.c:1232
static int load_sortCompare(const void *p1, const void *p2)
qsort compare function for files.
Definition load.c:422
static int load_load(nsave_t *save, const char *path)
Loads an individual save.
Definition load.c:118
int var_load(xmlNodePtr parent)
Loads the vars from XML file.
Definition nlua_var.c:85
static SaveCompatibility load_compatibility(const nsave_t *ns)
Checks to see if a save is compatible with current Naev.
Definition load.c:385
static void move_old_save(const char *path, const char *fname, const char *ext, const char *new_name)
Moves old Naev saves to subdirectories.
Definition load.c:773
void load_loadSnapshotMenu(const char *name, int disablesave)
Opens the load snapshot menu.
Definition load.c:567
int load_refresh(void)
Loads or refreshes saved games for the player.
Definition load.c:227
#define BUTTON_HEIGHT
Definition load.c:50
static void display_save_info(unsigned int wid, const nsave_t *ns)
Displays Naev save info.
Definition load.c:728
static void load_snapshot_menu_save(unsigned int wdw, const char *str)
Creates new custom snapshot.
Definition load.c:674
static int load_enumerateCallback(void *data, const char *origdir, const char *fname)
The PHYSFS_EnumerateCallback for load_refresh.
Definition load.c:276
static void load_menu_snapshots(unsigned int wdw, const char *str)
Opens the load snapshot menu.
Definition load.c:658
void load_loadGameMenu(void)
Opens the load game menu.
Definition load.c:492
static player_saves_t * load_saves
Definition load.c:57
static void load_snapshot_menu_load(unsigned int wdw, const char *str)
Loads a new game.
Definition load.c:900
void load_free(void)
Frees loaded save stuff.
Definition load.c:447
const nsave_t * load_getList(const char *name)
Gets the array (array.h) of loaded saves.
Definition load.c:477
static player_saves_t * load_player
Definition load.c:58
static void load_snapshot_menu_delete(unsigned int wdw, const char *str)
Deletes an old game.
Definition load.c:973
int pfaction_load(xmlNodePtr parent)
Loads the player's faction standings.
Definition faction.c:1791
static int load_game(const nsave_t *ns)
Actually loads a new game based on save structure.
Definition load.c:1114
static void load_snapshot_menu_close(unsigned int wdw, const char *str)
Closes the load snapshot menu.
Definition load.c:717
Spob * player_load(xmlNodePtr parent)
Loads the player stuff.
Definition player.c:3563
static xmlDocPtr load_xml_parsePhysFS(const char *filename)
Temporary (hopefully) wrapper around xml_parsePhysFS in support of gzipped XML (like ....
Definition load.c:1273
int load_gameFile(const char *file)
Loads the game from a file.
Definition load.c:1103
#define BUTTON_WIDTH
Definition load.c:49
int load_gameDiff(const char *file)
Loads the diffs from game file.
Definition load.c:1063
static void load_snapshot_menu_update(unsigned int wid, const char *str)
Updates the load snapshot menu.
Definition load.c:840
int save_loaded
Definition save.c:39
static int load_sortComparePlayers(const void *p1, const void *p2)
qsort compare function for files.
Definition load.c:411
Handles the important game menus.
int missions_loadActive(xmlNodePtr parent)
Loads the player's active missions from a save.
Definition mission.c:1477
int missions_loadCommodity(xmlNodePtr parent)
Loads the player's special mission commodities.
Definition mission.c:1400
int naev_versionCompare(const char *version)
Compares the version against the current naev version.
Definition naev.c:1120
Uint32 SDL_LOOPDONE
Definition naev.c:101
Header file with generic functions and naev-specifics.
#define APPNAME
Definition naev.h:34
const char * naev_version(int long_version)
Returns the version in a human readable string.
#define ABS(x)
Definition naev.h:36
#define PATH_MAX
Definition naev.h:50
int ndata_copyIfExists(const char *file1, const char *file2)
Copy a file, if it exists.
Definition ndata.c:303
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
void ntime_prettyBuf(char *str, int max, ntime_t t, int d)
Gets the time in a pretty human readable format filling a preset buffer.
Definition ntime.c:188
void pilot_calcStats(Pilot *pilot)
Recalculates the pilot's stats based on his outfits.
int pilot_rmOutfitRaw(Pilot *pilot, PilotOutfitSlot *s)
Removes an outfit from the pilot without doing any checks.
int pilot_addOutfitRaw(Pilot *pilot, const Outfit *outfit, PilotOutfitSlot *s)
Adds an outfit to the pilot, ignoring CPU or other limits.
int player_nships(void)
Gets the amount of ships player has in storage.
Definition player.c:2654
int player_ships(char **sships, glTexture **tships)
Returns a buffer with all the player's ships names.
Definition player.c:2627
int player_addOutfit(const Outfit *o, int quantity)
Adds an outfit to the player outfit stack.
Definition player.c:2828
void player_cleanup(void)
Cleans up player stuff like player_stack.
Definition player.c:730
int player_addEscorts(void)
Adds the player's escorts.
Definition player.c:3117
Player_t player
Definition player.c:74
Pilot * player_getShip(const char *shipname)
Gets a specific ship.
Definition player.c:2684
const char * plugin_name(const plugin_t *plg)
Tries to tget the name of a plugin.
Definition plugin.c:218
const plugin_t * plugin_list(void)
Returns the list of all the plugins.
Definition plugin.c:281
static const double d[]
Definition rng.c:273
int save_all_with_name(const char *name)
Saves the current game.
Definition save.c:105
void shiplog_new(void)
Set up the shiplog.
Definition shiplog.c:370
int shiplog_load(xmlNodePtr parent)
Loads the logfiile.
Definition shiplog.c:422
const char * start_chapter(void)
Gets the player's starting chapter.
Definition start.c:278
const char * start_gui(void)
Gets the module's starting ship was acquired.
Definition start.c:213
ShipOutfitSlot * sslot
Definition pilot.h:114
const Outfit * outfit
Definition pilot.h:112
The representation of an in-game pilot.
Definition pilot.h:217
PilotOutfitSlot ** outfits
Definition pilot.h:300
Pilot * p
Definition player.h:101
char * name
Definition player.h:103
char * loaded_version
Definition player.h:116
Ship outfit slot.
Definition ship.h:70
const Outfit * data
Definition ship.h:76
Represents a Space Object (SPOB), including and not limited to planets, stations, wormholes,...
Definition space.h:89
Abstraction for rendering sprite sheets.
Definition opengl_tex.h:36
A naev save.
Definition load.h:23
uint64_t credits
Definition load.h:40
char * shipmodel
Definition load.h:46
char * difficulty
Definition load.h:42
PHYSFS_sint64 modtime
Definition load.h:27
char * shipname
Definition load.h:45
char * player_name
Definition load.h:25
ntime_t date
Definition load.h:39
SaveCompatibility compatible
Definition load.h:35
char * path
Definition load.h:26
char * spob
Definition load.h:38
char * chapter
Definition load.h:41
char ** plugins
Definition load.h:34
char * version
Definition load.h:30
char * data
Definition load.h:31
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_setAccept(unsigned int wid, void(*accept)(unsigned int, const char *))
Sets the default accept function of the window.
Definition toolkit.c:847
void window_setCancel(unsigned int wid, void(*cancel)(unsigned int, const char *))
Sets the default cancel function of the window.
Definition toolkit.c:868
void toolkit_closeAll(void)
Closes all open toolkit windows.
Definition toolkit.c:1014
void window_onClose(unsigned int wid, void(*fptr)(unsigned int, const char *))
Sets the default close function of the window.
Definition toolkit.c:826
unsigned int window_get(const char *wdwname)
Gets the ID of a window.
Definition toolkit.c:666
void * window_getData(unsigned int wid)
Gets the custom data of a window.
Definition toolkit.c:922
void window_setData(unsigned int wid, void *data)
Sets custom data for a window.
Definition toolkit.c:905
int window_exists(const char *wdwname)
Checks to see if a window exists.
Definition toolkit.c:596
void window_destroy(unsigned int wid)
Kills the window.
Definition toolkit.c:1037
void unidiff_universeDefer(int enable)
Sets whether or not to defer universe change stuff.
Definition unidiff.c:1890