PageRenderTime 53ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/sv_save.c

https://gitlab.com/fzwoch/fodquake
C | 250 lines | 179 code | 41 blank | 30 comment | 61 complexity | d280491004aceae8bce8ecb9b4905f39 MD5 | raw file
Possible License(s): GPL-2.0
  1. /*
  2. Copyright (C) 1996-1997 Id Software, Inc.
  3. This program is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU General Public License
  5. as published by the Free Software Foundation; either version 2
  6. of the License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. See the GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  14. */
  15. #ifndef SERVERONLY
  16. #include <string.h>
  17. #include "quakedef.h"
  18. #include "filesystem.h"
  19. #include "server.h"
  20. #include "sv_world.h"
  21. extern cvar_t maxclients;
  22. #define SAVEGAME_COMMENT_LENGTH 39
  23. #define SAVEGAME_VERSION 6
  24. //Writes a SAVEGAME_COMMENT_LENGTH character comment
  25. void SV_SavegameComment (char *buffer) {
  26. int i;
  27. char kills[20];
  28. for (i = 0; i < SAVEGAME_COMMENT_LENGTH; i++)
  29. buffer[i] = ' ';
  30. memcpy (buffer, cl.levelname, strlen(cl.levelname));
  31. sprintf (kills, "kills:%3i/%-3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]);
  32. memcpy (buffer + 22, kills, strlen(kills));
  33. // convert space to _ to make stdio happy
  34. for (i = 0; i < SAVEGAME_COMMENT_LENGTH; i++)
  35. if (buffer[i] == ' ')
  36. buffer[i] = '_';
  37. buffer[SAVEGAME_COMMENT_LENGTH] = 0;
  38. }
  39. void SV_SaveGame_f (void) {
  40. char fname[MAX_OSPATH], comment[SAVEGAME_COMMENT_LENGTH+1];
  41. FILE *f;
  42. int i;
  43. if (Cmd_Argc() != 2) {
  44. Com_Printf ("Usage: %s <savefname> : save a game\n", Cmd_Argv(0));
  45. return;
  46. } else if (strstr(Cmd_Argv(1), "..")) {
  47. Com_Printf ("Relative pathfnames are not allowed.\n");
  48. return;
  49. } else if (sv.state != ss_active) {
  50. Com_Printf ("Not playing a local game.\n");
  51. return;
  52. } else if (cl.intermission) {
  53. Com_Printf ("Can't save in intermission.\n");
  54. return;
  55. } else if (deathmatch.value != 0 || coop.value != 0 || maxclients.value != 1) {
  56. Com_Printf ("Can't save multiplayer games.\n");
  57. return;
  58. }
  59. for (i = 1; i < MAX_CLIENTS; i++) {
  60. if (svs.clients[i] && svs.clients[i]->state == cs_spawned) {
  61. Com_Printf ("Can't save multiplayer games.\n");
  62. return;
  63. }
  64. }
  65. if (svs.clients[0] == 0 || svs.clients[0]->state != cs_spawned) {
  66. Com_Printf ("Can't save, client #0 not spawned.\n");
  67. return;
  68. } else if (svs.clients[0]->edict->v.health <= 0) {
  69. Com_Printf ("Can't save game with a dead player\n");
  70. // in fact, we can, but does it make sense?
  71. return;
  72. }
  73. Q_snprintfz (fname, sizeof(fname), "%s/save/%s", com_gamedir, Cmd_Argv(1));
  74. COM_DefaultExtension (fname, ".sav");
  75. Com_Printf ("Saving game to %s...\n", fname);
  76. if (!(f = fopen (fname, "w"))) {
  77. FS_CreatePath (fname);
  78. if (!(f = fopen (fname, "w"))) {
  79. Com_Printf ("ERROR: couldn't open.\n");
  80. return;
  81. }
  82. }
  83. fprintf (f, "%i\n", SAVEGAME_VERSION);
  84. SV_SavegameComment (comment);
  85. fprintf (f, "%s\n", comment);
  86. for (i = 0 ; i < NUM_SPAWN_PARMS; i++)
  87. fprintf (f, "%f\n", svs.clients[0]->spawn_parms[i]);
  88. fprintf (f, "%d\n", current_skill);
  89. fprintf (f, "%s\n", sv.name);
  90. fprintf (f, "%f\n", sv.time);
  91. // write the light styles
  92. for (i = 0; i < MAX_LIGHTSTYLES; i++) {
  93. if (sv.lightstyles[i])
  94. fprintf (f, "%s\n", sv.lightstyles[i]);
  95. else
  96. fprintf (f,"m\n");
  97. }
  98. ED_WriteGlobals (f);
  99. for (i = 0; i < sv.num_edicts; i++) {
  100. ED_Write (f, EDICT_NUM(i));
  101. fflush (f);
  102. }
  103. fclose (f);
  104. Com_Printf ("done.\n");
  105. }
  106. void SV_LoadGame_f (void) {
  107. char name[MAX_OSPATH], mapname[MAX_QPATH], str[32 * 1024], *start;
  108. FILE *f;
  109. float time, tfloat, spawn_parms[NUM_SPAWN_PARMS];
  110. edict_t *ent;
  111. int entnum, version, i, r;
  112. if (Cmd_Argc() != 2) {
  113. Com_Printf ("Usage: %s <savename> : load a game\n", Cmd_Argv(0));
  114. return;
  115. }
  116. Q_snprintfz(name, sizeof(name), "%s/save/%s", com_gamedir, Cmd_Argv(1));
  117. COM_DefaultExtension (name, ".sav");
  118. Com_Printf ("Loading game from %s...\n", name);
  119. if (!(f = fopen (name, "r"))) {
  120. Com_Printf ("ERROR: couldn't open.\n");
  121. return;
  122. }
  123. fscanf (f, "%i\n", &version);
  124. if (version != SAVEGAME_VERSION) {
  125. fclose (f);
  126. Com_Printf ("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION);
  127. return;
  128. }
  129. fscanf (f, "%s\n", str);
  130. for (i = 0; i < NUM_SPAWN_PARMS; i++)
  131. fscanf (f, "%f\n", &spawn_parms[i]);
  132. // this silliness is so we can load 1.06 save files, which have float skill values
  133. fscanf (f, "%f\n", &tfloat);
  134. current_skill = (int)(tfloat + 0.1);
  135. Cvar_Set (&skill, va("%i", current_skill));
  136. Cvar_SetValue (&deathmatch, 0);
  137. Cvar_SetValue (&coop, 0);
  138. Cvar_SetValue (&teamplay, 0);
  139. Cvar_SetValue (&maxclients, 1);
  140. fscanf (f, "%s\n", mapname);
  141. fscanf (f, "%f\n", &time);
  142. Host_EndGame();
  143. CL_BeginLocalConnection ();
  144. SV_SpawnServer (mapname, false);
  145. if (sv.state != ss_active) {
  146. Com_Printf ("Couldn't load map\n");
  147. return;
  148. }
  149. sv.paused = true; // pause until all clients connect
  150. sv.loadgame = true;
  151. Sys_Error("The local server is currently broken. Sorry.");
  152. // load the light styles
  153. for (i = 0; i < MAX_LIGHTSTYLES; i++) {
  154. fscanf (f, "%s\n", str);
  155. #if 0
  156. /* You need to fix that call */
  157. sv.lightstyles[i] = Junk_Alloc(strlen(str) + 1);
  158. #endif
  159. strcpy (sv.lightstyles[i], str);
  160. }
  161. // load the edicts out of the savegame file
  162. entnum = -1; // -1 is the globals
  163. while (!feof(f)) {
  164. for (i = 0; i < sizeof(str) - 1; i++) {
  165. r = fgetc (f);
  166. if (r == EOF || !r)
  167. break;
  168. str[i] = r;
  169. if (r == '}') {
  170. i++;
  171. break;
  172. }
  173. }
  174. if (i == sizeof(str)-1)
  175. Host_Error ("Loadgame buffer overflow");
  176. str[i] = 0;
  177. start = str;
  178. start = COM_Parse(str);
  179. if (!com_token[0])
  180. break; // end of file
  181. if (strcmp(com_token,"{"))
  182. Host_Error ("First token isn't a brace");
  183. if (entnum == -1) {
  184. // parse the global vars
  185. ED_ParseGlobals (start);
  186. } else {
  187. // parse an edict
  188. ent = EDICT_NUM(entnum);
  189. memset (&ent->v, 0, progs->entityfields * 4);
  190. ent->free = false;
  191. ED_ParseEdict (start, ent);
  192. // link it into the bsp tree
  193. if (!ent->free)
  194. SV_LinkEdict (ent, false);
  195. }
  196. entnum++;
  197. }
  198. sv.num_edicts = entnum;
  199. sv.time = time;
  200. fclose (f);
  201. for (i = 0; i < NUM_SPAWN_PARMS; i++)
  202. svs.clients[0]->spawn_parms[i] = spawn_parms[i];
  203. }
  204. #endif //!SERVERONLY