naev 0.10.4
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 "save.h"
39#include "shiplog.h"
40#include "start.h"
41#include "space.h"
42#include "toolkit.h"
43#include "unidiff.h"
44
45#define LOAD_WIDTH 600
46#define LOAD_HEIGHT 530
48#define BUTTON_WIDTH 120
49#define BUTTON_HEIGHT 30
54typedef struct filedata {
55 char *name;
56 PHYSFS_Stat stat;
58
59typedef struct player_saves_s {
60 char *name;
61 nsave_t *saves;
63
64static player_saves_t *load_saves = NULL;
66static int old_saves_detected = 0, player_warned = 0;
67static char *selected_player = NULL;
68extern int save_loaded;
70/*
71 * Prototypes.
72 */
73/* externs */
74/* player.c */
75extern Spob* player_load( xmlNodePtr parent );
76/* event.c */
77extern int events_loadActive( xmlNodePtr parent );
78/* news.c */
79extern int news_loadArticles( xmlNodePtr parent );
80/* nlua_var.c */
81extern int var_load( xmlNodePtr parent );
82/* faction.c */
83extern int pfaction_load( xmlNodePtr parent );
84/* hook.c */
85extern int hook_load( xmlNodePtr parent );
86/* space.c */
87extern int space_sysLoad( xmlNodePtr parent );
88/* economy.c */
89extern int economy_sysLoad( xmlNodePtr parent );
90/* unidiff.c */
91extern int diff_load( xmlNodePtr parent );
92/* static */
93static void load_menu_update( unsigned int wid, const char *str );
94static void load_menu_close( unsigned int wdw, const char *str );
95static void load_menu_load( unsigned int wdw, const char *str );
96static void load_menu_delete( unsigned int wdw, const char *str );
97static void load_menu_snapshots( unsigned int wdw, const char *str );
98static void load_snapshot_menu_update( unsigned int wid, const char *str );
99static void load_snapshot_menu_close( unsigned int wdw, const char *str );
100static void load_snapshot_menu_load( unsigned int wdw, const char *str );
101static void load_snapshot_menu_delete( unsigned int wdw, const char *str );
102static void load_snapshot_menu_save( unsigned int wdw, const char *str );
103static void display_save_info( unsigned int wid, const nsave_t *ns );
104static void move_old_save( const char *path, const char *fname, const char *ext, const char *new_name );
105static int load_load( nsave_t *save, const char *path );
106static int load_game( nsave_t *ns );
107static int load_gameInternal( const char* file, const char* version );
108static int load_gameInternalHook( void *data );
109static int load_enumerateCallback( void* data, const char* origdir, const char* fname );
110static int load_enumerateCallbackPlayer( void* data, const char* origdir, const char* fname );
111static int load_compatibilityTest( const nsave_t *ns );
112static const char* load_compatibilityString( const nsave_t *ns );
113static SaveCompatibility load_compatibility( const nsave_t *ns );
114static int load_sortComparePlayers( const void *p1, const void *p2 );
115static int load_sortCompare( const void *p1, const void *p2 );
116static xmlDocPtr load_xml_parsePhysFS( const char* filename );
117
124static int load_load( nsave_t *save, const char *path )
125{
126 xmlDocPtr doc;
127 xmlNodePtr root, parent, node, cur;
128 int cycles, periods, seconds;
129
130 memset( save, 0, sizeof(nsave_t) );
131
132 /* Load the XML. */
133 doc = load_xml_parsePhysFS( path );
134 if (doc == NULL) {
135 WARN( _("Unable to parse save path '%s'."), path);
136 return -1;
137 }
138 root = doc->xmlChildrenNode; /* base node */
139 if (root == NULL) {
140 WARN( _("Unable to get child node of save '%s'."), path);
141 xmlFreeDoc(doc);
142 return -1;
143 }
144
145 /* Save path. */
146 save->path = strdup(path);
147
148 /* Iterate inside the naev_save. */
149 parent = root->xmlChildrenNode;
150 do {
151 xml_onlyNodes(parent);
152
153 /* Info. */
154 if (xml_isNode(parent, "version")) {
155 node = parent->xmlChildrenNode;
156 do {
157 xmlr_strd(node, "naev", save->version);
158 xmlr_strd(node, "data", save->data);
159 } while (xml_nextNode(node));
160 continue;
161 }
162
163 else if (xml_isNode(parent, "player")) {
164 /* Get name. */
165 xmlr_attr_strd(parent, "name", save->player_name);
166 /* Parse rest. */
167 node = parent->xmlChildrenNode;
168 do {
169 xml_onlyNodes(node);
170
171 /* Player info. */
172 xmlr_strd(node, "location", save->spob);
173 xmlr_ulong(node, "credits", save->credits);
174 xmlr_strd(node, "chapter", save->chapter);
175 xmlr_strd(node, "difficulty", save->difficulty);
176
177 /* Time. */
178 if (xml_isNode(node, "time")) {
179 cur = node->xmlChildrenNode;
180 cycles = periods = seconds = 0;
181 do {
182 xmlr_int(cur, "SCU", cycles);
183 xmlr_int(cur, "STP", periods);
184 xmlr_int(cur, "STU", seconds);
185 } while (xml_nextNode(cur));
186 save->date = ntime_create( cycles, periods, seconds );
187 continue;
188 }
189
190 /* Ship info. */
191 if (xml_isNode(node, "ship")) {
192 xmlr_attr_strd(node, "name", save->shipname);
193 xmlr_attr_strd(node, "model", save->shipmodel);
194 continue;
195 }
196 } while (xml_nextNode(node));
197 continue;
198 }
199 else if (xml_isNode(parent, "plugins")) {
200 save->plugins = array_create( char* );
201 /* Parse rest. */
202 node = parent->xmlChildrenNode;
203 do {
204 xml_onlyNodes(node);
205
206 if (xml_isNode(node, "plugin")) {
207 const char *name = xml_get(node);
208 if (name != NULL)
209 array_push_back( &save->plugins, strdup(name) );
210 else
211 WARN(_("Save '%s' has unnamed plugin node!"), path);
212 }
213 } while (xml_nextNode(node));
214 continue;
215 }
216 } while (xml_nextNode(parent));
217
218 /* Defaults. */
219 if (save->chapter==NULL)
220 save->chapter = strdup( start_chapter() );
221
222 save->compatible = load_compatibility( save );
223
224 /* Clean up. */
225 xmlFreeDoc(doc);
226
227 return 0;
228}
229
233int load_refresh (void)
234{
235 if (load_saves != NULL)
236 load_free();
237
238 /* load the saves */
240 PHYSFS_enumerate( "saves", load_enumerateCallback, NULL );
242
243 return 0;
244}
245
246static int load_enumerateCallbackPlayer( void* data, const char* origdir, const char* fname )
247{
248 char *path;
249 const char *fmt;
250 size_t dir_len;
251 PHYSFS_Stat stat;
252
253 dir_len = strlen( origdir );
254
255 fmt = dir_len && origdir[dir_len-1]=='/' ? "%s%s" : "%s/%s";
256 asprintf( &path, fmt, origdir, fname );
257 if (!PHYSFS_stat( path, &stat ))
258 WARN( _("PhysicsFS: Cannot stat %s: %s"), path,
259 _(PHYSFS_getErrorByCode( PHYSFS_getLastErrorCode() ) ) );
260 /* TODO remove this sometime in the future. Maybe 0.12.0 or 0.13.0? */
261 else if (stat.filetype == PHYSFS_FILETYPE_REGULAR) {
262 player_saves_t *ps = (player_saves_t*) data;
263 nsave_t ns;
264 int ret = load_load( &ns, path );
265 if (ret == 0) {
266 ns.save_name = strdup( fname );
267 ns.save_name[ strlen(ns.save_name)-3 ] = '\0';
268 ns.modtime = stat.modtime;
269 array_push_back( &ps->saves, ns );
270 if (ps->name == NULL)
271 ps->name = strdup( ns.player_name );
272 }
273 }
274
275 free( path );
276 return PHYSFS_ENUM_OK;
277}
278
282static int load_enumerateCallback( void* data, const char* origdir, const char* fname )
283{
284 (void) data;
285 char *path, *backup_path;
286 const char *fmt;
287 size_t dir_len, name_len;
288 PHYSFS_Stat stat;
289
290 dir_len = strlen( origdir );
291 name_len = strlen( fname );
292
293 fmt = dir_len && origdir[dir_len-1]=='/' ? "%s%s" : "%s/%s";
294 asprintf( &path, fmt, origdir, fname );
295 if (!PHYSFS_stat( path, &stat ))
296 WARN( _("PhysicsFS: Cannot stat %s: %s"), path,
297 _(PHYSFS_getErrorByCode( PHYSFS_getLastErrorCode() ) ) );
298 /* TODO remove this sometime in the future. Maybe 0.12.0 or 0.13.0? */
299 else if (stat.filetype == PHYSFS_FILETYPE_REGULAR) {
300 if ((name_len < 4 || strcmp( &fname[name_len-3], ".ns" )) && (name_len < 11 || strcmp( &fname[name_len-10], ".ns.backup" ))) {
301 free( path );
302 return PHYSFS_ENUM_OK;
303 }
304 if (!PHYSFS_exists( "saves-pre-0.10.0" ))
305 PHYSFS_mkdir( "saves-pre-0.10.0" );
306 asprintf( &backup_path, "saves-pre-0.10.0/%s", fname );
307 if (!ndata_copyIfExists( path, backup_path ))
308 old_saves_detected = 1;
309 free( backup_path );
310 move_old_save( path, fname, ".ns", "autosave.ns" );
311 move_old_save( path, fname, ".ns.backup", "backup.ns" );
312 }
313 else if (stat.filetype == PHYSFS_FILETYPE_DIRECTORY) {
314 player_saves_t psave;
315 psave.name = NULL;
316 psave.saves = array_create( nsave_t );
317 PHYSFS_enumerate( path, load_enumerateCallbackPlayer, &psave );
318 if (psave.name!=NULL) {
319 qsort( psave.saves, array_size(psave.saves), sizeof(nsave_t), load_sortCompare );
320 array_push_back( &load_saves, psave );
321 }
322 else
323 array_free( psave.saves );
324 }
325
326 free( path );
327 return PHYSFS_ENUM_OK;
328}
329
330static int load_compatibilityTest( const nsave_t *ns )
331{
332 char buf[STRMAX], buf2[STRMAX];
333 const plugin_t *plugins = plugin_list();
334 int l;
335
336 switch (ns->compatible) {
337 case SAVE_COMPATIBILITY_NAEV_VERSION:
338 if (!dialogue_YesNo( _("Save game version mismatch"),
339 _("Save game '%s' version does not match Naev version:\n"
340 " Save version: #r%s#0\n"
341 " Naev version: %s\n"
342 "Are you sure you want to load this game? It may lose data."),
343 ns->player_name, ns->version, naev_version( 0 ) ))
344 return -1;
345 break;
346
347 case SAVE_COMPATIBILITY_PLUGINS:
348 buf[0] = '\0';
349 l = 0;
350 for (int i=0; i<array_size(ns->plugins); i++)
351 l += scnprintf( &buf[l], sizeof(buf)-l, "%s%s", (l>0)?_(", "):"#r", ns->plugins[i] );
352 l += scnprintf( &buf[l], sizeof(buf)-l, "#0" );
353 buf2[0] = '\0';
354 l = 0;
355 for (int i=0; i<array_size(plugins); i++)
356 l += scnprintf( &buf2[l], sizeof(buf2)-l, "%s%s", (l>0)?_(", "):"", plugin_name(&plugins[i]) );
357 if (!dialogue_YesNo( _("Save game plugin mismatch"),
358 _("Save game '%s' plugins do not match loaded plugins:\n"
359 " Save plugins: %s\n"
360 " Naev plugins: %s\n"
361 "Are you sure you want to load this game? It may lose data."),
362 ns->player_name, buf, buf2 ) )
363 return -1;
364 break;
365
366 case SAVE_COMPATIBILITY_OK:
367 break;
368 }
369
370 return 0;
371}
372
373static const char* load_compatibilityString( const nsave_t *ns )
374{
375 switch (ns->compatible) {
376 case SAVE_COMPATIBILITY_NAEV_VERSION:
377 return _("version mismatch");
378
379 case SAVE_COMPATIBILITY_PLUGINS:
380 return _("plugins mismatch");
381
382 case SAVE_COMPATIBILITY_OK:
383 return _("compatible");
384 }
385 return NULL;
386}
387
391static SaveCompatibility load_compatibility( const nsave_t *ns )
392{
393 int diff = naev_versionCompare( ns->version );
394 const plugin_t *plugins = plugin_list();
395
396 if (ABS(diff) >= 2)
397 return SAVE_COMPATIBILITY_NAEV_VERSION;
398
399 for (int i=0; i<array_size(ns->plugins); i++) {
400 int found = 0;
401 for (int j=0; j<array_size(plugins); j++) {
402 if (strcmp( ns->plugins[i], plugin_name(&plugins[j]) )==0) {
403 found = 1;
404 break;
405 }
406 }
407 if (!found)
408 return SAVE_COMPATIBILITY_PLUGINS;
409 }
410
411 return SAVE_COMPATIBILITY_OK;
412}
413
417static int load_sortComparePlayers( const void *p1, const void *p2 )
418{
419 const player_saves_t *ps1, *ps2;
420 ps1 = (const player_saves_t*) p1;
421 ps2 = (const player_saves_t*) p2;
422 return load_sortCompare( &ps1->saves[0], &ps2->saves[0] );
423}
424
428static int load_sortCompare( const void *p1, const void *p2 )
429{
430 const nsave_t *ns1, *ns2;
431 ns1 = (const nsave_t*) p1;
432 ns2 = (const nsave_t*) p2;
433
434 /* Sort by compatibility first. */
435 if (!ns1->compatible && ns2->compatible)
436 return -1;
437 else if (ns1->compatible && !ns2->compatible)
438 return +1;
439
440 /* Search by file modification date. */
441 if (ns1->modtime > ns2->modtime)
442 return -1;
443 else if (ns1->modtime < ns2->modtime)
444 return +1;
445
446 /* Finally sort by name. */
447 return strcmp( ns1->save_name, ns2->save_name );
448}
449
453void load_free (void)
454{
455 for (int i=0; i<array_size(load_saves); i++) {
456 player_saves_t *ps = &load_saves[i];
457 free( ps->name );
458 for (int j=0; j<array_size(ps->saves); j++) {
459 nsave_t *ns = &ps->saves[j];
460 for (int k=0; k<array_size(ns->plugins); k++)
461 free( ns->plugins[k] );
462 array_free( ns->plugins );
463 free(ns->save_name);
464 free(ns->player_name);
465 free(ns->path);
466 free(ns->version);
467 free(ns->data);
468 free(ns->spob);
469 free(ns->chapter);
470 free(ns->difficulty);
471 free(ns->shipname);
472 free(ns->shipmodel);
473 }
474 array_free( ps->saves );
475 }
477 load_saves = NULL;
478}
479
483const nsave_t *load_getList( const char *name )
484{
486 return NULL;
487 if (name==NULL)
488 return load_saves[0].saves;
489 for (int i=0; i<array_size(load_saves); i++)
490 if (strcmp(load_saves[i].name,name)==0)
491 return load_saves[i].saves;
492 return NULL;
493}
494
499{
500 unsigned int wid;
501 char **names;
502 int n;
503 int pos = 0;
504
505 /* window */
506 wid = window_create( "wdwLoadGameMenu", _("Load Pilot"), -1, -1, LOAD_WIDTH, LOAD_HEIGHT );
509
510 load_refresh();
511
512 n = array_size( load_saves );
513 if (n > 0) {
514 names = malloc( sizeof(char*)*n );
515 for (int i=0; i<n; i++) {
516 nsave_t *ns = &load_saves[i].saves[0];
517 if (ns->compatible) {
518 char buf[STRMAX_SHORT];
519 size_t l = 0;
520 l += scnprintf( &buf[l], sizeof(buf)-l, _("%s (#r%s#0)"),
521 ns->player_name, load_compatibilityString( ns ) );
522 names[i] = strdup( buf );
523 }
524 else
525 names[i] = strdup( ns->player_name );
526 if (selected_player != NULL && !strcmp( names[i], selected_player ))
527 pos = i;
528 }
529 }
530 /* case there are no players */
531 else {
532 names = malloc(sizeof(char*));
533 names[0] = strdup(_("None"));
534 n = 1;
535 }
536
537 /* Player text. */
538 window_addText( wid, -20, -40, BUTTON_WIDTH*2+20, LOAD_HEIGHT-40-20-2*(BUTTON_HEIGHT+20),
539 0, "txtPilot", &gl_smallFont, NULL, NULL );
540
541 window_addList( wid, 20, -40,
543 "lstNames", names, n, pos, load_menu_update, load_menu_load );
544
545 /* Buttons */
546 window_addButtonKey( wid, -20, 20, BUTTON_WIDTH, BUTTON_HEIGHT,
547 "btnBack", _("Back"), load_menu_close, SDLK_b );
548 window_addButtonKey( wid, -20-BUTTON_WIDTH-20, 20 + BUTTON_HEIGHT+15, BUTTON_WIDTH, BUTTON_HEIGHT,
549 "btnSnapshots", _("Snapshots"), load_menu_snapshots, SDLK_s );
550 window_addButtonKey( wid, -20, 20 + BUTTON_HEIGHT+15, BUTTON_WIDTH, BUTTON_HEIGHT,
551 "btnLoad", _("Load"), load_menu_load, SDLK_l );
552 window_addButton( wid, 20, 20, BUTTON_WIDTH, BUTTON_HEIGHT,
553 "btnDelete", _("Delete"), load_menu_delete );
554
555 if (old_saves_detected && !player_warned) {
556 /* TODO we should print the full OS path if possible here. */
557 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'."), "saves-pre-0.10.0");
558 player_warned = 1;
559 }
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, can_save;
573
574 ps = NULL;
575 for (int i=0; i<array_size(load_saves); i++) {
576 if (strcmp(load_saves[i].name, name)==0) {
577 ps = &load_saves[i];
578 break;
579 }
580 }
581 if (ps==NULL) {
582 WARN(_("Player '%s' not found in list of saves!"),name);
583 return;
584 }
585 load_player = ps;
586
587 /* window */
588 wid = window_create( "wdwLoadSnapshotMenu", _("Load Snapshot"), -1, -1, LOAD_WIDTH, LOAD_HEIGHT );
591
592 /* load the saves */
593 n = array_size( ps->saves );
594 if (n > 0) {
595 names = malloc( sizeof(char*)*n );
596 for (int i=0; i<n; i++) {
597 nsave_t *ns = &ps->saves[i];
598 if (ns->compatible) {
599 char buf[STRMAX_SHORT];
600 size_t l = 0;
601 l += scnprintf( &buf[l], sizeof(buf)-l, _("%s (#r%s#0)"),
602 ns->save_name, load_compatibilityString( ns ) );
603 names[i] = strdup( buf );
604 }
605 else
606 names[i] = strdup( ns->save_name );
607 }
608 }
609 /* case there are no files */
610 else {
611 names = malloc(sizeof(char*));
612 names[0] = strdup(_("None"));
613 n = 1;
614 }
615
616 /* Player text. */
617 window_addText( wid, -20, -40, BUTTON_WIDTH*2+20, LOAD_HEIGHT-40-20-2*(BUTTON_HEIGHT+20),
618 0, "txtPilot", &gl_smallFont, NULL, NULL );
619
620 window_addList( wid, 20, -40,
622 "lstSaves", names, n, 0, load_snapshot_menu_update, load_snapshot_menu_load );
623
624 /* Buttons */
625 window_addButtonKey( wid, -20, 20, BUTTON_WIDTH, BUTTON_HEIGHT,
626 "btnBack", _("Back"), load_snapshot_menu_close, SDLK_b );
627 window_addButtonKey( wid, -20-BUTTON_WIDTH-20, 20 + BUTTON_HEIGHT+15, BUTTON_WIDTH, BUTTON_HEIGHT,
628 "btnSave", _("Save As"), load_snapshot_menu_save, SDLK_s );
629 window_addButtonKey( wid, -20, 20 + BUTTON_HEIGHT+15, BUTTON_WIDTH, BUTTON_HEIGHT,
630 "btnLoad", _("Load"), load_snapshot_menu_load, SDLK_l );
631 window_addButton( wid, 20, 20, BUTTON_WIDTH, BUTTON_HEIGHT,
632 "btnDelete", _("Delete"), load_snapshot_menu_delete );
633
634 if (disablesave || window_exists( "wdwLoadGameMenu" ))
635 window_disableButton( wid, "btnSave" );
636 else {
637 can_save = landed && !player_isFlag(PLAYER_NOSAVE);
638 if (!can_save)
639 window_disableButton( wid, "btnSave" );
640 }
641}
642
648static void load_menu_snapshots( unsigned int wdw, const char *str )
649{
650 (void) str;
651 int pos;
652
653 pos = toolkit_getListPos( wdw, "lstNames" );
654 if (array_size(load_saves) <= 0)
655 return;
656 load_loadSnapshotMenu( load_saves[pos].name, 1 );
657}
658
664static void load_snapshot_menu_save( unsigned int wdw, const char *str )
665{
666 char *save_name = dialogue_input( _("Save game"), 1, 60, _("Please give the new snapshot a name:") );
667 if (save_name == NULL)
668 return;
669 char path[PATH_MAX];
670 snprintf(path, sizeof(path), "saves/%s/%s.ns", player.name, save_name);
671 if (PHYSFS_exists( path )) {
672 int r = dialogue_YesNo(_("Overwrite"),
673 _("You already have a snapshot named '%s'. Overwrite?"), save_name);
674 if (r==0) {
675 load_snapshot_menu_save( wdw, str );
676 free( save_name );
677 return;
678 }
679 }
680 if (save_all_with_name(save_name) < 0)
681 dialogue_alert( _("Failed to save the game! You should exit and check the log to see what happened and then file a bug report!") );
682 else {
683 load_refresh();
684 load_snapshot_menu_close( wdw, str );
686 }
687 free( save_name );
688}
689
695static void load_menu_close( unsigned int wdw, const char *str )
696{
697 (void)str;
698 window_destroy( wdw );
699}
700
706static void load_snapshot_menu_close( unsigned int wdw, const char *str )
707{
708 (void)str;
709 window_destroy( wdw );
710}
711
717static void display_save_info( unsigned int wid, const nsave_t *ns )
718{
719 char buf[STRMAX_SHORT], credits[ECON_CRED_STRLEN], date[64], difficulty[STRMAX_SHORT];
720 size_t l = 0;
721
722 if (ns->difficulty == NULL) {
723 const Difficulty *d = difficulty_cur();
724 snprintf( difficulty, sizeof(difficulty), _("%s (options)"), _(d->name) );
725 }
726 else
727 snprintf( difficulty, sizeof(difficulty), _("%s (this save)"), _(ns->difficulty) );
728
729 credits2str( credits, ns->credits, 2 );
730 ntime_prettyBuf( date, sizeof(date), ns->date, 2 );
731 l += scnprintf( &buf[l], sizeof(buf)-l, "#n%s", _("Name:") );
732 l += scnprintf( &buf[l], sizeof(buf)-l, "\n#0 %s", ns->player_name );
733 l += scnprintf( &buf[l], sizeof(buf)-l, "\n#n%s", _("Version:") );
734 if (ns->compatible == SAVE_COMPATIBILITY_NAEV_VERSION)
735 l += scnprintf( &buf[l], sizeof(buf)-l, "\n #r%s#0", ns->version );
736 else
737 l += scnprintf( &buf[l], sizeof(buf)-l, "\n#0 %s", ns->version );
738 l += scnprintf( &buf[l], sizeof(buf)-l, "\n#n%s", _("Difficulty:") );
739 l += scnprintf( &buf[l], sizeof(buf)-l, "\n#0 %s", difficulty );
740 l += scnprintf( &buf[l], sizeof(buf)-l, "\n#n%s", _("Date:") );
741 l += scnprintf( &buf[l], sizeof(buf)-l, "\n#0 %s", date );
742 l += scnprintf( &buf[l], sizeof(buf)-l, "\n#n%s", _("Chapter:") );
743 l += scnprintf( &buf[l], sizeof(buf)-l, "\n#0 %s", ns->chapter );
744 l += scnprintf( &buf[l], sizeof(buf)-l, "\n#n%s", _("Spob:") );
745 l += scnprintf( &buf[l], sizeof(buf)-l, "\n#0 %s", _(ns->spob) );
746 l += scnprintf( &buf[l], sizeof(buf)-l, "\n#n%s", _("Credits:") );
747 l += scnprintf( &buf[l], sizeof(buf)-l, "\n#0 %s", credits );
748 l += scnprintf( &buf[l], sizeof(buf)-l, "\n#n%s", _("Ship Name:") );
749 l += scnprintf( &buf[l], sizeof(buf)-l, "\n#0 %s", ns->shipname );
750 l += scnprintf( &buf[l], sizeof(buf)-l, "\n#n%s", _("Ship Model:") );
751 l += scnprintf( &buf[l], sizeof(buf)-l, "\n#0 %s", _(ns->shipmodel) );
752 window_modifyText( wid, "txtPilot", buf );
753}
754
762static void move_old_save( const char *path, const char *fname, const char *ext, const char *new_name )
763{
764 size_t name_len = strlen(fname);
765 size_t ext_len = strlen(ext);
766 if (name_len >= ext_len + 1 && !strcmp( &fname[name_len - ext_len], ext )) {
767 char *dirname = strdup( fname );
768 dirname[name_len - ext_len] = '\0';
769 char *new_path;
770 asprintf( &new_path, "saves/%s", dirname );
771 if (!PHYSFS_exists( new_path ))
772 PHYSFS_mkdir( new_path );
773 free( new_path );
774 asprintf( &new_path, "saves/%s/%s", dirname, new_name );
775 /* If it's going to overwrite a file, try to back it up. */
776 if (PHYSFS_exists( new_path )) {
777 int tries = 0;
778 char *bkp_path;
779 asprintf( &bkp_path, "%s.bkp", new_path );
780 while (PHYSFS_exists(bkp_path) && (tries++ < 10)) {
781 char *bkp_bkp_path;
782 asprintf( &bkp_bkp_path, "%s.bkp", bkp_path );
783 free( bkp_path );
784 bkp_path = bkp_bkp_path;
785 }
786 ndata_copyIfExists( new_path, bkp_path );
787 free( bkp_path );
788 }
789 /* Copy over the old file. */
790 if (!ndata_copyIfExists( path, new_path ))
791 if (!PHYSFS_delete( path ))
792 dialogue_alert( _("Unable to delete %s"), path );
793 free( new_path );
794 free( dirname );
795 }
796}
797
803static void load_menu_update( unsigned int wid, const char *str )
804{
805 (void) str;
806 int pos;
807 const nsave_t *ns;
808
809 /* Make sure list is ok. */
810 if (array_size( load_saves ) <= 0)
811 return;
812
813 /* Get position. */
814 pos = toolkit_getListPos( wid, "lstNames" );
815
816 ns = &load_saves[pos].saves[0];
817 if (selected_player != NULL)
818 free( selected_player );
819 selected_player = strdup( load_saves[pos].name );
820
821 display_save_info( wid, ns );
822}
823
829static void load_snapshot_menu_update( unsigned int wid, const char *str )
830{
831 (void) str;
832 int pos;
833 nsave_t *ns;
834
835 /* Make sure list is ok. */
836 if (array_size( load_player->saves ) <= 0)
837 return;
838
839 /* Get position. */
840 pos = toolkit_getListPos( wid, "lstSaves" );
841 ns = &load_player->saves[pos];
842
843 display_save_info( wid, ns );
844}
845
851static void load_menu_load( unsigned int wdw, const char *str )
852{
853 (void) str;
854 int pos;
855 unsigned int wid;
856 nsave_t *ns;
857
858 wid = window_get( "wdwLoadGameMenu" );
859 pos = toolkit_getListPos( wid, "lstNames" );
860
861 if (array_size(load_saves) <= 0)
862 return;
863
864 ns = &load_saves[pos].saves[0];
865
866 /* Check version. */
867 if (load_compatibilityTest( ns ))
868 return;
869
870 /* Close menus before loading for proper rendering. */
871 load_menu_close(wdw, NULL);
872
873 /* Close the main menu. */
875
876 /* Try to load the game. */
877 if (load_game( ns )) {
878 /* Failed so reopen both. */
879 menu_main();
881 }
882}
883
889static void load_snapshot_menu_load( unsigned int wdw, const char *str )
890{
891 (void) str;
892 int wid, pos;
893
894 wid = window_get( "wdwLoadSnapshotMenu" );
895
896 if (array_size( load_player->saves ) <= 0)
897 return;
898
899 pos = toolkit_getListPos( wid, "lstSaves" );
900
901 /* Check version. */
902 if (load_compatibilityTest( &load_player->saves[pos] ))
903 return;
904
905 /* Close menus before loading for proper rendering. */
906 load_snapshot_menu_close(wdw, NULL);
907
908 if (window_exists( "wdwLoadGameMenu" )) {
909 /* Close the main and the load menu. */
910 load_menu_close( window_get( "wdwLoadGameMenu" ), NULL );
912 }
913 else {
914 if (landed)
915 land_cleanup();
917 }
918
919 /* Try to load the game. */
920 if (load_game( &load_player->saves[pos] )) {
921 /* Failed so reopen both. */
922 /* TODO how to handle failure here? It can happen at many different points now. */
923 /*menu_main();
924 load_loadGameMenu();*/
925 }
926}
927
928static void load_menu_delete( unsigned int wdw, const char *str )
929{
930 unsigned int wid;
931 int n, pos;
932 char path[PATH_MAX];
933
934 wid = window_get( "wdwLoadGameMenu" );
935 pos = toolkit_getListPos( wid, "lstNames" );
936
937 if (array_size(load_saves) <= 0)
938 return;
939
940 if (dialogue_YesNo( _("Permanently Delete?"),
941 _("Are you sure you want to permanently delete the character '%s'?\n#rThis is an undoable action!#0"), load_saves[pos].name) == 0)
942 return;
943
944 /* Remove it. */
945 n = array_size( load_saves[pos].saves );
946 for (int i = 0; i < n; i++)
947 if (!PHYSFS_delete( load_saves[pos].saves[i].path ))
948 dialogue_alert( _("Unable to delete %s"), load_saves[pos].saves[i].path );
949 snprintf(path, sizeof(path), "saves/%s", load_saves[pos].name);
950 if (!PHYSFS_delete( path ))
951 dialogue_alert( _("Unable to delete '%s' directory"), load_saves[pos].name );
952
953 load_refresh();
954
955 /* need to reload the menu */
956 load_menu_close( wdw, str );
958}
959
965static void load_snapshot_menu_delete( unsigned int wdw, const char *str )
966{
967 unsigned int wid;
968 int pos, last_save;
969
970 wid = window_get( "wdwLoadSnapshotMenu" );
971
972 if (array_size(load_player->saves) <= 0)
973 return;
974
975 pos = toolkit_getListPos( wid, "lstSaves" );
976
977 if (dialogue_YesNo( _("Permanently Delete?"),
978 _("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)
979 return;
980
981 /* Remove it. */
982 if (!PHYSFS_delete( load_player->saves[pos].path ))
983 dialogue_alert( _("Unable to delete %s"), load_player->saves[pos].path );
984 last_save = (array_size(load_player->saves) <= 1);
985
986 /* Delete directory if all are gone. */
987 if (last_save) {
988 char path[PATH_MAX];
989 snprintf(path, sizeof(path), "saves/%s", load_player->name);
990 if (!PHYSFS_delete( path ))
991 dialogue_alert( _("Unable to delete '%s' directory"), load_player->name );
992 }
993
994 load_refresh();
995
996 /* need to reload the menu */
997 load_snapshot_menu_close( wdw, str );
998 if (window_exists( "wdwLoadGameMenu" )) {
999 wid = window_get( "wdwLoadGameMenu" );
1000 load_menu_close( wid, str );
1002 }
1003 if (!last_save)
1004 load_loadSnapshotMenu( selected_player, 1 );
1005}
1006
1007static void load_compatSlots (void)
1008{
1009 /* Vars for loading old saves. */
1010 char **sships;
1011 glTexture **tships;
1012 int nships;
1013 Pilot *ship;
1014
1015 nships = player_nships();
1016 sships = malloc(nships * sizeof(char*));
1017 tships = malloc(nships * sizeof(glTexture*));
1018 nships = player_ships( sships, tships );
1019 ship = player.p;
1020 for (int i=-1; i<nships; i++) {
1021 if (i >= 0)
1022 ship = player_getShip( sships[i] );
1023 /* Remove all outfits. */
1024 for (int j=0; j<array_size(ship->outfits); j++) {
1025 ShipOutfitSlot *sslot;
1026
1027 if (ship->outfits[j]->outfit != NULL) {
1028 player_addOutfit( ship->outfits[j]->outfit, 1 );
1029 pilot_rmOutfitRaw( ship, ship->outfits[j] );
1030 }
1031
1032 /* Add default outfit. */
1033 sslot = ship->outfits[j]->sslot;
1034 if (sslot->data != NULL)
1035 pilot_addOutfitRaw( ship, sslot->data, ship->outfits[j] );
1036 }
1037
1038 pilot_calcStats( ship );
1039 }
1040
1041 /* Clean up. */
1042 for (int i=0; i<nships; i++)
1043 free(sships[i]);
1044 free(sships);
1045 free(tships);
1046}
1047
1054int load_gameDiff( const char* file )
1055{
1056 xmlNodePtr node;
1057 xmlDocPtr doc;
1058
1059 /* Make sure it exists. */
1060 if (!PHYSFS_exists( file )) {
1061 dialogue_alert( _("Saved game file seems to have been deleted.") );
1062 return -1;
1063 }
1064
1065 /* Load the XML. */
1066 doc = load_xml_parsePhysFS( file );
1067 if (doc == NULL)
1068 goto err;
1069 node = doc->xmlChildrenNode; /* base node */
1070 if (node == NULL)
1071 goto err_doc;
1072
1073 /* Diffs should be cleared automatically first. */
1074 diff_load(node);
1075
1076 /* Free. */
1077 xmlFreeDoc(doc);
1078
1079 return 0;
1080
1081err_doc:
1082 xmlFreeDoc(doc);
1083err:
1084 WARN( _("Saved game '%s' invalid!"), file);
1085 return -1;
1086}
1087
1094int load_gameFile( const char *file )
1095{
1096 return load_gameInternal( file, naev_version(0) );
1097}
1098
1105static int load_game( nsave_t *ns )
1106{
1107 return load_gameInternal( ns->path, ns->version );
1108}
1109
1117static int load_gameInternal( const char* file, const char* version )
1118{
1119 const char** data;
1120
1121 /* Make sure it exists. */
1122 if (!PHYSFS_exists( file )) {
1123 dialogue_alert( _("Saved game file seems to have been deleted.") );
1124 return -1;
1125 }
1126
1127 /* Some global cleaning has to be done here. */
1129 hook_cleanup();
1130
1131 data = malloc( sizeof(const char*) * 2 );
1132 data[0] = file;
1133 data[1] = version;
1134 /* If the player isn't loaded, hooks aren't run so we can just go right away. */
1135 if ((player.p == NULL) || player_isFlag(PLAYER_DESTROYED)) /* same condition in hook.c */
1136 return load_gameInternalHook( data );
1137 else {
1138 /* Break out of potential inner loops. */
1139 SDL_Event event;
1140 SDL_memset( &event, 0, sizeof(event) );
1141 event.type = SDL_LOOPDONE;
1142 SDL_PushEvent( &event );
1143
1144 /* Delay one frame. */
1145 hook_addFunc( load_gameInternalHook, data, "safe" );
1146 }
1147 return 0;
1148}
1149
1153static int load_gameInternalHook( void *data )
1154{
1155 xmlNodePtr node;
1156 xmlDocPtr doc;
1157 Spob *pnt;
1158 const char **sdata = data;
1159 const char *file = sdata[0];
1160 const char *version = sdata[1];
1161 int version_diff = (version!=NULL) ? naev_versionCompare(version) : 0;
1162 free(data);
1163
1164 /* Load the XML. */
1165 doc = load_xml_parsePhysFS( file );
1166 if (doc == NULL)
1167 goto err;
1168 node = doc->xmlChildrenNode; /* base node */
1169 if (node == NULL)
1170 goto err_doc;
1171
1172 /* Clean up possible stuff that should be cleaned. */
1175
1176 /* Welcome message - must be before space_init. */
1177 player_message( _("#gWelcome to %s!"), APPNAME );
1178 player_message( "#g v%s", naev_version(0) );
1179
1180 /* Now begin to load. */
1181 diff_load(node); /* Must load first to work properly. */
1183 missions_loadCommodity(node); /* Must be loaded before player. */
1184 pfaction_load(node); /* Must be loaded before player so the messages show up properly. */
1185 pnt = player_load(node);
1186 player.loaded_version = strdup( (version!=NULL) ? version : naev_version(0) );
1187
1188 /* Sanitize for new version. */
1189 if (version_diff <= -2) {
1190 WARN( _("Old version detected. Sanitizing ships for slots") );
1191 load_compatSlots();
1192 }
1193
1194 /* Load more stuff. */
1195 space_sysLoad(node);
1196 var_load(node);
1197 missions_loadActive(node);
1198 events_loadActive(node);
1199 news_loadArticles( node );
1200 hook_load(node);
1201
1202 /* Initialize the economy. */
1203 economy_init();
1204 economy_sysLoad(node);
1205
1206 /* Initialise the ship log */
1207 shiplog_new();
1208 shiplog_load(node);
1209
1210 /* Check validity. */
1212
1213 /* Run the load event trigger. */
1214 events_trigger( EVENT_TRIGGER_LOAD );
1215
1216 /* Create escorts in space. */
1218
1219 /* Load the GUI. */
1220 if (gui_load( gui_pick() )) {
1221 if (player.p->ship->gui != NULL)
1222 gui_load( player.p->ship->gui );
1223 }
1224
1225 /* Land the player. */
1226 land( pnt, 1 );
1227
1228 /* Sanitize the GUI. */
1229 gui_setCargo();
1230 gui_setShip();
1231
1232 xmlFreeDoc(doc);
1233
1234 /* Set loaded. */
1235 save_loaded = 1;
1236
1237 return 0;
1238
1239err_doc:
1240 xmlFreeDoc(doc);
1241err:
1242 dialogue_alert( _("Saved game '%s' invalid!"), file);
1243 menu_main();
1244 return -1;
1245}
1246
1250static xmlDocPtr load_xml_parsePhysFS( const char* filename )
1251{
1252 char buf[PATH_MAX];
1253 snprintf( buf, sizeof(buf), "%s/%s", PHYSFS_getWriteDir(), filename );
1254 return xmlParseFile( buf );
1255}
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 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:436
int dialogue_YesNo(const char *caption, const char *fmt,...)
Runs a dialogue with both yes and no options.
Definition: dialogue.c:344
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:742
void events_trigger(EventTrigger_t trigger)
Runs all the events matching a trigger.
Definition: event.c:314
glFont gl_smallFont
Definition: font.c:154
int gui_load(const char *name)
Attempts to load the actual GUI.
Definition: gui.c:1839
char * gui_pick(void)
Determines which GUI should be used.
Definition: gui.c:1818
void gui_setShip(void)
Player just upgraded their ship or modified it.
Definition: gui.c:1765
void player_message(const char *fmt,...)
Adds a mesg to the queue to be displayed on screen.
Definition: gui.c:330
void gui_setCargo(void)
Player just changed their cargo.
Definition: gui.c:1741
void hook_cleanup(void)
Gets rid of all current hooks.
Definition: hook.c:1104
unsigned int hook_addFunc(int(*func)(void *), void *data, const char *stack)
Adds a function hook to be run.
Definition: hook.c:582
void land_cleanup(void)
Cleans up some land-related variables.
Definition: land.c:1672
int landed
Definition: land.c:74
void land(Spob *p, int load)
Opens up all the land dialogue stuff.
Definition: land.c:1201
#define LOAD_WIDTH
Definition: load.c:45
static void load_menu_update(unsigned int wid, const char *str)
Updates the load menu.
Definition: load.c:803
int news_loadArticles(xmlNodePtr parent)
Loads the player's active articles from a save, initilizes news.
Definition: news.c:483
static void load_menu_close(unsigned int wdw, const char *str)
Closes the load game menu.
Definition: load.c:695
static void load_menu_load(unsigned int wdw, const char *str)
Loads a new game.
Definition: load.c:851
#define LOAD_HEIGHT
Definition: load.c:46
int space_sysLoad(xmlNodePtr parent)
Loads player's space properties from an XML node.
Definition: space.c:3894
static int load_gameInternal(const char *file, const char *version)
Actually loads a new game.
Definition: load.c:1117
int diff_load(xmlNodePtr parent)
Loads the diffs.
Definition: unidiff.c:1740
int events_loadActive(xmlNodePtr parent)
Loads the player's active events from a save.
Definition: event.c:804
static int load_game(nsave_t *ns)
Actually loads a new game based on save structure.
Definition: load.c:1105
static int load_gameInternalHook(void *data)
Loads a game .Meant to be run in a function hook.
Definition: load.c:1153
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:1208
static int load_sortCompare(const void *p1, const void *p2)
qsort compare function for files.
Definition: load.c:428
static int load_load(nsave_t *save, const char *path)
Loads an individual save.
Definition: load.c:124
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:391
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:762
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:233
#define BUTTON_HEIGHT
Definition: load.c:49
static void display_save_info(unsigned int wid, const nsave_t *ns)
Displays Naev save info.
Definition: load.c:717
static void load_snapshot_menu_save(unsigned int wdw, const char *str)
Creates new custom snapshot.
Definition: load.c:664
static int load_enumerateCallback(void *data, const char *origdir, const char *fname)
The PHYSFS_EnumerateCallback for load_refresh.
Definition: load.c:282
static void load_menu_snapshots(unsigned int wdw, const char *str)
Opens the load snapshot menu.
Definition: load.c:648
void load_loadGameMenu(void)
Opens the load game menu.
Definition: load.c:498
static player_saves_t * load_saves
Definition: load.c:64
static void load_snapshot_menu_load(unsigned int wdw, const char *str)
Loads a new game.
Definition: load.c:889
void load_free(void)
Frees loaded save stuff.
Definition: load.c:453
const nsave_t * load_getList(const char *name)
Gets the array (array.h) of loaded saves.
Definition: load.c:483
static player_saves_t * load_player
Definition: load.c:65
static void load_snapshot_menu_delete(unsigned int wdw, const char *str)
Deletes an old game.
Definition: load.c:965
int pfaction_load(xmlNodePtr parent)
Loads the player's faction standings.
Definition: faction.c:1756
static void load_snapshot_menu_close(unsigned int wdw, const char *str)
Closes the load snapshot menu.
Definition: load.c:706
Spob * player_load(xmlNodePtr parent)
Loads the player stuff.
Definition: player.c:3519
static xmlDocPtr load_xml_parsePhysFS(const char *filename)
Temporary (hopefully) wrapper around xml_parsePhysFS in support of gzipped XML (like ....
Definition: load.c:1250
int load_gameFile(const char *file)
Loads the game from a file.
Definition: load.c:1094
#define BUTTON_WIDTH
Definition: load.c:48
int load_gameDiff(const char *file)
Loads the diffs from game file.
Definition: load.c:1054
static void load_snapshot_menu_update(unsigned int wid, const char *str)
Updates the load snapshot menu.
Definition: load.c:829
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:417
Handles the important game menus.
void menu_small_close(void)
Closes the small menu.
Definition: menu.c:494
void menu_main(void)
Opens the main menu (titlescreen).
Definition: menu.c:165
void menu_main_close(void)
Closes the main menu.
Definition: menu.c:330
int missions_loadActive(xmlNodePtr parent)
Loads the player's active missions from a save.
Definition: mission.c:1376
int missions_loadCommodity(xmlNodePtr parent)
Loads the player's special mission commodities.
Definition: mission.c:1299
int naev_versionCompare(const char *version)
Compares the version against the current naev version.
Definition: naev.c:1071
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.
Definition: naev_version.c:25
#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:304
int asprintf(char **strp, const char *fmt,...)
Like sprintf(), but it allocates a large-enough string and returns the pointer in the first argument....
Definition: nstring.c:161
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:178
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.
Definition: pilot_outfit.c:877
int pilot_rmOutfitRaw(Pilot *pilot, PilotOutfitSlot *s)
Removes an outfit from the pilot without doing any checks.
Definition: pilot_outfit.c:424
int pilot_addOutfitRaw(Pilot *pilot, const Outfit *outfit, PilotOutfitSlot *s)
Adds an outfit to the pilot, ignoring CPU or other limits.
Definition: pilot_outfit.c:273
int player_nships(void)
Gets the amount of ships player has in storage.
Definition: player.c:2633
int player_ships(char **sships, glTexture **tships)
Returns a buffer with all the player's ships names.
Definition: player.c:2606
int player_addOutfit(const Outfit *o, int quantity)
Adds an outfit to the player outfit stack.
Definition: player.c:2803
void player_cleanup(void)
Cleans up player stuff like player_stack.
Definition: player.c:697
int player_addEscorts(void)
Adds the player's escorts.
Definition: player.c:3074
Player_t player
Definition: player.c:73
Pilot * player_getShip(const char *shipname)
Gets a specific ship.
Definition: player.c:2663
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:257
ShipOutfitSlot * sslot
Definition: pilot.h:114
const Outfit * outfit
Definition: pilot.h:112
The representation of an in-game pilot.
Definition: pilot.h:210
PilotOutfitSlot ** outfits
Definition: pilot.h:292
const Ship * ship
Definition: pilot.h:219
Pilot * p
Definition: player.h:101
char * name
Definition: player.h:103
char * loaded_version
Definition: player.h:121
Ship outfit slot.
Definition: ship.h:70
const Outfit * data
Definition: ship.h:76
char * gui
Definition: ship.h:149
Represents a Space Object (SPOB), including and not limited to planets, stations, wormholes,...
Definition: space.h:88
Struct containing a file's name and stat structure.
Definition: load.c:54
Abstraction for rendering sprite sheets.
Definition: opengl_tex.h:34
A naev save.
Definition: load.h:22
uint64_t credits
Definition: load.h:39
char * shipmodel
Definition: load.h:45
char * difficulty
Definition: load.h:41
char * shipname
Definition: load.h:44
char * player_name
Definition: load.h:24
ntime_t date
Definition: load.h:38
SaveCompatibility compatible
Definition: load.h:34
char * path
Definition: load.h:25
char * spob
Definition: load.h:37
char * chapter
Definition: load.h:40
char ** plugins
Definition: load.h:33
char * version
Definition: load.h:29
char * data
Definition: load.h:30
Definition: plugin.h:6
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:696
void window_setAccept(unsigned int wid, void(*accept)(unsigned int, const char *))
Sets the default accept function of the window.
Definition: toolkit.c:879
void window_setCancel(unsigned int wid, void(*cancel)(unsigned int, const char *))
Sets the default cancel function of the window.
Definition: toolkit.c:900
void toolkit_closeAll(void)
Closes all open toolkit windows.
Definition: toolkit.c:1019
unsigned int window_get(const char *wdwname)
Gets the ID of a window.
Definition: toolkit.c:671
int window_exists(const char *wdwname)
Checks to see if a window exists.
Definition: toolkit.c:598
void window_destroy(unsigned int wid)
Kills the window.
Definition: toolkit.c:1042
void unidiff_universeDefer(int enable)
Sets whether or not to defer universe change stuff.
Definition: unidiff.c:1832