/** * @brief Console command binding for save function * @sa SAV_GameSave * @note called via 'game_save' command */ static void SAV_GameSave_f (void) { char comment[MAX_VAR] = ""; char *error = NULL; bool result; /* get argument */ if (Cmd_Argc() < 2) { Com_Printf("Usage: %s <filename> <comment|*cvar>\n", Cmd_Argv(0)); return; } if (!CP_IsRunning()) { Com_Printf("No running game - no saving...\n"); return; } /* get comment */ if (Cmd_Argc() > 2) { const char *arg = Cmd_Argv(2); Q_strncpyz(comment, arg, sizeof(comment)); } result = SAV_GameSave(Cmd_Argv(1), comment, &error); if (!result) { if (error) CP_Popup(_("Note"), "%s\n%s", _("Error saving game."), error); else CP_Popup(_("Note"), "%s\n%s", "%s\n", _("Error saving game.")); } }
/** * @brief Saves to the quick save slot * @sa SAV_GameQuickLoad_f */ static void SAV_GameQuickSave_f (void) { if (!CP_IsRunning()) return; if (!SAV_QuickSave()) Com_Printf("Could not save the campaign\n"); else MS_AddNewMessage(_("Quicksave"), _("Campaign was successfully saved."), MSG_INFO); }
static void GAME_SCP_Frame (float secondsSinceLastFrame) { if (!scd->initialized && CP_IsRunning()) { SCP_Parse(); SCP_CampaignActivateFirstStage(); scd->initialized = true; } GAME_CP_Frame(secondsSinceLastFrame); }
/** * @brief Saves to the quick save slot */ static void SAV_GameQuickSave_f (void) { if (!CP_IsRunning()) return; if (cgi->CL_OnBattlescape()) return; char* error = nullptr; bool result = SAV_GameSave("slotquick", _("QuickSave"), &error); if (!result) Com_Printf("Error saving the xml game: %s\n", error ? error : ""); else MS_AddNewMessage(_("Quicksave"), _("Campaign was successfully saved."), MSG_INFO); }
/** * @brief Loads the last saved game * @note At saving the archive cvar cl_lastsave was set to the latest savegame * @sa SAV_GameLoad */ static void SAV_GameContinue_f (void) { const char *error = NULL; if (cgi->CL_OnBattlescape()) { cgi->UI_PopWindow(false); return; } if (!CP_IsRunning()) { /* try to load the last saved campaign */ if (!SAV_GameLoad(cl_lastsave->string, &error)) { Cbuf_Execute(); /* wipe outstanding campaign commands */ cgi->UI_Popup(_("Error"), "%s\n%s", _("Error loading game."), error ? error : ""); Cmd_ExecuteString("game_exit"); } } else { /* just continue the current running game */ cgi->UI_PopWindow(false); } }
/** * @brief Show campaign stats in console */ static void CP_CampaignStats_f (void) { campaign_t *campaign = ccs.curCampaign; const salary_t *salary; if (!CP_IsRunning()) { Com_Printf("No campaign active\n"); return; } salary = &campaign->salaries; Com_Printf("Campaign id: %s\n", campaign->id); Com_Printf("..research list: %s\n", campaign->researched); Com_Printf("..equipment: %s\n", campaign->equipment); Com_Printf("..team: %i\n", campaign->team); Com_Printf("..salaries:\n"); Com_Printf("...soldier_base: %i\n", CP_GetSalaryBaseEmployee(salary, EMPL_SOLDIER)); Com_Printf("...soldier_rankbonus: %i\n", CP_GetSalaryRankBonusEmployee(salary, EMPL_SOLDIER)); Com_Printf("...worker_base: %i\n", CP_GetSalaryBaseEmployee(salary, EMPL_WORKER)); Com_Printf("...worker_rankbonus: %i\n", CP_GetSalaryRankBonusEmployee(salary, EMPL_WORKER)); Com_Printf("...scientist_base: %i\n", CP_GetSalaryBaseEmployee(salary, EMPL_SCIENTIST)); Com_Printf("...scientist_rankbonus: %i\n", CP_GetSalaryRankBonusEmployee(salary, EMPL_SCIENTIST)); Com_Printf("...pilot_base: %i\n", CP_GetSalaryBaseEmployee(salary, EMPL_PILOT)); Com_Printf("...pilot_rankbonus: %i\n", CP_GetSalaryRankBonusEmployee(salary, EMPL_PILOT)); Com_Printf("...robot_base: %i\n", CP_GetSalaryBaseEmployee(salary, EMPL_ROBOT)); Com_Printf("...robot_rankbonus: %i\n", CP_GetSalaryRankBonusEmployee(salary, EMPL_ROBOT)); Com_Printf("...aircraft_factor: %i\n", salary->aircraftFactor); Com_Printf("...aircraft_divisor: %i\n", salary->aircraftDivisor); Com_Printf("...base_upkeep: %i\n", salary->baseUpkeep); Com_Printf("...admin_initial: %i\n", salary->adminInitial); Com_Printf("...admin_soldier: %i\n", CP_GetSalaryAdminEmployee(salary, EMPL_SOLDIER)); Com_Printf("...admin_worker: %i\n", CP_GetSalaryAdminEmployee(salary, EMPL_WORKER)); Com_Printf("...admin_scientist: %i\n", CP_GetSalaryAdminEmployee(salary, EMPL_SCIENTIST)); Com_Printf("...admin_pilot: %i\n", CP_GetSalaryAdminEmployee(salary, EMPL_PILOT)); Com_Printf("...admin_robot: %i\n", CP_GetSalaryAdminEmployee(salary, EMPL_ROBOT)); Com_Printf("...debt_interest: %.5f\n", salary->debtInterest); }
/** * @brief This is a savegame function which stores the game in xml-Format. * @param[in] filename The Filename to save to (without extension) * @param[in] comment Description of the savegame * @param[out] error On failure an errormessage may be set. */ static bool SAV_GameSave (const char *filename, const char *comment, char **error) { xmlNode_t *topNode, *node; char savegame[MAX_OSPATH]; int res; int requiredBufferLength; uLongf bufLen; saveFileHeader_t header; char dummy[2]; int i; dateLong_t date; char message[30]; char timeStampBuffer[32]; if (!CP_IsRunning()) { *error = _("No campaign active."); Com_Printf("Error: No campaign active.\n"); return false; } if (!B_AtLeastOneExists()) { *error = _("Nothing to save yet."); Com_Printf("Error: Nothing to save yet.\n"); return false; } Com_MakeTimestamp(timeStampBuffer, sizeof(timeStampBuffer)); Com_sprintf(savegame, sizeof(savegame), "save/%s.%s", filename, SAVEGAME_EXTENSION); topNode = mxmlNewXML("1.0"); node = XML_AddNode(topNode, SAVE_ROOTNODE); /* writing Header */ XML_AddInt(node, SAVE_SAVEVERSION, SAVE_FILE_VERSION); XML_AddString(node, SAVE_COMMENT, comment); XML_AddString(node, SAVE_UFOVERSION, UFO_VERSION); XML_AddString(node, SAVE_REALDATE, timeStampBuffer); CP_DateConvertLong(&ccs.date, &date); Com_sprintf(message, sizeof(message), _("%i %s %02i"), date.year, Date_GetMonthName(date.month - 1), date.day); XML_AddString(node, SAVE_GAMEDATE, message); /* working through all subsystems. perhaps we should redesign it, order is not important anymore */ Com_Printf("Calling subsystems\n"); for (i = 0; i < saveSubsystemsAmount; i++) { if (!saveSubsystems[i].save(node)) Com_Printf("...subsystem '%s' failed to save the data\n", saveSubsystems[i].name); else Com_Printf("...subsystem '%s' - saved\n", saveSubsystems[i].name); } /* calculate the needed buffer size */ OBJZERO(header); header.compressed = LittleLong(save_compressed->integer); header.version = LittleLong(SAVE_FILE_VERSION); header.subsystems = LittleLong(saveSubsystemsAmount); Q_strncpyz(header.name, comment, sizeof(header.name)); Q_strncpyz(header.gameVersion, UFO_VERSION, sizeof(header.gameVersion)); CP_DateConvertLong(&ccs.date, &date); Com_sprintf(header.gameDate, sizeof(header.gameDate), _("%i %s %02i"), date.year, Date_GetMonthName(date.month - 1), date.day); Q_strncpyz(header.realDate, timeStampBuffer, sizeof(header.realDate)); requiredBufferLength = mxmlSaveString(topNode, dummy, 2, MXML_NO_CALLBACK); header.xmlSize = LittleLong(requiredBufferLength); byte* const buf = Mem_PoolAllocTypeN(byte, requiredBufferLength + 1, cp_campaignPool); if (!buf) { mxmlDelete(topNode); *error = _("Could not allocate enough memory to save this game"); Com_Printf("Error: Could not allocate enough memory to save this game\n"); return false; } res = mxmlSaveString(topNode, (char*)buf, requiredBufferLength + 1, MXML_NO_CALLBACK); mxmlDelete(topNode); Com_Printf("XML Written to buffer (%d Bytes)\n", res); if (header.compressed) bufLen = compressBound(requiredBufferLength); else bufLen = requiredBufferLength; byte* const fbuf = Mem_PoolAllocTypeN(byte, bufLen + sizeof(header), cp_campaignPool); memcpy(fbuf, &header, sizeof(header)); if (header.compressed) { res = compress(fbuf + sizeof(header), &bufLen, buf, requiredBufferLength); Mem_Free(buf); if (res != Z_OK) { Mem_Free(fbuf); *error = _("Memory error compressing save-game data - set save_compressed cvar to 0"); Com_Printf("Memory error compressing save-game data (%s) (Error: %i)!\n", comment, res); return false; } } else { memcpy(fbuf + sizeof(header), buf, requiredBufferLength); Mem_Free(buf); } /* last step - write data */ res = FS_WriteFile(fbuf, bufLen + sizeof(header), savegame); Mem_Free(fbuf); return true; }