shithub: choc

Download patch

ref: fa843fc93409d2b83d2b0dae4d743acd5f028ea9
parent: f3a3dd9aa480a060a54bfc1b1a203aeaf90ef073
author: Simon Howard <fraggle@gmail.com>
date: Wed Jan 18 19:09:20 EST 2006

Add functions to r/w structures to the savegame buffer, rather than
copying the raw structures. This way, we read and write to the DOS
savegame format always, regardless of the compiler and processor
architecture, to ensure Vanilla compatibility.

Subversion-branch: /trunk/chocolate-doom
Subversion-revision: 298

--- a/src/p_saveg.c
+++ b/src/p_saveg.c
@@ -1,7 +1,7 @@
 // Emacs style mode select   -*- C++ -*- 
 //-----------------------------------------------------------------------------
 //
-// $Id: p_saveg.c 296 2006-01-16 21:40:38Z fraggle $
+// $Id: p_saveg.c 298 2006-01-19 00:09:20Z fraggle $
 //
 // Copyright(C) 1993-1996 Id Software, Inc.
 // Copyright(C) 2005 Simon Howard
@@ -22,6 +22,12 @@
 // 02111-1307, USA.
 //
 // $Log$
+// Revision 1.5  2006/01/19 00:09:20  fraggle
+// Add functions to r/w structures to the savegame buffer, rather than
+// copying the raw structures.  This way, we read and write to the DOS
+// savegame format always, regardless of the compiler and processor
+// architecture, to ensure Vanilla compatibility.
+//
 // Revision 1.4  2006/01/16 21:40:38  fraggle
 // Vanilla savegame load/save
 //
@@ -43,7 +49,7 @@
 //-----------------------------------------------------------------------------
 
 static const char
-rcsid[] = "$Id: p_saveg.c 296 2006-01-16 21:40:38Z fraggle $";
+rcsid[] = "$Id: p_saveg.c 298 2006-01-19 00:09:20Z fraggle $";
 
 #include "dstrings.h"
 #include "deh_main.h"
@@ -75,15 +81,1234 @@
     return filename;
 }
 
+// Endian-safe integer read/write functions
 
+static byte saveg_read8(void)
+{
+    int result;
+
+    result = *save_p;
+
+    save_p += 1;
+
+    return result;
+}
+
+static void saveg_write8(byte value)
+{
+    *save_p = value;
+
+    save_p += 1;
+}
+
+static short saveg_read16(void)
+{
+    int result;
+
+    result = save_p[0] | (save_p[1] << 8);
+
+    save_p += 2;
+
+    return result;
+}
+
+static void saveg_write16(short value)
+{
+    save_p[0] = value & 0xff;
+    save_p[1] = (value >> 8) & 0xff;
+
+    save_p += 2;
+}
+
+static int saveg_read32(void)
+{
+    int result;
+
+    result = save_p[0] | (save_p[1] << 8)
+           | (save_p[2] << 16) | (save_p[3] << 24);
+
+    save_p += 4;
+
+    return result;
+}
+
+static void saveg_write32(int value)
+{
+    save_p[0] = value & 0xff;
+    save_p[1] = (value >> 8) & 0xff;
+    save_p[2] = (value >> 16) & 0xff;
+    save_p[3] = (value >> 24) & 0xff;
+
+    save_p += 4;
+}
+
+// Pointers
+
+static void *saveg_readp(void)
+{
+    return (void *) saveg_read32();
+}
+
+static void saveg_writep(void *p)
+{
+    saveg_write32((int) p);
+}
+
+// Enum values are 32-bit integers.
+
+#define saveg_read_enum saveg_read32
+#define saveg_write_enum saveg_write32
+
 //
