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