cp_save.c

Go to the documentation of this file.
00001 
00006 /*
00007 Copyright (C) 2002-2010 UFO: Alien Invasion.
00008 
00009 This program is free software; you can redistribute it and/or
00010 modify it under the terms of the GNU General Public License
00011 as published by the Free Software Foundation; either version 2
00012 of the License, or (at your option) any later version.
00013 
00014 This program is distributed in the hope that it will be useful,
00015 but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00017 
00018 See the GNU General Public License for more details.
00019 
00020 You should have received a copy of the GNU General Public License
00021 along with this program; if not, write to the Free Software
00022 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00023 
00024 */
00025 
00026 #include "../client.h" /* cl_genericPool */
00027 #include "../cl_game.h" /* GAME_ReloadMode */
00028 #include "../ui/ui_main.h"
00029 #include "../ui/ui_popup.h"
00030 #include "cp_campaign.h"
00031 #include "cp_save.h"
00032 #include "cp_time.h"
00033 #include "save/save.h"
00034 
00035 #define SAVEGAME_EXTENSION "savx"
00036 
00037 typedef struct saveFileHeader_s {
00038     uint32_t version;           
00039     uint32_t compressed;        
00040     uint32_t dummy[14];         
00041     char gameVersion[16];       
00042     char name[32];              
00043     char gameDate[32];          
00044     char realDate[32];          
00045     uint32_t xmlSize;
00046 } saveFileHeader_t;
00047 
00048 typedef struct saveSubsystems_s {
00049     const char *name;
00050     qboolean (*save) (mxml_node_t *parent); 
00051     qboolean (*load) (mxml_node_t *parent); 
00052 } saveSubsystems_t;
00053 
00054 static saveSubsystems_t saveSubsystems[MAX_SAVESUBSYSTEMS];
00055 static int saveSubsystemsAmount;
00056 static cvar_t* save_compressed;
00057 
00064 static qboolean SAV_GameActionsAfterLoad (void)
00065 {
00066     B_PostLoadInit();
00067     AIR_PostLoadInit();
00068 
00069     /* Make sure the date&time is displayed when loading. */
00070     CL_UpdateTime();
00071 
00072     /* Update number of UFO detected by radar */
00073     RADAR_SetRadarAfterLoading();
00074 
00075     return qtrue;
00076 }
00077 
00082 static qboolean SAV_VerifyHeader (saveFileHeader_t const * const header)
00083 {
00084     int len;
00085     /*check the length of the string*/
00086     len = strlen(header->name);
00087     if (len < 0 || len > sizeof(header->name)) {
00088         Com_DPrintf(DEBUG_CLIENT, "Name is %d Bytes long, max is "UFO_SIZE_T"\n", len, sizeof(header->name));
00089         return qfalse;
00090     }
00091     len = strlen(header->gameVersion);
00092     if (len < 0 || len > sizeof(header->gameVersion)) {
00093         Com_DPrintf(DEBUG_CLIENT, "gameVersion is %d Bytes long, max is "UFO_SIZE_T"\n", len, sizeof(header->gameVersion));
00094         return qfalse;
00095     }
00096     len = strlen(header->gameDate);
00097     if (len < 0 || len > sizeof(header->gameDate)) {
00098         Com_DPrintf(DEBUG_CLIENT, "gameDate is %d Bytes long, max is "UFO_SIZE_T"\n", len, sizeof(header->gameDate));
00099         return qfalse;
00100     }
00101     len = strlen(header->realDate);
00102     if (len < 0 || len > sizeof(header->realDate)) {
00103         Com_DPrintf(DEBUG_CLIENT, "realDate is %d Bytes long, max is "UFO_SIZE_T"\n", len, sizeof(header->realDate));
00104         return qfalse;
00105     }
00106 
00107     /* saved games should not be bigger than 15MB */
00108     if (header->xmlSize < 0 || header->xmlSize > 15 * 1024 * 1024) {
00109         Com_DPrintf(DEBUG_CLIENT, "Save size seems to be to large (over 15 MB) %i.\n", header->xmlSize);
00110         return qfalse;
00111     }
00112     if (header->version == 0) {
00113         Com_DPrintf(DEBUG_CLIENT, "Version is invalid - must be greater than zero\n");
00114         return qfalse;
00115     }
00116     if (header->version > SAVE_FILE_VERSION) {
00117         Com_Printf("Savefile is newer than the game!\n");
00118     }
00119     return qtrue;
00120 }
00121 
00128 static qboolean SAV_GameLoad (const char *file, char **error)
00129 {
00130     uLongf len;
00131     char filename[MAX_OSPATH];
00132     qFILE f;
00133     byte *cbuf, *buf;
00134     int i, clen;
00135     mxml_node_t *topNode, *node;
00136     saveFileHeader_t header;
00137 
00138     Q_strncpyz(filename, file, sizeof(filename));
00139 
00140     /* open file */
00141     FS_OpenFile(va("save/%s.%s", filename, SAVEGAME_EXTENSION), &f, FILE_READ);
00142     if (!f.f) {
00143         Com_Printf("Couldn't open file '%s'\n", filename);
00144         return qfalse;
00145     }
00146 
00147     clen = FS_FileLength(&f);
00148     cbuf = (byte *) Mem_PoolAlloc(sizeof(byte) * clen, cl_genericPool, 0);
00149     if (FS_Read(cbuf, clen, &f) != clen)
00150         Com_Printf("Warning: Could not read %i bytes from savefile\n", clen);
00151     FS_CloseFile(&f);
00152     Com_Printf("Loading savegame xml (size %d)\n", clen);
00153 
00154     memcpy(&header, cbuf, sizeof(header));
00155     /* swap all int values if needed */
00156     header.compressed = LittleLong(header.compressed);
00157     header.version = LittleLong(header.version);
00158     header.xmlSize = LittleLong(header.xmlSize);
00159     /* doing some header verification */
00160     if (!SAV_VerifyHeader(&header)) {
00161         /* our header is not valid, we MUST abort loading the game! */
00162         Com_Printf("The Header of the savegame '%s.%s' is corrupted. Loading aborted\n", filename, SAVEGAME_EXTENSION);
00163         Mem_Free(cbuf);
00164         return qfalse;
00165     }
00166 
00167     Com_Printf("Loading savegame\n"
00168             "...version: %i\n"
00169             "...game version: %s\n"
00170             "...xml Size: %i, compressed? %c\n",
00171             header.version, header.gameVersion, header.xmlSize, header.compressed ? 'y' : 'n');
00172     len = header.xmlSize + 50;
00173     buf = (byte *) Mem_PoolAlloc(sizeof(byte)*len, cl_genericPool, 0);
00174 
00175     if (header.compressed) {
00176         /* uncompress data, skipping comment header */
00177         const int res = uncompress(buf, &len, cbuf + sizeof(header), clen - sizeof(header));
00178         Mem_Free(cbuf);
00179 
00180         if (res != Z_OK) {
00181             Mem_Free(buf);
00182             *error = _("Error decompressing data");
00183             Com_Printf("Error decompressing data in '%s'.\n", filename);
00184             return qfalse;
00185         }
00186         topNode = mxmlLoadString(NULL, (char*)buf , mxml_ufo_type_cb);
00187         if (!topNode) {
00188             Mem_Free(buf);
00189             Com_Printf("Error: Failure in loading the xml data!\n");
00190             return qfalse;
00191         }
00192     } else {
00193         /*memcpy(buf, cbuf + sizeof(header), clen - sizeof(header));*/
00194         topNode = mxmlLoadString(NULL, (char*)(cbuf + sizeof(header)) , mxml_ufo_type_cb);
00195         Mem_Free(cbuf);
00196         if (!topNode) {
00197             Com_Printf("Error: Failure in loading the xml data!\n");
00198             return qfalse;
00199         }
00200     }
00201 
00202     /* doing a subsystem run ;) */
00203     GAME_ReloadMode();
00204     node = mxml_GetNode(topNode, SAVE_ROOTNODE);
00205     if (!node) {
00206         Com_Printf("Error: Failure in loading the xml data! (savegame node not found)\n");
00207         Mem_Free(buf);
00208         mxmlDelete(topNode);
00209         return qfalse;
00210     }
00211 
00212     Com_Printf("Load '%s' %d subsystems\n", filename, saveSubsystemsAmount);
00213     for (i = 0; i < saveSubsystemsAmount; i++) {
00214         Com_Printf("...Running subsystem '%s'\n", saveSubsystems[i].name);
00215         if (!saveSubsystems[i].load(node)) {
00216             Com_Printf("...subsystem '%s' returned false - savegame could not be loaded\n",
00217                     saveSubsystems[i].name);
00218             return qfalse;
00219         } else
00220             Com_Printf("...subsystem '%s' - loaded.\n", saveSubsystems[i].name);
00221     }
00222     mxmlDelete(node);
00223 
00224     SAV_GameActionsAfterLoad();
00225 
00226     Com_Printf("File '%s' successfully loaded from %s xml savegame.\n",
00227             filename, header.compressed ? "compressed" : "");
00228     Mem_Free(buf);
00229 
00230     mxmlDelete(topNode);
00231 
00232     UI_InitStack("geoscape", NULL, qtrue, qtrue);
00233     return qtrue;
00234 }
00235 
00242 static qboolean SAV_GameSave (const char *filename, const char *comment, char **error)
00243 {
00244     mxml_node_t *topNode, *node;
00245     char savegame[MAX_OSPATH];
00246     int res;
00247     int requiredBufferLength;
00248     byte *buf, *fbuf;
00249     uLongf bufLen;
00250     saveFileHeader_t header;
00251     char dummy[2];
00252     int i;
00253     dateLong_t date;
00254     char message[30];
00255     char timeStampBuffer[32];
00256 
00257     if (!CP_IsRunning()) {
00258         *error = _("No campaign active.");
00259         Com_Printf("Error: No campaign active.\n");
00260         return qfalse;
00261     }
00262 
00263     if (!ccs.numBases) {
00264         *error = _("Nothing to save yet.");
00265         Com_Printf("Error: Nothing to save yet.\n");
00266         return qfalse;
00267     }
00268 
00269     Com_MakeTimestamp(timeStampBuffer, sizeof(timeStampBuffer));
00270     Com_sprintf(savegame, sizeof(savegame), "save/%s.%s", filename, SAVEGAME_EXTENSION);
00271     topNode = mxmlNewXML("1.0");
00272     node = mxml_AddNode(topNode, SAVE_ROOTNODE);
00273     /* writing  Header */
00274     mxml_AddInt(node, SAVE_SAVEVERSION, SAVE_FILE_VERSION);
00275     mxml_AddString(node, SAVE_COMMENT, comment);
00276     mxml_AddString(node, SAVE_UFOVERSION, UFO_VERSION);
00277     mxml_AddString(node, SAVE_REALDATE, timeStampBuffer);
00278     CL_DateConvertLong(&ccs.date, &date);
00279     Com_sprintf(message, sizeof(message), _("%i %s %02i"),
00280         date.year, Date_GetMonthName(date.month - 1), date.day);
00281     mxml_AddString(node, SAVE_GAMEDATE, message);
00282     /* working through all subsystems. perhaps we should redesign it, order is not important anymore */
00283     Com_Printf("Calling subsystems\n");
00284     for (i = 0; i < saveSubsystemsAmount; i++) {
00285         if (!saveSubsystems[i].save(node))
00286             Com_Printf("...subsystem '%s' failed to save the data\n", saveSubsystems[i].name);
00287         else
00288             Com_Printf("...subsystem '%s' - saved\n", saveSubsystems[i].name);
00289     }
00290 
00291     /* calculate the needed buffer size */
00292     memset(&header, 0, sizeof(header));
00293     header.compressed = LittleLong(save_compressed->integer);
00294     header.version = LittleLong(SAVE_FILE_VERSION);
00295     Q_strncpyz(header.name, comment, sizeof(header.name));
00296     Q_strncpyz(header.gameVersion, UFO_VERSION, sizeof(header.gameVersion));
00297     CL_DateConvertLong(&ccs.date, &date);
00298     Com_sprintf(header.gameDate, sizeof(header.gameDate), _("%i %s %02i"),
00299         date.year, Date_GetMonthName(date.month - 1), date.day);
00300     Q_strncpyz(header.realDate, timeStampBuffer, sizeof(header.realDate));
00301 
00302     requiredBufferLength = mxmlSaveString(topNode, dummy, 2, MXML_NO_CALLBACK);
00303 
00304     header.xmlSize = LittleLong(requiredBufferLength);
00305     buf = (byte *) Mem_PoolAlloc(sizeof(byte) * requiredBufferLength + 1, cl_genericPool, 0);
00306     if (!buf) {
00307         mxmlDelete(topNode);
00308         *error = _("Could not allocate enough memory to save this game");
00309         Com_Printf("Error: Could not allocate enough memory to save this game\n");
00310         return qfalse;
00311     }
00312     res = mxmlSaveString(topNode, (char*)buf, requiredBufferLength + 1, MXML_NO_CALLBACK);
00313     mxmlDelete(topNode);
00314     Com_Printf("XML Written to buffer (%d Bytes)\n", res);
00315 
00316     if (header.compressed)
00317         bufLen = (uLongf) (24 + 1.02 * requiredBufferLength);
00318     else
00319         bufLen = requiredBufferLength;
00320 
00321     fbuf = (byte *) Mem_PoolAlloc(sizeof(byte) * bufLen + sizeof(header), cl_genericPool, 0);
00322     memcpy(fbuf, &header, sizeof(header));
00323 
00324     if (header.compressed) {
00325         res = compress(fbuf + sizeof(header), &bufLen, buf, requiredBufferLength + 1);
00326         Mem_Free(buf);
00327 
00328         if (res != Z_OK) {
00329             Mem_Free(fbuf);
00330             *error = _("Memory error compressing save-game data - set save_compressed cvar to 0");
00331             Com_Printf("Memory error compressing save-game data (%s) (Error: %i)!\n", comment, res);
00332             return qfalse;
00333         }
00334     } else {
00335         memcpy(fbuf + sizeof(header), buf, requiredBufferLength + 1);
00336         Mem_Free(buf);
00337     }
00338 
00339     /* last step - write data */
00340     res = FS_WriteFile(fbuf, bufLen + sizeof(header), savegame);
00341     Mem_Free(fbuf);
00342 
00343     return qtrue;
00344 }
00345 
00351 static void SAV_GameSave_f (void)
00352 {
00353     char comment[MAX_VAR] = "";
00354     char *error = NULL;
00355     qboolean result;
00356 
00357     /* get argument */
00358     if (Cmd_Argc() < 2) {
00359         Com_Printf("Usage: %s <filename> <comment|*cvar>\n", Cmd_Argv(0));
00360         return;
00361     }
00362 
00363     if (!CP_IsRunning()) {
00364         Com_Printf("No running game - no saving...\n");
00365         return;
00366     }
00367 
00368     /* get comment */
00369     if (Cmd_Argc() > 2) {
00370         const char *arg = Cmd_Argv(2);
00371         Q_strncpyz(comment, arg, sizeof(comment));
00372     }
00373 
00374     result = SAV_GameSave(Cmd_Argv(1), comment, &error);
00375     if (!result) {
00376         if (error)
00377             Com_sprintf(popupText, sizeof(popupText), "%s\n%s", _("Error saving game."), error);
00378         else
00379             Com_sprintf(popupText, sizeof(popupText), "%s\n", _("Error saving game."));
00380         UI_Popup(_("Note"), popupText);
00381     }
00382 }
00383 
00389 static void SAV_GameReadGameComment (const int idx)
00390 {
00391     saveFileHeader_t header;
00392     qFILE f;
00393 
00394     FS_OpenFile(va("save/slot%i.%s", idx, SAVEGAME_EXTENSION), &f, FILE_READ);
00395     if (f.f || f.z) {
00396         if (FS_Read(&header, sizeof(header), &f) != sizeof(header))
00397             Com_Printf("Warning: Savefile header may be corrupted\n");
00398 
00399         if (!SAV_VerifyHeader(&header))
00400             Com_Printf("Savegame header for slot%d is corrupted!\n", idx);
00401         else
00402             UI_ExecuteConfunc("update_save_game_info %i \"%s\" \"%s\" \"%s\"", idx, header.name, header.gameDate, header.realDate);
00403 
00404         FS_CloseFile(&f);
00405     }
00406 }
00407 
00417 static void SAV_GameReadGameComments_f (void)
00418 {
00419     if (Cmd_Argc() == 2) {
00420         /* checks whether we plan to save without a running game */
00421         if (!CP_IsRunning() && !strncmp(Cmd_Argv(1), "save", 4)) {
00422             UI_PopWindow(qfalse);
00423             return;
00424         }
00425     }
00426 
00427     if (Cmd_Argc() == 2) {
00428         int idx = atoi(Cmd_Argv(1));
00429         SAV_GameReadGameComment(idx);
00430     } else {
00431         int i;
00432         /* read all game comments */
00433         for (i = 0; i < 8; i++) {
00434             SAV_GameReadGameComment(i);
00435         }
00436     }
00437 }
00438 
00443 static void SAV_GameLoad_f (void)
00444 {
00445     char *error = NULL;
00446     const cvar_t *gamedesc;
00447 
00448     /* get argument */
00449     if (Cmd_Argc() < 2) {
00450         Com_Printf("Usage: %s <filename>\n", Cmd_Argv(0));
00451         return;
00452     }
00453 
00454     /* try to get game description from "mn_<filename>" as indicator whether file will exist */
00455     gamedesc = Cvar_FindVar(va("mn_%s", Cmd_Argv(1)));
00456     if (!gamedesc || gamedesc->string[0] == '\0') {
00457         Com_DPrintf(DEBUG_CLIENT, "don't load file '%s', there is no description for it\n", Cmd_Argv(1));
00458         return;
00459     }
00460 
00461     Com_DPrintf(DEBUG_CLIENT, "load file '%s'\n", Cmd_Argv(1));
00462 
00463     /* load and go to map */
00464     if (!SAV_GameLoad(Cmd_Argv(1), &error)) {
00465         Cbuf_Execute(); /* wipe outstanding campaign commands */
00466         Com_sprintf(popupText, sizeof(popupText), "%s\n%s", _("Error loading game."), error ? error : "");
00467         UI_Popup(_("Error"), popupText);
00468         Cmd_ExecuteString("game_exit");
00469     }
00470 }
00471 
00477 static void SAV_GameContinue_f (void)
00478 {
00479     char *error = NULL;
00480 
00481     if (CL_OnBattlescape()) {
00482         UI_PopWindow(qfalse);
00483         return;
00484     }
00485 
00486     if (!CP_IsRunning()) {
00487         /* try to load the last saved campaign */
00488         if (!SAV_GameLoad(cl_lastsave->string, &error)) {
00489             Cbuf_Execute(); /* wipe outstanding campaign commands */
00490             Com_sprintf(popupText, sizeof(popupText), "%s\n%s", _("Error loading game."), error ? error : "");
00491             UI_Popup(_("Error"), popupText);
00492             Cmd_ExecuteString("game_exit");
00493         }
00494     } else {
00495         /* just continue the current running game */
00496         UI_PopWindow(qfalse);
00497     }
00498 }
00499 
00505 static qboolean SAV_AddSubsystem (saveSubsystems_t *subsystem)
00506 {
00507     if (saveSubsystemsAmount >= MAX_SAVESUBSYSTEMS)
00508         return qfalse;
00509 
00510     saveSubsystems[saveSubsystemsAmount].name = subsystem->name;
00511     saveSubsystems[saveSubsystemsAmount].load = subsystem->load;
00512     saveSubsystems[saveSubsystemsAmount].save = subsystem->save;
00513     saveSubsystemsAmount++;
00514 
00515     Com_Printf("added %s subsystem\n", subsystem->name);
00516     return qtrue;
00517 }
00518 
00524 static void SAV_GameSaveNameCleanup_f (void)
00525 {
00526     int slotID;
00527     char cvar[16];
00528     qFILE f;
00529     saveFileHeader_t header;
00530 
00531     /* get argument */
00532     if (Cmd_Argc() < 2) {
00533         Com_Printf("Usage: %s <[0-7]>\n", Cmd_Argv(0));
00534         return;
00535     }
00536 
00537     slotID = atoi(Cmd_Argv(1));
00538     if (slotID < 0 || slotID > 7)
00539         return;
00540 
00541     FS_OpenFile(va("save/slot%i.%s", slotID, SAVEGAME_EXTENSION), &f, FILE_READ);
00542     if (!f.f && !f.z)
00543         return;
00544 
00545     /* read the comment */
00546     if (FS_Read(&header, sizeof(header), &f) != sizeof(header))
00547         Com_Printf("Warning: Savefile header may be corrupted\n");
00548 
00549     Com_sprintf(cvar, sizeof(cvar), "mn_slot%i", slotID);
00550     Cvar_Set(cvar, header.name);
00551     FS_CloseFile(&f);
00552 }
00553 
00558 qboolean SAV_QuickSave (void)
00559 {
00560     char *error = NULL;
00561     qboolean result;
00562 
00563     if (CL_OnBattlescape())
00564         return qfalse;
00565 
00566     result = SAV_GameSave("slotquick", _("QuickSave"), &error);
00567     if (!result)
00568         Com_Printf("Error saving the xml game: %s\n", error ? error : "");
00569 
00570     return qtrue;
00571 }
00572 
00577 static void SAV_GameQuickLoadInit_f (void)
00578 {
00579     qFILE f;
00580 
00581     FS_OpenFile(va("save/slotquick.%s", SAVEGAME_EXTENSION), &f, FILE_READ);
00582     if (f.f || f.z) {
00583         UI_PushWindow("quickload", NULL);
00584         FS_CloseFile(&f);
00585     }
00586 }
00587 
00592 static void SAV_GameQuickSave_f (void)
00593 {
00594     if (!CP_IsRunning())
00595         return;
00596 
00597     if (!SAV_QuickSave())
00598         Com_Printf("Could not save the campaign\n");
00599     else
00600         MS_AddNewMessage(_("Quicksave"), _("Campaign was successfully saved."), qfalse, MSG_INFO, NULL);
00601 }
00602 
00607 static void SAV_GameQuickLoad_f (void)
00608 {
00609     char *error = NULL;
00610 
00611     if (CL_OnBattlescape()) {
00612         Com_Printf("Could not load the campaign while you are on the battlefield\n");
00613         return;
00614     }
00615 
00616     if (!SAV_GameLoad("slotquick", &error)) {
00617         Cbuf_Execute(); /* wipe outstanding campaign commands */
00618         Com_sprintf(popupText, sizeof(popupText), "%s\n%s", _("Error loading game."), error ? error : "");
00619         UI_Popup(_("Error"), popupText);
00620     } else {
00621         MS_AddNewMessage(_("Campaign loaded"), _("Quicksave campaign was successfully loaded."), qfalse, MSG_INFO, NULL);
00622         Cmd_ExecuteString("check_baseattacks");
00623     }
00624 }
00625 
00631 void SAV_Init (void)
00632 {
00633     static saveSubsystems_t b_subsystemXML = {"base", B_SaveXML, B_LoadXML};
00634     static saveSubsystems_t rs_subsystemXML = {"research", RS_SaveXML, RS_LoadXML};
00635     static saveSubsystems_t cp_subsystemXML = {"campaign", CP_SaveXML, CP_LoadXML};
00636     static saveSubsystems_t hos_subsystemXML = {"hospital", HOS_SaveXML, HOS_LoadXML};
00637     static saveSubsystems_t bs_subsystemXML = {"market", BS_SaveXML, BS_LoadXML};
00638     static saveSubsystems_t e_subsystemXML = {"employee", E_SaveXML, E_LoadXML};
00639     static saveSubsystems_t ac_subsystemXML = {"aliencont", AC_SaveXML, AC_LoadXML};
00640     static saveSubsystems_t pr_subsystemXML = {"production", PR_SaveXML, PR_LoadXML};
00641     static saveSubsystems_t air_subsystemXML = {"aircraft", AIR_SaveXML, AIR_LoadXML};
00642     static saveSubsystems_t ab_subsystemXML = {"alien base", AB_SaveXML, AB_LoadXML};
00643     static saveSubsystems_t int_subsystemXML = {"interest", CP_SaveInterestsXML, CP_LoadInterestsXML};
00644     static saveSubsystems_t mis_subsystemXML = {"mission", CP_SaveMissionsXML, CP_LoadMissionsXML};
00645     static saveSubsystems_t ms_subsystemXML = {"messagesystem", MS_SaveXML, MS_LoadXML};
00646     static saveSubsystems_t stats_subsystemXML = {"stats", STATS_SaveXML, STATS_LoadXML};
00647     static saveSubsystems_t na_subsystemXML = {"nations", NAT_SaveXML, NAT_LoadXML};
00648     static saveSubsystems_t trans_subsystemXML = {"transfer", TR_SaveXML, TR_LoadXML};
00649     static saveSubsystems_t xvi_subsystemXML = {"xvirate", XVI_SaveXML, XVI_LoadXML};
00650     static saveSubsystems_t ins_subsystemXML = {"installation", INS_SaveXML, INS_LoadXML};
00651     static saveSubsystems_t mso_subsystemXML = {"messageoptions", MSO_SaveXML, MSO_LoadXML};
00652     static saveSubsystems_t us_subsystemXML = {"ufostores", US_SaveXML, US_LoadXML};
00653 
00654     saveSubsystemsAmount = 0;
00655     memset(&saveSubsystems, 0, sizeof(saveSubsystems));
00656 
00657     Com_Printf("\n--- save subsystem initialization --\n");
00658 
00659     /* don't mess with the order */
00660     SAV_AddSubsystem(&b_subsystemXML);
00661     SAV_AddSubsystem(&rs_subsystemXML);
00662     SAV_AddSubsystem(&cp_subsystemXML);
00663     SAV_AddSubsystem(&hos_subsystemXML);
00664     SAV_AddSubsystem(&bs_subsystemXML);
00665     SAV_AddSubsystem(&e_subsystemXML);
00666     SAV_AddSubsystem(&ac_subsystemXML);
00667     SAV_AddSubsystem(&air_subsystemXML);
00668     SAV_AddSubsystem(&ab_subsystemXML);
00669     SAV_AddSubsystem(&int_subsystemXML);
00670     SAV_AddSubsystem(&mis_subsystemXML);
00671     SAV_AddSubsystem(&ins_subsystemXML);
00672     SAV_AddSubsystem(&us_subsystemXML);
00673     SAV_AddSubsystem(&pr_subsystemXML);
00674     SAV_AddSubsystem(&ms_subsystemXML);
00675     SAV_AddSubsystem(&stats_subsystemXML);
00676     SAV_AddSubsystem(&na_subsystemXML);
00677     SAV_AddSubsystem(&trans_subsystemXML);
00678     SAV_AddSubsystem(&xvi_subsystemXML);
00679     SAV_AddSubsystem(&mso_subsystemXML);
00680 
00681     Cmd_AddCommand("game_quickloadinit", SAV_GameQuickLoadInit_f, "Check whether there is a quicksave at all");
00682     Cmd_AddCommand("game_quicksave", SAV_GameQuickSave_f, _("Saves to the quick save slot"));
00683     Cmd_AddCommand("game_quickload", SAV_GameQuickLoad_f, "Loads the quick save slot");
00684     Cmd_AddCommand("game_save", SAV_GameSave_f, "Saves to a given filename");
00685     Cmd_AddCommand("game_load", SAV_GameLoad_f, "Loads a given filename");
00686     Cmd_AddCommand("game_comments", SAV_GameReadGameComments_f, "Loads the savegame names");
00687     Cmd_AddCommand("game_continue", SAV_GameContinue_f, "Continue with the last saved game");
00688     Cmd_AddCommand("game_savenamecleanup", SAV_GameSaveNameCleanup_f, "Remove the date string from mn_slotX cvars");
00689     save_compressed = Cvar_Get("save_compressed", "1", CVAR_ARCHIVE, "Save the savefiles compressed if set to 1");
00690 }
00691 

Generated by  doxygen 1.6.2