+// Structure read/write functions
+//
+
+//
+// mapthing_t
+//
+
+static void saveg_read_mapthing_t(mapthing_t *str)
+{
+    // short x;
+    str->x = saveg_read16();
+
+    // short y;
+    str->y = saveg_read16();
+
+    // short angle;
+    str->angle = saveg_read16();
+
+    // short type;
+    str->type = saveg_read16();
+
+    // short options;
+    str->options = saveg_read16();
+}
+
+static void saveg_write_mapthing_t(mapthing_t *str)
+{
+    // short x;
+    saveg_write16(str->x);
+
+    // short y;
+    saveg_write16(str->y);
+
+    // short angle;
+    saveg_write16(str->angle);
+
+    // short type;
+    saveg_write16(str->type);
+
+    // short options;
+    saveg_write16(str->options);
+}
+
+//
+// actionf_t
+// 
+
+static void saveg_read_actionf_t(actionf_t *str)
+{
+    // actionf_p1 acp1;
+    str->acp1 = saveg_readp();
+}
+
+static void saveg_write_actionf_t(actionf_t *str)
+{
+    // actionf_p1 acp1;
+    saveg_writep(str->acp1);
+}
+
+//
+// think_t
+//
+// This is just an actionf_t.
+//
+
+#define saveg_read_think_t saveg_read_actionf_t
+#define saveg_write_think_t saveg_write_actionf_t
+
+//
+// thinker_t
+//
+
+static void saveg_read_thinker_t(thinker_t *str)
+{
+    // struct thinker_s* prev;
+    str->prev = saveg_readp();
+
+    // struct thinker_s* next;
+    str->next = saveg_readp();
+
+    // think_t function;
+    saveg_read_think_t(&str->function);
+}
+
+static void saveg_write_thinker_t(thinker_t *str)
+{
+    // struct thinker_s* prev;
+    saveg_writep(str->prev);
+
+    // struct thinker_s* next;
+    saveg_writep(str->next);
+
+    // think_t function;
+    saveg_write_think_t(&str->function);
+}
+
+//
+// mobj_t
+//
+
+static void saveg_read_mobj_t(mobj_t *str)
+{
+    int pl;
+
+    // thinker_t thinker;
+    saveg_read_thinker_t(&str->thinker);
+
+    // fixed_t x;
+    str->x = saveg_read32();
+
+    // fixed_t y;
+    str->y = saveg_read32();
+
+    // fixed_t z;
+    str->z = saveg_read32();
+
+    // struct mobj_s* snext;
+    str->snext = saveg_readp();
+
+    // struct mobj_s* sprev;
+    str->sprev = saveg_readp();
+
+    // angle_t angle;
+    str->angle = saveg_read32();
+
+    // spritenum_t sprite;
+    str->sprite = saveg_read_enum();
+
+    // int frame;
+    str->frame = saveg_read32();
+
+    // struct mobj_s* bnext;
+    str->bnext = saveg_readp();
+
+    // struct mobj_s* bprev;
+    str->bprev = saveg_readp();
+
+    // struct subsector_s* subsector;
+    str->subsector = saveg_readp();
+
+    // fixed_t floorz;
+    str->floorz = saveg_read32();
+
+    // fixed_t ceilingz;
+    str->ceilingz = saveg_read32();
+
+    // fixed_t radius;
+    str->radius = saveg_read32();
+
+    // fixed_t height;
+    str->height = saveg_read32();
+
+    // fixed_t momx;
+    str->momx = saveg_read32();
+
+    // fixed_t momy;
+    str->momy = saveg_read32();
+
+    // fixed_t momz;
+    str->momz = saveg_read32();
+
+    // int validcount;
+    str->validcount = saveg_read32();
+
+    // mobjtype_t type;
+    str->type = saveg_read_enum();
+
+    // mobjinfo_t* info;
+    str->info = saveg_readp();
+
+    // int tics;
+    str->tics = saveg_read32();
+
+    // state_t* state;
+    str->state = &states[saveg_read32()];
+
+    // int flags;
+    str->flags = saveg_read32();
+
+    // int health;
+    str->health = saveg_read32();
+
+    // int movedir;
+    str->movedir = saveg_read32();
+
+    // int movecount;
+    str->movecount = saveg_read32();
+
+    // struct mobj_s* target;
+    str->target = saveg_readp();
+
+    // int reactiontime;
+    str->reactiontime = saveg_read32();
+
+    // int threshold;
+    str->threshold = saveg_read32();
+
+    // struct player_s* player;
+    pl = saveg_read32();
+
+    if (pl > 0)
+    {
+        str->player = &players[pl - 1];
+        str->player->mo = str;
+    }
+    else
+    {
+        str->player = NULL;
+    }
+
+    // int lastlook;
+    str->lastlook = saveg_read32();
+
+    // mapthing_t spawnpoint;
+    saveg_read_mapthing_t(&str->spawnpoint);
+
+    // struct mobj_s* tracer;
+    str->tracer = saveg_readp();
+}
+
+static void saveg_write_mobj_t(mobj_t *str)
+{
+    // thinker_t thinker;
+    saveg_write_thinker_t(&str->thinker);
+
+    // fixed_t x;
+    saveg_write32(str->x);
+
+    // fixed_t y;
+    saveg_write32(str->y);
+
+    // fixed_t z;
+    saveg_write32(str->z);
+
+    // struct mobj_s* snext;
+    saveg_writep(str->snext);
+
+    // struct mobj_s* sprev;
+    saveg_writep(str->sprev);
+
+    // angle_t angle;
+    saveg_write32(str->angle);
+
+    // spritenum_t sprite;
+    saveg_write_enum(str->sprite);
+
+    // int frame;
+    saveg_write32(str->frame);
+
+    // struct mobj_s* bnext;
+    saveg_writep(str->bnext);
+
+    // struct mobj_s* bprev;
+    saveg_writep(str->bprev);
+
+    // struct subsector_s* subsector;
+    saveg_writep(str->subsector);
+
+    // fixed_t floorz;
+    saveg_write32(str->floorz);
+
+    // fixed_t ceilingz;
+    saveg_write32(str->ceilingz);
+
+    // fixed_t radius;
+    saveg_write32(str->radius);
+
+    // fixed_t height;
+    saveg_write32(str->height);
+
+    // fixed_t momx;
+    saveg_write32(str->momx);
+
+    // fixed_t momy;
+    saveg_write32(str->momy);
+
+    // fixed_t momz;
+    saveg_write32(str->momz);
+
+    // int validcount;
+    saveg_write32(str->validcount);
+
+    // mobjtype_t type;
+    saveg_write_enum(str->type);
+
+    // mobjinfo_t* info;
+    saveg_writep(str->info);
+
+    // int tics;
+    saveg_write32(str->tics);
+
+    // state_t* state;
+    saveg_write32(str->state - states);
+
+    // int flags;
+    saveg_write32(str->flags);
+
+    // int health;
+    saveg_write32(str->health);
+
+    // int movedir;
+    saveg_write32(str->movedir);
+
+    // int movecount;
+    saveg_write32(str->movecount);
+
+    // struct mobj_s* target;
+    saveg_writep(str->target);
+
+    // int reactiontime;
+    saveg_write32(str->reactiontime);
+
+    // int threshold;
+    saveg_write32(str->threshold);
+
+    // struct player_s* player;
+    if (str->player)
+    {
+        saveg_write32(str->player - players + 1);
+    }
+    else
+    {
+        saveg_write32(0);
+    }
+
+    // int lastlook;
+    saveg_write32(str->lastlook);
+
+    // mapthing_t spawnpoint;
+    saveg_write_mapthing_t(&str->spawnpoint);
+
+    // struct mobj_s* tracer;
+    saveg_writep(str->tracer);
+}
+
+
+//
+// ticcmd_t
+//
+
+static void saveg_read_ticcmd_t(ticcmd_t *str)
+{
+
+    // signed char forwardmove;
+    str->forwardmove = saveg_read8();
+
+    // signed char sidemove;
+    str->sidemove = saveg_read8();
+
+    // short angleturn;
+    str->angleturn = saveg_read16();
+
+    // short consistancy;
+    str->consistancy = saveg_read16();
+
+    // byte chatchar;
+    str->chatchar = saveg_read8();
+
+    // byte buttons;
+    str->buttons = saveg_read8();
+}
+
+static void saveg_write_ticcmd_t(ticcmd_t *str)
+{
+
+    // signed char forwardmove;
+    saveg_write8(str->forwardmove);
+
+    // signed char sidemove;
+    saveg_write8(str->sidemove);
+
+    // short angleturn;
+    saveg_write16(str->angleturn);
+
+    // short consistancy;
+    saveg_write16(str->consistancy);
+
+    // byte chatchar;
+    saveg_write8(str->chatchar);
+
+    // byte buttons;
+    saveg_write8(str->buttons);
+}
+
+//
+// pspdef_t
+//
+
+static void saveg_read_pspdef_t(pspdef_t *str)
+{
+    int state;
+
+    // state_t* state;
+    state = saveg_read32();
+
+    if (state > 0)
+    {
+        str->state = &states[state];
+    }
+    else
+    {
+        str->state = NULL;
+    }
+
+    // int tics;
+    str->tics = saveg_read32();
+
+    // fixed_t sx;
+    str->sx = saveg_read32();
+
+    // fixed_t sy;
+    str->sy = saveg_read32();
+}
+
+static void saveg_write_pspdef_t(pspdef_t *str)
+{
+    // state_t* state;
+    if (str->state)
+    {
+        saveg_write32(str->state - states);
+    }
+    else
+    {
+        saveg_write32(0);
+    }
+
+    // int tics;
+    saveg_write32(str->tics);
+
+    // fixed_t sx;
+    saveg_write32(str->sx);
+
+    // fixed_t sy;
+    saveg_write32(str->sy);
+}
+
+//
+// player_t
+//
+
+static void saveg_read_player_t(player_t *str)
+{
+    int i;
+
+    // mobj_t* mo;
+    str->mo = saveg_readp();
+
+    // playerstate_t playerstate;
+    str->playerstate = saveg_read_enum();
+
+    // ticcmd_t cmd;
+    saveg_read_ticcmd_t(&str->cmd);
+
+    // fixed_t viewz;
+    str->viewz = saveg_read32();
+
+    // fixed_t viewheight;
+    str->viewheight = saveg_read32();
+
+    // fixed_t deltaviewheight;
+    str->deltaviewheight = saveg_read32();
+
+    // fixed_t bob;
+    str->bob = saveg_read32();
+
+    // int health;
+    str->health = saveg_read32();
+
+    // int armorpoints;
+    str->armorpoints = saveg_read32();
+
+    // int armortype;
+    str->armortype = saveg_read32();
+
+    // int powers[NUMPOWERS];
+    for (i=0; i<NUMPOWERS; ++i)
+    {
+        str->powers[i] = saveg_read32();
+    }
+
+    // boolean cards[NUMCARDS];
+    for (i=0; i<NUMCARDS; ++i)
+    {
+        str->cards[i] = saveg_read32();
+    }
+
+    // boolean backpack;
+    str->backpack = saveg_read32();
+
+    // int frags[MAXPLAYERS];
+    for (i=0; i<MAXPLAYERS; ++i)
+    {
+        str->frags[i] = saveg_read32();
+    }
+
+    // weapontype_t readyweapon;
+    str->readyweapon = saveg_read_enum();
+
+    // weapontype_t pendingweapon;
+    str->pendingweapon = saveg_read_enum();
+
+    // boolean weaponowned[NUMWEAPONS];
+    for (i=0; i<NUMWEAPONS; ++i)
+    {
+        str->weaponowned[i] = saveg_read32();
+    }
+
+    // int ammo[NUMAMMO];
+    for (i=0; i<NUMAMMO; ++i)
+    {
+        str->ammo[i] = saveg_read32();
+    }
+
+    // int maxammo[NUMAMMO];
+    for (i=0; i<NUMAMMO; ++i)
+    {
+        str->maxammo[i] = saveg_read32();
+    }
+
+    // int attackdown;
+    str->attackdown = saveg_read32();
+
+    // int usedown;
+    str->usedown = saveg_read32();
+
+    // int cheats;
+    str->cheats = saveg_read32();
+
+    // int refire;
+    str->refire = saveg_read32();
+
+    // int killcount;
+    str->killcount = saveg_read32();
+
+    // int itemcount;
+    str->itemcount = saveg_read32();
+
+    // int secretcount;
+    str->secretcount = saveg_read32();
+
+    // char* message;
+    str->message = saveg_readp();
+
+    // int damagecount;
+    str->damagecount = saveg_read32();
+
+    // int bonuscount;
+    str->bonuscount = saveg_read32();
+
+    // mobj_t* attacker;
+    str->attacker = saveg_readp();
+
+    // int extralight;
+    str->extralight = saveg_read32();
+
+    // int fixedcolormap;
+    str->fixedcolormap = saveg_read32();
+
+    // int colormap;
+    str->colormap = saveg_read32();
+
+    // pspdef_t psprites[NUMPSPRITES];
+    for (i=0; i<NUMPSPRITES; ++i)
+    {
+        saveg_read_pspdef_t(&str->psprites[i]);
+    }
+
+    // boolean didsecret;
+    str->didsecret = saveg_read32();
+}
+
+static void saveg_write_player_t(player_t *str)
+{
+    int i;
+
+    // mobj_t* mo;
+    saveg_writep(str->mo);
+
+    // playerstate_t playerstate;
+    saveg_write_enum(str->playerstate);
+
+    // ticcmd_t cmd;
+    saveg_write_ticcmd_t(&str->cmd);
+
+    // fixed_t viewz;
+    saveg_write32(str->viewz);
+
+    // fixed_t viewheight;
+    saveg_write32(str->viewheight);
+
+    // fixed_t deltaviewheight;
+    saveg_write32(str->deltaviewheight);
+
+    // fixed_t bob;
+    saveg_write32(str->bob);
+
+    // int health;
+    saveg_write32(str->health);
+
+    // int armorpoints;
+    saveg_write32(str->armorpoints);
+
+    // int armortype;
+    saveg_write32(str->armortype);
+
+    // int powers[NUMPOWERS];
+    for (i=0; i<NUMPOWERS; ++i)
+    {
+        saveg_write32(str->powers[i]);
+    }
+
+    // boolean cards[NUMCARDS];
+    for (i=0; i<NUMCARDS; ++i)
+    {
+        saveg_write32(str->cards[i]);
+    }
+
+    // boolean backpack;
+    saveg_write32(str->backpack);
+
+    // int frags[MAXPLAYERS];
+    for (i=0; i<MAXPLAYERS; ++i)
+    {
+        saveg_write32(str->frags[i]);
+    }
+
+    // weapontype_t readyweapon;
+    saveg_write_enum(str->readyweapon);
+
+    // weapontype_t pendingweapon;
+    saveg_write_enum(str->pendingweapon);
+
+    // boolean weaponowned[NUMWEAPONS];
+    for (i=0; i<NUMWEAPONS; ++i)
+    {
+        saveg_write32(str->weaponowned[i]);
+    }
+
+    // int ammo[NUMAMMO];
+    for (i=0; i<NUMAMMO; ++i)
+    {
+        saveg_write32(str->ammo[i]);
+    }
+
+    // int maxammo[NUMAMMO];
+    for (i=0; i<NUMAMMO; ++i)
+    {
+        saveg_write32(str->maxammo[i]);
+    }
+
+    // int attackdown;
+    saveg_write32(str->attackdown);
+
+    // int usedown;
+    saveg_write32(str->usedown);
+
+    // int cheats;
+    saveg_write32(str->cheats);
+
+    // int refire;
+    saveg_write32(str->refire);
+
+    // int killcount;
+    saveg_write32(str->killcount);
+
+    // int itemcount;
+    saveg_write32(str->itemcount);
+
+    // int secretcount;
+    saveg_write32(str->secretcount);
+
+    // char* message;
+    saveg_writep(str->message);
+
+    // int damagecount;
+    saveg_write32(str->damagecount);
+
+    // int bonuscount;
+    saveg_write32(str->bonuscount);
+
+    // mobj_t* attacker;
+    saveg_writep(str->attacker);
+
+    // int extralight;
+    saveg_write32(str->extralight);
+
+    // int fixedcolormap;
+    saveg_write32(str->fixedcolormap);
+
+    // int colormap;
+    saveg_write32(str->colormap);
+
+    // pspdef_t psprites[NUMPSPRITES];
+    for (i=0; i<NUMPSPRITES; ++i)
+    {
+        saveg_write_pspdef_t(&str->psprites[i]);
+    }
+
+    // boolean didsecret;
+    saveg_write32(str->didsecret);
+}
+
+
+//
+// ceiling_t
+//
+
+static void saveg_read_ceiling_t(ceiling_t *str)
+{
+    int sector;
+
+    // thinker_t thinker;
+    saveg_read_thinker_t(&str->thinker);
+
+    // ceiling_e type;
+    str->type = saveg_read_enum();
+
+    // sector_t* sector;
+    sector = saveg_read32();
+    str->sector = &sectors[sector];
+
+    // fixed_t bottomheight;
+    str->bottomheight = saveg_read32();
+
+    // fixed_t topheight;
+    str->topheight = saveg_read32();
+
+    // fixed_t speed;
+    str->speed = saveg_read32();
+
+    // boolean crush;
+    str->crush = saveg_read32();
+
+    // int direction;
+    str->direction = saveg_read32();
+
+    // int tag;
+    str->tag = saveg_read32();
+
+    // int olddirection;
+    str->olddirection = saveg_read32();
+}
+
+static void saveg_write_ceiling_t(ceiling_t *str)
+{
+    // thinker_t thinker;
+    saveg_write_thinker_t(&str->thinker);
+
+    // ceiling_e type;
+    saveg_write_enum(str->type);
+
+    // sector_t* sector;
+    saveg_write32(str->sector - sectors);
+
+    // fixed_t bottomheight;
+    saveg_write32(str->bottomheight);
+
+    // fixed_t topheight;
+    saveg_write32(str->topheight);
+
+    // fixed_t speed;
+    saveg_write32(str->speed);
+
+    // boolean crush;
+    saveg_write32(str->crush);
+
+    // int direction;
+    saveg_write32(str->direction);
+
+    // int tag;
+    saveg_write32(str->tag);
+
+    // int olddirection;
+    saveg_write32(str->olddirection);
+}
+
+//
+// vldoor_t
+//
+
+static void saveg_read_vldoor_t(vldoor_t *str)
+{
+    int sector;
+
+    // thinker_t thinker;
+    saveg_read_thinker_t(&str->thinker);
+
+    // vldoor_e type;
+    str->type = saveg_read_enum();
+
+    // sector_t* sector;
+    sector = saveg_read32();
+    str->sector = &sectors[sector];
+
+    // fixed_t topheight;
+    str->topheight = saveg_read32();
+
+    // fixed_t speed;
+    str->speed = saveg_read32();
+
+    // int direction;
+    str->direction = saveg_read32();
+
+    // int topwait;
+    str->topwait = saveg_read32();
+
+    // int topcountdown;
+    str->topcountdown = saveg_read32();
+}
+
+static void saveg_write_vldoor_t(vldoor_t *str)
+{
+    // thinker_t thinker;
+    saveg_write_thinker_t(&str->thinker);
+
+    // vldoor_e type;
+    saveg_write_enum(str->type);
+
+    // sector_t* sector;
+    saveg_write32(str->sector - sectors);
+
+    // fixed_t topheight;
+    saveg_write32(str->topheight);
+
+    // fixed_t speed;
+    saveg_write32(str->speed);
+
+    // int direction;
+    saveg_write32(str->direction);
+
+    // int topwait;
+    saveg_write32(str->topwait);
+
+    // int topcountdown;
+    saveg_write32(str->topcountdown);
+}
+
+//
+// floormove_t
+//
+
+static void saveg_read_floormove_t(floormove_t *str)
+{
+    int sector;
+
+    // thinker_t thinker;
+    saveg_read_thinker_t(&str->thinker);
+
+    // floor_e type;
+    str->type = saveg_read_enum();
+
+    // boolean crush;
+    str->crush = saveg_read32();
+
+    // sector_t* sector;
+    sector = saveg_read32();
+    str->sector = &sectors[sector];
+
+    // int direction;
+    str->direction = saveg_read32();
+
+    // int newspecial;
+    str->newspecial = saveg_read32();
+
+    // short texture;
+    str->texture = saveg_read16();
+
+    // fixed_t floordestheight;
+    str->floordestheight = saveg_read32();
+
+    // fixed_t speed;
+    str->speed = saveg_read32();
+}
+
+static void saveg_write_floormove_t(floormove_t *str)
+{
+    // thinker_t thinker;
+    saveg_write_thinker_t(&str->thinker);
+
+    // floor_e type;
+    saveg_write_enum(str->type);
+
+    // boolean crush;
+    saveg_write32(str->crush);
+
+    // sector_t* sector;
+    saveg_write32(str->sector - sectors);
+
+    // int direction;
+    saveg_write32(str->direction);
+
+    // int newspecial;
+    saveg_write32(str->newspecial);
+
+    // short texture;
+    saveg_write16(str->texture);
+
+    // fixed_t floordestheight;
+    saveg_write32(str->floordestheight);
+
+    // fixed_t speed;
+    saveg_write32(str->speed);
+}
+
+//
+// plat_t
+//
+
+static void saveg_read_plat_t(plat_t *str)
+{
+    int sector;
+
+    // thinker_t thinker;
+    saveg_read_thinker_t(&str->thinker);
+
+    // sector_t* sector;
+    sector = saveg_read32();
+    str->sector = &sectors[sector];
+
+    // fixed_t speed;
+    str->speed = saveg_read32();
+
+    // fixed_t low;
+    str->low = saveg_read32();
+
+    // fixed_t high;
+    str->high = saveg_read32();
+
+    // int wait;
+    str->wait = saveg_read32();
+
+    // int count;
+    str->count = saveg_read32();
+
+    // plat_e status;
+    str->status = saveg_read_enum();
+
+    // plat_e oldstatus;
+    str->oldstatus = saveg_read_enum();
+
+    // boolean crush;
+    str->crush = saveg_read32();
+
+    // int tag;
+    str->tag = saveg_read32();
+
+    // plattype_e type;
+    str->type = saveg_read_enum();
+}
+
+static void saveg_write_plat_t(plat_t *str)
+{
+    // thinker_t thinker;
+    saveg_write_thinker_t(&str->thinker);
+
+    // sector_t* sector;
+    saveg_write32(str->sector - sectors);
+
+    // fixed_t speed;
+    saveg_write32(str->speed);
+
+    // fixed_t low;
+    saveg_write32(str->low);
+
+    // fixed_t high;
+    saveg_write32(str->high);
+
+    // int wait;
+    saveg_write32(str->wait);
+
+    // int count;
+    saveg_write32(str->count);
+
+    // plat_e status;
+    saveg_write_enum(str->status);
+
+    // plat_e oldstatus;
+    saveg_write_enum(str->oldstatus);
+
+    // boolean crush;
+    saveg_write32(str->crush);
+
+    // int tag;
+    saveg_write32(str->tag);
+
+    // plattype_e type;
+    saveg_write_enum(str->type);
+}
+
+//
+// lightflash_t
+//
+
+static void saveg_read_lightflash_t(lightflash_t *str)
+{
+    int sector;
+
+    // thinker_t thinker;
+    saveg_read_thinker_t(&str->thinker);
+
+    // sector_t* sector;
+    sector = saveg_read32();
+    str->sector = &sectors[sector];
+
+    // int count;
+    str->count = saveg_read32();
+
+    // int maxlight;
+    str->maxlight = saveg_read32();
+
+    // int minlight;
+    str->minlight = saveg_read32();
+
+    // int maxtime;
+    str->maxtime = saveg_read32();
+
+    // int mintime;
+    str->mintime = saveg_read32();
+}
+
+static void saveg_write_lightflash_t(lightflash_t *str)
+{
+    // thinker_t thinker;
+    saveg_write_thinker_t(&str->thinker);
+
+    // sector_t* sector;
+    saveg_write32(str->sector - sectors);
+
+    // int count;
+    saveg_write32(str->count);
+
+    // int maxlight;
+    saveg_write32(str->maxlight);
+
+    // int minlight;
+    saveg_write32(str->minlight);
+
+    // int maxtime;
+    saveg_write32(str->maxtime);
+
+    // int mintime;
+    saveg_write32(str->mintime);
+}
+
+//
+// strobe_t
+//
+
+static void saveg_read_strobe_t(strobe_t *str)
+{
+    int sector;
+
+    // thinker_t thinker;
+    saveg_read_thinker_t(&str->thinker);
+
+    // sector_t* sector;
+    sector = saveg_read32();
+    str->sector = &sectors[sector];
+
+    // int count;
+    str->count = saveg_read32();
+
+    // int minlight;
+    str->minlight = saveg_read32();
+
+    // int maxlight;
+    str->maxlight = saveg_read32();
+
+    // int darktime;
+    str->darktime = saveg_read32();
+
+    // int brighttime;
+    str->brighttime = saveg_read32();
+}
+
+static void saveg_write_strobe_t(strobe_t *str)
+{
+    // thinker_t thinker;
+    saveg_write_thinker_t(&str->thinker);
+
+    // sector_t* sector;
+    saveg_write32(str->sector - sectors);
+
+    // int count;
+    saveg_write32(str->count);
+
+    // int minlight;
+    saveg_write32(str->minlight);
+
+    // int maxlight;
+    saveg_write32(str->maxlight);
+
+    // int darktime;
+    saveg_write32(str->darktime);
+
+    // int brighttime;
+    saveg_write32(str->brighttime);
+}
+
+//
+// glow_t
+//
+
+static void saveg_read_glow_t(glow_t *str)
+{
+    int sector;
+
+    // thinker_t thinker;
+    saveg_read_thinker_t(&str->thinker);
+
+    // sector_t* sector;
+    sector = saveg_read32();
+    str->sector = &sectors[sector];
+
+    // int minlight;
+    str->minlight = saveg_read32();
+
+    // int maxlight;
+    str->maxlight = saveg_read32();
+
+    // int direction;
+    str->direction = saveg_read32();
+}
+
+static void saveg_write_glow_t(glow_t *str)
+{
+    // thinker_t thinker;
+    saveg_write_thinker_t(&str->thinker);
+
+    // sector_t* sector;
+    saveg_write32(str->sector - sectors);
+
+    // int minlight;
+    saveg_write32(str->minlight);
+
+    // int maxlight;
+    saveg_write32(str->maxlight);
+
+    // int direction;
+    saveg_write32(str->direction);
+}
+
+
+//
 // P_ArchivePlayers
 //
 void P_ArchivePlayers (void)
 {
     int		i;
-    int		j;
-    player_t*	dest;
 		
     for (i=0 ; i<MAXPLAYERS ; i++)
     {
@@ -92,17 +1317,7 @@
 	
 	PADSAVEP();
 
-	dest = (player_t *)save_p;
-	memcpy (dest,&players[i],sizeof(player_t));
-	save_p += sizeof(player_t);
-	for (j=0 ; j<NUMPSPRITES ; j++)
-	{
-	    if (dest->psprites[j].state)
-	    {
-		dest->psprites[j].state 
-		    = (state_t *)(dest->psprites[j].state-states);
-	    }
-	}
+        saveg_write_player_t(&players[i]);
     }
 }
 
