mirror of
https://github.com/yquake2/zaero.git
synced 2024-11-22 03:51:13 +00:00
Port the new savegame system
This commit is contained in:
parent
59bfb6f8c4
commit
6d456db7d1
5 changed files with 1077 additions and 980 deletions
4
Makefile
4
Makefile
|
@ -91,7 +91,7 @@ ZAERO_OBJS = \
|
||||||
build/g_misc.o \
|
build/g_misc.o \
|
||||||
build/g_monster.o \
|
build/g_monster.o \
|
||||||
build/g_phys.o \
|
build/g_phys.o \
|
||||||
build/g_save.o \
|
build/savegame.o \
|
||||||
build/g_spawn.o \
|
build/g_spawn.o \
|
||||||
build/g_svcmds.o \
|
build/g_svcmds.o \
|
||||||
build/g_target.o \
|
build/g_target.o \
|
||||||
|
@ -174,7 +174,7 @@ build/g_monster.o: src/g_monster.c
|
||||||
build/g_phys.o: src/g_phys.c
|
build/g_phys.o: src/g_phys.c
|
||||||
$(CC) $(CFLAGS) -o $@ -c $<
|
$(CC) $(CFLAGS) -o $@ -c $<
|
||||||
|
|
||||||
build/g_save.o: src/g_save.c
|
build/savegame.o: src/savegame/savegame.c
|
||||||
$(CC) $(CFLAGS) -o $@ -c $<
|
$(CC) $(CFLAGS) -o $@ -c $<
|
||||||
|
|
||||||
build/g_spawn.o: src/g_spawn.c
|
build/g_spawn.o: src/g_spawn.c
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
#define Z_FREE(block) gi.TagFree(block)
|
#define Z_FREE(block) gi.TagFree(block)
|
||||||
|
|
||||||
// the "gamename" client command will print this plus compile date
|
// the "gamename" client command will print this plus compile date
|
||||||
#define GAMEVERSION "Zaero 1.1"
|
#define GAMEVERSION "zaero"
|
||||||
|
|
||||||
// protocol bytes that can be directly added to messages
|
// protocol bytes that can be directly added to messages
|
||||||
#define svc_muzzleflash 1
|
#define svc_muzzleflash 1
|
||||||
|
|
742
src/g_save.c
742
src/g_save.c
|
@ -1,742 +0,0 @@
|
||||||
#include "g_local.h"
|
|
||||||
|
|
||||||
#define Function(f) {#f, f}
|
|
||||||
|
|
||||||
mmove_t mmove_reloc;
|
|
||||||
|
|
||||||
field_t fields[] = {
|
|
||||||
{"classname", FOFS(classname), F_LSTRING},
|
|
||||||
{"model", FOFS(model), F_LSTRING},
|
|
||||||
{"spawnflags", FOFS(spawnflags), F_INT},
|
|
||||||
{"speed", FOFS(speed), F_FLOAT},
|
|
||||||
{"accel", FOFS(accel), F_FLOAT},
|
|
||||||
{"decel", FOFS(decel), F_FLOAT},
|
|
||||||
{"target", FOFS(target), F_LSTRING},
|
|
||||||
{"targetname", FOFS(targetname), F_LSTRING},
|
|
||||||
{"pathtarget", FOFS(pathtarget), F_LSTRING},
|
|
||||||
{"deathtarget", FOFS(deathtarget), F_LSTRING},
|
|
||||||
{"killtarget", FOFS(killtarget), F_LSTRING},
|
|
||||||
{"combattarget", FOFS(combattarget), F_LSTRING},
|
|
||||||
{"message", FOFS(message), F_LSTRING},
|
|
||||||
{"team", FOFS(team), F_LSTRING},
|
|
||||||
{"wait", FOFS(wait), F_FLOAT},
|
|
||||||
{"delay", FOFS(delay), F_FLOAT},
|
|
||||||
{"random", FOFS(random), F_FLOAT},
|
|
||||||
{"move_origin", FOFS(move_origin), F_VECTOR},
|
|
||||||
{"move_angles", FOFS(move_angles), F_VECTOR},
|
|
||||||
{"style", FOFS(style), F_INT},
|
|
||||||
{"count", FOFS(count), F_INT},
|
|
||||||
{"health", FOFS(health), F_INT},
|
|
||||||
{"sounds", FOFS(sounds), F_INT},
|
|
||||||
{"light", 0, F_IGNORE},
|
|
||||||
{"dmg", FOFS(dmg), F_INT},
|
|
||||||
{"mass", FOFS(mass), F_INT},
|
|
||||||
{"volume", FOFS(volume), F_FLOAT},
|
|
||||||
{"attenuation", FOFS(attenuation), F_FLOAT},
|
|
||||||
{"map", FOFS(map), F_LSTRING},
|
|
||||||
{"origin", FOFS(s.origin), F_VECTOR},
|
|
||||||
{"angles", FOFS(s.angles), F_VECTOR},
|
|
||||||
{"angle", FOFS(s.angles), F_ANGLEHACK},
|
|
||||||
|
|
||||||
// Knightmare- hack for setting alpha, allows mappers to specify
|
|
||||||
// an entity's alpha value with the key "salpha"
|
|
||||||
#ifdef KMQUAKE2_ENGINE_MOD
|
|
||||||
{"salpha", FOFS(s.alpha), F_FLOAT},
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// zaero
|
|
||||||
{"mangle", FOFS(mangle), F_VECTOR},
|
|
||||||
{"active", FOFS(active), F_INT},
|
|
||||||
{"spawnflags2", FOFS(spawnflags2), F_INT},
|
|
||||||
{"mteam", FOFS(mteam), F_LSTRING},
|
|
||||||
{"mirrortarget", 0, F_IGNORE},
|
|
||||||
{"mirrorlevelsave", 0, F_IGNORE},
|
|
||||||
|
|
||||||
// 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},
|
|
||||||
{"noise", STOFS(noise), F_LSTRING, FFL_SPAWNTEMP},
|
|
||||||
{"pausetime", STOFS(pausetime), F_FLOAT, FFL_SPAWNTEMP},
|
|
||||||
{"item", STOFS(item), F_LSTRING, FFL_SPAWNTEMP},
|
|
||||||
|
|
||||||
//need for item field in edict struct, FFL_SPAWNTEMP item will be skipped on saves
|
|
||||||
{"item", FOFS(item), F_ITEM},
|
|
||||||
|
|
||||||
{"gravity", STOFS(gravity), F_LSTRING, FFL_SPAWNTEMP},
|
|
||||||
{"sky", STOFS(sky), F_LSTRING, FFL_SPAWNTEMP},
|
|
||||||
{"skyrotate", STOFS(skyrotate), F_FLOAT, FFL_SPAWNTEMP},
|
|
||||||
{"skyaxis", STOFS(skyaxis), F_VECTOR, FFL_SPAWNTEMP},
|
|
||||||
{"minyaw", STOFS(minyaw), F_FLOAT, FFL_SPAWNTEMP},
|
|
||||||
{"maxyaw", STOFS(maxyaw), F_FLOAT, FFL_SPAWNTEMP},
|
|
||||||
{"minpitch", STOFS(minpitch), F_FLOAT, FFL_SPAWNTEMP},
|
|
||||||
{"maxpitch", STOFS(maxpitch), F_FLOAT, FFL_SPAWNTEMP},
|
|
||||||
{"nextmap", STOFS(nextmap), F_LSTRING, FFL_SPAWNTEMP},
|
|
||||||
|
|
||||||
{0, 0, 0, 0}
|
|
||||||
};
|
|
||||||
|
|
||||||
field_t levelfields[] =
|
|
||||||
{
|
|
||||||
{"changemap", LLOFS(changemap), F_LSTRING},
|
|
||||||
|
|
||||||
{"sight_client", LLOFS(sight_client), F_EDICT},
|
|
||||||
{"sight_entity", LLOFS(sight_entity), F_EDICT},
|
|
||||||
{"sound_entity", LLOFS(sound_entity), F_EDICT},
|
|
||||||
{"sound2_entity", LLOFS(sound2_entity), F_EDICT},
|
|
||||||
|
|
||||||
{NULL, 0, F_INT}
|
|
||||||
};
|
|
||||||
|
|
||||||
field_t clientfields[] =
|
|
||||||
{
|
|
||||||
{"pers.weapon", CLOFS(pers.weapon), F_ITEM},
|
|
||||||
{"pers.lastweapon", CLOFS(pers.lastweapon), F_ITEM},
|
|
||||||
{"pers.lastweapon2", CLOFS(pers.lastweapon2), F_ITEM},
|
|
||||||
{"newweapon", CLOFS(newweapon), F_ITEM},
|
|
||||||
|
|
||||||
// evolve
|
|
||||||
{"", CLOFS(zCameraTrack), F_EDICT},
|
|
||||||
{"", CLOFS(zCameraLocalEntity), F_EDICT},
|
|
||||||
|
|
||||||
{NULL, 0, F_INT}
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
============
|
|
||||||
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.
|
|
||||||
============
|
|
||||||
*/
|
|
||||||
void InitGame (void)
|
|
||||||
{
|
|
||||||
gi.dprintf ("==== InitGame ====\n");
|
|
||||||
|
|
||||||
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
|
|
||||||
dedicated = gi.cvar ("dedicated", "0", CVAR_NOSET);
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
//maxspectators = gi.cvar ("maxspectators", "4", CVAR_SERVERINFO);
|
|
||||||
deathmatch = gi.cvar ("deathmatch", "0", CVAR_LATCH);
|
|
||||||
coop = gi.cvar ("coop", "0", CVAR_LATCH);
|
|
||||||
skill = gi.cvar ("skill", "1", CVAR_LATCH);
|
|
||||||
|
|
||||||
//Knightmare- increase maxentities
|
|
||||||
//maxentities = gi.cvar ("maxentities", "1024", CVAR_LATCH);
|
|
||||||
maxentities = gi.cvar ("maxentities", va("%i",MAX_EDICTS), CVAR_LATCH);
|
|
||||||
|
|
||||||
// change anytime vars
|
|
||||||
dmflags = gi.cvar ("dmflags", "0", CVAR_SERVERINFO);
|
|
||||||
fraglimit = gi.cvar ("fraglimit", "0", CVAR_SERVERINFO);
|
|
||||||
timelimit = gi.cvar ("timelimit", "0", CVAR_SERVERINFO);
|
|
||||||
password = gi.cvar ("password", "", CVAR_USERINFO);
|
|
||||||
//spectator_password = gi.cvar ("spectator_password", "", CVAR_USERINFO);
|
|
||||||
//needpass = gi.cvar ("needpass", "0", CVAR_SERVERINFO);
|
|
||||||
//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_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
|
|
||||||
//sv_maplist = gi.cvar ("sv_maplist", "", 0);
|
|
||||||
|
|
||||||
// items
|
|
||||||
InitItems ();
|
|
||||||
|
|
||||||
Com_sprintf (game.helpmessage1, sizeof(game.helpmessage1), "");
|
|
||||||
|
|
||||||
Com_sprintf (game.helpmessage2, sizeof(game.helpmessage2), "");
|
|
||||||
|
|
||||||
// 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
|
|
||||||
game.maxclients = maxclients->value;
|
|
||||||
game.clients = gi.TagMalloc (game.maxclients * sizeof(game.clients[0]), TAG_GAME);
|
|
||||||
globals.num_edicts = game.maxclients+1;
|
|
||||||
}
|
|
||||||
|
|
||||||
//=========================================================
|
|
||||||
|
|
||||||
void WriteField1 (FILE *f, field_t *field, byte *base)
|
|
||||||
{
|
|
||||||
void *p;
|
|
||||||
int len;
|
|
||||||
int index;
|
|
||||||
|
|
||||||
if (field->flags & FFL_SPAWNTEMP)
|
|
||||||
return;
|
|
||||||
|
|
||||||
p = (void *)(base + field->ofs);
|
|
||||||
switch (field->type)
|
|
||||||
{
|
|
||||||
case F_INT:
|
|
||||||
case F_FLOAT:
|
|
||||||
case F_ANGLEHACK:
|
|
||||||
case F_VECTOR:
|
|
||||||
case F_IGNORE:
|
|
||||||
break;
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
//relative to code segment
|
|
||||||
case F_FUNCTION:
|
|
||||||
if (*(byte **)p == NULL)
|
|
||||||
index = 0;
|
|
||||||
else
|
|
||||||
index = *(byte **)p - ((byte *)InitGame);
|
|
||||||
*(int *)p = index;
|
|
||||||
break;
|
|
||||||
|
|
||||||
//relative to data segment
|
|
||||||
case F_MMOVE:
|
|
||||||
if (*(byte **)p == NULL)
|
|
||||||
index = 0;
|
|
||||||
else
|
|
||||||
index = *(byte **)p - (byte *)&mmove_reloc;
|
|
||||||
*(int *)p = index;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
gi.error ("WriteEdict: unknown field type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void WriteField2 (FILE *f, field_t *field, byte *base)
|
|
||||||
{
|
|
||||||
int len;
|
|
||||||
void *p;
|
|
||||||
|
|
||||||
if (field->flags & FFL_SPAWNTEMP)
|
|
||||||
return;
|
|
||||||
|
|
||||||
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 *p;
|
|
||||||
int len;
|
|
||||||
int index;
|
|
||||||
|
|
||||||
if (field->flags & FFL_SPAWNTEMP)
|
|
||||||
return;
|
|
||||||
|
|
||||||
p = (void *)(base + field->ofs);
|
|
||||||
switch (field->type)
|
|
||||||
{
|
|
||||||
case F_INT:
|
|
||||||
case F_FLOAT:
|
|
||||||
case F_ANGLEHACK:
|
|
||||||
case F_VECTOR:
|
|
||||||
case F_IGNORE:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case F_LSTRING:
|
|
||||||
len = *(int *)p;
|
|
||||||
if (!len)
|
|
||||||
*(char **)p = NULL;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
SBF: FIXME - 32 extra bytes alloc'd since the saved
|
|
||||||
string might not be long enough
|
|
||||||
*/
|
|
||||||
*(char **)p = gi.TagMalloc (32+len, TAG_LEVEL);
|
|
||||||
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;
|
|
||||||
|
|
||||||
//relative to code segment
|
|
||||||
case F_FUNCTION:
|
|
||||||
index = *(int *)p;
|
|
||||||
if ( index == 0 )
|
|
||||||
*(byte **)p = NULL;
|
|
||||||
else
|
|
||||||
*(byte **)p = ((byte *)InitGame) + index;
|
|
||||||
break;
|
|
||||||
|
|
||||||
//relative to data segment
|
|
||||||
case F_MMOVE:
|
|
||||||
index = *(int *)p;
|
|
||||||
if (index == 0)
|
|
||||||
*(byte **)p = NULL;
|
|
||||||
else
|
|
||||||
*(byte **)p = (byte *)&mmove_reloc + index;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
gi.error ("ReadEdict: unknown field type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//=========================================================
|
|
||||||
|
|
||||||
/*
|
|
||||||
==============
|
|
||||||
WriteClient
|
|
||||||
|
|
||||||
All pointer variables (except function pointers) must be handled specially.
|
|
||||||
==============
|
|
||||||
*/
|
|
||||||
void WriteClient (FILE *f, gclient_t *client)
|
|
||||||
{
|
|
||||||
field_t *field;
|
|
||||||
gclient_t temp;
|
|
||||||
|
|
||||||
// all of the ints, floats, and vectors stay as they are
|
|
||||||
temp = *client;
|
|
||||||
|
|
||||||
// change the pointers to lengths or indexes
|
|
||||||
for (field=clientfields ; field->name ; field++)
|
|
||||||
{
|
|
||||||
WriteField1 (f, field, (byte *)&temp);
|
|
||||||
}
|
|
||||||
|
|
||||||
// write the block
|
|
||||||
fwrite (&temp, sizeof(temp), 1, f);
|
|
||||||
|
|
||||||
// now write any allocated data following the edict
|
|
||||||
for (field=clientfields ; field->name ; field++)
|
|
||||||
{
|
|
||||||
WriteField2 (f, field, (byte *)client);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
==============
|
|
||||||
ReadClient
|
|
||||||
|
|
||||||
All pointer variables (except function pointers) must be handled specially.
|
|
||||||
==============
|
|
||||||
*/
|
|
||||||
void ReadClient (FILE *f, gclient_t *client)
|
|
||||||
{
|
|
||||||
field_t *field;
|
|
||||||
|
|
||||||
fread (client, sizeof(*client), 1, f);
|
|
||||||
|
|
||||||
for (field=clientfields ; field->name ; field++)
|
|
||||||
{
|
|
||||||
ReadField (f, field, (byte *)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.
|
|
||||||
============
|
|
||||||
*/
|
|
||||||
void WriteGame (const 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__);
|
|
||||||
fwrite (str, sizeof(str), 1, f);
|
|
||||||
|
|
||||||
game.autosaved = autosave;
|
|
||||||
fwrite (&game, sizeof(game), 1, f);
|
|
||||||
game.autosaved = false;
|
|
||||||
|
|
||||||
for (i=0 ; i<game.maxclients ; i++)
|
|
||||||
WriteClient (f, &game.clients[i]);
|
|
||||||
|
|
||||||
fclose (f);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ReadGame (const char *filename)
|
|
||||||
{
|
|
||||||
FILE *f;
|
|
||||||
int i;
|
|
||||||
char str[16];
|
|
||||||
|
|
||||||
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);
|
|
||||||
gi.error ("Savegame from an older version.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
g_edicts = gi.TagMalloc (game.maxentities * sizeof(g_edicts[0]), TAG_GAME);
|
|
||||||
globals.edicts = g_edicts;
|
|
||||||
|
|
||||||
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.
|
|
||||||
==============
|
|
||||||
*/
|
|
||||||
void WriteEdict (FILE *f, edict_t *ent)
|
|
||||||
{
|
|
||||||
field_t *field;
|
|
||||||
edict_t temp;
|
|
||||||
|
|
||||||
// all of the ints, floats, and vectors stay as they are
|
|
||||||
temp = *ent;
|
|
||||||
|
|
||||||
// change the pointers to lengths or indexes
|
|
||||||
for (field=fields ; field->name ; field++)
|
|
||||||
{
|
|
||||||
WriteField1 (f, field, (byte *)&temp);
|
|
||||||
}
|
|
||||||
|
|
||||||
// write the block
|
|
||||||
fwrite (&temp, sizeof(temp), 1, f);
|
|
||||||
|
|
||||||
// now write any allocated data following the edict
|
|
||||||
for (field=fields ; field->name ; field++)
|
|
||||||
{
|
|
||||||
WriteField2 (f, field, (byte *)ent);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
==============
|
|
||||||
WriteLevelLocals
|
|
||||||
|
|
||||||
All pointer variables (except function pointers) must be handled specially.
|
|
||||||
==============
|
|
||||||
*/
|
|
||||||
void WriteLevelLocals (FILE *f)
|
|
||||||
{
|
|
||||||
field_t *field;
|
|
||||||
level_locals_t temp;
|
|
||||||
|
|
||||||
// all of the ints, floats, and vectors stay as they are
|
|
||||||
temp = level;
|
|
||||||
|
|
||||||
// change the pointers to lengths or indexes
|
|
||||||
for (field=levelfields ; field->name ; field++)
|
|
||||||
{
|
|
||||||
WriteField1 (f, field, (byte *)&temp);
|
|
||||||
}
|
|
||||||
|
|
||||||
// write the block
|
|
||||||
fwrite (&temp, sizeof(temp), 1, f);
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
==============
|
|
||||||
*/
|
|
||||||
void ReadEdict (FILE *f, edict_t *ent)
|
|
||||||
{
|
|
||||||
field_t *field;
|
|
||||||
|
|
||||||
fread (ent, sizeof(*ent), 1, f);
|
|
||||||
|
|
||||||
for (field=fields ; field->name ; field++)
|
|
||||||
{
|
|
||||||
ReadField (f, field, (byte *)ent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
==============
|
|
||||||
ReadLevelLocals
|
|
||||||
|
|
||||||
All pointer variables (except function pointers) must be handled specially.
|
|
||||||
==============
|
|
||||||
*/
|
|
||||||
void ReadLevelLocals (FILE *f)
|
|
||||||
{
|
|
||||||
field_t *field;
|
|
||||||
|
|
||||||
fread (&level, sizeof(level), 1, f);
|
|
||||||
|
|
||||||
for (field=levelfields ; field->name ; field++)
|
|
||||||
{
|
|
||||||
ReadField (f, field, (byte *)&level);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
=================
|
|
||||||
WriteLevel
|
|
||||||
|
|
||||||
=================
|
|
||||||
*/
|
|
||||||
void WriteLevel (const char *filename)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
edict_t *ent;
|
|
||||||
FILE *f;
|
|
||||||
void *base;
|
|
||||||
|
|
||||||
f = fopen (filename, "wb");
|
|
||||||
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
|
|
||||||
base = (void *)InitGame;
|
|
||||||
fwrite (&base, sizeof(base), 1, f);
|
|
||||||
|
|
||||||
// write out level_locals_t
|
|
||||||
WriteLevelLocals (f);
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
=================
|
|
||||||
*/
|
|
||||||
void ReadLevel (const char *filename)
|
|
||||||
{
|
|
||||||
int entnum;
|
|
||||||
FILE *f;
|
|
||||||
int i;
|
|
||||||
void *base;
|
|
||||||
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
|
|
||||||
gi.FreeTags (TAG_LEVEL);
|
|
||||||
|
|
||||||
// wipe all the entities
|
|
||||||
memset (g_edicts, 0, game.maxentities*sizeof(g_edicts[0]));
|
|
||||||
globals.num_edicts = maxclients->value+1;
|
|
||||||
|
|
||||||
// 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
|
|
||||||
fread (&base, sizeof(base), 1, f);
|
|
||||||
/*#ifdef _WIN32
|
|
||||||
if (base != (void *)InitGame)
|
|
||||||
{
|
|
||||||
fclose (f);
|
|
||||||
gi.error ("ReadLevel: function pointers have moved");
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
gi.dprintf("Function offsets %d\n", ((byte *)base) - ((byte *)InitGame));
|
|
||||||
#endif*/
|
|
||||||
|
|
||||||
// load the level locals
|
|
||||||
ReadLevelLocals (f);
|
|
||||||
|
|
||||||
// load all the entities
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
if (fread (&entnum, sizeof(entnum), 1, f) != 1)
|
|
||||||
{
|
|
||||||
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
|
|
||||||
memset (&ent->area, 0, sizeof(ent->area));
|
|
||||||
gi.linkentity (ent);
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose (f);
|
|
||||||
|
|
||||||
// mark all clients as unconnected
|
|
||||||
for (i=0 ; i<maxclients->value ; i++)
|
|
||||||
{
|
|
||||||
ent = &g_edicts[i+1];
|
|
||||||
ent->client = game.clients + i;
|
|
||||||
ent->client->pers.connected = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
if (ent->classname)
|
|
||||||
if (strcmp(ent->classname, "target_crosslevel_target") == 0)
|
|
||||||
ent->nextthink = level.time + ent->delay;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
235
src/q_shared.c
235
src/q_shared.c
|
@ -326,7 +326,6 @@ BoxOnPlaneSide
|
||||||
Returns 1, 2, or 1 + 2
|
Returns 1, 2, or 1 + 2
|
||||||
==================
|
==================
|
||||||
*/
|
*/
|
||||||
#if !id386
|
|
||||||
int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct cplane_s *p)
|
int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct cplane_s *p)
|
||||||
{
|
{
|
||||||
float dist1, dist2;
|
float dist1, dist2;
|
||||||
|
@ -393,240 +392,6 @@ dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
|
||||||
|
|
||||||
return sides;
|
return sides;
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
#pragma warning( disable: 4035 )
|
|
||||||
|
|
||||||
__declspec( naked ) int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct cplane_s *p)
|
|
||||||
{
|
|
||||||
static int bops_initialized;
|
|
||||||
static int Ljmptab[8];
|
|
||||||
|
|
||||||
__asm {
|
|
||||||
|
|
||||||
push ebx
|
|
||||||
|
|
||||||
cmp bops_initialized, 1
|
|
||||||
je initialized
|
|
||||||
mov bops_initialized, 1
|
|
||||||
|
|
||||||
mov Ljmptab[0*4], offset Lcase0
|
|
||||||
mov Ljmptab[1*4], offset Lcase1
|
|
||||||
mov Ljmptab[2*4], offset Lcase2
|
|
||||||
mov Ljmptab[3*4], offset Lcase3
|
|
||||||
mov Ljmptab[4*4], offset Lcase4
|
|
||||||
mov Ljmptab[5*4], offset Lcase5
|
|
||||||
mov Ljmptab[6*4], offset Lcase6
|
|
||||||
mov Ljmptab[7*4], offset Lcase7
|
|
||||||
|
|
||||||
initialized:
|
|
||||||
|
|
||||||
mov edx,ds:dword ptr[4+12+esp]
|
|
||||||
mov ecx,ds:dword ptr[4+4+esp]
|
|
||||||
xor eax,eax
|
|
||||||
mov ebx,ds:dword ptr[4+8+esp]
|
|
||||||
mov al,ds:byte ptr[17+edx]
|
|
||||||
cmp al,8
|
|
||||||
jge Lerror
|
|
||||||
fld ds:dword ptr[0+edx]
|
|
||||||
fld st(0)
|
|
||||||
jmp dword ptr[Ljmptab+eax*4]
|
|
||||||
Lcase0:
|
|
||||||
fmul ds:dword ptr[ebx]
|
|
||||||
fld ds:dword ptr[0+4+edx]
|
|
||||||
fxch st(2)
|
|
||||||
fmul ds:dword ptr[ecx]
|
|
||||||
fxch st(2)
|
|
||||||
fld st(0)
|
|
||||||
fmul ds:dword ptr[4+ebx]
|
|
||||||
fld ds:dword ptr[0+8+edx]
|
|
||||||
fxch st(2)
|
|
||||||
fmul ds:dword ptr[4+ecx]
|
|
||||||
fxch st(2)
|
|
||||||
fld st(0)
|
|
||||||
fmul ds:dword ptr[8+ebx]
|
|
||||||
fxch st(5)
|
|
||||||
faddp st(3),st(0)
|
|
||||||
fmul ds:dword ptr[8+ecx]
|
|
||||||
fxch st(1)
|
|
||||||
faddp st(3),st(0)
|
|
||||||
fxch st(3)
|
|
||||||
faddp st(2),st(0)
|
|
||||||
jmp LSetSides
|
|
||||||
Lcase1:
|
|
||||||
fmul ds:dword ptr[ecx]
|
|
||||||
fld ds:dword ptr[0+4+edx]
|
|
||||||
fxch st(2)
|
|
||||||
fmul ds:dword ptr[ebx]
|
|
||||||
fxch st(2)
|
|
||||||
fld st(0)
|
|
||||||
fmul ds:dword ptr[4+ebx]
|
|
||||||
fld ds:dword ptr[0+8+edx]
|
|
||||||
fxch st(2)
|
|
||||||
fmul ds:dword ptr[4+ecx]
|
|
||||||
fxch st(2)
|
|
||||||
fld st(0)
|
|
||||||
fmul ds:dword ptr[8+ebx]
|
|
||||||
fxch st(5)
|
|
||||||
faddp st(3),st(0)
|
|
||||||
fmul ds:dword ptr[8+ecx]
|
|
||||||
fxch st(1)
|
|
||||||
faddp st(3),st(0)
|
|
||||||
fxch st(3)
|
|
||||||
faddp st(2),st(0)
|
|
||||||
jmp LSetSides
|
|
||||||
Lcase2:
|
|
||||||
fmul ds:dword ptr[ebx]
|
|
||||||
fld ds:dword ptr[0+4+edx]
|
|
||||||
fxch st(2)
|
|
||||||
fmul ds:dword ptr[ecx]
|
|
||||||
fxch st(2)
|
|
||||||
fld st(0)
|
|
||||||
fmul ds:dword ptr[4+ecx]
|
|
||||||
fld ds:dword ptr[0+8+edx]
|
|
||||||
fxch st(2)
|
|
||||||
fmul ds:dword ptr[4+ebx]
|
|
||||||
fxch st(2)
|
|
||||||
fld st(0)
|
|
||||||
fmul ds:dword ptr[8+ebx]
|
|
||||||
fxch st(5)
|
|
||||||
faddp st(3),st(0)
|
|
||||||
fmul ds:dword ptr[8+ecx]
|
|
||||||
fxch st(1)
|
|
||||||
faddp st(3),st(0)
|
|
||||||
fxch st(3)
|
|
||||||
faddp st(2),st(0)
|
|
||||||
jmp LSetSides
|
|
||||||
Lcase3:
|
|
||||||
fmul ds:dword ptr[ecx]
|
|
||||||
fld ds:dword ptr[0+4+edx]
|
|
||||||
fxch st(2)
|
|
||||||
fmul ds:dword ptr[ebx]
|
|
||||||
fxch st(2)
|
|
||||||
fld st(0)
|
|
||||||
fmul ds:dword ptr[4+ecx]
|
|
||||||
fld ds:dword ptr[0+8+edx]
|
|
||||||
fxch st(2)
|
|
||||||
fmul ds:dword ptr[4+ebx]
|
|
||||||
fxch st(2)
|
|
||||||
fld st(0)
|
|
||||||
fmul ds:dword ptr[8+ebx]
|
|
||||||
fxch st(5)
|
|
||||||
faddp st(3),st(0)
|
|
||||||
fmul ds:dword ptr[8+ecx]
|
|
||||||
fxch st(1)
|
|
||||||
faddp st(3),st(0)
|
|
||||||
fxch st(3)
|
|
||||||
faddp st(2),st(0)
|
|
||||||
jmp LSetSides
|
|
||||||
Lcase4:
|
|
||||||
fmul ds:dword ptr[ebx]
|
|
||||||
fld ds:dword ptr[0+4+edx]
|
|
||||||
fxch st(2)
|
|
||||||
fmul ds:dword ptr[ecx]
|
|
||||||
fxch st(2)
|
|
||||||
fld st(0)
|
|
||||||
fmul ds:dword ptr[4+ebx]
|
|
||||||
fld ds:dword ptr[0+8+edx]
|
|
||||||
fxch st(2)
|
|
||||||
fmul ds:dword ptr[4+ecx]
|
|
||||||
fxch st(2)
|
|
||||||
fld st(0)
|
|
||||||
fmul ds:dword ptr[8+ecx]
|
|
||||||
fxch st(5)
|
|
||||||
faddp st(3),st(0)
|
|
||||||
fmul ds:dword ptr[8+ebx]
|
|
||||||
fxch st(1)
|
|
||||||
faddp st(3),st(0)
|
|
||||||
fxch st(3)
|
|
||||||
faddp st(2),st(0)
|
|
||||||
jmp LSetSides
|
|
||||||
Lcase5:
|
|
||||||
fmul ds:dword ptr[ecx]
|
|
||||||
fld ds:dword ptr[0+4+edx]
|
|
||||||
fxch st(2)
|
|
||||||
fmul ds:dword ptr[ebx]
|
|
||||||
fxch st(2)
|
|
||||||
fld st(0)
|
|
||||||
fmul ds:dword ptr[4+ebx]
|
|
||||||
fld ds:dword ptr[0+8+edx]
|
|
||||||
fxch st(2)
|
|
||||||
fmul ds:dword ptr[4+ecx]
|
|
||||||
fxch st(2)
|
|
||||||
fld st(0)
|
|
||||||
fmul ds:dword ptr[8+ecx]
|
|
||||||
fxch st(5)
|
|
||||||
faddp st(3),st(0)
|
|
||||||
fmul ds:dword ptr[8+ebx]
|
|
||||||
fxch st(1)
|
|
||||||
faddp st(3),st(0)
|
|
||||||
fxch st(3)
|
|
||||||
faddp st(2),st(0)
|
|
||||||
jmp LSetSides
|
|
||||||
Lcase6:
|
|
||||||
fmul ds:dword ptr[ebx]
|
|
||||||
fld ds:dword ptr[0+4+edx]
|
|
||||||
fxch st(2)
|
|
||||||
fmul ds:dword ptr[ecx]
|
|
||||||
fxch st(2)
|
|
||||||
fld st(0)
|
|
||||||
fmul ds:dword ptr[4+ecx]
|
|
||||||
fld ds:dword ptr[0+8+edx]
|
|
||||||
fxch st(2)
|
|
||||||
fmul ds:dword ptr[4+ebx]
|
|
||||||
fxch st(2)
|
|
||||||
fld st(0)
|
|
||||||
fmul ds:dword ptr[8+ecx]
|
|
||||||
fxch st(5)
|
|
||||||
faddp st(3),st(0)
|
|
||||||
fmul ds:dword ptr[8+ebx]
|
|
||||||
fxch st(1)
|
|
||||||
faddp st(3),st(0)
|
|
||||||
fxch st(3)
|
|
||||||
faddp st(2),st(0)
|
|
||||||
jmp LSetSides
|
|
||||||
Lcase7:
|
|
||||||
fmul ds:dword ptr[ecx]
|
|
||||||
fld ds:dword ptr[0+4+edx]
|
|
||||||
fxch st(2)
|
|
||||||
fmul ds:dword ptr[ebx]
|
|
||||||
fxch st(2)
|
|
||||||
fld st(0)
|
|
||||||
fmul ds:dword ptr[4+ecx]
|
|
||||||
fld ds:dword ptr[0+8+edx]
|
|
||||||
fxch st(2)
|
|
||||||
fmul ds:dword ptr[4+ebx]
|
|
||||||
fxch st(2)
|
|
||||||
fld st(0)
|
|
||||||
fmul ds:dword ptr[8+ecx]
|
|
||||||
fxch st(5)
|
|
||||||
faddp st(3),st(0)
|
|
||||||
fmul ds:dword ptr[8+ebx]
|
|
||||||
fxch st(1)
|
|
||||||
faddp st(3),st(0)
|
|
||||||
fxch st(3)
|
|
||||||
faddp st(2),st(0)
|
|
||||||
LSetSides:
|
|
||||||
faddp st(2),st(0)
|
|
||||||
fcomp ds:dword ptr[12+edx]
|
|
||||||
xor ecx,ecx
|
|
||||||
fnstsw ax
|
|
||||||
fcomp ds:dword ptr[12+edx]
|
|
||||||
and ah,1
|
|
||||||
xor ah,1
|
|
||||||
add cl,ah
|
|
||||||
fnstsw ax
|
|
||||||
and ah,1
|
|
||||||
add ah,ah
|
|
||||||
add cl,ah
|
|
||||||
pop ebx
|
|
||||||
mov eax,ecx
|
|
||||||
ret
|
|
||||||
Lerror:
|
|
||||||
int 3
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#pragma warning( default: 4035 )
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void ClearBounds (vec3_t mins, vec3_t maxs)
|
void ClearBounds (vec3_t mins, vec3_t maxs)
|
||||||
{
|
{
|
||||||
|
|
1074
src/savegame/savegame.c
Normal file
1074
src/savegame/savegame.c
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue