diff --git a/source/exhumed/src/aistuff.h b/source/exhumed/src/aistuff.h
index a6d5a1b99..dce33840f 100644
--- a/source/exhumed/src/aistuff.h
+++ b/source/exhumed/src/aistuff.h
@@ -31,10 +31,14 @@ struct Anim
     short field_2;
     short field_4;
     short nSprite;
+
+    short AnimRunRec;
+    uint8_t AnimFlags;
+
 };
 
-extern Anim AnimList[];
-extern uint8_t AnimFlags[];
+enum { kMaxAnims = 400 };
+extern FreeListArray<Anim, kMaxAnims> AnimList;
 
 void InitAnims();
 void DestroyAnim(int nAnim);
diff --git a/source/exhumed/src/anims.cpp b/source/exhumed/src/anims.cpp
index 8ee5a664e..aedeb1026 100644
--- a/source/exhumed/src/anims.cpp
+++ b/source/exhumed/src/anims.cpp
@@ -25,37 +25,42 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
 BEGIN_PS_NS
 
-enum { kMaxAnims = 400 };
-
 short nMagicSeq = -1;
 short nPreMagicSeq  = -1;
 short nSavePointSeq = -1;
-short nAnimsFree = 0;
+FreeListArray<Anim, kMaxAnims> AnimList;
 
-short AnimRunRec[kMaxAnims];
-short AnimsFree[kMaxAnims];
-Anim AnimList[kMaxAnims];
-uint8_t AnimFlags[kMaxAnims];
 
-static SavegameHelper sghanims("anims",
-    SV(nMagicSeq),
-    SV(nPreMagicSeq),
-    SV(nSavePointSeq),
-    SV(nAnimsFree),
-    SA(AnimRunRec),
-    SA(AnimsFree),
-    SA(AnimList),
-    SA(AnimFlags),
-    nullptr);
+FSerializer& Serialize(FSerializer& arc, const char* keyname, Anim& w, Anim* def)
+{
+    if (arc.BeginObject(keyname))
+    {
+        arc("seq", w.nSeq)
+            ("val1", w.field_2)
+            ("val2", w.field_4)
+            ("sprite", w.nSprite)
+            ("runrec", w.AnimRunRec)
+            ("flags", w.AnimFlags)
+            .EndObject();
+    }
+    return arc;
+}
+
+void SerializeAnim(FSerializer& arc)
+{
+    if (arc.BeginObject("anims"))
+    {
+        arc("magic", nMagicSeq)
+            ("premagic", nPreMagicSeq)
+            ("savepoint", nSavePointSeq)
+            ("list", AnimList)
+            .EndObject();
+    }
+}
 
 void InitAnims()
 {
-    for (int i = 0; i < kMaxAnims; i++) {
-        AnimsFree[i] = i;
-    }
-
-    nAnimsFree = kMaxAnims;
-
+    AnimList.Clear();
     nMagicSeq     = SeqOffsets[kSeqItems] + 21;
     nPreMagicSeq  = SeqOffsets[kSeqMagic2];
     nSavePointSeq = SeqOffsets[kSeqItems] + 12;
@@ -68,25 +73,21 @@ void DestroyAnim(int nAnim)
     if (nSprite >= 0)
     {
         StopSpriteSound(nSprite);
-        runlist_SubRunRec(AnimRunRec[nAnim]);
+        runlist_SubRunRec(AnimList[nAnim].AnimRunRec);
         runlist_DoSubRunRec(sprite[nSprite].extra);
         runlist_FreeRun(sprite[nSprite].lotag - 1);
     }
 
-    AnimsFree[nAnimsFree] = nAnim;
-    nAnimsFree++;
+    AnimList.Release(nAnim);
 }
 
 int BuildAnim(int nSprite, int val, int val2, int x, int y, int z, int nSector, int nRepeat, int nFlag)
 {
-	if (!nAnimsFree) {
+    int nAnim = AnimList.Get();
+	if (nAnim < 0) {
 		return -1;
 	}
 
-    nAnimsFree--;
-
-    short nAnim = AnimsFree[nAnimsFree];
-
     if (nSprite == -1) {
         nSprite = insertsprite(nSector, 500);
     }
@@ -127,9 +128,9 @@ int BuildAnim(int nSprite, int val, int val2, int x, int y, int z, int nSector,
     sprite[nSprite].owner = -1;
     sprite[nSprite].extra = runlist_AddRunRec(sprite[nSprite].lotag - 1, nAnim | 0x100000);
 
-    AnimRunRec[nAnim] = runlist_AddRunRec(NewRun, nAnim | 0x100000);
+    AnimList[nAnim].AnimRunRec = runlist_AddRunRec(NewRun, nAnim | 0x100000);
     AnimList[nAnim].nSprite = nSprite;
-    AnimFlags[nAnim] = nFlag;
+    AnimList[nAnim].AnimFlags = nFlag;
     AnimList[nAnim].field_2 = 0;
     AnimList[nAnim].nSeq = SeqOffsets[val] + val2;
     AnimList[nAnim].field_4 = 256;
@@ -236,7 +237,7 @@ void FuncAnim(int a, int, int nRun)
             AnimList[nAnim].field_2++;
             if (AnimList[nAnim].field_2 >= SeqSize[nSeq])
             {
-                if (AnimFlags[nAnim] & 0x10)
+                if (AnimList[nAnim].AnimFlags & 0x10)
                 {
                     AnimList[nAnim].field_2 = 0;
                 }
@@ -245,14 +246,14 @@ void FuncAnim(int a, int, int nRun)
                     AnimList[nAnim].field_2 = 0;
                     AnimList[nAnim].nSeq = nMagicSeq;
                     short nAnimSprite = AnimList[nAnim].nSprite;
-                    AnimFlags[nAnim] |= 0x10;
+                    AnimList[nAnim].AnimFlags |= 0x10;
                     sprite[nAnimSprite].cstat |= 2;
                 }
                 else if (nSeq == nSavePointSeq)
                 {
                     AnimList[nAnim].field_2 = 0;
                     AnimList[nAnim].nSeq++;
-                    AnimFlags[nAnim] |= 0x10;
+                    AnimList[nAnim].AnimFlags |= 0x10;
                 }
                 else
                 {
diff --git a/source/exhumed/src/player.cpp b/source/exhumed/src/player.cpp
index 034471178..77779d1c2 100644
--- a/source/exhumed/src/player.cpp
+++ b/source/exhumed/src/player.cpp
@@ -90,12 +90,10 @@ short nPlayerScore[kMaxPlayers];
 short nPlayerColor[kMaxPlayers];
 int nPlayerDY[kMaxPlayers];
 int nPlayerDX[kMaxPlayers];
-char playerNames[kMaxPlayers][11];
 short nPistolClip[kMaxPlayers];
 int nXDamage[kMaxPlayers];
 int nYDamage[kMaxPlayers];
 short nDoppleSprite[kMaxPlayers];
-short namelen[kMaxPlayers];
 short nPlayerOldWeapon[kMaxPlayers];
 short nPlayerClip[kMaxPlayers];
 short nPlayerPushSound[kMaxPlayers];
@@ -461,9 +459,6 @@ void RestartPlayer(short nPlayer)
 		RestoreGreenPal();
 	}
 
-	sprintf(playerNames[nPlayer], "JOE%d", nPlayer);
-	namelen[nPlayer] = strlen(playerNames[nPlayer]);
-
 	ototalvel[nPlayer] = totalvel[nPlayer] = 0;
 
 	memset(&sPlayerInput[nPlayer], 0, sizeof(PlayerInput));
@@ -2418,7 +2413,7 @@ do_default_b:
                                 {
                                     short nAnim = sprite[nValB].owner;
                                     AnimList[nAnim].nSeq++;
-                                    AnimFlags[nAnim] &= 0xEF;
+                                    AnimList[nAnim].AnimFlags &= 0xEF;
                                     AnimList[nAnim].field_2 = 0;
 
                                     changespritestat(nValB, 899);
@@ -2809,50 +2804,98 @@ loc_1BD2E:
     }
 }
 
-static SavegameHelper sghplayer("player",
-    SV(lPlayerXVel),
-    SV(lPlayerYVel),
-    SV(obobangle),
-    SV(bobangle),
-    SV(nStandHeight),
-    SV(PlayerCount),
-    SV(nNetStartSprites),
-    SV(nCurStartSprite),
-    SV(nLocalPlayer),
-    SA(nBreathTimer),
-    SA(nPlayerSwear),
-    SA(nPlayerPushSect),
-    SA(nDeathType),
-    SA(nPlayerScore),
-    SA(nPlayerColor),
-    SA(nPlayerDY),
-    SA(nPlayerDX),
-    SA(playerNames),
-    SA(nPistolClip),
-    SA(nXDamage),
-    SA(nYDamage),
-    SA(nDoppleSprite),
-    SA(namelen),
-    SA(nPlayerOldWeapon),
-    SA(nPlayerClip),
-    SA(nPlayerPushSound),
-    SA(nTauntTimer),
-    SA(nPlayerTorch),
-    SA(nPlayerWeapons),
-    SA(nPlayerLives),
-    SA(nPlayerItem),
-    SA(PlayerList),
-    SA(nPlayerInvisible),
-    SA(nPlayerDouble),
-    SA(nPlayerViewSect),
-    SA(nPlayerFloorSprite),
-    SA(sPlayerSave),
-    SA(totalvel),
-    SA(eyelevel),
-    SA(nNetStartSprite),
-    SA(nPlayerGrenade),
-    SA(nGrenadePlayer),
-    SA(word_D282A),
-    nullptr);
+
+FSerializer& Serialize(FSerializer& arc, const char* keyname, Player& w, Player* def)
+{
+    if (arc.BeginObject(keyname))
+    {
+        arc("health", w.nHealth)
+            ("at2", w.field_2)
+            ("action", w.nAction)
+            ("sprite", w.nSprite)
+            ("mummy", w.bIsMummified)
+            ("invincible", w.invincibility)
+            ("air", w.nAir)
+            ("seq", w.nSeq)
+            ("maskamount", w.nMaskAmount)
+            ("keys", w.keys)
+            ("magic", w.nMagic)
+            .Array("items", w.items, countof(w.items))
+            .Array("ammo", w.nAmmo, countof(w.nAmmo))
+            ("weapon", w.nCurrentWeapon)
+            ("isfiring", w.bIsFiring)
+            ("field3f", w.field_3FOUR)
+            ("field38", w.field_38)
+            ("field3a", w.field_3A)
+            ("field3c", w.field_3C)
+            ("seq", w.nSeq)
+            ("horizon", w.horizon)
+            ("angle", w.angle)
+            .EndObject();
+    }
+    return arc;
+}
+
+FSerializer& Serialize(FSerializer& arc, const char* keyname, PlayerSave& w, PlayerSave* def)
+{
+    if (arc.BeginObject(keyname))
+    {
+        arc("x", w.x)
+            ("y", w.y)
+            ("z", w.z)
+            ("sector", w.nSector)
+            ("angle", w.nAngle)
+            .EndObject();
+    }
+    return arc;
+}
+
+void SerializePlayer(FSerializer& arc)
+{
+    if (arc.BeginObject("player"))
+    {
+        arc("lxvel", lPlayerXVel)
+            ("lyvel", lPlayerYVel)
+            ("bobangle", bobangle)
+            ("standheight", nStandHeight)
+            ("playercount", PlayerCount)
+            ("netstartsprites", nNetStartSprites)
+            ("localplayer", nLocalPlayer)
+            .Array("grenadeplayer", nGrenadePlayer, countof(nGrenadePlayer))
+            .Array("curstartsprite", nNetStartSprite, PlayerCount)
+            .Array("breathtimer", nBreathTimer, PlayerCount)
+            .Array("playerswear", nPlayerSwear, PlayerCount)
+            .Array("pushsect", nPlayerPushSect, PlayerCount)
+            .Array("deathtype", nDeathType, PlayerCount)
+            .Array("score", nPlayerScore, PlayerCount)
+            .Array("color", nPlayerColor, PlayerCount)
+            .Array("dx", nPlayerDX, PlayerCount)
+            .Array("dy", nPlayerDY, PlayerCount)
+            .Array("pistolclip", nPistolClip, PlayerCount)
+            .Array("xdamage", nXDamage, PlayerCount)
+            .Array("ydamage", nYDamage, PlayerCount)
+            .Array("dopplesprite", nDoppleSprite, PlayerCount)
+            .Array("oldweapon", nPlayerOldWeapon, PlayerCount)
+            .Array("clip", nPlayerClip, PlayerCount)
+            .Array("pushsound", nPlayerPushSound, PlayerCount)
+            .Array("taunttimer", nTauntTimer, PlayerCount)
+            .Array("torch", nPlayerTorch, PlayerCount)
+            .Array("weapons", nPlayerWeapons, PlayerCount)
+            .Array("lives", nPlayerLives, PlayerCount)
+            .Array("item", nPlayerItem, PlayerCount)
+            .Array("list", PlayerList, PlayerCount)
+            .Array("invisible", nPlayerInvisible, PlayerCount)
+            .Array("double", nPlayerDouble, PlayerCount)
+            .Array("viewsect", nPlayerViewSect, PlayerCount)
+            .Array("floorspr", nPlayerFloorSprite, PlayerCount)
+            .Array("save", sPlayerSave, PlayerCount)
+            .Array("totalvel", totalvel, PlayerCount)
+            .Array("eyelevel", eyelevel, PlayerCount)
+            .Array("netstartsprite", nNetStartSprite, PlayerCount)
+            .Array("grenade", nPlayerGrenade, PlayerCount)
+            .Array("d282a", word_D282A, PlayerCount)
+            .EndObject();
+    }
+}
 
 END_PS_NS
diff --git a/source/exhumed/src/save.cpp b/source/exhumed/src/save.cpp
index 4037dfcfb..cab72540c 100644
--- a/source/exhumed/src/save.cpp
+++ b/source/exhumed/src/save.cpp
@@ -29,6 +29,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
 BEGIN_PS_NS
 
+void SerializeAnim(FSerializer& arc);
+void SerializePlayer(FSerializer& arc);
 void SerializeRa(FSerializer& arc);
 void SerializeRand(FSerializer& arc);
 void SerializeRunList(FSerializer& arc);
@@ -67,6 +69,8 @@ void GameInterface::SerializeGameState(FSerializer& arc)
 {
     if (arc.BeginObject("exhumed"))
     {
+    SerializeAnim(arc);
+    SerializePlayer(arc);
     SerializeRa(arc);
     SerializeRand(arc);
     SerializeRunList(arc);