@@ -114,7 +1329,6 @@
 void P_UnArchivePlayers (void)
 {
     int		i;
-    int		j;
 	
     for (i=0 ; i<MAXPLAYERS ; i++)
     {
@@ -123,22 +1337,12 @@
 	
 	PADSAVEP();
 
-	memcpy (&players[i],save_p, sizeof(player_t));
-	save_p += sizeof(player_t);
+        saveg_read_player_t(&players[i]);
 	
 	// will be set when unarc thinker
 	players[i].mo = NULL;	
 	players[i].message = NULL;
 	players[i].attacker = NULL;
-
-	for (j=0 ; j<NUMPSPRITES ; j++)
-	{
-	    if (players[i]. psprites[j].state)
-	    {
-		players[i]. psprites[j].state 
-		    = &states[ (int)players[i].psprites[j].state ];
-	    }
-	}
     }
 }
 
@@ -153,20 +1357,17 @@
     sector_t*		sec;
     line_t*		li;
     side_t*		si;
-    short*		put;
-	
-    put = (short *)save_p;
     
     // do sectors
     for (i=0, sec = sectors ; i<numsectors ; i++,sec++)
     {
-	*put++ = sec->floorheight >> FRACBITS;
-	*put++ = sec->ceilingheight >> FRACBITS;
-	*put++ = sec->floorpic;
-	*put++ = sec->ceilingpic;
-	*put++ = sec->lightlevel;
-	*put++ = sec->special;		// needed?
-	*put++ = sec->tag;		// needed?
+	saveg_write16(sec->floorheight >> FRACBITS);
+	saveg_write16(sec->ceilingheight >> FRACBITS);
+	saveg_write16(sec->floorpic);
+	saveg_write16(sec->ceilingpic);
+	saveg_write16(sec->lightlevel);
+	saveg_write16(sec->special);		// needed?
+	saveg_write16(sec->tag);		// needed?
     }
 
     
