ref: 21bc4c4ab90df0455eaeba6a4c959005493f0a76
parent: 7f27444e2e93702fbd23dedc0fb7e7b4f3e13e50
author: Simon Howard <[email protected]>
date: Sun Aug 25 01:44:45 EDT 2013
First step towards portable Hexen savegames. Perform endianness conversions for ACS vars and add functions to read/write player_t structures. Subversion-branch: /branches/v2-branch Subversion-revision: 2625
--- a/src/hexen/sv_save.c
+++ b/src/hexen/sv_save.c
@@ -37,8 +37,8 @@
#define MOBJ_NULL -1
#define MOBJ_XX_PLAYER -2
#define GET_BYTE (*SavePtr.b++)
-#define GET_WORD (*SavePtr.w++)
-#define GET_LONG (*SavePtr.l++)
+#define GET_WORD SHORT(*SavePtr.w++)
+#define GET_LONG LONG(*SavePtr.l++)
#define MAX_MAPS 99
#define BASE_SLOT 6
#define REBORN_SLOT 7
@@ -142,6 +142,7 @@
static void StreamOutByte(byte val);
static void StreamOutWord(unsigned short val);
static void StreamOutLong(unsigned int val);
+static void StreamOutPtr(void *ptr);
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
@@ -259,6 +260,527 @@
// CODE --------------------------------------------------------------------
+// Autogenerated functions for reading/writing structs:
+
+//
+// acsstore_t
+//
+
+static void StreamIn_acsstore_t(acsstore_t *str)
+{
+ int i;
+
+ // int map;
+ str->map = GET_LONG;
+
+ // int script;
+ str->script = GET_LONG;
+
+ // byte args[4];
+ for (i=0; i<4; ++i)
+ {
+ str->args[i] = GET_BYTE;
+ }
+}
+
+static void StreamOut_acsstore_t(acsstore_t *str)
+{
+ int i;
+
+ // int map;
+ StreamOutLong(str->map);
+
+ // int script;
+ StreamOutLong(str->script);
+
+ // byte args[4];
+ for (i=0; i<4; ++i)
+ {
+ StreamOutByte(str->args[i]);
+ }
+}
+
+
+//
+// ticcmd_t
+// (this is based on the Vanilla definition of the struct)
+//
+
+static void StreamIn_ticcmd_t(ticcmd_t *str)
+{
+ // char forwardmove;
+ str->forwardmove = GET_BYTE;
+
+ // char sidemove;
+ str->sidemove = GET_BYTE;
+
+ // short angleturn;
+ str->angleturn = GET_WORD;
+
+ // short consistancy;
+ str->consistancy = GET_WORD;
+
+ // byte chatchar;
+ str->chatchar = GET_BYTE;
+
+ // byte buttons;
+ str->buttons = GET_BYTE;
+
+ // byte lookfly;
+ str->lookfly = GET_BYTE;
+
+ // byte arti;
+ str->arti = GET_BYTE;
+}
+
+static void StreamOut_ticcmd_t(ticcmd_t *str)
+{
+ // char forwardmove;
+ StreamOutByte(str->forwardmove);
+
+ // char sidemove;
+ StreamOutByte(str->sidemove);
+
+ // short angleturn;
+ StreamOutWord(str->angleturn);
+
+ // short consistancy;
+ StreamOutWord(str->consistancy);
+
+ // byte chatchar;
+ StreamOutByte(str->chatchar);
+
+ // byte buttons;
+ StreamOutByte(str->buttons);
+
+ // byte lookfly;
+ StreamOutByte(str->lookfly);
+
+ // byte arti;
+ StreamOutByte(str->arti);
+}
+
+
+
+//
+// inventory_t
+//
+
+static void StreamIn_inventory_t(inventory_t *str)
+{
+ // int type;
+ str->type = GET_LONG;
+
+ // int count;
+ str->count = GET_LONG;
+}
+
+static void StreamOut_inventory_t(inventory_t *str)
+{
+ // int type;
+ StreamOutLong(str->type);
+
+ // int count;
+ StreamOutLong(str->count);
+}
+
+
+//
+// pspdef_t
+//
+
+static void StreamIn_pspdef_t(pspdef_t *str)
+{
+ int state_num;
+
+ // state_t *state;
+
+ // This is a pointer; it is stored as an index into the states table.
+
+ state_num = GET_LONG;
+
+ if (state_num != 0)
+ {
+ str->state = states + state_num;
+ }
+ else
+ {
+ str->state = NULL;
+ }
+
+ // int tics;
+ str->tics = GET_LONG;
+
+ // fixed_t sx, sy;
+ str->sx = GET_LONG;
+ str->sy = GET_LONG;
+}
+
+static void StreamOut_pspdef_t(pspdef_t *str)
+{
+ // state_t *state;
+ // This is a pointer; store the index in the states table,
+ // rather than the pointer itself.
+ if (str->state != NULL)
+ {
+ StreamOutLong(str->state - states);
+ }
+ else
+ {
+ StreamOutLong(0);
+ }
+
+ // int tics;
+ StreamOutLong(str->tics);
+
+ // fixed_t sx, sy;
+ StreamOutLong(str->sx);
+ StreamOutLong(str->sy);
+}
+
+
+//
+// player_t
+//
+
+static void StreamIn_player_t(player_t *str)
+{
+ int i;
+
+ // mobj_t *mo;
+ // Pointer value is reset on load.
+ GET_LONG;
+ str->mo = NULL;
+
+ // playerstate_t playerstate;
+ str->playerstate = GET_LONG;
+
+ // ticcmd_t cmd;
+ StreamIn_ticcmd_t(&str->cmd);
+
+ // pclass_t class;
+ str->class = GET_LONG;
+
+ // fixed_t viewz;
+ str->viewz = GET_LONG;
+
+ // fixed_t viewheight;
+ str->viewheight = GET_LONG;
+
+ // fixed_t deltaviewheight;
+ str->deltaviewheight = GET_LONG;
+
+ // fixed_t bob;
+ str->bob = GET_LONG;
+
+ // int flyheight;
+ str->flyheight = GET_LONG;
+
+ // int lookdir;
+ str->lookdir = GET_LONG;
+
+ // boolean centering;
+ str->centering = GET_LONG;
+
+ // int health;
+ str->health = GET_LONG;
+
+ // int armorpoints[NUMARMOR];
+ for (i=0; i<NUMARMOR; ++i)
+ {
+ str->armorpoints[i] = GET_LONG;
+ }
+
+ // inventory_t inventory[NUMINVENTORYSLOTS];
+ for (i=0; i<NUMINVENTORYSLOTS; ++i)
+ {
+ StreamIn_inventory_t(&str->inventory[i]);
+ }
+
+ // artitype_t readyArtifact;
+ str->readyArtifact = GET_LONG;
+
+ // int artifactCount;
+ str->artifactCount = GET_LONG;
+
+ // int inventorySlotNum;
+ str->inventorySlotNum = GET_LONG;
+
+ // int powers[NUMPOWERS];
+ for (i=0; i<NUMPOWERS; ++i)
+ {
+ str->powers[i] = GET_LONG;
+ }
+
+ // int keys;
+ str->keys = GET_LONG;
+
+ // int pieces;
+ str->pieces = GET_LONG;
+
+ // signed int frags[MAXPLAYERS];
+ for (i=0; i<MAXPLAYERS; ++i)
+ {
+ str->frags[i] = GET_LONG;
+ }
+
+ // weapontype_t readyweapon;
+ str->readyweapon = GET_LONG;
+
+ // weapontype_t pendingweapon;
+ str->pendingweapon = GET_LONG;
+
+ // boolean weaponowned[NUMWEAPONS];
+ for (i=0; i<NUMWEAPONS; ++i)
+ {
+ str->weaponowned[i] = GET_LONG;
+ }
+
+ // int mana[NUMMANA];
+ for (i=0; i<NUMMANA; ++i)
+ {
+ str->mana[i] = GET_LONG;
+ }
+
+ // int attackdown, usedown;
+ str->attackdown = GET_LONG;
+ str->usedown = GET_LONG;
+
+ // int cheats;
+ str->cheats = GET_LONG;
+
+ // int refire;
+ str->refire = GET_LONG;
+
+ // int killcount, itemcount, secretcount;
+ str->killcount = GET_LONG;
+ str->itemcount = GET_LONG;
+ str->secretcount = GET_LONG;
+
+ // char message[80];
+ for (i=0; i<80; ++i)
+ {
+ str->message[i] = GET_BYTE;
+ }
+
+ // int messageTics;
+ str->messageTics = GET_LONG;
+
+ // short ultimateMessage;
+ str->ultimateMessage = GET_WORD;
+
+ // short yellowMessage;
+ str->yellowMessage = GET_WORD;
+
+ // int damagecount, bonuscount;
+ str->damagecount = GET_LONG;
+ str->bonuscount = GET_LONG;
+
+ // int poisoncount;
+ str->poisoncount = GET_LONG;
+
+ // mobj_t *poisoner;
+ // Pointer value is reset.
+ GET_LONG;
+ str->poisoner = NULL;
+
+ // mobj_t *attacker;
+ // Pointer value is reset.
+ GET_LONG;
+ str->attacker = NULL;
+
+ // int extralight;
+ str->extralight = GET_LONG;
+
+ // int fixedcolormap;
+ str->fixedcolormap = GET_LONG;
+
+ // int colormap;
+ str->colormap = GET_LONG;
+
+ // pspdef_t psprites[NUMPSPRITES];
+ for (i=0; i<NUMPSPRITES; ++i)
+ {
+ StreamIn_pspdef_t(&str->psprites[i]);
+ }
+
+ // int morphTics;
+ str->morphTics = GET_LONG;
+
+ // unsigned int jumpTics;
+ str->jumpTics = GET_LONG;
+
+ // unsigned int worldTimer;
+ str->worldTimer = GET_LONG;
+}
+
+static void StreamOut_player_t(player_t *str)
+{
+ int i;
+
+ // mobj_t *mo;
+ StreamOutPtr(str->mo);
+
+ // playerstate_t playerstate;
+ StreamOutLong(str->playerstate);
+
+ // ticcmd_t cmd;
+ StreamOut_ticcmd_t(&str->cmd);
+
+ // pclass_t class;
+ StreamOutLong(str->class);
+
+ // fixed_t viewz;
+ StreamOutLong(str->viewz);
+
+ // fixed_t viewheight;
+ StreamOutLong(str->viewheight);
+
+ // fixed_t deltaviewheight;
+ StreamOutLong(str->deltaviewheight);
+
+ // fixed_t bob;
+ StreamOutLong(str->bob);
+
+ // int flyheight;
+ StreamOutLong(str->flyheight);
+
+ // int lookdir;
+ StreamOutLong(str->lookdir);
+
+ // boolean centering;
+ StreamOutLong(str->centering);
+
+ // int health;
+ StreamOutLong(str->health);
+
+ // int armorpoints[NUMARMOR];
+ for (i=0; i<NUMARMOR; ++i)
+ {
+ StreamOutLong(str->armorpoints[i]);
+ }
+
+ // inventory_t inventory[NUMINVENTORYSLOTS];
+ for (i=0; i<NUMINVENTORYSLOTS; ++i)
+ {
+ StreamOut_inventory_t(&str->inventory[i]);
+ }
+
+ // artitype_t readyArtifact;
+ StreamOutLong(str->readyArtifact);
+
+ // int artifactCount;
+ StreamOutLong(str->artifactCount);
+
+ // int inventorySlotNum;
+ StreamOutLong(str->inventorySlotNum);
+
+ // int powers[NUMPOWERS];
+ for (i=0; i<NUMPOWERS; ++i)
+ {
+ StreamOutLong(str->powers[i]);
+ }
+
+ // int keys;
+ StreamOutLong(str->keys);
+
+ // int pieces;
+ StreamOutLong(str->pieces);
+
+ // signed int frags[MAXPLAYERS];
+ for (i=0; i<MAXPLAYERS; ++i)
+ {
+ StreamOutLong(str->frags[i]);
+ }
+
+ // weapontype_t readyweapon;
+ StreamOutLong(str->readyweapon);
+
+ // weapontype_t pendingweapon;
+ StreamOutLong(str->pendingweapon);
+
+ // boolean weaponowned[NUMWEAPONS];
+ for (i=0; i<NUMWEAPONS; ++i)
+ {
+ StreamOutLong(str->weaponowned[i]);
+ }
+
+ // int mana[NUMMANA];
+ for (i=0; i<NUMMANA; ++i)
+ {
+ StreamOutLong(str->mana[i]);
+ }
+
+ // int attackdown, usedown;
+ StreamOutLong(str->attackdown);
+ StreamOutLong(str->usedown);
+
+ // int cheats;
+ StreamOutLong(str->cheats);
+
+ // int refire;
+ StreamOutLong(str->refire);
+
+ // int killcount, itemcount, secretcount;
+ StreamOutLong(str->killcount);
+ StreamOutLong(str->itemcount);
+ StreamOutLong(str->secretcount);
+
+ // char message[80];
+ for (i=0; i<80; ++i)
+ {
+ StreamOutByte(str->message[i]);
+ }
+
+ // int messageTics;
+ StreamOutLong(str->messageTics);
+
+ // short ultimateMessage;
+ StreamOutWord(str->ultimateMessage);
+
+ // short yellowMessage;
+ StreamOutWord(str->yellowMessage);
+
+ // int damagecount, bonuscount;
+ StreamOutLong(str->damagecount);
+ StreamOutLong(str->bonuscount);
+
+ // int poisoncount;
+ StreamOutLong(str->poisoncount);
+
+ // mobj_t *poisoner;
+ StreamOutPtr(str->poisoner);
+
+ // mobj_t *attacker;
+ StreamOutPtr(str->attacker);
+
+ // int extralight;
+ StreamOutLong(str->extralight);
+
+ // int fixedcolormap;
+ StreamOutLong(str->fixedcolormap);
+
+ // int colormap;
+ StreamOutLong(str->colormap);
+
+ // pspdef_t psprites[NUMPSPRITES];
+ for (i=0; i<NUMPSPRITES; ++i)
+ {
+ StreamOut_pspdef_t(&str->psprites[i]);
+ }
+
+ // int morphTics;
+ StreamOutLong(str->morphTics);
+
+ // unsigned int jumpTics;
+ StreamOutLong(str->jumpTics);
+
+ // unsigned int worldTimer;
+ StreamOutLong(str->worldTimer);
+}
+
+
+
//==========================================================================
//
// SV_SaveGame
@@ -269,6 +791,7 @@
{
char fileName[100];
char versionText[HXS_VERSION_TEXT_LENGTH];
+ unsigned int i;
// Open the output file
sprintf(fileName, "%shex6.hxs", SavePath);
@@ -290,9 +813,16 @@
StreamOutByte(gameskill);
// Write global script info
- StreamOutBuffer(WorldVars, sizeof(WorldVars));
- StreamOutBuffer(ACSStore, sizeof(ACSStore));
+ for (i = 0; i < MAX_ACS_WORLD_VARS; ++i)
+ {
+ StreamOutLong(WorldVars[i]);
+ }
+ for (i = 0; i < MAX_ACS_STORE + 1; ++i)
+ {
+ StreamOut_acsstore_t(&ACSStore[i]);
+ }
+
ArchivePlayers();
// Place a termination marker
@@ -394,11 +924,17 @@
gameskill = GET_BYTE;
// Read global script info
- memcpy(WorldVars, SavePtr.b, sizeof(WorldVars));
- SavePtr.b += sizeof(WorldVars);
- memcpy(ACSStore, SavePtr.b, sizeof(ACSStore));
- SavePtr.b += sizeof(ACSStore);
+ for (i = 0; i < MAX_ACS_WORLD_VARS; ++i)
+ {
+ WorldVars[i] = GET_LONG;
+ }
+
+ for (i = 0; i < MAX_ACS_STORE + 1; ++i)
+ {
+ StreamIn_acsstore_t(&ACSStore[i]);
+ }
+
// Read the player structures
UnarchivePlayers();
@@ -727,8 +1263,6 @@
static void ArchivePlayers(void)
{
int i;
- int j;
- player_t tempPlayer;
StreamOutLong(ASEG_PLAYERS);
for (i = 0; i < MAXPLAYERS; i++)
@@ -742,16 +1276,7 @@
continue;
}
StreamOutByte(PlayerClass[i]);
- tempPlayer = players[i];
- for (j = 0; j < NUMPSPRITES; j++)
- {
- if (tempPlayer.psprites[j].state)
- {
- tempPlayer.psprites[j].state =
- (state_t *) (tempPlayer.psprites[j].state - states);
- }
- }
- StreamOutBuffer(&tempPlayer, sizeof(player_t));
+ StreamOut_player_t(&players[i]);
}
}
@@ -763,7 +1288,7 @@
static void UnarchivePlayers(void)
{
- int i, j;
+ int i;
AssertSegment(ASEG_PLAYERS);
for (i = 0; i < MAXPLAYERS; i++)
@@ -777,20 +1302,8 @@
continue;
}
PlayerClass[i] = GET_BYTE;
- memcpy(&players[i], SavePtr.b, sizeof(player_t));
- SavePtr.b += sizeof(player_t);
- players[i].mo = NULL; // Will be set when unarc thinker
+ StreamIn_player_t(&players[i]);
P_ClearMessage(&players[i]);
- players[i].attacker = NULL;
- players[i].poisoner = 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];
- }
- }
}
}
@@ -1361,7 +1874,11 @@
StreamOutWord(ACSInfo[i].state);
StreamOutWord(ACSInfo[i].waitValue);
}
- StreamOutBuffer(MapVars, sizeof(MapVars));
+
+ for (i = 0; i< MAX_ACS_MAP_VARS; ++i)
+ {
+ StreamOutLong(MapVars[i]);
+ }
}
//==========================================================================
@@ -1380,8 +1897,11 @@
ACSInfo[i].state = GET_WORD;
ACSInfo[i].waitValue = GET_WORD;
}
- memcpy(MapVars, SavePtr.b, sizeof(MapVars));
- SavePtr.b += sizeof(MapVars);
+
+ for (i = 0; i < MAX_ACS_MAP_VARS; ++i)
+ {
+ MapVars[i] = GET_LONG;
+ }
}
//==========================================================================
@@ -1753,6 +2273,7 @@
static void StreamOutWord(unsigned short val)
{
+ val = SHORT(val);
fwrite(&val, sizeof(unsigned short), 1, SavingFP);
}
@@ -1764,5 +2285,26 @@
static void StreamOutLong(unsigned int val)
{
+ val = LONG(val);
fwrite(&val, sizeof(int), 1, SavingFP);
}
+
+//==========================================================================
+//
+// StreamOutPtr
+//
+//==========================================================================
+
+static void StreamOutPtr(void *val)
+{
+ long ptr;
+
+ // Write a pointer value. In Vanilla Hexen pointers are 32-bit but
+ // nowadays they might be larger. Whatever value we write here isn't
+ // going to be much use when we reload the game.
+
+ ptr = (long) val;
+ StreamOutLong((unsigned int) (ptr & 0xffffffff));
+}
+
+