mirror of
https://github.com/yquake2/zaero.git
synced 2024-11-25 13:21:52 +00:00
Den Savegamecode hoch auf 3.20 portiert. Muss noch mal ordentlich
durchgetestet werden, gerade auf 32Bit und Linux
This commit is contained in:
parent
347d281530
commit
2590b35e2a
2 changed files with 86 additions and 130 deletions
|
@ -559,10 +559,10 @@ extern int meansOfDeath;
|
||||||
|
|
||||||
extern edict_t *g_edicts;
|
extern edict_t *g_edicts;
|
||||||
|
|
||||||
#define FOFS(x) (int)&(((edict_t *)0)->x)
|
#define FOFS(x) (size_t)&(((edict_t *)NULL)->x)
|
||||||
#define STOFS(x) (int)&(((spawn_temp_t *)0)->x)
|
#define STOFS(x) (size_t)&(((spawn_temp_t *)NULL)->x)
|
||||||
#define LLOFS(x) (int)&(((level_locals_t *)0)->x)
|
#define LLOFS(x) (size_t)&(((level_locals_t *)NULL)->x)
|
||||||
#define CLOFS(x) (int)&(((gclient_t *)0)->x)
|
#define CLOFS(x) (size_t)&(((gclient_t *)NULL)->x)
|
||||||
|
|
||||||
#define random() ((rand () & 0x7fff) / ((float)0x7fff))
|
#define random() ((rand () & 0x7fff) / ((float)0x7fff))
|
||||||
#define crandom() (2.0 * (random() - 0.5))
|
#define crandom() (2.0 * (random() - 0.5))
|
||||||
|
@ -631,6 +631,8 @@ typedef enum {
|
||||||
F_EDICT, // index on disk, pointer in memory
|
F_EDICT, // index on disk, pointer in memory
|
||||||
F_ITEM, // index on disk, pointer in memory
|
F_ITEM, // index on disk, pointer in memory
|
||||||
F_CLIENT, // index on disk, pointer in memory
|
F_CLIENT, // index on disk, pointer in memory
|
||||||
|
F_FUNCTION,
|
||||||
|
F_MMOVE,
|
||||||
F_IGNORE
|
F_IGNORE
|
||||||
} fieldtype_t;
|
} fieldtype_t;
|
||||||
|
|
||||||
|
|
206
src/g_save.c
206
src/g_save.c
|
@ -1,13 +1,8 @@
|
||||||
|
|
||||||
#include "g_local.h"
|
#include "g_local.h"
|
||||||
|
|
||||||
#if defined(_DEBUG) && defined(_Z_TESTMODE)
|
#define Function(f) {#f, f}
|
||||||
|
|
||||||
void InitTestWeapon(void);
|
|
||||||
void InitTestItem(void);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
mmove_t mmove_reloc;
|
||||||
|
|
||||||
field_t fields[] = {
|
field_t fields[] = {
|
||||||
{"classname", FOFS(classname), F_LSTRING},
|
{"classname", FOFS(classname), F_LSTRING},
|
||||||
|
@ -70,83 +65,33 @@ field_t fields[] = {
|
||||||
{"maxyaw", STOFS(maxyaw), F_FLOAT, FFL_SPAWNTEMP},
|
{"maxyaw", STOFS(maxyaw), F_FLOAT, FFL_SPAWNTEMP},
|
||||||
{"minpitch", STOFS(minpitch), F_FLOAT, FFL_SPAWNTEMP},
|
{"minpitch", STOFS(minpitch), F_FLOAT, FFL_SPAWNTEMP},
|
||||||
{"maxpitch", STOFS(maxpitch), F_FLOAT, FFL_SPAWNTEMP},
|
{"maxpitch", STOFS(maxpitch), F_FLOAT, FFL_SPAWNTEMP},
|
||||||
{"nextmap", STOFS(nextmap), F_LSTRING, FFL_SPAWNTEMP}
|
{"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[] =
|
|
||||||
{
|
|
||||||
{"", FOFS(classname), F_LSTRING},
|
|
||||||
{"", FOFS(target), F_LSTRING},
|
|
||||||
{"", FOFS(targetname), F_LSTRING},
|
|
||||||
{"", FOFS(killtarget), F_LSTRING},
|
|
||||||
{"", FOFS(team), F_LSTRING},
|
|
||||||
{"", FOFS(pathtarget), F_LSTRING},
|
|
||||||
{"", FOFS(deathtarget), F_LSTRING},
|
|
||||||
{"", FOFS(combattarget), F_LSTRING},
|
|
||||||
{"", FOFS(model), F_LSTRING},
|
|
||||||
{"", FOFS(model2), F_LSTRING},
|
|
||||||
{"", FOFS(model3), F_LSTRING},
|
|
||||||
{"", FOFS(model4), F_LSTRING},
|
|
||||||
{"", FOFS(map), F_LSTRING},
|
|
||||||
{"", FOFS(message), F_LSTRING},
|
|
||||||
|
|
||||||
{"", FOFS(client), F_CLIENT},
|
|
||||||
{"", FOFS(item), F_ITEM},
|
|
||||||
|
|
||||||
{"", FOFS(goalentity), F_EDICT},
|
|
||||||
{"", FOFS(movetarget), F_EDICT},
|
|
||||||
{"", FOFS(enemy), F_EDICT},
|
|
||||||
{"", FOFS(oldenemy), F_EDICT},
|
|
||||||
{"", FOFS(activator), F_EDICT},
|
|
||||||
{"", FOFS(groundentity), F_EDICT},
|
|
||||||
{"", FOFS(teamchain), F_EDICT},
|
|
||||||
{"", FOFS(teammaster), F_EDICT},
|
|
||||||
{"", FOFS(owner), F_EDICT},
|
|
||||||
{"", FOFS(mynoise), F_EDICT},
|
|
||||||
{"", FOFS(mynoise2), F_EDICT},
|
|
||||||
{"", FOFS(target_ent), F_EDICT},
|
|
||||||
{"", FOFS(chain), F_EDICT},
|
|
||||||
|
|
||||||
// evolve
|
{0, 0, 0, 0}
|
||||||
{"", FOFS(laser), F_EDICT},
|
|
||||||
{"", FOFS(zRaduisList), F_EDICT},
|
|
||||||
{"", FOFS(zSchoolChain), F_EDICT},
|
|
||||||
{"", FOFS(rideWith[0]), F_EDICT},
|
|
||||||
{"", FOFS(rideWith[1]), F_EDICT},
|
|
||||||
{"", FOFS(mteam), F_LSTRING},
|
|
||||||
{NULL, 0, F_INT}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
field_t levelfields[] =
|
field_t levelfields[] =
|
||||||
{
|
{
|
||||||
{"", LLOFS(changemap), F_LSTRING},
|
{"changemap", LLOFS(changemap), F_LSTRING},
|
||||||
|
|
||||||
{"", LLOFS(sight_client), F_EDICT},
|
{"sight_client", LLOFS(sight_client), F_EDICT},
|
||||||
{"", LLOFS(sight_entity), F_EDICT},
|
{"sight_entity", LLOFS(sight_entity), F_EDICT},
|
||||||
{"", LLOFS(sound_entity), F_EDICT},
|
{"sound_entity", LLOFS(sound_entity), F_EDICT},
|
||||||
{"", LLOFS(sound2_entity), F_EDICT},
|
{"sound2_entity", LLOFS(sound2_entity), F_EDICT},
|
||||||
|
|
||||||
{NULL, 0, F_INT}
|
{NULL, 0, F_INT}
|
||||||
};
|
};
|
||||||
|
|
||||||
field_t clientfields[] =
|
field_t clientfields[] =
|
||||||
{
|
{
|
||||||
{"", CLOFS(pers.weapon), F_ITEM},
|
{"pers.weapon", CLOFS(pers.weapon), F_ITEM},
|
||||||
{"", CLOFS(pers.lastweapon), F_ITEM},
|
{"pers.lastweapon", CLOFS(pers.lastweapon), F_ITEM},
|
||||||
{"", CLOFS(pers.lastweapon2), F_ITEM},
|
{"pers.lastweapon2", CLOFS(pers.lastweapon2), F_ITEM},
|
||||||
{"", CLOFS(newweapon), F_ITEM},
|
{"newweapon", CLOFS(newweapon), F_ITEM},
|
||||||
|
|
||||||
// evolve
|
// evolve
|
||||||
{"", CLOFS(zCameraTrack), F_EDICT},
|
{"zCameraTrack", CLOFS(zCameraTrack), F_EDICT},
|
||||||
{"", CLOFS(zCameraLocalEntity), F_EDICT},
|
{"zCameraLocalEntitiy", CLOFS(zCameraLocalEntity), F_EDICT},
|
||||||
|
|
||||||
{NULL, 0, F_INT}
|
{NULL, 0, F_INT}
|
||||||
};
|
};
|
||||||
|
@ -204,23 +149,10 @@ void InitGame (void)
|
||||||
bob_roll = gi.cvar ("bob_roll", "0.002", 0);
|
bob_roll = gi.cvar ("bob_roll", "0.002", 0);
|
||||||
|
|
||||||
gamedir = gi.cvar ("gamedir", "baseq2", CVAR_SERVERINFO);
|
gamedir = gi.cvar ("gamedir", "baseq2", CVAR_SERVERINFO);
|
||||||
#ifdef CACHE_SOUND
|
|
||||||
printSoundRejects = gi.cvar("printsoundrejects", "0", CVAR_SERVERINFO);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// items
|
// items
|
||||||
InitItems ();
|
InitItems ();
|
||||||
|
|
||||||
#if defined(_DEBUG) && defined(_Z_TESTMODE)
|
|
||||||
|
|
||||||
gi.dprintf ("==== InitTestWeapon ====\n");
|
|
||||||
InitTestWeapon();
|
|
||||||
|
|
||||||
gi.dprintf ("==== InitTestItem ====\n");
|
|
||||||
InitTestItem();
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Com_sprintf (game.helpmessage1, sizeof(game.helpmessage1), "");
|
Com_sprintf (game.helpmessage1, sizeof(game.helpmessage1), "");
|
||||||
|
|
||||||
Com_sprintf (game.helpmessage2, sizeof(game.helpmessage2), "");
|
Com_sprintf (game.helpmessage2, sizeof(game.helpmessage2), "");
|
||||||
|
@ -248,6 +180,9 @@ void WriteField1 (FILE *f, field_t *field, byte *base)
|
||||||
int len;
|
int len;
|
||||||
int index;
|
int index;
|
||||||
|
|
||||||
|
if (field->flags & FFL_SPAWNTEMP)
|
||||||
|
return;
|
||||||
|
|
||||||
p = (void *)(base + field->ofs);
|
p = (void *)(base + field->ofs);
|
||||||
switch (field->type)
|
switch (field->type)
|
||||||
{
|
{
|
||||||
|
@ -288,16 +223,38 @@ void WriteField1 (FILE *f, field_t *field, byte *base)
|
||||||
*(int *)p = index;
|
*(int *)p = index;
|
||||||
break;
|
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:
|
default:
|
||||||
gi.error ("WriteEdict: unknown field type");
|
gi.error ("WriteEdict: unknown field type");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void WriteField2 (FILE *f, field_t *field, byte *base)
|
void WriteField2 (FILE *f, field_t *field, byte *base)
|
||||||
{
|
{
|
||||||
int len;
|
int len;
|
||||||
void *p;
|
void *p;
|
||||||
|
|
||||||
|
if (field->flags & FFL_SPAWNTEMP)
|
||||||
|
return;
|
||||||
|
|
||||||
p = (void *)(base + field->ofs);
|
p = (void *)(base + field->ofs);
|
||||||
switch (field->type)
|
switch (field->type)
|
||||||
{
|
{
|
||||||
|
@ -309,6 +266,8 @@ void WriteField2 (FILE *f, field_t *field, byte *base)
|
||||||
fwrite (*(char **)p, len, 1, f);
|
fwrite (*(char **)p, len, 1, f);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -318,6 +277,9 @@ void ReadField (FILE *f, field_t *field, byte *base)
|
||||||
int len;
|
int len;
|
||||||
int index;
|
int index;
|
||||||
|
|
||||||
|
if (field->flags & FFL_SPAWNTEMP)
|
||||||
|
return;
|
||||||
|
|
||||||
p = (void *)(base + field->ofs);
|
p = (void *)(base + field->ofs);
|
||||||
switch (field->type)
|
switch (field->type)
|
||||||
{
|
{
|
||||||
|
@ -334,17 +296,11 @@ void ReadField (FILE *f, field_t *field, byte *base)
|
||||||
*(char **)p = NULL;
|
*(char **)p = NULL;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
*(char **)p = gi.TagMalloc (len, TAG_LEVEL);
|
/*
|
||||||
fread (*(char **)p, len, 1, f);
|
SBF: FIXME - 32 extra bytes alloc'd since the saved
|
||||||
}
|
string might not be long enough
|
||||||
break;
|
*/
|
||||||
case F_GSTRING:
|
*(char **)p = gi.TagMalloc (32+len, TAG_LEVEL);
|
||||||
len = *(int *)p;
|
|
||||||
if (!len)
|
|
||||||
*(char **)p = NULL;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*(char **)p = gi.TagMalloc (len, TAG_GAME);
|
|
||||||
fread (*(char **)p, len, 1, f);
|
fread (*(char **)p, len, 1, f);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -370,6 +326,24 @@ void ReadField (FILE *f, field_t *field, byte *base)
|
||||||
*(gitem_t **)p = &itemlist[index];
|
*(gitem_t **)p = &itemlist[index];
|
||||||
break;
|
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:
|
default:
|
||||||
gi.error ("ReadEdict: unknown field type");
|
gi.error ("ReadEdict: unknown field type");
|
||||||
}
|
}
|
||||||
|
@ -441,7 +415,7 @@ A single player death will automatically restore from the
|
||||||
last save position.
|
last save position.
|
||||||
============
|
============
|
||||||
*/
|
*/
|
||||||
void WriteGame (char *filename, qboolean autosave)
|
void WriteGame (const char *filename, qboolean autosave)
|
||||||
{
|
{
|
||||||
FILE *f;
|
FILE *f;
|
||||||
int i;
|
int i;
|
||||||
|
@ -468,16 +442,14 @@ void WriteGame (char *filename, qboolean autosave)
|
||||||
fclose (f);
|
fclose (f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReadGame (char *filename)
|
void ReadGame (const char *filename)
|
||||||
{
|
{
|
||||||
FILE *f;
|
FILE *f;
|
||||||
int i;
|
int i;
|
||||||
char str[16];
|
char str[16];
|
||||||
|
|
||||||
gi.FreeTags (TAG_GAME);
|
gi.FreeTags (TAG_GAME);
|
||||||
#ifdef CACHE_SOUND
|
|
||||||
initSoundList();
|
|
||||||
#endif
|
|
||||||
f = fopen (filename, "rb");
|
f = fopen (filename, "rb");
|
||||||
if (!f)
|
if (!f)
|
||||||
gi.error ("Couldn't open %s", filename);
|
gi.error ("Couldn't open %s", filename);
|
||||||
|
@ -503,7 +475,6 @@ void ReadGame (char *filename)
|
||||||
//==========================================================
|
//==========================================================
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
==============
|
==============
|
||||||
WriteEdict
|
WriteEdict
|
||||||
|
@ -516,15 +487,11 @@ void WriteEdict (FILE *f, edict_t *ent)
|
||||||
field_t *field;
|
field_t *field;
|
||||||
edict_t temp;
|
edict_t temp;
|
||||||
|
|
||||||
if (Q_stricmp(ent->classname, "misc_viper") == 0)
|
|
||||||
{
|
|
||||||
temp = *ent;
|
|
||||||
}
|
|
||||||
// all of the ints, floats, and vectors stay as they are
|
// all of the ints, floats, and vectors stay as they are
|
||||||
temp = *ent;
|
temp = *ent;
|
||||||
|
|
||||||
// change the pointers to lengths or indexes
|
// change the pointers to lengths or indexes
|
||||||
for (field=savefields ; field->name ; field++)
|
for (field=fields ; field->name ; field++)
|
||||||
{
|
{
|
||||||
WriteField1 (f, field, (byte *)&temp);
|
WriteField1 (f, field, (byte *)&temp);
|
||||||
}
|
}
|
||||||
|
@ -533,7 +500,7 @@ void WriteEdict (FILE *f, edict_t *ent)
|
||||||
fwrite (&temp, sizeof(temp), 1, f);
|
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++)
|
for (field=fields ; field->name ; field++)
|
||||||
{
|
{
|
||||||
WriteField2 (f, field, (byte *)ent);
|
WriteField2 (f, field, (byte *)ent);
|
||||||
}
|
}
|
||||||
|
@ -570,7 +537,6 @@ void WriteLevelLocals (FILE *f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
==============
|
==============
|
||||||
ReadEdict
|
ReadEdict
|
||||||
|
@ -584,7 +550,7 @@ void ReadEdict (FILE *f, edict_t *ent)
|
||||||
|
|
||||||
fread (ent, sizeof(*ent), 1, f);
|
fread (ent, sizeof(*ent), 1, f);
|
||||||
|
|
||||||
for (field=savefields ; field->name ; field++)
|
for (field=fields ; field->name ; field++)
|
||||||
{
|
{
|
||||||
ReadField (f, field, (byte *)ent);
|
ReadField (f, field, (byte *)ent);
|
||||||
}
|
}
|
||||||
|
@ -609,17 +575,13 @@ void ReadLevelLocals (FILE *f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=================
|
=================
|
||||||
WriteLevel
|
WriteLevel
|
||||||
|
|
||||||
=================
|
=================
|
||||||
*/
|
*/
|
||||||
void WriteLevel (char *filename)
|
void WriteLevel (const char *filename)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
edict_t *ent;
|
edict_t *ent;
|
||||||
|
@ -654,8 +616,6 @@ void WriteLevel (char *filename)
|
||||||
fwrite (&i, sizeof(i), 1, f);
|
fwrite (&i, sizeof(i), 1, f);
|
||||||
|
|
||||||
fclose (f);
|
fclose (f);
|
||||||
|
|
||||||
// write out zaero between level
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -663,7 +623,7 @@ void WriteLevel (char *filename)
|
||||||
=================
|
=================
|
||||||
ReadLevel
|
ReadLevel
|
||||||
|
|
||||||
SpawnEntities will already have been called on the
|
SpawnEntities will allready have been called on the
|
||||||
level the same way it was when the level was saved.
|
level the same way it was when the level was saved.
|
||||||
|
|
||||||
That is necessary to get the baselines
|
That is necessary to get the baselines
|
||||||
|
@ -675,7 +635,7 @@ calling ReadLevel.
|
||||||
No clients are connected yet.
|
No clients are connected yet.
|
||||||
=================
|
=================
|
||||||
*/
|
*/
|
||||||
void ReadLevel (char *filename)
|
void ReadLevel (const char *filename)
|
||||||
{
|
{
|
||||||
int entnum;
|
int entnum;
|
||||||
FILE *f;
|
FILE *f;
|
||||||
|
@ -690,9 +650,7 @@ void ReadLevel (char *filename)
|
||||||
// free any dynamic memory allocated by loading the level
|
// free any dynamic memory allocated by loading the level
|
||||||
// base state
|
// base state
|
||||||
gi.FreeTags (TAG_LEVEL);
|
gi.FreeTags (TAG_LEVEL);
|
||||||
#ifdef CACHE_SOUND
|
|
||||||
initSoundList();
|
|
||||||
#endif
|
|
||||||
// wipe all the entities
|
// wipe all the entities
|
||||||
memset (g_edicts, 0, game.maxentities*sizeof(g_edicts[0]));
|
memset (g_edicts, 0, game.maxentities*sizeof(g_edicts[0]));
|
||||||
globals.num_edicts = maxclients->value+1;
|
globals.num_edicts = maxclients->value+1;
|
||||||
|
@ -707,11 +665,7 @@ void ReadLevel (char *filename)
|
||||||
|
|
||||||
// check function pointer base address
|
// check function pointer base address
|
||||||
fread (&base, sizeof(base), 1, f);
|
fread (&base, sizeof(base), 1, f);
|
||||||
if (base != (void *)InitGame)
|
gi.dprintf("Function offsets %d\n", ((byte *)base) - ((byte *)InitGame));
|
||||||
{
|
|
||||||
fclose (f);
|
|
||||||
gi.error ("ReadLevel: function pointers have moved");
|
|
||||||
}
|
|
||||||
|
|
||||||
// load the level locals
|
// load the level locals
|
||||||
ReadLevelLocals (f);
|
ReadLevelLocals (f);
|
||||||
|
|
Loading…
Reference in a new issue