@@ -173,9 +1374,9 @@
     // do lines
     for (i=0, li = lines ; i<numlines ; i++,li++)
     {
-	*put++ = li->flags;
-	*put++ = li->special;
-	*put++ = li->tag;
+	saveg_write16(li->flags);
+	saveg_write16(li->special);
+	saveg_write16(li->tag);
 	for (j=0 ; j<2 ; j++)
 	{
 	    if (li->sidenum[j] == -1)
@@ -183,15 +1384,13 @@
 	    
 	    si = &sides[li->sidenum[j]];
 
-	    *put++ = si->textureoffset >> FRACBITS;
-	    *put++ = si->rowoffset >> FRACBITS;
-	    *put++ = si->toptexture;
-	    *put++ = si->bottomtexture;
-	    *put++ = si->midtexture;	
+	    saveg_write16(si->textureoffset >> FRACBITS);
+	    saveg_write16(si->rowoffset >> FRACBITS);
+	    saveg_write16(si->toptexture);
+	    saveg_write16(si->bottomtexture);
+	    saveg_write16(si->midtexture);	
 	}
     }
-	
-    save_p = (byte *)put;
 }
 
 
@@ -206,20 +1405,17 @@
     sector_t*		sec;
     line_t*		li;
     side_t*		si;
-    short*		get;
-	
-    get = (short *)save_p;
     
     // do sectors
     for (i=0, sec = sectors ; i<numsectors ; i++,sec++)
     {
-	sec->floorheight = *get++ << FRACBITS;
-	sec->ceilingheight = *get++ << FRACBITS;
-	sec->floorpic = *get++;
-	sec->ceilingpic = *get++;
-	sec->lightlevel = *get++;
-	sec->special = *get++;		// needed?
-	sec->tag = *get++;		// needed?
+	sec->floorheight = saveg_read16() << FRACBITS;
+	sec->ceilingheight = saveg_read16() << FRACBITS;
+	sec->floorpic = saveg_read16();
+	sec->ceilingpic = saveg_read16();
+	sec->lightlevel = saveg_read16();
+	sec->special = saveg_read16();		// needed?
+	sec->tag = saveg_read16();		// needed?
 	sec->specialdata = 0;
 	sec->soundtarget = 0;
     }
