- Exhumed: serialize the status bar as JSON - added a helper class to handle static arrays with an attached free list more easily.

This commit is contained in:
Christoph Oelckers 2020-11-30 00:01:52 +01:00
parent 1b2895bee6
commit e8c56b1f9f
3 changed files with 164 additions and 78 deletions

View File

@ -19,6 +19,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#pragma once #pragma once
#include "compat.h" #include "compat.h"
#include "freelistarray.h"
BEGIN_PS_NS BEGIN_PS_NS

View File

@ -0,0 +1,106 @@
#pragma once
/*
** freelistarray.cpp
** fixed size array with free list management
**
**---------------------------------------------------------------------------
** Copyright 2020 Christoph Oelckers
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OFf
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include "serializer.h"
#include "tarray.h"
template<class Type, int size> class FreeListArray
{
int freecount;
short FreeList[size];
Type DataList[size];
public:
enum { count = size };
void Clear()
{
freecount = size;
for (int i = 0; i < size; i++)
{
FreeList[i] = size - i - 1;
}
}
int Get()
{
if (freecount == 0) return -1;
return FreeList[--freecount];
}
void Release(int i)
{
FreeList[freecount++] = i;
}
Type& operator[](size_t index)
{
return DataList[index];
}
void Serialize(FSerializer& arc, const char* key)
{
if (arc.BeginObject(key))
{
FixedBitArray<size> check;
if (arc.isWriting())
{
check.SetAll(true);
for (int i = 0; i < freecount; i++) check.Clear(FreeList[i]);
arc.SerializeMemory("used", check.Storage(), check.StorageSize());
arc.SparseArray("data", DataList, size, check);
}
else
{
arc.SerializeMemory("used", check.Storage(), check.StorageSize());
arc.SparseArray("data", DataList, size, check);
freecount = 0;
for (int i = 0; i < size; i++)
{
if (!check[i]) FreeList[freecount++] = i;
}
}
arc.EndObject();
}
}
};
template<class Type, int size>
FSerializer& Serialize(FSerializer& arc, const char* key, FreeListArray<Type, size> &w, FreeListArray<Type, size> * def)
{
w.Serialize(arc, key);
return arc;
}

View File

@ -42,9 +42,6 @@ BEGIN_PS_NS
// All this must be moved into the status bar once it is made persistent! // All this must be moved into the status bar once it is made persistent!
const int kMaxStatusAnims = 50; const int kMaxStatusAnims = 50;
short word_9AD54[kMaxPlayers] = { 0, 0, 0, 0, 0, 0, 0, 0 };
int dword_9AD64[kMaxPlayers] = { 0, 0, 0, 0, 0, 0, 0, 0 };
short nStatusSeqOffset; short nStatusSeqOffset;
short nHealthFrames; short nHealthFrames;
short nMagicFrames; short nMagicFrames;
@ -55,11 +52,7 @@ short nHealthFrame;
short nMagicFrame; short nMagicFrame;
short nMaskY; short nMaskY;
static short nStatusFree = 0;
short statusmask[MAXXDIM];
char message_text[80];
int magicperline; int magicperline;
int airperline; int airperline;
int healthperline; int healthperline;
@ -99,12 +92,10 @@ struct statusAnim
// int16_t nPage; // int16_t nPage;
int8_t nPrevAnim; int8_t nPrevAnim;
int8_t nNextAnim; int8_t nNextAnim;
uint8_t StatusAnimFlags;
}; };
FreeListArray<statusAnim, kMaxStatusAnims> StatusAnim;
statusAnim StatusAnim[kMaxStatusAnims];
uint8_t StatusAnimsFree[kMaxStatusAnims];
uint8_t StatusAnimFlags[kMaxStatusAnims];
short nItemSeqOffset[] = {91, 72, 76, 79, 68, 87, 83}; short nItemSeqOffset[] = {91, 72, 76, 79, 68, 87, 83};
@ -113,6 +104,20 @@ void SetItemSeq();
void SetItemSeq2(int nSeqOffset); void SetItemSeq2(int nSeqOffset);
void DestroyStatusAnim(short nAnim); void DestroyStatusAnim(short nAnim);
FSerializer& Serialize(FSerializer& arc, const char* keyname, statusAnim& w, statusAnim* def)
{
if (arc.BeginObject(keyname))
{
arc("s1", w.s1)
("s2", w.s2)
("prev", w.nPrevAnim)
("next", w.nNextAnim)
("flags", w.StatusAnimFlags)
.EndObject();
}
return arc;
}
void InitStatus() void InitStatus()
{ {
@ -138,14 +143,11 @@ void InitStatus()
SetHealthFrame(0); SetHealthFrame(0);
SetMagicFrame(); SetMagicFrame();
for (int i = 0; i < kMaxStatusAnims; i++) { StatusAnim.Clear();
StatusAnimsFree[i] = i;
}
nLastAnim = -1; nLastAnim = -1;
nFirstAnim = -1; nFirstAnim = -1;
nItemSeq = -1; nItemSeq = -1;
nStatusFree = kMaxStatusAnims;
statusx = xdim - 320; statusx = xdim - 320;
statusy = ydim - 200; statusy = ydim - 200;
} }
@ -179,13 +181,7 @@ int BuildStatusAnim(int val, int nFlags)
} }
} }
if (nStatusFree <= 0) { int nStatusAnim = StatusAnim.Get();
return -1;
}
nStatusFree--;
uint8_t nStatusAnim = StatusAnimsFree[nStatusFree];
StatusAnim[nStatusAnim].nPrevAnim = -1; StatusAnim[nStatusAnim].nPrevAnim = -1;
StatusAnim[nStatusAnim].nNextAnim = nLastAnim; StatusAnim[nStatusAnim].nNextAnim = nLastAnim;
@ -201,7 +197,7 @@ int BuildStatusAnim(int val, int nFlags)
StatusAnim[nStatusAnim].s1 = val; StatusAnim[nStatusAnim].s1 = val;
StatusAnim[nStatusAnim].s2 = 0; StatusAnim[nStatusAnim].s2 = 0;
StatusAnimFlags[nStatusAnim] = nFlags; StatusAnim[nStatusAnim].StatusAnimFlags = nFlags;
return nStatusAnim; return nStatusAnim;
} }
@ -248,7 +244,7 @@ void MoveStatusAnims()
if (StatusAnim[i].s2 >= nSize) if (StatusAnim[i].s2 >= nSize)
{ {
if (StatusAnimFlags[i] & 0x10) { if (StatusAnim[i].StatusAnimFlags & 0x10) {
StatusAnim[i].s2 = 0; StatusAnim[i].s2 = 0;
} }
else { else {
@ -279,8 +275,7 @@ void DestroyStatusAnim(short nAnim)
nLastAnim = nNext; nLastAnim = nNext;
} }
StatusAnimsFree[nStatusFree] = (uint8_t)nAnim; StatusAnim.Release(nAnim);
nStatusFree++;
} }
void SetMagicFrame() void SetMagicFrame()
@ -686,20 +681,6 @@ private:
for (int i = 0; i < nTotalPlayers; i++) for (int i = 0; i < nTotalPlayers; i++)
{ {
int nScore = nPlayerScore[i];
if (word_9AD54[i] == nScore)
{
int v9 = dword_9AD64[i];
if (v9 && v9 <= leveltime*4) {
dword_9AD64[i] = 0;
}
}
else
{
word_9AD54[i] = nScore;
dword_9AD64[i] = leveltime*4 + 30;
}
DrawGraphic(tileGetTexture(nTile), x, 7, DI_ITEM_CENTER, 1, -1, -1, 1, 1); DrawGraphic(tileGetTexture(nTile), x, 7, DI_ITEM_CENTER, 1, -1, -1, 1, 1);
if (i != nLocalPlayer) { if (i != nLocalPlayer) {
@ -1037,43 +1018,41 @@ void DrawStatusBar()
} }
// I'm not sure this really needs to be saved. // This should not be necessary but the game only lazily updates the statusbar data.
static SavegameHelper sghstatus("status", void SerializeStatus(FSerializer& arc)
SV(nMaskY), {
SV(nStatusFree), if (arc.BeginObject("status"))
SV(magicperline), {
SV(airperline), arc("masky", nMaskY)
SV(healthperline), ("magicperline", magicperline)
SV(nAirFrames), ("airperline", airperline)
SV(nCounter), ("healthperline", healthperline)
SV(nCounterDest), ("airframes", nAirFrames)
SV(nItemFrames), ("counter", nCounter)
SV(nItemSeq), ("counterdest", nCounterDest)
SV(nMagicFrames), ("itemframes", nItemFrames)
SV(nHealthLevel), ("itemseq", nItemSeq)
SV(nItemFrame), ("magicframes", nMagicFrames)
SV(nMeterRange), ("healthlevel", nHealthLevel)
SV(nMagicLevel), ("itemframe", nItemFrame)
SV(nHealthFrame), ("meterrange", nMeterRange)
SV(nMagicFrame), ("magiclevel", nMagicLevel)
SV(statusx), ("healthframe", nHealthFrame)
SV(statusy), ("magicframe", nMagicFrame)
SV(airframe), ("statusx", statusx)
SV(nFirstAnim), ("statusy", statusy)
SV(nLastAnim), ("airframe", airframe)
SV(nItemAltSeq), ("firstanim", nFirstAnim)
SV(airpages), ("lastanim", nLastAnim)
SV(ammodelay), ("itemaltseq", nItemAltSeq)
SV(nCounterBullet), ("airpages", airpages)
SA(statusmask), ("ammodelay", ammodelay)
SA(message_text), ("counterbullet", nCounterBullet)
SA(nDigit), .Array("digit", nDigit, 3)
SA(StatusAnim), .Array("itemseqoffset", nItemSeqOffset, countof(nItemSeqOffset))
SA(StatusAnimsFree), ("statusanim", StatusAnim)
SA(StatusAnimFlags), .EndObject();
SA(nItemSeqOffset), }
SA(word_9AD54), }
SA(dword_9AD64),
nullptr);
END_PS_NS END_PS_NS