Reformat g_save.c

This commit is contained in:
Yamagi Burmeister 2011-10-14 13:04:38 +00:00
parent 0f1fbc8290
commit f13b82939e

View file

@ -1,21 +1,29 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
* Copyright (C) 1997-2001 Id Software, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* =======================================================================
*
* The savegame system. Unused by the CTF game but nevertheless called
* during game initialization. Therefor no new savegame code ist
* imported.
*
* =======================================================================
*/
#include "header/local.h"
@ -54,7 +62,7 @@ field_t fields[] = {
{"attenuation", FOFS(attenuation), F_FLOAT},
{"map", FOFS(map), F_LSTRING},
// temp spawn vars -- only valid when the spawn function is called
/* temp spawn vars -- only valid when the spawn function is called */
{"lip", STOFS(lip), F_INT, FFL_SPAWNTEMP},
{"distance", STOFS(distance), F_INT, FFL_SPAWNTEMP},
{"height", STOFS(height), F_INT, FFL_SPAWNTEMP},
@ -72,16 +80,7 @@ field_t fields[] = {
{"nextmap", STOFS(nextmap), F_LSTRING, FFL_SPAWNTEMP}
};
// -------- just for savegames ----------
// all pointer fields should be listed here, or savegames
// won't work properly (they will crash and burn).
// this wasn't just tacked on to the fields array, because
// these don't need names, we wouldn't want map fields using
// some of these, and if one were accidentally present twice
// it would double swizzle (fuck) the pointer.
field_t savefields[] =
{
field_t savefields[] = {
{"", FOFS(classname), F_LSTRING},
{"", FOFS(target), F_LSTRING},
{"", FOFS(targetname), F_LSTRING},
@ -114,8 +113,7 @@ field_t savefields[] =
{NULL, 0, F_INT}
};
field_t levelfields[] =
{
field_t levelfields[] = {
{"", LLOFS(changemap), F_LSTRING},
{"", LLOFS(sight_client), F_EDICT},
@ -126,8 +124,7 @@ field_t levelfields[] =
{NULL, 0, F_INT}
};
field_t clientfields[] =
{
field_t clientfields[] = {
{"", CLOFS(pers.weapon), F_ITEM},
{"", CLOFS(pers.lastweapon), F_ITEM},
{"", CLOFS(newweapon), F_ITEM},
@ -136,15 +133,12 @@ field_t clientfields[] =
};
/*
============
InitGame
This will be called when the dll is first loaded, which
only happens when a new game is started or a save game
is loaded.
============
* This will be called when the dll is first loaded, which
* only happens when a new game is started or a save game
* is loaded.
*/
void InitGame (void)
void
InitGame(void)
{
gi.dprintf("Game is starting up.\n");
gi.dprintf("Game is ctf.\n");
@ -152,98 +146,91 @@ void InitGame (void)
gun_x = gi.cvar("gun_x", "0", 0);
gun_y = gi.cvar("gun_y", "0", 0);
gun_z = gi.cvar("gun_z", "0", 0);
//FIXME: sv_ prefix is wrong for these
sv_rollspeed = gi.cvar("sv_rollspeed", "200", 0);
sv_rollangle = gi.cvar("sv_rollangle", "2", 0);
sv_maxvelocity = gi.cvar("sv_maxvelocity", "2000", 0);
sv_gravity = gi.cvar("sv_gravity", "800", 0);
// noset vars
/* noset vars */
dedicated = gi.cvar("dedicated", "0", CVAR_NOSET);
// latched vars
/* latched vars */
sv_cheats = gi.cvar("cheats", "0", CVAR_SERVERINFO | CVAR_LATCH);
gi.cvar("gamename", GAMEVERSION, CVAR_SERVERINFO | CVAR_LATCH);
gi.cvar("gamedate", __DATE__, CVAR_SERVERINFO | CVAR_LATCH);
maxclients = gi.cvar("maxclients", "4", CVAR_SERVERINFO | CVAR_LATCH);
deathmatch = gi.cvar("deathmatch", "0", CVAR_LATCH);
coop = gi.cvar("coop", "0", CVAR_LATCH);
skill = gi.cvar("skill", "1", CVAR_LATCH);
maxentities = gi.cvar("maxentities", "1024", CVAR_LATCH);
//ZOID
//This game.dll only supports deathmatch
if (!deathmatch->value) {
/* This game.dll only supports deathmatch */
if (!deathmatch->value)
{
gi.dprintf("Forcing deathmatch.\n");
gi.cvar_set("deathmatch", "1");
}
//force coop off
/* force coop off */
if (coop->value)
{
gi.cvar_set("coop", "0");
//ZOID
}
// change anytime vars
/* change anytime vars */
dmflags = gi.cvar("dmflags", "0", CVAR_SERVERINFO);
fraglimit = gi.cvar("fraglimit", "0", CVAR_SERVERINFO);
timelimit = gi.cvar("timelimit", "0", CVAR_SERVERINFO);
//ZOID
capturelimit = gi.cvar("capturelimit", "0", CVAR_SERVERINFO);
instantweap = gi.cvar("instantweap", "0", CVAR_SERVERINFO);
//ZOID
password = gi.cvar("password", "", CVAR_USERINFO);
filterban = gi.cvar("filterban", "1", 0);
g_select_empty = gi.cvar("g_select_empty", "0", CVAR_ARCHIVE);
run_pitch = gi.cvar("run_pitch", "0.002", 0);
run_roll = gi.cvar("run_roll", "0.005", 0);
bob_up = gi.cvar("bob_up", "0.005", 0);
bob_pitch = gi.cvar("bob_pitch", "0.002", 0);
bob_roll = gi.cvar("bob_roll", "0.002", 0);
// flood control
/* flood control */
flood_msgs = gi.cvar("flood_msgs", "4", 0);
flood_persecond = gi.cvar("flood_persecond", "4", 0);
flood_waitdelay = gi.cvar("flood_waitdelay", "10", 0);
// dm map list
/* dm map list */
sv_maplist = gi.cvar("sv_maplist", "", 0);
// items
/* items */
InitItems();
Com_sprintf(game.helpmessage1, sizeof(game.helpmessage1), "");
Com_sprintf(game.helpmessage2, sizeof(game.helpmessage2), "");
// initialize all entities for this game
/* initialize all entities for this game */
game.maxentities = maxentities->value;
g_edicts = gi.TagMalloc(game.maxentities * sizeof(g_edicts[0]), TAG_GAME);
globals.edicts = g_edicts;
globals.max_edicts = game.maxentities;
// initialize all clients for this game
/* initialize all clients for this game */
game.maxclients = maxclients->value;
game.clients = gi.TagMalloc(game.maxclients * sizeof(game.clients[0]), TAG_GAME);
globals.num_edicts = game.maxclients + 1;
//ZOID
CTFInit();
//ZOID
}
//=========================================================
/* ========================================================= */
void WriteField1 (FILE *f, field_t *field, byte *base)
void
WriteField1(FILE *f, field_t *field, byte *base)
{
void *p;
int len;
int index;
p = (void *)(base + field->ofs);
switch (field->type)
{
case F_INT:
@ -255,31 +242,55 @@ void WriteField1 (FILE *f, field_t *field, byte *base)
case F_LSTRING:
case F_GSTRING:
if (*(char **)p)
{
len = strlen(*(char **)p) + 1;
}
else
{
len = 0;
}
*(int *)p = len;
break;
case F_EDICT:
if (*(edict_t **)p == NULL)
{
index = -1;
}
else
{
index = *(edict_t **)p - g_edicts;
}
*(int *)p = index;
break;
case F_CLIENT:
if (*(gclient_t **)p == NULL)
{
index = -1;
}
else
{
index = *(gclient_t **)p - game.clients;
}
*(int *)p = index;
break;
case F_ITEM:
if (*(edict_t **)p == NULL)
{
index = -1;
}
else
{
index = *(gitem_t **)p - itemlist;
}
*(int *)p = index;
break;
@ -288,34 +299,40 @@ void WriteField1 (FILE *f, field_t *field, byte *base)
}
}
void WriteField2 (FILE *f, field_t *field, byte *base)
void
WriteField2(FILE *f, field_t *field, byte *base)
{
int len;
void *p;
p = (void *)(base + field->ofs);
switch (field->type)
{
case F_LSTRING:
case F_GSTRING:
if (*(char **)p)
{
len = strlen(*(char **)p) + 1;
fwrite(*(char **)p, len, 1, f);
}
break;
default:
break;
}
}
void ReadField (FILE *f, field_t *field, byte *base)
void
ReadField(FILE *f, field_t *field, byte *base)
{
void *p;
int len;
int index;
p = (void *)(base + field->ofs);
switch (field->type)
{
case F_INT:
@ -327,44 +344,70 @@ void ReadField (FILE *f, field_t *field, byte *base)
case F_LSTRING:
len = *(int *)p;
if (!len)
{
*(char **)p = NULL;
}
else
{
*(char **)p = gi.TagMalloc(len, TAG_LEVEL);
fread(*(char **)p, len, 1, f);
}
break;
case F_GSTRING:
len = *(int *)p;
if (!len)
{
*(char **)p = NULL;
}
else
{
*(char **)p = gi.TagMalloc(len, TAG_GAME);
fread(*(char **)p, len, 1, f);
}
break;
case F_EDICT:
index = *(int *)p;
if (index == -1)
{
*(edict_t **)p = NULL;
}
else
{
*(edict_t **)p = &g_edicts[index];
}
break;
case F_CLIENT:
index = *(int *)p;
if (index == -1)
{
*(gclient_t **)p = NULL;
}
else
{
*(gclient_t **)p = &game.clients[index];
}
break;
case F_ITEM:
index = *(int *)p;
if (index == -1)
{
*(gitem_t **)p = NULL;
}
else
{
*(gitem_t **)p = &itemlist[index];
}
break;
default:
@ -372,33 +415,31 @@ void ReadField (FILE *f, field_t *field, byte *base)
}
}
//=========================================================
/* ========================================================= */
/*
==============
WriteClient
All pointer variables (except function pointers) must be handled specially.
==============
* All pointer variables (except function
* pointers) must be handled specially.
*/
void WriteClient (FILE *f, gclient_t *client)
void
WriteClient(FILE *f, gclient_t *client)
{
field_t *field;
gclient_t temp;
// all of the ints, floats, and vectors stay as they are
/* all of the ints, floats, and vectors stay as they are */
temp = *client;
// change the pointers to lengths or indexes
/* change the pointers to lengths or indexes */
for (field = clientfields; field->name; field++)
{
WriteField1(f, field, (byte *)&temp);
}
// write the block
/* write the block */
fwrite(&temp, sizeof(temp), 1, f);
// now write any allocated data following the edict
/* now write any allocated data following the edict */
for (field = clientfields; field->name; field++)
{
WriteField2(f, field, (byte *)client);
@ -406,13 +447,11 @@ void WriteClient (FILE *f, gclient_t *client)
}
/*
==============
ReadClient
All pointer variables (except function pointers) must be handled specially.
==============
* All pointer variables (except function
* pointers) must be handled specially.
*/
void ReadClient (FILE *f, gclient_t *client)
void
ReadClient(FILE *f, gclient_t *client)
{
field_t *field;
@ -425,31 +464,33 @@ void ReadClient (FILE *f, gclient_t *client)
}
/*
============
WriteGame
This will be called whenever the game goes to a new level,
and when the user explicitly saves the game.
Game information include cross level data, like multi level
triggers, help computer info, and all client states.
A single player death will automatically restore from the
last save position.
============
* This will be called whenever the game goes to a new level,
* and when the user explicitly saves the game.
*
* Game information include cross level data, like multi level
* triggers, help computer info, and all client states.
*
* A single player death will automatically restore from the
* last save position.
*/
void WriteGame (char *filename, qboolean autosave)
void
WriteGame(char *filename, qboolean autosave)
{
FILE *f;
int i;
char str[16];
if (!autosave)
{
SaveClientData();
}
f = fopen(filename, "wb");
if (!f)
{
gi.error("Couldn't open %s", filename);
}
memset(str, 0, sizeof(str));
strcpy(str, __DATE__);
@ -460,12 +501,15 @@ void WriteGame (char *filename, qboolean autosave)
game.autosaved = false;
for (i = 0; i < game.maxclients; i++)
{
WriteClient(f, &game.clients[i]);
}
fclose(f);
}
void ReadGame (char *filename)
void
ReadGame(char *filename)
{
FILE *f;
int i;
@ -474,10 +518,14 @@ void ReadGame (char *filename)
gi.FreeTags(TAG_GAME);
f = fopen(filename, "rb");
if (!f)
{
gi.error("Couldn't open %s", filename);
}
fread(str, sizeof(str), 1, f);
if (strcmp(str, __DATE__))
{
fclose(f);
@ -489,87 +537,81 @@ void ReadGame (char *filename)
fread(&game, sizeof(game), 1, f);
game.clients = gi.TagMalloc(game.maxclients * sizeof(game.clients[0]), TAG_GAME);
for (i = 0; i < game.maxclients; i++)
{
ReadClient(f, &game.clients[i]);
}
fclose(f);
}
//==========================================================
/* ========================================================== */
/*
==============
WriteEdict
All pointer variables (except function pointers) must be handled specially.
==============
* All pointer variables (except function
* pointers) must be handled specially.
*/
void WriteEdict (FILE *f, edict_t *ent)
void
WriteEdict(FILE *f, edict_t *ent)
{
field_t *field;
edict_t temp;
// all of the ints, floats, and vectors stay as they are
/* all of the ints, floats, and vectors stay as they are */
temp = *ent;
// change the pointers to lengths or indexes
/* change the pointers to lengths or indexes */
for (field = savefields; field->name; field++)
{
WriteField1(f, field, (byte *)&temp);
}
// write the block
/* write the block */
fwrite(&temp, sizeof(temp), 1, f);
// now write any allocated data following the edict
/* now write any allocated data following the edict */
for (field = savefields; field->name; field++)
{
WriteField2(f, field, (byte *)ent);
}
}
/*
==============
WriteLevelLocals
All pointer variables (except function pointers) must be handled specially.
==============
* All pointer variables (except function
* pointers) must be handled specially.
*/
void WriteLevelLocals (FILE *f)
void
WriteLevelLocals(FILE *f)
{
field_t *field;
level_locals_t temp;
// all of the ints, floats, and vectors stay as they are
/* all of the ints, floats, and vectors stay as they are */
temp = level;
// change the pointers to lengths or indexes
/* change the pointers to lengths or indexes */
for (field = levelfields; field->name; field++)
{
WriteField1(f, field, (byte *)&temp);
}
// write the block
/* write the block */
fwrite(&temp, sizeof(temp), 1, f);
// now write any allocated data following the edict
/* now write any allocated data following the edict */
for (field = levelfields; field->name; field++)
{
WriteField2(f, field, (byte *)&level);
}
}
/*
==============
ReadEdict
All pointer variables (except function pointers) must be handled specially.
==============
* All pointer variables (except function
* pointers) must be handled specially.
*/
void ReadEdict (FILE *f, edict_t *ent)
void
ReadEdict(FILE *f, edict_t *ent)
{
field_t *field;
@ -582,13 +624,11 @@ void ReadEdict (FILE *f, edict_t *ent)
}
/*
==============
ReadLevelLocals
All pointer variables (except function pointers) must be handled specially.
==============
* All pointer variables (except function
* pointers) must be handled specially.
*/
void ReadLevelLocals (FILE *f)
void
ReadLevelLocals(FILE *f)
{
field_t *field;
@ -600,13 +640,8 @@ void ReadLevelLocals (FILE *f)
}
}
/*
=================
WriteLevel
=================
*/
void WriteLevel (char *filename)
void
WriteLevel(char *filename)
{
int i;
edict_t *ent;
@ -614,53 +649,57 @@ void WriteLevel (char *filename)
void *base;
f = fopen(filename, "wb");
if (!f)
gi.error ("Couldn't open %s", filename);
// write out edict size for checking
if (!f)
{
gi.error("Couldn't open %s", filename);
}
/* write out edict size for checking */
i = sizeof(edict_t);
fwrite(&i, sizeof(i), 1, f);
// write out a function pointer for checking
/* write out a function pointer for checking */
base = (void *)InitGame;
fwrite(&base, sizeof(base), 1, f);
// write out level_locals_t
/* write out level_locals_t */
WriteLevelLocals(f);
// write out all the entities
/* write out all the entities */
for (i = 0; i < globals.num_edicts; i++)
{
ent = &g_edicts[i];
if (!ent->inuse)
{
continue;
}
fwrite(&i, sizeof(i), 1, f);
WriteEdict(f, ent);
}
i = -1;
fwrite(&i, sizeof(i), 1, f);
fclose(f);
}
/*
=================
ReadLevel
SpawnEntities will allready have been called on the
level the same way it was when the level was saved.
That is necessary to get the baselines
set up identically.
The server will have cleared all of the world links before
calling ReadLevel.
No clients are connected yet.
=================
* SpawnEntities will allready have been called on the
* level the same way it was when the level was saved.
*
* That is necessary to get the baselines
* set up identically.
*
* The server will have cleared all of the world links before
* calling ReadLevel.
*
* No clients are connected yet.
*/
void ReadLevel (char *filename)
void
ReadLevel(char *filename)
{
int entnum;
FILE *f;
@ -669,37 +708,42 @@ void ReadLevel (char *filename)
edict_t *ent;
f = fopen(filename, "rb");
if (!f)
gi.error ("Couldn't open %s", filename);
// free any dynamic memory allocated by loading the level
// base state
if (!f)
{
gi.error("Couldn't open %s", filename);
}
/* free any dynamic memory allocated by
loading the level base state */
gi.FreeTags(TAG_LEVEL);
// wipe all the entities
/* wipe all the entities */
memset(g_edicts, 0, game.maxentities * sizeof(g_edicts[0]));
globals.num_edicts = maxclients->value + 1;
// check edict size
/* check edict size */
fread(&i, sizeof(i), 1, f);
if (i != sizeof(edict_t))
{
fclose(f);
gi.error("ReadLevel: mismatched edict size");
}
// check function pointer base address
/* check function pointer base address */
fread(&base, sizeof(base), 1, f);
if (base != (void *)InitGame)
{
fclose(f);
gi.error("ReadLevel: function pointers have moved");
}
// load the level locals
/* load the level locals */
ReadLevelLocals(f);
// load all the entities
/* load all the entities */
while (1)
{
if (fread(&entnum, sizeof(entnum), 1, f) != 1)
@ -707,22 +751,28 @@ void ReadLevel (char *filename)
fclose(f);
gi.error("ReadLevel: failed to read entnum");
}
if (entnum == -1)
{
break;
}
if (entnum >= globals.num_edicts)
{
globals.num_edicts = entnum + 1;
}
ent = &g_edicts[entnum];
ReadEdict(f, ent);
// let the server rebuild world links for this ent
/* let the server rebuild world links for this ent */
memset(&ent->area, 0, sizeof(ent->area));
gi.linkentity(ent);
}
fclose(f);
// mark all clients as unconnected
/* mark all clients as unconnected */
for (i = 0; i < maxclients->value; i++)
{
ent = &g_edicts[i + 1];
@ -730,18 +780,24 @@ void ReadLevel (char *filename)
ent->client->pers.connected = false;
}
// do any load time things at this point
/* do any load time things at this point */
for (i = 0; i < globals.num_edicts; i++)
{
ent = &g_edicts[i];
if (!ent->inuse)
{
continue;
}
// fire any cross-level triggers
/* fire any cross-level triggers */
if (ent->classname)
{
if (strcmp(ent->classname, "target_crosslevel_target") == 0)
{
ent->nextthink = level.time + ent->delay;
}
}
}
}