@@ -227,22 +1423,21 @@
     // do lines
     for (i=0, li = lines ; i<numlines ; i++,li++)
     {
-	li->flags = *get++;
-	li->special = *get++;
-	li->tag = *get++;
+	li->flags = saveg_read16();
+	li->special = saveg_read16();
+	li->tag = saveg_read16();
 	for (j=0 ; j<2 ; j++)
 	{
 	    if (li->sidenum[j] == -1)
 		continue;
 	    si = &sides[li->sidenum[j]];
-	    si->textureoffset = *get++ << FRACBITS;
-	    si->rowoffset = *get++ << FRACBITS;
-	    si->toptexture = *get++;
-	    si->bottomtexture = *get++;
-	    si->midtexture = *get++;
+	    si->textureoffset = saveg_read16() << FRACBITS;
+	    si->rowoffset = saveg_read16() << FRACBITS;
+	    si->toptexture = saveg_read16();
+	    si->bottomtexture = saveg_read16();
+	    si->midtexture = saveg_read16();
 	}
     }
-    save_p = (byte *)get;	
 }
 
 
@@ -280,7 +1475,6 @@
 void P_ArchiveThinkers (void)
 {
     thinker_t*		th;
-    mobj_t*		mobj;
 
     // save off the current thinkers
     for (th = thinkercap.next ; th != &thinkercap ; th=th->next)
@@ -287,24 +1481,10 @@
     {
 	if (th->function.acp1 == (actionf_p1)P_MobjThinker)
 	{
-	    *save_p++ = tc_mobj;
+            saveg_write8(tc_mobj);
 	    PADSAVEP();
-	    mobj = (mobj_t *)save_p;
-	    memcpy (mobj, th, sizeof(*mobj));
-	    save_p += sizeof(*mobj);
+            saveg_write_mobj_t((mobj_t *) th);
 
-            // Hack fix for structure packing bug, see above.
-
-            if (sizeof(mobj_t) == 156)
-            {
-                memmove(save_p - 6, save_p - 4, 4);
-                save_p -= 2;
-            }
-
-	    mobj->state = (state_t *)(mobj->state - states);
-	    
-	    if (mobj->player)
-		mobj->player = (player_t *)((mobj->player-players) + 1);
 	    continue;
 	}
 		
@@ -312,7 +1492,7 @@
     }
 
     // add a terminating marker
-    *save_p++ = tc_end;	
+    saveg_write8(tc_end);
 }
 
 
