/* =============== Host_Loadgame_f =============== */ void Host_Loadgame_f (void) { char name[MAX_OSPATH]; FILE *f; char mapname[MAX_QPATH]; float time, tfloat; char str[32768]; const char *start; int i, r; edict_t *ent; int entnum; int version; float spawn_parms[NUM_SPAWN_PARMS]; if (cmd_source != src_command) return; if (Cmd_Argc() != 2) { Con_Printf ("load <savename> : load a game\n"); return; } cls.demonum = -1; // stop demo loop in case this fails q_snprintf (name, sizeof(name), "%s/%s", com_gamedir, Cmd_Argv(1)); COM_AddExtension (name, ".sav", sizeof(name)); // we can't call SCR_BeginLoadingPlaque, because too much stack space has // been used. The menu calls it before stuffing loadgame command // SCR_BeginLoadingPlaque (); Con_Printf ("Loading game from %s...\n", name); f = fopen (name, "r"); if (!f) { Con_Printf ("ERROR: couldn't open.\n"); return; } fscanf (f, "%i\n", &version); if (version != SAVEGAME_VERSION) { fclose (f); Con_Printf ("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION); return; } fscanf (f, "%s\n", str); for (i = 0; i < NUM_SPAWN_PARMS; i++) fscanf (f, "%f\n", &spawn_parms[i]); // this silliness is so we can load 1.06 save files, which have float skill values fscanf (f, "%f\n", &tfloat); current_skill = (int)(tfloat + 0.1); Cvar_SetValue ("skill", (float)current_skill); fscanf (f, "%s\n",mapname); fscanf (f, "%f\n",&time); CL_Disconnect_f (); SV_SpawnServer (mapname); if (!sv.active) { fclose (f); Con_Printf ("Couldn't load map\n"); return; } sv.paused = true; // pause until all clients connect sv.loadgame = true; // load the light styles for (i = 0; i < MAX_LIGHTSTYLES; i++) { fscanf (f, "%s\n", str); sv.lightstyles[i] = (const char *)Hunk_Strdup (str, "lightstyles"); } // load the edicts out of the savegame file entnum = -1; // -1 is the globals while (!feof(f)) { qboolean inside_string = false; for (i = 0; i < (int) sizeof(str) - 1; i++) { r = fgetc (f); if (r == EOF || !r) break; str[i] = r; if (r == '"') { inside_string = !inside_string; } else if (r == '}' && !inside_string) // only handle } characters outside of quoted strings { i++; break; } } if (i == (int) sizeof(str) - 1) { fclose (f); Sys_Error ("Loadgame buffer overflow"); } str[i] = 0; start = str; start = COM_Parse(str); if (!com_token[0]) break; // end of file if (strcmp(com_token,"{")) { fclose (f); Sys_Error ("First token isn't a brace"); } if (entnum == -1) { // parse the global vars ED_ParseGlobals (start); } else { // parse an edict ent = EDICT_NUM(entnum); memset (&ent->v, 0, progs->entityfields * 4); ent->free = false; ED_ParseEdict (start, ent); // link it into the bsp tree if (!ent->free) SV_LinkEdict (ent, false); } entnum++; } sv.num_edicts = entnum; sv.time = time; fclose (f); for (i = 0; i < NUM_SPAWN_PARMS; i++) svs.clients->spawn_parms[i] = spawn_parms[i]; if (cls.state != ca_dedicated) { CL_EstablishConnection ("local"); Host_Reconnect_f (); } }
static int LoadGamestate (const char *level, const char *startspot, int ClientsMode) { FILE *f; char mapname[MAX_QPATH]; float playtime, sk; char str[32768]; const char *start; int i, r; edict_t *ent; int entnum; int version; // float spawn_parms[NUM_SPAWN_PARMS]; qboolean auto_correct = false; if (ClientsMode == 1) /* for RestoreClients() only: map must be active */ { if (!sv.active) { Con_Printf ("%s: server not active\n", __thisfunc__); return -1; } FS_MakePath_BUF (FS_USERDIR, &r, savename, sizeof(savename), "clients.gip"); if (r) { Host_Error("%s: %d: string buffer overflow!", __thisfunc__, __LINE__); return -1; } } else { FS_MakePath_VABUF (FS_USERDIR, &r, savename, sizeof(savename), "%s.gip", level); if (r) { Host_Error("%s: %d: string buffer overflow!", __thisfunc__, __LINE__); return -1; } if (ClientsMode != 2 && ClientsMode != 3) Con_Printf ("Loading game from %s...\n", savename); } f = fopen (savename, "r"); if (!f) { if (ClientsMode == 2) Con_Printf ("%s: ERROR: couldn't open savefile\n", __thisfunc__); return -1; } fscanf (f, "%i\n", &version); if (version != SAVEGAME_VERSION) { fclose (f); Con_Printf ("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION); return -1; } if (ClientsMode != 1) { fscanf (f, "%s\n", str); // for (i = 0; i < NUM_SPAWN_PARMS; i++) // fscanf (f, "%f\n", &spawn_parms[i]); fscanf (f, "%f\n", &sk); Cvar_SetValue ("skill", sk); fscanf (f, "%s\n", mapname); fscanf (f, "%f\n", &playtime); SV_SpawnServer (mapname, startspot); if (!sv.active) { fclose (f); Con_Printf ("Couldn't load map\n"); return -1; } // load the light styles for (i = 0; i < MAX_LIGHTSTYLES; i++) { fscanf (f, "%s\n", str); sv.lightstyles[i] = (const char *)Hunk_Strdup (str, "lightstyles"); } SV_LoadEffects (f); } // load the edicts out of the savegame file while (!feof(f)) { fscanf (f, "%i\n", &entnum); for (i = 0; i < (int) sizeof(str) - 1; i++) { r = fgetc (f); if (r == EOF || !r) break; str[i] = r; if (r == '}') { i++; break; } } if (i == (int) sizeof(str) - 1) { fclose (f); Host_Error ("%s: Loadgame buffer overflow", __thisfunc__); } str[i] = 0; start = str; start = COM_Parse(str); if (!com_token[0]) break; // end of file if (strcmp(com_token,"{")) { fclose (f); Host_Error ("%s: First token isn't a brace", __thisfunc__); } // parse an edict if (entnum == -1) { ED_ParseGlobals (start); // Need to restore this *sv_globals.startspot = PR_SetEngineString(sv.startspot); } else { ent = EDICT_NUM(entnum); /* default to active edict: ED_ParseEdict() set it * to free if it really is free. cf. ED_Write() */ ent->free = false; /* ED_ParseEdict() will always memset ent->v to 0, * because SaveGamestate() doesn't write entnum 0 */ ED_ParseEdict (start, ent); if (ClientsMode == 1 || ClientsMode == 2 || ClientsMode == 3) ent->v.stats_restored = true; // link it into the bsp tree if (!ent->free) { if (entnum >= sv.num_edicts) { /* This is necessary to restore "generated" edicts which were * not available during the map parsing by ED_LoadFromFile(). * This includes items dropped by monsters, items "dropped" by * an item_spawner such as the "prizes" in the Temple of Mars * (romeric5), a health sphere generated by the Crusader's * Holy Strength ability, or a respawning-candidate killed * monster in the expansion pack's nightmare mode. -- THOMAS */ /* Moved this into the if (!ent->free) construct: less debug * chatter. Even if this skips a free edict in between, the * skipped free edict wasn't parsed by ED_LoadFromFile() and * it will remain as a freed edict. (There is no harm because * we are dealing with extra edicts not originally present in * the map.) -- O.S. */ Con_DPrintf("%s: entnum %d >= sv.num_edicts (%d)\n", __thisfunc__, entnum, sv.num_edicts); sv.num_edicts = entnum + 1; } SV_LinkEdict (ent, false); if (ent->v.modelindex && ent->v.model) { i = SV_ModelIndex(PR_GetString(ent->v.model)); if (i != ent->v.modelindex) { ent->v.modelindex = i; auto_correct = true; } } } } } fclose (f); if (ClientsMode == 0) { sv.time = playtime; sv.paused = true; *sv_globals.serverflags = svs.serverflags; RestoreClients (0); } else if (ClientsMode == 2) { sv.time = playtime; } else if (ClientsMode == 3) { sv.time = playtime; *sv_globals.serverflags = svs.serverflags; RestoreClients (3); } if (ClientsMode != 1 && auto_correct) { Con_DPrintf("*** Auto-corrected model indexes!\n"); } // for (i = 0; i < NUM_SPAWN_PARMS; i++) // svs.clients->spawn_parms[i] = spawn_parms[i]; return 0; }