shithub: choc

Download patch

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));
+}
+
+