@@ -345,7 +1525,7 @@
     // read in saved thinkers
     while (1)
     {
-	tclass = *save_p++;
+	tclass = saveg_read8();
 	switch (tclass)
 	{
 	  case tc_end:
@@ -354,24 +1534,9 @@
 	  case tc_mobj:
 	    PADSAVEP();
 	    mobj = Z_Malloc (sizeof(*mobj), PU_LEVEL, NULL);
-	    memcpy (mobj, save_p, sizeof(*mobj));
-	    save_p += sizeof(*mobj);
+            saveg_read_mobj_t(mobj);
 
-            // Hack fix for structure packing bug, see above.
-
-            if (sizeof(mobj_t) == 156)
-            {
-                save_p -= 2;
-                memmove(&mobj->tracer, save_p - 4, 4);
-            }
-
-	    mobj->state = &states[(int)mobj->state];
 	    mobj->target = NULL;
-	    if (mobj->player)
-	    {
-		mobj->player = &players[(int)mobj->player-1];
-		mobj->player->mo = mobj;
-	    }
 	    P_SetThingPosition (mobj);
 	    mobj->info = &mobjinfo[mobj->type];
 	    mobj->floorz = mobj->subsector->sector->floorheight;
@@ -379,7 +1544,7 @@
 	    mobj->thinker.function.acp1 = (actionf_p1)P_MobjThinker;
 	    P_AddThinker (&mobj->thinker);
 	    break;
-			
+
 	  default:
 	    I_Error ("Unknown tclass %i in savegame",tclass);
 	}
@@ -421,13 +1586,6 @@
 void P_ArchiveSpecials (void)
 {
     thinker_t*		th;
-    ceiling_t*		ceiling;
-    vldoor_t*		door;
-    floormove_t*	floor;
-    plat_t*		plat;
-    lightflash_t*	flash;
-    strobe_t*		strobe;
-    glow_t*		glow;
     int			i;
 	
     // save off the current thinkers
@@ -441,12 +1599,9 @@
 	    
 	    if (i<MAXCEILINGS)
 	    {
-		*save_p++ = tc_ceiling;
+                saveg_write8(tc_ceiling);
 		PADSAVEP();
-		ceiling = (ceiling_t *)save_p;
-		memcpy (ceiling, th, sizeof(*ceiling));
-		save_p += sizeof(*ceiling);
-		ceiling->sector = (sector_t *)(ceiling->sector - sectors);
+                saveg_write_ceiling_t((ceiling_t *) th);
 	    }
 	    continue;
 	}
@@ -453,84 +1608,63 @@
 			
 	if (th->function.acp1 == (actionf_p1)T_MoveCeiling)
 	{
-	    *save_p++ = tc_ceiling;
+            saveg_write8(tc_ceiling);
 	    PADSAVEP();
-	    ceiling = (ceiling_t *)save_p;
-	    memcpy (ceiling, th, sizeof(*ceiling));
-	    save_p += sizeof(*ceiling);
-	    ceiling->sector = (sector_t *)(ceiling->sector - sectors);
+            saveg_write_ceiling_t((ceiling_t *) th);
 	    continue;
 	}
 			
 	if (th->function.acp1 == (actionf_p1)T_VerticalDoor)
 	{
-	    *save_p++ = tc_door;
+            saveg_write8(tc_door);
 	    PADSAVEP();
-	    door = (vldoor_t *)save_p;
-	    memcpy (door, th, sizeof(*door));
-	    save_p += sizeof(*door);
-	    door->sector = (sector_t *)(door->sector - sectors);
+            saveg_write_vldoor_t((vldoor_t *) th);
 	    continue;
 	}
 			
 	if (th->function.acp1 == (actionf_p1)T_MoveFloor)
 	{
-	    *save_p++ = tc_floor;
+            saveg_write8(tc_floor);
 	    PADSAVEP();
-	    floor = (floormove_t *)save_p;
-	    memcpy (floor, th, sizeof(*floor));
-	    save_p += sizeof(*floor);
-	    floor->sector = (sector_t *)(floor->sector - sectors);
+            saveg_write_floormove_t((floormove_t *) th);
 	    continue;
 	}
 			
 	if (th->function.acp1 == (actionf_p1)T_PlatRaise)
 	{
-	    *save_p++ = tc_plat;
+            saveg_write8(tc_plat);
 	    PADSAVEP();
-	    plat = (plat_t *)save_p;
-	    memcpy (plat, th, sizeof(*plat));
-	    save_p += sizeof(*plat);
-	    plat->sector = (sector_t *)(plat->sector - sectors);
+            saveg_write_plat_t((plat_t *) th);
 	    continue;
 	}
 			
 	if (th->function.acp1 == (actionf_p1)T_LightFlash)
 	{
-	    *save_p++ = tc_flash;
+            saveg_write8(tc_flash);
 	    PADSAVEP();
-	    flash = (lightflash_t *)save_p;
-	    memcpy (flash, th, sizeof(*flash));
-	    save_p += sizeof(*flash);
-	    flash->sector = (sector_t *)(flash->sector - sectors);
+            saveg_write_lightflash_t((lightflash_t *) th);
 	    continue;
 	}
 			
 	if (th->function.acp1 == (actionf_p1)T_StrobeFlash)
 	{
-	    *save_p++ = tc_strobe;
+            saveg_write8(tc_strobe);
 	    PADSAVEP();
-	    strobe = (strobe_t *)save_p;
-	    memcpy (strobe, th, sizeof(*strobe));
-	    save_p += sizeof(*strobe);
-	    strobe->sector = (sector_t *)(strobe->sector - sectors);
+            saveg_write_strobe_t((strobe_t *) th);
 	    continue;
 	}
 			
 	if (th->function.acp1 == (actionf_p1)T_Glow)
 	{
-	    *save_p++ = tc_glow;
+            saveg_write8(tc_glow);
 	    PADSAVEP();
-	    glow = (glow_t *)save_p;
-	    memcpy (glow, th, sizeof(*glow));
-	    save_p += sizeof(*glow);
-	    glow->sector = (sector_t *)(glow->sector - sectors);
+            saveg_write_glow_t((glow_t *) th);
 	    continue;
 	}
     }
 	
     // add a terminating marker
