ref: 6537d7e90c48d76eb982701de8d0af6feb147fd0
dir: /src/heretic/p_saveg.c/
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 1993-2008 Raven Software
// Copyright(C) 2008 Simon Howard
//
// 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.
//
//-----------------------------------------------------------------------------
// P_tick.c
#include "doomdef.h"
#include "i_swap.h"
#include "i_system.h"
#include "m_misc.h"
#include "p_local.h"
#include "v_video.h"
#define SVG_RAM 0
#define SVG_FILE 1
static FILE *SaveGameFP;
static int SaveGameType;
static byte *savebuffer, *save_p;
//==========================================================================
//
// SV_Filename
//
// Generate the filename to use for a particular savegame slot.
// Returns a malloc()'d buffer that must be freed by the caller.
//
//==========================================================================
char *SV_Filename(int slot)
{
char *filename;
size_t filename_len;
filename_len = strlen(savegamedir) + strlen(SAVEGAMENAME) + 8;
filename = malloc(filename_len);
M_snprintf(filename, filename_len,
"%s" SAVEGAMENAME "%d.hsg", savegamedir, slot);
return filename;
}
//==========================================================================
//
// SV_Open
//
//==========================================================================
void SV_Open(char *fileName)
{
SaveGameType = SVG_FILE;
SaveGameFP = fopen(fileName, "wb");
}
void SV_OpenRead(char *filename)
{
SaveGameType = SVG_FILE;
SaveGameFP = fopen(filename, "rb");
}
//==========================================================================
//
// SV_Close
//
//==========================================================================
void SV_Close(char *fileName)
{
int length;
SV_WriteByte(SAVE_GAME_TERMINATOR);
if (SaveGameType == SVG_RAM)
{
length = save_p - savebuffer;
if (length > SAVEGAMESIZE)
{
I_Error("Savegame buffer overrun");
}
M_WriteFile(fileName, savebuffer, length);
Z_Free(savebuffer);
}
else
{ // SVG_FILE
fclose(SaveGameFP);
}
}
//==========================================================================
//
// SV_Write
//
//==========================================================================
void SV_Write(void *buffer, int size)
{
if (SaveGameType == SVG_RAM)
{
memcpy(save_p, buffer, size);
save_p += size;
}
else
{ // SVG_FILE
fwrite(buffer, size, 1, SaveGameFP);
}
}
void SV_WriteByte(byte val)
{
SV_Write(&val, sizeof(byte));
}
void SV_WriteWord(unsigned short val)
{
val = SHORT(val);
SV_Write(&val, sizeof(unsigned short));
}
void SV_WriteLong(unsigned int val)
{
val = LONG(val);
SV_Write(&val, sizeof(int));
}
void SV_WritePtr(void *ptr)
{
long val = (long) ptr;
SV_WriteLong(val & 0xffffffff);
}
//==========================================================================
//
// SV_Read
//
//==========================================================================
void SV_Read(void *buffer, int size)
{
if (SaveGameType == SVG_RAM)
{
memcpy(buffer, save_p, size);
save_p += size;
}
else
{ // SVG_FILE
fread(buffer, size, 1, SaveGameFP);
}
}
byte SV_ReadByte(void)
{
byte result;
SV_Read(&result, sizeof(byte));
return result;
}
uint16_t SV_ReadWord(void)
{
uint16_t result;
SV_Read(&result, sizeof(unsigned short));
return SHORT(result);
}
uint32_t SV_ReadLong(void)
{
uint32_t result;
SV_Read(&result, sizeof(int));
return LONG(result);
}
//
// ticcmd_t
//
static void saveg_read_ticcmd_t(ticcmd_t *str)
{
// char forwardmove;
str->forwardmove = SV_ReadByte();
// char sidemove;
str->sidemove = SV_ReadByte();
// short angleturn;
str->angleturn = SV_ReadWord();
// short consistancy;
str->consistancy = SV_ReadWord();
// byte chatchar;
str->chatchar = SV_ReadByte();
// byte buttons;
str->buttons = SV_ReadByte();
// byte lookfly;
str->lookfly = SV_ReadByte();
// byte arti;
str->arti = SV_ReadByte();
}
static void saveg_write_ticcmd_t(ticcmd_t *str)
{
// char forwardmove;
SV_WriteByte(str->forwardmove);
// char sidemove;
SV_WriteByte(str->sidemove);
// short angleturn;
SV_WriteWord(str->angleturn);
// short consistancy;
SV_WriteWord(str->consistancy);
// byte chatchar;
SV_WriteByte(str->chatchar);
// byte buttons;
SV_WriteByte(str->buttons);
// byte lookfly;
SV_WriteByte(str->lookfly);
// byte arti;
SV_WriteByte(str->arti);
}
//
// inventory_t
//
static void saveg_read_inventory_t(inventory_t *str)
{
// int type;
str->type = SV_ReadLong();
// int count;
str->count = SV_ReadLong();
}
static void saveg_write_inventory_t(inventory_t *str)
{
// int type;
SV_WriteLong(str->type);
// int count;
SV_WriteLong(str->count);
}
//
// state_t *
//
static void saveg_read_state_ptr(state_t **state)
{
int statenum;
statenum = SV_ReadLong();
// We have read a state number, but it is indexed according to the state
// table in Vanilla Heretic v1.3. To support v1.0 HHE patches we have
// three extra states, so map the state number to our internal state
// number.
if (statenum >= S_PHOENIXFXIX_1)
{
statenum = (statenum - S_PHOENIXFXIX_1) + S_PHOENIXPUFF1;
}
if (statenum == 0)
{
*state = NULL;
}
else
{
*state = &states[statenum];
}
}
static void saveg_write_state_ptr(state_t *state)
{
int statenum;
// NULL states are just written as zero.
if (state == NULL)
{
SV_WriteLong(0);
return;
}
statenum = state - states;
// Our internal state table has three extra states than Vanilla, so map
// to the state numbers used by Vanilla Heretic v1.3 for savegame
// compatibility.
if (statenum >= S_PHOENIXPUFF1)
{
statenum = (statenum - S_PHOENIXPUFF1) + S_PHOENIXFXIX_1;
}
else if (statenum >= S_PHOENIXFXIX_1)
{
// Now we're really in trouble. This state doesn't exist in Vanilla
// Heretic v1.3 (but does in v1.0). Map to a frame that might be
// vaguely sensible.
statenum = S_PHOENIXFXI1_8;
}
SV_WriteLong(statenum);
}
//
// pspdef_t
//
static void saveg_read_pspdef_t(pspdef_t *str)
{
// state_t *state;
saveg_read_state_ptr(&str->state);
// int tics;
str->tics = SV_ReadLong();
// fixed_t sx, sy;
str->sx = SV_ReadLong();
str->sy = SV_ReadLong();
}
static void saveg_write_pspdef_t(pspdef_t *str)
{
// state_t *state;
saveg_write_state_ptr(str->state);
// int tics;
SV_WriteLong(str->tics);
// fixed_t sx, sy;
SV_WriteLong(str->sx);
SV_WriteLong(str->sy);
}
//
// player_t
//
static void saveg_read_player_t(player_t *str)
{
int i;
// mobj_t *mo;
SV_ReadLong();
str->mo = NULL;
// playerstate_t playerstate;
str->playerstate = SV_ReadLong();
// ticcmd_t cmd;
saveg_read_ticcmd_t(&str->cmd);
// fixed_t viewz;
str->viewz = SV_ReadLong();
// fixed_t viewheight;
str->viewheight = SV_ReadLong();
// fixed_t deltaviewheight;
str->deltaviewheight = SV_ReadLong();
// fixed_t bob;
str->bob = SV_ReadLong();
// int flyheight;
str->flyheight = SV_ReadLong();
// int lookdir;
str->lookdir = SV_ReadLong();
// boolean centering;
str->centering = SV_ReadLong();
// int health;
str->health = SV_ReadLong();
// int armorpoints, armortype;
str->armorpoints = SV_ReadLong();
str->armortype = SV_ReadLong();
// inventory_t inventory[NUMINVENTORYSLOTS];
for (i=0; i<NUMINVENTORYSLOTS; ++i)
{
saveg_read_inventory_t(&str->inventory[i]);
}
// artitype_t readyArtifact;
str->readyArtifact = SV_ReadLong();
// int artifactCount;
str->artifactCount = SV_ReadLong();
// int inventorySlotNum;
str->inventorySlotNum = SV_ReadLong();
// int powers[NUMPOWERS];
for (i=0; i<NUMPOWERS; ++i)
{
str->powers[i] = SV_ReadLong();
}
// boolean keys[NUMKEYS];
for (i=0; i<NUMKEYS; ++i)
{
str->keys[i] = SV_ReadLong();
}
// boolean backpack;
str->backpack = SV_ReadLong();
// signed int frags[MAXPLAYERS];
for (i=0; i<MAXPLAYERS; ++i)
{
str->frags[i] = SV_ReadLong();
}
// weapontype_t readyweapon;
str->readyweapon = SV_ReadLong();
// weapontype_t pendingweapon;
str->pendingweapon = SV_ReadLong();
// boolean weaponowned[NUMWEAPONS];
for (i=0; i<NUMWEAPONS; ++i)
{
str->weaponowned[i] = SV_ReadLong();
}
// int ammo[NUMAMMO];
for (i=0; i<NUMAMMO; ++i)
{
str->ammo[i] = SV_ReadLong();
}
// int maxammo[NUMAMMO];
for (i=0; i<NUMAMMO; ++i)
{
str->maxammo[i] = SV_ReadLong();
}
// int attackdown, usedown;
str->attackdown = SV_ReadLong();
str->usedown = SV_ReadLong();
// int cheats;
str->cheats = SV_ReadLong();
// int refire;
str->refire = SV_ReadLong();
// int killcount, itemcount, secretcount;
str->killcount = SV_ReadLong();
str->itemcount = SV_ReadLong();
str->secretcount = SV_ReadLong();
// char *message;
SV_ReadLong();
str->message = NULL;
// int messageTics;
str->messageTics = SV_ReadLong();
// int damagecount, bonuscount;
str->damagecount = SV_ReadLong();
str->bonuscount = SV_ReadLong();
// int flamecount;
str->flamecount = SV_ReadLong();
// mobj_t *attacker;
SV_ReadLong();
str->attacker = NULL;
// int extralight;
str->extralight = SV_ReadLong();
// int fixedcolormap;
str->fixedcolormap = SV_ReadLong();
// int colormap;
str->colormap = SV_ReadLong();
// pspdef_t psprites[NUMPSPRITES];
for (i=0; i<NUMPSPRITES; ++i)
{
saveg_read_pspdef_t(&str->psprites[i]);
}
// boolean didsecret;
str->didsecret = SV_ReadLong();
// int chickenTics;
str->chickenTics = SV_ReadLong();
// int chickenPeck;
str->chickenPeck = SV_ReadLong();
// mobj_t *rain1;
SV_ReadLong();
str->rain1 = NULL;
// mobj_t *rain2;
SV_ReadLong();
str->rain2 = NULL;
}
static void saveg_write_player_t(player_t *str)
{
int i;
// mobj_t *mo;
// pointer will be trashed, but it gets restored on load as
// the player number reference is stored in the mo.
SV_WritePtr(str->mo);
// playerstate_t playerstate;
SV_WriteLong(str->playerstate);
// ticcmd_t cmd;
saveg_write_ticcmd_t(&str->cmd);
// fixed_t viewz;
SV_WriteLong(str->viewz);
// fixed_t viewheight;
SV_WriteLong(str->viewheight);
// fixed_t deltaviewheight;
SV_WriteLong(str->deltaviewheight);
// fixed_t bob;
SV_WriteLong(str->bob);
// int flyheight;
SV_WriteLong(str->flyheight);
// int lookdir;
SV_WriteLong(str->lookdir);
// boolean centering;
SV_WriteLong(str->centering);
// int health;
SV_WriteLong(str->health);
// int armorpoints, armortype;
SV_WriteLong(str->armorpoints);
SV_WriteLong(str->armortype);
// inventory_t inventory[NUMINVENTORYSLOTS];
for (i=0; i<NUMINVENTORYSLOTS; ++i)
{
saveg_write_inventory_t(&str->inventory[i]);
}
// artitype_t readyArtifact;
SV_WriteLong(str->readyArtifact);
// int artifactCount;
SV_WriteLong(str->artifactCount);
// int inventorySlotNum;
SV_WriteLong(str->inventorySlotNum);
// int powers[NUMPOWERS];
for (i=0; i<NUMPOWERS; ++i)
{
SV_WriteLong(str->powers[i]);
}
// boolean keys[NUMKEYS];
for (i=0; i<NUMKEYS; ++i)
{
SV_WriteLong(str->keys[i]);
}
// boolean backpack;
SV_WriteLong(str->backpack);
// signed int frags[MAXPLAYERS];
for (i=0; i<MAXPLAYERS; ++i)
{
SV_WriteLong(str->frags[i]);
}
// weapontype_t readyweapon;
SV_WriteLong(str->readyweapon);
// weapontype_t pendingweapon;
SV_WriteLong(str->pendingweapon);
// boolean weaponowned[NUMWEAPONS];
for (i=0; i<NUMWEAPONS; ++i)
{
SV_WriteLong(str->weaponowned[i]);
}
// int ammo[NUMAMMO];
for (i=0; i<NUMAMMO; ++i)
{
SV_WriteLong(str->ammo[i]);
}
// int maxammo[NUMAMMO];
for (i=0; i<NUMAMMO; ++i)
{
SV_WriteLong(str->maxammo[i]);
}
// int attackdown, usedown;
SV_WriteLong(str->attackdown);
SV_WriteLong(str->usedown);
// int cheats;
SV_WriteLong(str->cheats);
// int refire;
SV_WriteLong(str->refire);
// int killcount, itemcount, secretcount;
SV_WriteLong(str->killcount);
SV_WriteLong(str->itemcount);
SV_WriteLong(str->secretcount);
// char *message;
SV_WritePtr(str->message);
// int messageTics;
SV_WriteLong(str->messageTics);
// int damagecount, bonuscount;
SV_WriteLong(str->damagecount);
SV_WriteLong(str->bonuscount);
// int flamecount;
SV_WriteLong(str->flamecount);
// mobj_t *attacker;
SV_WritePtr(str->attacker);
// int extralight;
SV_WriteLong(str->extralight);
// int fixedcolormap;
SV_WriteLong(str->fixedcolormap);
// int colormap;
SV_WriteLong(str->colormap);
// pspdef_t psprites[NUMPSPRITES];
for (i=0; i<NUMPSPRITES; ++i)
{
saveg_write_pspdef_t(&str->psprites[i]);
}
// boolean didsecret;
SV_WriteLong(str->didsecret);
// int chickenTics;
SV_WriteLong(str->chickenTics);
// int chickenPeck;
SV_WriteLong(str->chickenPeck);
// mobj_t *rain1;
SV_WritePtr(str->rain1);
// mobj_t *rain2;
SV_WritePtr(str->rain2);
}
//
// mapthing_t
//
static void saveg_read_mapthing_t(mapthing_t *str)
{
// short x, y;
str->x = SV_ReadWord();
str->y = SV_ReadWord();
// short angle;
str->angle = SV_ReadWord();
// short type;
str->type = SV_ReadWord();
// short options;
str->options = SV_ReadWord();
}
static void saveg_write_mapthing_t(mapthing_t *str)
{
// short x, y;
SV_WriteWord(str->x);
SV_WriteWord(str->y);
// short angle;
SV_WriteWord(str->angle);
// short type;
SV_WriteWord(str->type);
// short options;
SV_WriteWord(str->options);
}
//
// thinker_t
//
static void saveg_read_thinker_t(thinker_t *str)
{
// struct thinker_s *prev, *next;
SV_ReadLong();
str->prev = NULL;
SV_ReadLong();
str->next = NULL;
// think_t function;
SV_ReadLong();
str->function = NULL;
}
static void saveg_write_thinker_t(thinker_t *str)
{
// struct thinker_s *prev, *next;
SV_WritePtr(str->prev);
SV_WritePtr(str->next);
// think_t function;
SV_WritePtr(str->function);
}
//
// specialval_t
//
static void saveg_read_specialval_t(specialval_t *str)
{
// This can also be a mobj_t ptr, but we just assume it's
// an int. This is probably a really bad assumption that's
// likely to end in tears.
// int i;
str->i = SV_ReadLong();
}
static void saveg_write_specialval_t(specialval_t *str)
{
// int i;
SV_WriteLong(str->i);
}
//
// mobj_t
//
static void saveg_read_mobj_t(mobj_t *str)
{
int i;
// thinker_t thinker;
saveg_read_thinker_t(&str->thinker);
// fixed_t x, y, z;
str->x = SV_ReadLong();
str->y = SV_ReadLong();
str->z = SV_ReadLong();
// struct mobj_s *snext, *sprev;
SV_ReadLong();
str->snext = NULL;
SV_ReadLong();
str->sprev = NULL;
// angle_t angle;
str->angle = SV_ReadLong();
// spritenum_t sprite;
str->sprite = SV_ReadLong();
// int frame;
str->frame = SV_ReadLong();
// struct mobj_s *bnext, *bprev;
SV_ReadLong();
str->bnext = NULL;
SV_ReadLong();
str->bprev = NULL;
// struct subsector_s *subsector;
SV_ReadLong();
str->subsector = NULL;
// fixed_t floorz, ceilingz;
str->floorz = SV_ReadLong();
str->ceilingz = SV_ReadLong();
// fixed_t radius, height;
str->radius = SV_ReadLong();
str->height = SV_ReadLong();
// fixed_t momx, momy, momz;
str->momx = SV_ReadLong();
str->momy = SV_ReadLong();
str->momz = SV_ReadLong();
// int validcount;
str->validcount = SV_ReadLong();
// mobjtype_t type;
str->type = SV_ReadLong();
// An extra thing type was added for v1.0 HHE compatibility.
// Map from the v1.3 thing type index to the internal one.
if (str->type >= MT_PHOENIXFX_REMOVED)
{
++str->type;
}
// mobjinfo_t *info;
SV_ReadLong();
str->info = NULL;
// int tics;
str->tics = SV_ReadLong();
// state_t *state;
saveg_read_state_ptr(&str->state);
// int damage;
str->damage = SV_ReadLong();
// int flags;
str->flags = SV_ReadLong();
// int flags2;
str->flags2 = SV_ReadLong();
// specialval_t special1;
saveg_read_specialval_t(&str->special1);
// specialval_t special2;
saveg_read_specialval_t(&str->special2);
// Now we have a bunch of hacks to try to NULL out special values
// where special[12] contained a mobj_t pointer that isn't valid
// any more. This isn't in Vanilla but at least it stops the game
// from crashing.
switch (str->type)
{
// Gas pods use special2.m to point to the pod generator
// that made it.
case MT_POD:
str->special2.m = NULL;
break;
// Several thing types use special1.m to mean 'target':
case MT_MACEFX4: // A_DeathBallImpact
case MT_WHIRLWIND: // A_WhirlwindSeek
case MT_MUMMYFX1: // A_MummyFX1Seek
case MT_HORNRODFX2: // A_SkullRodPL2Seek
case MT_PHOENIXFX1: // A_PhoenixPuff
str->special1.m = NULL;
break;
default:
break;
}
// int health;
str->health = SV_ReadLong();
// int movedir;
str->movedir = SV_ReadLong();
// int movecount;
str->movecount = SV_ReadLong();
// struct mobj_s *target;
SV_ReadLong();
str->target = NULL;
// int reactiontime;
str->reactiontime = SV_ReadLong();
// int threshold;
str->threshold = SV_ReadLong();
// struct player_s *player;
i = SV_ReadLong();
if (i != 0)
{
str->player = &players[i - 1];
str->player->mo = str;
}
else
{
str->player = NULL;
}
// int lastlook;
str->lastlook = SV_ReadLong();
// mapthing_t spawnpoint;
saveg_read_mapthing_t(&str->spawnpoint);
}
static void saveg_write_mobj_t(mobj_t *str)
{
// thinker_t thinker;
saveg_write_thinker_t(&str->thinker);
// fixed_t x, y, z;
SV_WriteLong(str->x);
SV_WriteLong(str->y);
SV_WriteLong(str->z);
// struct mobj_s *snext, *sprev;
SV_WritePtr(str->snext);
SV_WritePtr(str->sprev);
// angle_t angle;
SV_WriteLong(str->angle);
// spritenum_t sprite;
SV_WriteLong(str->sprite);
// int frame;
SV_WriteLong(str->frame);
// struct mobj_s *bnext, *bprev;
SV_WritePtr(str->bnext);
SV_WritePtr(str->bprev);
// struct subsector_s *subsector;
SV_WritePtr(str->subsector);
// fixed_t floorz, ceilingz;
SV_WriteLong(str->floorz);
SV_WriteLong(str->ceilingz);
// fixed_t radius, height;
SV_WriteLong(str->radius);
SV_WriteLong(str->height);
// fixed_t momx, momy, momz;
SV_WriteLong(str->momx);
SV_WriteLong(str->momy);
SV_WriteLong(str->momz);
// int validcount;
SV_WriteLong(str->validcount);
// mobjtype_t type;
// Our mobjinfo table has an extra entry, for compatibility with v1.0
// HHE patches. So translate the internal thing type index to the
// equivalent for Vanilla Heretic v1.3, for savegame compatibility.
if (str->type > MT_PHOENIXFX_REMOVED)
{
SV_WriteLong(str->type - 1);
}
else if (str->type == MT_PHOENIXFX_REMOVED)
{
// This should never happen, but just in case, do something
// vaguely sensible ... ?
SV_WriteLong(MT_PHOENIXFX1);
}
else
{
SV_WriteLong(str->type);
}
// mobjinfo_t *info;
SV_WritePtr(str->info);
// int tics;
SV_WriteLong(str->tics);
// state_t *state;
saveg_write_state_ptr(str->state);
// int damage;
SV_WriteLong(str->damage);
// int flags;
SV_WriteLong(str->flags);
// int flags2;
SV_WriteLong(str->flags2);
// specialval_t special1;
saveg_write_specialval_t(&str->special1);
// specialval_t special2;
saveg_write_specialval_t(&str->special2);
// int health;
SV_WriteLong(str->health);
// int movedir;
SV_WriteLong(str->movedir);
// int movecount;
SV_WriteLong(str->movecount);
// struct mobj_s *target;
SV_WritePtr(str->target);
// int reactiontime;
SV_WriteLong(str->reactiontime);
// int threshold;
SV_WriteLong(str->threshold);
// struct player_s *player;
if (str->player != NULL)
{
SV_WriteLong(str->player - players + 1);
}
else
{
SV_WriteLong(0);
}
// int lastlook;
SV_WriteLong(str->lastlook);
// mapthing_t spawnpoint;
saveg_write_mapthing_t(&str->spawnpoint);
}
//
// ceiling_t
//
static void saveg_read_ceiling_t(ceiling_t *str)
{
int i;
// thinker_t thinker;
saveg_read_thinker_t(&str->thinker);
// ceiling_e type;
str->type = SV_ReadLong();
// sector_t *sector;
i = SV_ReadLong();
str->sector = §ors[i];
// fixed_t bottomheight, topheight;
str->bottomheight = SV_ReadLong();
str->topheight = SV_ReadLong();
// fixed_t speed;
str->speed = SV_ReadLong();
// boolean crush;
str->crush = SV_ReadLong();
// int direction;
str->direction = SV_ReadLong();
// int tag;
str->tag = SV_ReadLong();
// int olddirection;
str->olddirection = SV_ReadLong();
}
static void saveg_write_ceiling_t(ceiling_t *str)
{
// thinker_t thinker;
saveg_write_thinker_t(&str->thinker);
// ceiling_e type;
SV_WriteLong(str->type);
// sector_t *sector;
SV_WriteLong(str->sector - sectors);
// fixed_t bottomheight, topheight;
SV_WriteLong(str->bottomheight);
SV_WriteLong(str->topheight);
// fixed_t speed;
SV_WriteLong(str->speed);
// boolean crush;
SV_WriteLong(str->crush);
// int direction;
SV_WriteLong(str->direction);
// int tag;
SV_WriteLong(str->tag);
// int olddirection;
SV_WriteLong(str->olddirection);
}
//
// vldoor_t
//
static void saveg_read_vldoor_t(vldoor_t *str)
{
int i;
// thinker_t thinker;
saveg_read_thinker_t(&str->thinker);
// vldoor_e type;
str->type = SV_ReadLong();
// sector_t *sector;
i = SV_ReadLong();
str->sector = §ors[i];
// fixed_t topheight;
str->topheight = SV_ReadLong();
// fixed_t speed;
str->speed = SV_ReadLong();
// int direction;
str->direction = SV_ReadLong();
// int topwait;
str->topwait = SV_ReadLong();
// int topcountdown;
str->topcountdown = SV_ReadLong();
}
static void saveg_write_vldoor_t(vldoor_t *str)
{
// thinker_t thinker;
saveg_write_thinker_t(&str->thinker);
// vldoor_e type;
SV_WriteLong(str->type);
// sector_t *sector;
SV_WriteLong(str->sector - sectors);
// fixed_t topheight;
SV_WriteLong(str->topheight);
// fixed_t speed;
SV_WriteLong(str->speed);
// int direction;
SV_WriteLong(str->direction);
// int topwait;
SV_WriteLong(str->topwait);
// int topcountdown;
SV_WriteLong(str->topcountdown);
}
//
// floormove_t
//
static void saveg_read_floormove_t(floormove_t *str)
{
int i;
// thinker_t thinker;
saveg_read_thinker_t(&str->thinker);
// floor_e type;
str->type = SV_ReadLong();
// boolean crush;
str->crush = SV_ReadLong();
// sector_t *sector;
i = SV_ReadLong();
str->sector = §ors[i];
// int direction;
str->direction = SV_ReadLong();
// int newspecial;
str->newspecial = SV_ReadLong();
// short texture;
str->texture = SV_ReadWord();
// fixed_t floordestheight;
str->floordestheight = SV_ReadLong();
// fixed_t speed;
str->speed = SV_ReadLong();
}
static void saveg_write_floormove_t(floormove_t *str)
{
// thinker_t thinker;
saveg_write_thinker_t(&str->thinker);
// floor_e type;
SV_WriteLong(str->type);
// boolean crush;
SV_WriteLong(str->crush);
// sector_t *sector;
SV_WriteLong(str->sector - sectors);
// int direction;
SV_WriteLong(str->direction);
// int newspecial;
SV_WriteLong(str->newspecial);
// short texture;
SV_WriteWord(str->texture);
// fixed_t floordestheight;
SV_WriteLong(str->floordestheight);
// fixed_t speed;
SV_WriteLong(str->speed);
}
//
// plat_t
//
static void saveg_read_plat_t(plat_t *str)
{
int i;
// thinker_t thinker;
saveg_read_thinker_t(&str->thinker);
// sector_t *sector;
i = SV_ReadLong();
str->sector = §ors[i];
// fixed_t speed;
str->speed = SV_ReadLong();
// fixed_t low;
str->low = SV_ReadLong();
// fixed_t high;
str->high = SV_ReadLong();
// int wait;
str->wait = SV_ReadLong();
// int count;
str->count = SV_ReadLong();
// plat_e status;
str->status = SV_ReadLong();
// plat_e oldstatus;
str->oldstatus = SV_ReadLong();
// boolean crush;
str->crush = SV_ReadLong();
// int tag;
str->tag = SV_ReadLong();
// plattype_e type;
str->type = SV_ReadLong();
}
static void saveg_write_plat_t(plat_t *str)
{
// thinker_t thinker;
saveg_write_thinker_t(&str->thinker);
// sector_t *sector;
SV_WriteLong(str->sector - sectors);
// fixed_t speed;
SV_WriteLong(str->speed);
// fixed_t low;
SV_WriteLong(str->low);
// fixed_t high;
SV_WriteLong(str->high);
// int wait;
SV_WriteLong(str->wait);
// int count;
SV_WriteLong(str->count);
// plat_e status;
SV_WriteLong(str->status);
// plat_e oldstatus;
SV_WriteLong(str->oldstatus);
// boolean crush;
SV_WriteLong(str->crush);
// int tag;
SV_WriteLong(str->tag);
// plattype_e type;
SV_WriteLong(str->type);
}
//
// lightflash_t
//
static void saveg_read_lightflash_t(lightflash_t *str)
{
int i;
// thinker_t thinker;
saveg_read_thinker_t(&str->thinker);
// sector_t *sector;
i = SV_ReadLong();
str->sector = §ors[i];
// int count;
str->count = SV_ReadLong();
// int maxlight;
str->maxlight = SV_ReadLong();
// int minlight;
str->minlight = SV_ReadLong();
// int maxtime;
str->maxtime = SV_ReadLong();
// int mintime;
str->mintime = SV_ReadLong();
}
static void saveg_write_lightflash_t(lightflash_t *str)
{
// thinker_t thinker;
saveg_write_thinker_t(&str->thinker);
// sector_t *sector;
SV_WriteLong(str->sector - sectors);
// int count;
SV_WriteLong(str->count);
// int maxlight;
SV_WriteLong(str->maxlight);
// int minlight;
SV_WriteLong(str->minlight);
// int maxtime;
SV_WriteLong(str->maxtime);
// int mintime;
SV_WriteLong(str->mintime);
}
//
// strobe_t
//
static void saveg_read_strobe_t(strobe_t *str)
{
int i;
// thinker_t thinker;
saveg_read_thinker_t(&str->thinker);
// sector_t *sector;
i = SV_ReadLong();
str->sector = §ors[i];
// int count;
str->count = SV_ReadLong();
// int minlight;
str->minlight = SV_ReadLong();
// int maxlight;
str->maxlight = SV_ReadLong();
// int darktime;
str->darktime = SV_ReadLong();
// int brighttime;
str->brighttime = SV_ReadLong();
}
static void saveg_write_strobe_t(strobe_t *str)
{
// thinker_t thinker;
saveg_write_thinker_t(&str->thinker);
// sector_t *sector;
SV_WriteLong(str->sector - sectors);
// int count;
SV_WriteLong(str->count);
// int minlight;
SV_WriteLong(str->minlight);
// int maxlight;
SV_WriteLong(str->maxlight);
// int darktime;
SV_WriteLong(str->darktime);
// int brighttime;
SV_WriteLong(str->brighttime);
}
//
// glow_t
//
static void saveg_read_glow_t(glow_t *str)
{
int i;
// thinker_t thinker;
saveg_read_thinker_t(&str->thinker);
// sector_t *sector;
i = SV_ReadLong();
str->sector = §ors[i];
// int minlight;
str->minlight = SV_ReadLong();
// int maxlight;
str->maxlight = SV_ReadLong();
// int direction;
str->direction = SV_ReadLong();
}
static void saveg_write_glow_t(glow_t *str)
{
// thinker_t thinker;
saveg_write_thinker_t(&str->thinker);
// sector_t *sector;
SV_WriteLong(str->sector - sectors);
// int minlight;
SV_WriteLong(str->minlight);
// int maxlight;
SV_WriteLong(str->maxlight);
// int direction;
SV_WriteLong(str->direction);
}
/*
====================
=
= P_ArchivePlayers
=
====================
*/
void P_ArchivePlayers(void)
{
int i;
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i])
{
continue;
}
saveg_write_player_t(&players[i]);
}
}
/*
====================
=
= P_UnArchivePlayers
=
====================
*/
void P_UnArchivePlayers(void)
{
int i;
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i])
continue;
saveg_read_player_t(&players[i]);
players[i].mo = NULL; // will be set when unarc thinker
players[i].message = NULL;
players[i].attacker = NULL;
}
}
//=============================================================================
/*
====================
=
= P_ArchiveWorld
=
====================
*/
void P_ArchiveWorld(void)
{
int i, j;
sector_t *sec;
line_t *li;
side_t *si;
// Sectors
for (i = 0, sec = sectors; i < numsectors; i++, sec++)
{
SV_WriteWord(sec->floorheight >> FRACBITS);
SV_WriteWord(sec->ceilingheight >> FRACBITS);
SV_WriteWord(sec->floorpic);
SV_WriteWord(sec->ceilingpic);
SV_WriteWord(sec->lightlevel);
SV_WriteWord(sec->special); // needed?
SV_WriteWord(sec->tag); // needed?
}
// Lines
for (i = 0, li = lines; i < numlines; i++, li++)
{
SV_WriteWord(li->flags);
SV_WriteWord(li->special);
SV_WriteWord(li->tag);
for (j = 0; j < 2; j++)
{
if (li->sidenum[j] == -1)
{
continue;
}
si = &sides[li->sidenum[j]];
SV_WriteWord(si->textureoffset >> FRACBITS);
SV_WriteWord(si->rowoffset >> FRACBITS);
SV_WriteWord(si->toptexture);
SV_WriteWord(si->bottomtexture);
SV_WriteWord(si->midtexture);
}
}
}
/*
====================
=
= P_UnArchiveWorld
=
====================
*/
void P_UnArchiveWorld(void)
{
int i, j;
sector_t *sec;
line_t *li;
side_t *si;
//
// do sectors
//
for (i = 0, sec = sectors; i < numsectors; i++, sec++)
{
sec->floorheight = SV_ReadWord() << FRACBITS;
sec->ceilingheight = SV_ReadWord() << FRACBITS;
sec->floorpic = SV_ReadWord();
sec->ceilingpic = SV_ReadWord();
sec->lightlevel = SV_ReadWord();
sec->special = SV_ReadWord(); // needed?
sec->tag = SV_ReadWord(); // needed?
sec->specialdata = 0;
sec->soundtarget = 0;
}
//
// do lines
//
for (i = 0, li = lines; i < numlines; i++, li++)
{
li->flags = SV_ReadWord();
li->special = SV_ReadWord();
li->tag = SV_ReadWord();
for (j = 0; j < 2; j++)
{
if (li->sidenum[j] == -1)
continue;
si = &sides[li->sidenum[j]];
si->textureoffset = SV_ReadWord() << FRACBITS;
si->rowoffset = SV_ReadWord() << FRACBITS;
si->toptexture = SV_ReadWord();
si->bottomtexture = SV_ReadWord();
si->midtexture = SV_ReadWord();
}
}
}
//=============================================================================
typedef enum
{
tc_end,
tc_mobj
} thinkerclass_t;
/*
====================
=
= P_ArchiveThinkers
=
====================
*/
void P_ArchiveThinkers(void)
{
thinker_t *th;
for (th = thinkercap.next; th != &thinkercap; th = th->next)
{
if (th->function == P_MobjThinker)
{
SV_WriteByte(tc_mobj);
saveg_write_mobj_t((mobj_t *) th);
}
//I_Error("P_ArchiveThinkers: Unknown thinker function");
}
// Add a terminating marker
SV_WriteByte(tc_end);
}
/*
====================
=
= P_UnArchiveThinkers
=
====================
*/
void P_UnArchiveThinkers(void)
{
byte tclass;
thinker_t *currentthinker, *next;
mobj_t *mobj;
//
// remove all the current thinkers
//
currentthinker = thinkercap.next;
while (currentthinker != &thinkercap)
{
next = currentthinker->next;
if (currentthinker->function == P_MobjThinker)
P_RemoveMobj((mobj_t *) currentthinker);
else
Z_Free(currentthinker);
currentthinker = next;
}
P_InitThinkers();
// read in saved thinkers
while (1)
{
tclass = SV_ReadByte();
switch (tclass)
{
case tc_end:
return; // end of list
case tc_mobj:
mobj = Z_Malloc(sizeof(*mobj), PU_LEVEL, NULL);
saveg_read_mobj_t(mobj);
mobj->target = NULL;
P_SetThingPosition(mobj);
mobj->info = &mobjinfo[mobj->type];
mobj->floorz = mobj->subsector->sector->floorheight;
mobj->ceilingz = mobj->subsector->sector->ceilingheight;
mobj->thinker.function = P_MobjThinker;
P_AddThinker(&mobj->thinker);
break;
default:
I_Error("Unknown tclass %i in savegame", tclass);
}
}
}
//=============================================================================
/*
====================
=
= P_ArchiveSpecials
=
====================
*/
enum
{
tc_ceiling,
tc_door,
tc_floor,
tc_plat,
tc_flash,
tc_strobe,
tc_glow,
tc_endspecials
} specials_e;
void P_ArchiveSpecials(void)
{
/*
T_MoveCeiling, (ceiling_t: sector_t * swizzle), - active list
T_VerticalDoor, (vldoor_t: sector_t * swizzle),
T_MoveFloor, (floormove_t: sector_t * swizzle),
T_LightFlash, (lightflash_t: sector_t * swizzle),
T_StrobeFlash, (strobe_t: sector_t *),
T_Glow, (glow_t: sector_t *),
T_PlatRaise, (plat_t: sector_t *), - active list
*/
thinker_t *th;
for (th = thinkercap.next; th != &thinkercap; th = th->next)
{
if (th->function == T_MoveCeiling)
{
SV_WriteByte(tc_ceiling);
saveg_write_ceiling_t((ceiling_t *) th);
}
else if (th->function == T_VerticalDoor)
{
SV_WriteByte(tc_door);
saveg_write_vldoor_t((vldoor_t *) th);
}
else if (th->function == T_MoveFloor)
{
SV_WriteByte(tc_floor);
saveg_write_floormove_t((floormove_t *) th);
}
else if (th->function == T_PlatRaise)
{
SV_WriteByte(tc_plat);
saveg_write_plat_t((plat_t *) th);
}
else if (th->function == T_LightFlash)
{
SV_WriteByte(tc_flash);
saveg_write_lightflash_t((lightflash_t *) th);
}
else if (th->function == T_StrobeFlash)
{
SV_WriteByte(tc_strobe);
saveg_write_strobe_t((strobe_t *) th);
}
else if (th->function == T_Glow)
{
SV_WriteByte(tc_glow);
saveg_write_glow_t((glow_t *) th);
}
}
// Add a terminating marker
SV_WriteByte(tc_endspecials);
}
/*
====================
=
= P_UnArchiveSpecials
=
====================
*/
void P_UnArchiveSpecials(void)
{
byte tclass;
ceiling_t *ceiling;
vldoor_t *door;
floormove_t *floor;
plat_t *plat;
lightflash_t *flash;
strobe_t *strobe;
glow_t *glow;
// read in saved thinkers
while (1)
{
tclass = SV_ReadByte();
switch (tclass)
{
case tc_endspecials:
return; // end of list
case tc_ceiling:
ceiling = Z_Malloc(sizeof(*ceiling), PU_LEVEL, NULL);
saveg_read_ceiling_t(ceiling);
ceiling->sector->specialdata = T_MoveCeiling; // ???
ceiling->thinker.function = T_MoveCeiling;
P_AddThinker(&ceiling->thinker);
P_AddActiveCeiling(ceiling);
break;
case tc_door:
door = Z_Malloc(sizeof(*door), PU_LEVEL, NULL);
saveg_read_vldoor_t(door);
door->sector->specialdata = door;
door->thinker.function = T_VerticalDoor;
P_AddThinker(&door->thinker);
break;
case tc_floor:
floor = Z_Malloc(sizeof(*floor), PU_LEVEL, NULL);
saveg_read_floormove_t(floor);
floor->sector->specialdata = T_MoveFloor;
floor->thinker.function = T_MoveFloor;
P_AddThinker(&floor->thinker);
break;
case tc_plat:
plat = Z_Malloc(sizeof(*plat), PU_LEVEL, NULL);
saveg_read_plat_t(plat);
plat->sector->specialdata = T_PlatRaise;
// In the original Heretic code this was a conditional "fix"
// of the thinker function, but the save code (above) decides
// whether to save a T_PlatRaise based on thinker function
// anyway, so it can't be NULL. Having the conditional causes
// a bug, as our saveg_read_thinker_t sets these to NULL.
// if (plat->thinker.function)
plat->thinker.function = T_PlatRaise;
P_AddThinker(&plat->thinker);
P_AddActivePlat(plat);
break;
case tc_flash:
flash = Z_Malloc(sizeof(*flash), PU_LEVEL, NULL);
saveg_read_lightflash_t(flash);
flash->thinker.function = T_LightFlash;
P_AddThinker(&flash->thinker);
break;
case tc_strobe:
strobe = Z_Malloc(sizeof(*strobe), PU_LEVEL, NULL);
saveg_read_strobe_t(strobe);
strobe->thinker.function = T_StrobeFlash;
P_AddThinker(&strobe->thinker);
break;
case tc_glow:
glow = Z_Malloc(sizeof(*glow), PU_LEVEL, NULL);
saveg_read_glow_t(glow);
glow->thinker.function = T_Glow;
P_AddThinker(&glow->thinker);
break;
default:
I_Error("P_UnarchiveSpecials:Unknown tclass %i "
"in savegame", tclass);
}
}
}