// changing levels within a unit void Host_Changelevel2_f (void) { char level[MAX_QPATH]; char _startspot[MAX_QPATH]; char *startspot; if (Cmd_Argc() < 2) { Con_Printf ("changelevel2 <levelname> : continue game on a new level in the unit\n"); return; } if (!sv.active || cls.demoplayback) { Con_Printf ("Only the server may changelevel\n"); return; } strcpy (level, Cmd_Argv(1)); if (Cmd_Argc() == 2) startspot = NULL; else { strcpy (_startspot, Cmd_Argv(2)); startspot = _startspot; } SV_SaveSpawnparms (); // save the current level's state SaveGamestate (); // try to restore the new level if (LoadGamestate (level, startspot)) SV_SpawnServer (level, startspot); }
/* ================== Host_Changelevel2_f changing levels within a unit ================== */ static void Host_Changelevel2_f (void) { char level[MAX_QPATH]; char _startspot[MAX_QPATH]; char *startspot; if (Cmd_Argc() < 2) { Con_Printf ("changelevel2 <levelname> : continue game on a new level in the unit\n"); return; } if (!sv.active || cls.demoplayback) { Con_Printf ("Only the server may changelevel\n"); return; } q_snprintf (level, sizeof(level), "maps/%s.bsp", Cmd_Argv(1)); if (!FS_FileExists(level, NULL)) Host_Error ("%s: cannot find map %s", __thisfunc__, level); q_strlcpy (level, Cmd_Argv(1), sizeof(level)); if (Cmd_Argc() == 2) startspot = NULL; else { q_strlcpy (_startspot, Cmd_Argv(2), sizeof(_startspot)); startspot = _startspot; } SV_SaveSpawnparms (); // save the current level's state old_svtime = sv.time; if (SaveGamestate(false) != 0) return; // try to restore the new level if (LoadGamestate(level, startspot, 0) != 0) { SV_SpawnServer (level, startspot); if (!sv.active) Host_Error ("%s: cannot run map %s", __thisfunc__, level); RestoreClients (0); } }
static void RestoreClients (int ClientsMode) { int i, j; edict_t *ent; double time_diff; if (LoadGamestate(NULL, NULL, 1) != 0) return; /* O.S. -- mode 3 is only in response to the single player game "restart restore" * command issued by progs.dat::client.hc::respawn() function. No level change, * just respawning in the same map with the same playtime from when clients.gip * was saved, therefore there _CANNOT_ be a time_diff. See uhexen2 bug #2176023: * http://sourceforge.net/tracker/?group_id=124987&atid=701006&aid=2176023&func=detail */ time_diff = (ClientsMode == 3) ? 0 : sv.time - old_svtime; for (i = 0, host_client = svs.clients; i < svs.maxclients; i++, host_client++) { if (host_client->active) { ent = host_client->edict; //ent->v.colormap = NUM_FOR_EDICT(ent); ent->v.team = (host_client->colors & 15) + 1; ent->v.netname = PR_SetEngineString(host_client->name); ent->v.playerclass = host_client->playerclass; // copy spawn parms out of the client_t for (j = 0; j < NUM_SPAWN_PARMS; j++) sv_globals.parm[j] = host_client->spawn_parms[j]; // call the spawn function *sv_globals.time = sv.time; *sv_globals.self = EDICT_TO_PROG(ent); G_FLOAT(OFS_PARM0) = time_diff; PR_ExecuteProgram (*sv_globals.ClientReEnter); } } SaveGamestate (true); }
/* =============== Host_Savegame_f =============== */ static void Host_Savegame_f (void) { FILE *f; int i, error_state; char comment[SAVEGAME_COMMENT_LENGTH+1]; const char *p; if (cmd_source != src_command) return; if (!sv.active) { Con_Printf ("Not playing a local game.\n"); return; } if (cl.intermission) { Con_Printf ("Can't save in intermission.\n"); return; } #ifndef TESTSAVE if (svs.maxclients != 1) { Con_Printf ("Can't save multiplayer games.\n"); return; } #endif if (Cmd_Argc() != 2) { Con_Printf ("save <savename> : save a game\n"); return; } p = Cmd_Argv(1); if (*p == '.' || strstr(p, "..")) { Con_Printf ("Invalid save name.\n"); return; } for (i = 0; i < svs.maxclients; i++) { if (svs.clients[i].active && (svs.clients[i].edict->v.health <= 0) ) { Con_Printf ("Can't savegame with a dead player\n"); return; } } error_state = SaveGamestate (false); // don't bother doing more if SaveGamestate failed if (error_state) return; FS_MakePath_BUF (FS_USERDIR, &error_state, savename, sizeof(savename), p); if (error_state) { Con_Printf ("%s: save directory name too long\n", __thisfunc__); return; } if (Sys_mkdir(savename, false) != 0) { Con_Printf ("Unable to create save directory\n"); return; } Host_RemoveGIPFiles(savename); FS_MakePath_BUF (FS_USERDIR, NULL, savename, sizeof(savename), "clients.gip"); Sys_unlink(savename); FS_MakePath_BUF (FS_USERDIR, NULL, savedest, sizeof(savedest), p); Con_Printf ("Saving game to %s...\n", savedest); error_state = Host_CopyFiles(FS_GetUserdir(), "*.gip", savedest); if (error_state) goto finish; FS_MakePath_VABUF (FS_USERDIR, &error_state, savedest, sizeof(savedest), "%s/info.dat", p); if (error_state) { Host_Error("%s: %d: string buffer overflow!", __thisfunc__, __LINE__); return; } f = fopen (savedest, "w"); if (!f) { error_state = 1; Con_Printf ("%s: Unable to open %s for writing!\n", __thisfunc__, savedest); goto finish; } fprintf (f, "%i\n", SAVEGAME_VERSION); Host_SavegameComment (comment); fprintf (f, "%s\n", comment); for (i = 0; i < NUM_SPAWN_PARMS; i++) fprintf (f, "%f\n", svs.clients->spawn_parms[i]); fprintf (f, "%d\n", current_skill); fprintf (f, "%s\n", sv.name); fprintf (f, "%f\n", sv.time); fprintf (f, "%d\n", svs.maxclients); fprintf (f, "%f\n", deathmatch.value); fprintf (f, "%f\n", coop.value); fprintf (f, "%f\n", teamplay.value); fprintf (f, "%f\n", randomclass.value); fprintf (f, "%f\n", cl_playerclass.value); // mission pack, objectives strings fprintf (f, "%u\n", info_mask); fprintf (f, "%u\n", info_mask2); error_state = ferror(f); fclose(f); finish: if (error_state) Host_Error ("%s: The game could not be saved properly!", __thisfunc__); }