-    *save_p++ = tc_endspecials;	
+    saveg_write8(tc_endspecials);
 
 }
 
@@ -553,7 +1687,8 @@
     // read in saved thinkers
     while (1)
     {
-	tclass = *save_p++;
+	tclass = saveg_read8();
+
 	switch (tclass)
 	{
 	  case tc_endspecials:
@@ -562,9 +1697,7 @@
 	  case tc_ceiling:
 	    PADSAVEP();
 	    ceiling = Z_Malloc (sizeof(*ceiling), PU_LEVEL, NULL);
-	    memcpy (ceiling, save_p, sizeof(*ceiling));
-	    save_p += sizeof(*ceiling);
-	    ceiling->sector = &sectors[(int)ceiling->sector];
+            saveg_read_ceiling_t(ceiling);
 	    ceiling->sector->specialdata = ceiling;
 
 	    if (ceiling->thinker.function.acp1)
@@ -577,9 +1710,7 @@
 	  case tc_door:
 	    PADSAVEP();
 	    door = Z_Malloc (sizeof(*door), PU_LEVEL, NULL);
-	    memcpy (door, save_p, sizeof(*door));
-	    save_p += sizeof(*door);
-	    door->sector = &sectors[(int)door->sector];
+            saveg_read_vldoor_t(door);
 	    door->sector->specialdata = door;
 	    door->thinker.function.acp1 = (actionf_p1)T_VerticalDoor;
 	    P_AddThinker (&door->thinker);
@@ -588,9 +1719,7 @@
 	  case tc_floor:
 	    PADSAVEP();
 	    floor = Z_Malloc (sizeof(*floor), PU_LEVEL, NULL);
-	    memcpy (floor, save_p, sizeof(*floor));
-	    save_p += sizeof(*floor);
-	    floor->sector = &sectors[(int)floor->sector];
+            saveg_read_floormove_t(floor);
 	    floor->sector->specialdata = floor;
 	    floor->thinker.function.acp1 = (actionf_p1)T_MoveFloor;
 	    P_AddThinker (&floor->thinker);
@@ -599,9 +1728,7 @@
 	  case tc_plat:
 	    PADSAVEP();
 	    plat = Z_Malloc (sizeof(*plat), PU_LEVEL, NULL);
-	    memcpy (plat, save_p, sizeof(*plat));
-	    save_p += sizeof(*plat);
-	    plat->sector = &sectors[(int)plat->sector];
+            saveg_read_plat_t(plat);
 	    plat->sector->specialdata = plat;
 
 	    if (plat->thinker.function.acp1)
@@ -614,9 +1741,7 @@
 	  case tc_flash:
 	    PADSAVEP();
 	    flash = Z_Malloc (sizeof(*flash), PU_LEVEL, NULL);
-	    memcpy (flash, save_p, sizeof(*flash));
-	    save_p += sizeof(*flash);
-	    flash->sector = &sectors[(int)flash->sector];
+            saveg_read_lightflash_t(flash);
 	    flash->thinker.function.acp1 = (actionf_p1)T_LightFlash;
 	    P_AddThinker (&flash->thinker);
 	    break;
@@ -624,9 +1749,7 @@
 	  case tc_strobe:
 	    PADSAVEP();
 	    strobe = Z_Malloc (sizeof(*strobe), PU_LEVEL, NULL);
-	    memcpy (strobe, save_p, sizeof(*strobe));
-	    save_p += sizeof(*strobe);
-	    strobe->sector = &sectors[(int)strobe->sector];
+            saveg_read_strobe_t(strobe);
 	    strobe->thinker.function.acp1 = (actionf_p1)T_StrobeFlash;
 	    P_AddThinker (&strobe->thinker);
 	    break;
@@ -634,9 +1757,7 @@
 	  case tc_glow:
 	    PADSAVEP();
 	    glow = Z_Malloc (sizeof(*glow), PU_LEVEL, NULL);
-	    memcpy (glow, save_p, sizeof(*glow));
-	    save_p += sizeof(*glow);
-	    glow->sector = &sectors[(int)glow->sector];
+            saveg_read_glow_t(glow);
 	    glow->thinker.function.acp1 = (actionf_p1)T_Glow;
 	    P_AddThinker (&glow->thinker);
 	    break;