made SW's panel sprites into actual DObjects

so that they can a) cleanly be exposed to scripting later and b) serialized for savegames without using gross hacks.
This commit is contained in:
Christoph Oelckers 2023-10-03 12:27:15 +02:00
parent 88d5d15094
commit 330e2af217
9 changed files with 527 additions and 617 deletions

View file

@ -102,6 +102,7 @@ IMPLEMENT_POINTER(user.targetActor)
IMPLEMENT_POINTER(user.flameActor)
IMPLEMENT_POINTER(user.attachActor)
IMPLEMENT_POINTER(user.WpnGoalActor)
IMPLEMENT_POINTER(user.PlayerP)
IMPLEMENT_POINTERS_END
IMPLEMENT_CLASS(DSWPlayer, false, true)
@ -113,8 +114,36 @@ IMPLEMENT_POINTER(PlayerUnderActor)
IMPLEMENT_POINTER(KillerActor)
IMPLEMENT_POINTER(HitBy)
IMPLEMENT_POINTER(last_camera_act)
IMPLEMENT_POINTER(CurWpn)
IMPLEMENT_POINTER(Chops)
IMPLEMENT_POINTER(PanelSpriteList)
IMPLEMENT_POINTER(Wpn[0])
IMPLEMENT_POINTER(Wpn[1])
IMPLEMENT_POINTER(Wpn[2])
IMPLEMENT_POINTER(Wpn[3])
IMPLEMENT_POINTER(Wpn[4])
IMPLEMENT_POINTER(Wpn[5])
IMPLEMENT_POINTER(Wpn[6])
IMPLEMENT_POINTER(Wpn[7])
IMPLEMENT_POINTER(Wpn[8])
IMPLEMENT_POINTER(Wpn[9])
IMPLEMENT_POINTER(Wpn[10])
IMPLEMENT_POINTER(Wpn[11])
IMPLEMENT_POINTER(Wpn[12])
IMPLEMENT_POINTER(Wpn[13])
IMPLEMENT_POINTERS_END
static_assert(MAX_WEAPONS == 14);
IMPLEMENT_CLASS(DPanelSprite, false, true)
IMPLEMENT_POINTERS_START(DPanelSprite)
IMPLEMENT_POINTER(Next)
IMPLEMENT_POINTER(Prev)
IMPLEMENT_POINTER(sibling)
IMPLEMENT_POINTER(PlayerP)
IMPLEMENT_POINTERS_END
void MarkSOInterp();
extern int FinishTimer;
@ -271,7 +300,7 @@ void GameInterface::app_init()
gs = gs_defaults;
for (int i = 0; i < MAX_SW_PLAYERS; i++)
INITLIST(&getPlayer(i)->PanelSpriteList);
INITLIST(getPlayer(i)->PanelSpriteList);
DebugOperate = true;
enginecompatibility_mode = ENGINECOMPATIBILITY_19961112;
@ -300,7 +329,7 @@ void GameInterface::app_init()
memset(Track, 0, sizeof(Track));
for (int i = 0; i < MAX_SW_PLAYERS; i++)
INITLIST(&(getPlayer(i)->PanelSpriteList));
INITLIST(getPlayer(i)->PanelSpriteList);
LoadCustomInfoFromScript("engine/swcustom.txt"); // load the internal definitions. These also apply to the shareware version.
if (!SW_SHAREWARE)
@ -423,7 +452,7 @@ void InitLevel(MapRecord *maprec)
getPlayer(i)->Clear();
getPlayer(i)->playerreadyflag = ready_bak;
getPlayer(i)->PlayerVersion = ver_bak;
INITLIST(&getPlayer(i)->PanelSpriteList);
INITLIST(getPlayer(i)->PanelSpriteList);
}
memset(puser, 0, sizeof(puser));
@ -594,7 +623,6 @@ void TerminateLevel(void)
pp->hi_sectp = pp->lo_sectp = nullptr;
pp->cursector = pp->lastcursector = pp->lv_sector = nullptr;
pp->sop_control = pp->sop_riding = nullptr;
pp->PanelSpriteList = {};
memset(pp->cookieQuote, 0, sizeof(pp->cookieQuote));
pp->DoPlayerAction = nullptr;
@ -614,7 +642,7 @@ void TerminateLevel(void)
pp->KillerActor = nullptr;;
INITLIST(&pp->PanelSpriteList);
INITLIST(pp->PanelSpriteList);
}
}

View file

@ -331,11 +331,11 @@ class DSWPlayer;
struct PERSONALITY;
struct ATTRIBUTE;
struct SECTOR_OBJECT;
struct PANEL_SPRITE;
class DPanelSprite;
struct ANIM;
class DSWActor;
typedef void pANIMATOR (PANEL_SPRITE*);
typedef void pANIMATOR (DPanelSprite*);
typedef void (*soANIMATORp) (SECTOR_OBJECT*);
// this needs to work with incomplete data, so avoid the asserting macros.
@ -1682,14 +1682,11 @@ class DSWPlayer final : public DCorePlayer
HAS_OBJECT_POINTERS
DSWPlayer() = default;
public:
void Clear()
{
Super::Clear();
// Quick'n dirty clear
memset(&lowActor, 0, sizeof(DSWPlayer) - myoffsetof(DSWPlayer, lowActor));
}
DSWPlayer(uint8_t p) : DCorePlayer(p) {}
void Clear();
DSWPlayer(uint8_t p);
DSWPlayer& operator=(DSWPlayer&) = delete;
DSWPlayer(DSWPlayer&) = delete;
void OnDestroy() override;
void Serialize(FSerializer& arc) override;
TObjPtr<DSWActor*> lowActor, highActor;
TObjPtr<DSWActor*> remoteActor;
@ -1765,17 +1762,11 @@ public:
SECTOR_OBJECT* sop_control; // sector object pointer
SECTOR_OBJECT* sop_riding; // sector object pointer
struct
{
PANEL_SPRITE* Next, *Prev;
} PanelSpriteList;
DPanelSprite* PanelSpriteList; // this is just a sentinel object that does not do anything. No read barrier here as this is strictly owned by the player.
// hack stuff to get a working pointer to this list element without running into type punning warnings with GCC.
// The list uses itself as sentinel element despite the type mismatch.
PANEL_SPRITE* GetPanelSpriteList()
DPanelSprite* GetPanelSpriteList()
{
void* p = &PanelSpriteList;
return reinterpret_cast<PANEL_SPRITE*>(p);
return PanelSpriteList;
}
// Key stuff
@ -1787,9 +1778,9 @@ public:
int WpnFlags;
int16_t WpnAmmo[MAX_WEAPONS];
int16_t WpnNum;
PANEL_SPRITE* CurWpn;
PANEL_SPRITE* Wpn[MAX_WEAPONS];
PANEL_SPRITE* Chops;
TObjPtr<DPanelSprite*> CurWpn;
TObjPtr<DPanelSprite*> Wpn[MAX_WEAPONS];
TObjPtr<DPanelSprite*> Chops;
uint8_t WpnRocketType; // rocket type
uint8_t WpnRocketHeat; // 5 to 0 range
uint8_t WpnRocketNuke; // 1, you have it, or you don't

View file

@ -88,7 +88,7 @@ INVENTORY_DATA InventoryData[MAX_INVENTORY+1] =
//
//---------------------------------------------------------------------------
void PanelInvTestSuicide(PANEL_SPRITE* psp)
void PanelInvTestSuicide(DPanelSprite* psp)
{
if (psp->flags & (PANF_SUICIDE))
{

View file

@ -32,37 +32,33 @@ BEGIN_SW_NS
/********************************************************************/
struct List
inline void INITLIST(DPanelSprite* list)
{
struct List *Next;
struct List *Prev;
};
inline void INITLIST(void* listp)
{
List* list = (List*)listp;
list->Prev = list->Next = list;
}
inline void INSERT(void* listp, void* nodepp)
inline void INSERT(DPanelSprite* list, DPanelSprite* nodep)
{
List* list = (List*)listp;
List* nodep = (List*)nodepp;
GC::WriteBarrier(list);
GC::WriteBarrier(list->Next);
GC::WriteBarrier(nodep);
nodep->Prev = list;
nodep->Next = list->Next;
list->Next = nodep;
nodep->Next->Prev = nodep;
}
inline void REMOVE(PANEL_SPRITE* nodep)
inline void REMOVE(DPanelSprite* nodep)
{
GC::WriteBarrier(nodep->Next);
GC::WriteBarrier(nodep->Prev);
nodep->Prev->Next = nodep->Next;
nodep->Next->Prev = nodep->Prev;
}
inline bool EMPTY(void* listp)
inline bool EMPTY(DPanelSprite* list)
{
List* list = (List*)listp;
return list->Next == list;
}

File diff suppressed because it is too large Load diff

View file

@ -59,7 +59,7 @@ struct PANEL_STATE
{
short picndx; // for pip stuff in conpic.h
int tics;
void (*Animator)(PANEL_SPRITE*); // JBF: return type was long
void (*Animator)(DPanelSprite*); // JBF: return type was long
PANEL_STATE* NextState;
uint32_t flags;
uint8_t xvel;
@ -92,7 +92,7 @@ enum
PANF_DRAW_BEFORE_VIEW = (BIT(30)), // draw before drawrooms
};
typedef void (*PANEL_SPRITE_FUNCp)(PANEL_SPRITE*);
typedef void (*PANEL_SPRITE_FUNCp)(DPanelSprite*);
struct PANEL_SPRITE_OVERLAY
{
@ -104,12 +104,16 @@ struct PANEL_SPRITE_OVERLAY
short yoff; // from panel sprite center y
};
struct PANEL_SPRITE
class DPanelSprite : public DObject
{
PANEL_SPRITE* Next, * Prev;
PANEL_SPRITE* sibling;
DECLARE_CLASS(DPanelSprite, DObject)
HAS_OBJECT_POINTERS
void Serialize(FSerializer& arc) override;
public:
DPanelSprite* Next, * Prev;
TObjPtr<DPanelSprite*> sibling;
PANEL_STATE* State, *RetractState, *PresentState, *ActionState, *RestState;
DSWPlayer* PlayerP;
TObjPtr<DSWPlayer*> PlayerP;
DVector2 pos, opos, bobpos;
PANEL_SPRITE_OVERLAY over[8];
@ -177,14 +181,14 @@ enum
};
PANEL_SPRITE* pSpawnSprite(DSWPlayer* pp, PANEL_STATE* state, uint8_t priority, double x, double y);
void pSetSuicide(PANEL_SPRITE* psp);
DPanelSprite* pSpawnSprite(DSWPlayer* pp, PANEL_STATE* state, uint8_t priority, double x, double y);
void pSetSuicide(DPanelSprite* psp);
bool pKillScreenSpiteIDs(DSWPlayer* pp, short id);
void PreUpdatePanel(double interpfrac);
void UpdatePanel(double interpfrac);
void PlayerUpdateArmor(DSWPlayer* pp,short value);
void pToggleCrosshair(void);
void pKillSprite(PANEL_SPRITE* psp);
void pKillSprite(DPanelSprite* psp);
void InitChops(DSWPlayer* pp);
void ChopsSetRetract(DSWPlayer* pp);

View file

@ -175,6 +175,29 @@ void processWeapon(DSWPlayer* const pp);
extern short target_ang;
void DSWPlayer::Clear()
{
Super::Clear();
// Quick'n dirty clear. PanelSpriteList must be preserved, though, but cleared itself.
auto p = PanelSpriteList;
memset(&lowActor, 0, sizeof(DSWPlayer) - myoffsetof(DSWPlayer, lowActor));
PanelSpriteList = p;
INITLIST(p);
}
DSWPlayer::DSWPlayer(uint8_t p) : DCorePlayer(p)
{
PanelSpriteList = Create<DPanelSprite>();
GC::WriteBarrier(this, PanelSpriteList);
}
void DSWPlayer::OnDestroy()
{
pClearSpriteList(this);
PanelSpriteList->Destroy();
PanelSpriteList = nullptr;
}
//////////////////////
//
// PLAYER SPECIFIC
@ -1008,7 +1031,7 @@ int SetVisNorm(void)
return 0;
}
void pSetVisNorm(PANEL_SPRITE* psp)
void pSetVisNorm(DPanelSprite* psp)
{
// SetVisNorm();
}
@ -6905,7 +6928,7 @@ void InitAllPlayers(void)
pp->FadeTics = 0;
pp->StartColor = 0;
INITLIST(&pp->PanelSpriteList);
INITLIST(pp->PanelSpriteList);
}
}

View file

@ -205,91 +205,6 @@ FSerializer& Serialize(FSerializer& arc, const char* keyname, ATTRIBUTE*& w, ATT
//
//---------------------------------------------------------------------------
// Temporary array to serialize the panel sprites.
static TArray<PANEL_SPRITE*> pspAsArray;
FSerializer& Serialize(FSerializer& arc, const char* keyname, PANEL_SPRITE*& w, PANEL_SPRITE** def)
{
unsigned idx = ~0u;
if (arc.isWriting())
{
if (w != nullptr)
{
idx = pspAsArray.Find(w);
if ((unsigned)idx >= pspAsArray.Size())
{
for (unsigned i = 0; i < MAX_SW_PLAYERS_REG; i++)
{
// special case for pointing to the list head
if ((List*)w == (List*)&getPlayer(i)->PanelSpriteList)
{
idx = 1000'0000 + i;
break;
}
}
if (idx >= pspAsArray.Size() && idx < 1000'0000)
idx = pspAsArray.Push(w);
}
}
arc(keyname, idx);
}
else
{
unsigned int ndx;
arc(keyname, ndx);
if (ndx == ~0u) w = nullptr;
else if (ndx >= 1000'0000) w = (PANEL_SPRITE*)&(getPlayer(ndx - 1000'0000)->PanelSpriteList);
else if ((unsigned)ndx >= pspAsArray.Size())
I_Error("Bad panel sprite index in savegame");
else w = pspAsArray[ndx];
}
return arc;
}
//---------------------------------------------------------------------------
//
// we need to allocate the needed panel sprites before loading anything else
//
//---------------------------------------------------------------------------
void preSerializePanelSprites(FSerializer& arc)
{
if (arc.isReading())
{
unsigned siz;
arc("panelcount", siz);
pspAsArray.Resize(siz);
for (unsigned i = 0; i < siz; i++)
{
pspAsArray[i] = (PANEL_SPRITE*)CallocMem(sizeof(PANEL_SPRITE), 1);
}
}
}
void postSerializePanelSprites(FSerializer& arc)
{
if (arc.BeginArray("panelsprites"))
{
for(unsigned i = 0; i < pspAsArray.Size(); i++)
{
arc(nullptr, *pspAsArray[i]);
}
arc.EndArray();
}
if (arc.isWriting())
{
unsigned siz = pspAsArray.Size();
arc("panelcount", siz);
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
FSerializer& Serialize(FSerializer& arc, const char* keyname, PANEL_SPRITE_OVERLAY& w, PANEL_SPRITE_OVERLAY* def)
{
if (arc.BeginObject(keyname))
@ -311,62 +226,50 @@ FSerializer& Serialize(FSerializer& arc, const char* keyname, PANEL_SPRITE_OVERL
//
//---------------------------------------------------------------------------
FSerializer& Serialize(FSerializer& arc, const char* keyname, PANEL_SPRITE& w, PANEL_SPRITE* def)
void DPanelSprite::Serialize(FSerializer& arc)
{
static PANEL_SPRITE nul;
if (!def)
{
def = &nul;
if (arc.isReading()) w = {};
}
Super::Serialize(arc);
arc("Next", Next)
("Prev", Prev)
("sibling", sibling)
("State", State)
("RetractState", RetractState)
("PresentState", PresentState)
("ActionState", ActionState)
("RestState", RestState)
("pos", pos)
.Array("over", over, countof(over))
("id", ID)
("picndx", picndx)
("picnum", picnum)
("vel", vel)
("vel_adj", vel_adj)
("orig", bobpos)
("flags", flags)
("priority", priority)
("scale", scale)
("jump_speed", jump_speed)
("jump_grav", jump_grav)
("xspeed", xspeed)
("tics", tics)
("delay", delay)
("ang", ang)
("rotate_ang", rotate_ang)
("sin_ndx", sin_ndx)
("sin_amt", sin_amt)
("sin_arc_speed", sin_arc_speed)
("bob_height_divider", bob_height_divider)
("shade", shade)
("pal", pal)
("kill_tics", kill_tics)
("WeaponType", WeaponType)
("playerp", PlayerP);
if (arc.BeginObject(keyname))
{
arc("Next", w.Next)
("Prev", w.Prev)
("sibling", w.sibling)
("State", w.State)
("RetractState", w.RetractState)
("PresentState", w.PresentState)
("ActionState", w.ActionState)
("RestState", w.RestState)
("pos", w.pos)
.Array("over", w.over, countof(w.over))
("id", w.ID)
("picndx", w.picndx)
("picnum", w.picnum)
("vel", w.vel)
("vel_adj", w.vel_adj)
("orig", w.bobpos)
("flags", w.flags)
("priority", w.priority)
("scale", w.scale)
("jump_speed", w.jump_speed)
("jump_grav", w.jump_grav)
("xspeed", w.xspeed)
("tics", w.tics)
("delay", w.delay)
("ang", w.ang)
("rotate_ang", w.rotate_ang)
("sin_ndx", w.sin_ndx)
("sin_amt", w.sin_amt)
("sin_arc_speed", w.sin_arc_speed)
("bob_height_divider", w.bob_height_divider)
("shade", w.shade)
("pal", w.pal)
("kill_tics", w.kill_tics)
("WeaponType", w.WeaponType)
("playerp", w.PlayerP);
SerializeCodePtr(arc, "PanelSpriteFunc", (void**)&w.PanelSpriteFunc);
arc.EndObject();
}
SerializeCodePtr(arc, "PanelSpriteFunc", (void**)&PanelSpriteFunc);
if (arc.isReading())
{
w.opos = w.pos;
opos = pos;
}
return arc;
}
//---------------------------------------------------------------------------
@ -408,20 +311,6 @@ FSerializer& Serialize(FSerializer& arc, const char* keyname, REMOTE_CONTROL& w,
//
//---------------------------------------------------------------------------
FSerializer& Serialize(FSerializer& arc, const char* keyname, DSWPlayer*& w, DSWPlayer** def)
{
int ndx = w ? int(w->pnum) : -1;
arc(keyname, ndx);
w = ndx == -1 ? nullptr : getPlayer(ndx);
return arc;
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void DSWPlayer::Serialize(FSerializer& arc)
{
Super::Serialize(arc);
@ -532,6 +421,7 @@ void DSWPlayer::Serialize(FSerializer& arc)
("cookieTime", cookieTime)
("WpnReloadState", WpnReloadState)
("keypressbits", KeyPressBits)
("PanelSpriteList", PanelSpriteList)
("chops", Chops);
SerializeCodePtr(arc, "DoPlayerAction", (void**)&DoPlayerAction);
@ -735,9 +625,9 @@ FSerializer& Serialize(FSerializer& arc, const char* keyname, USER& w, USER* def
("hi_sp", w.highActor, def->highActor)
("lo_sp", w.lowActor, def->lowActor)
("active_range", w.active_range, def->active_range)
("Attach", w.attachActor, def->attachActor)
("PlayerP", w.PlayerP, def->PlayerP)
("Sibling", w.Sibling, def->Sibling)
("Attach", w.attachActor, def->attachActor);
arc("PlayerP", w.PlayerP, def->PlayerP);
arc("Sibling", w.Sibling, def->Sibling)
("change", w.change, def->change)
("z_tgt", w.z_tgt, def->z_tgt)
("vel_tgt", w.vel_tgt, def->vel_tgt)
@ -1056,10 +946,8 @@ void DSWActor::Serialize(FSerializer& arc)
void GameInterface::SerializeGameState(FSerializer& arc)
{
pspAsArray.Clear();
Saveable_Init();
preSerializePanelSprites(arc);
if (arc.BeginObject("state"))
{
so_serializeinterpolations(arc);
@ -1106,24 +994,6 @@ void GameInterface::SerializeGameState(FSerializer& arc)
arc.EndObject();
}
// these cannot be deferred to writing out the actors because we need to fill in pspAsArray before calling postSerializePanelSprites.
// The organization of this list is a mess and needs to be refactored into something workable.
if (arc.BeginArray("playerpanelsprites"))
{
for (int i = 0; i < MAXPLAYERS; i++)
{
if (arc.BeginObject(nullptr))
{
auto p = getPlayer(i);
arc("panelnext", p->PanelSpriteList.Next)
("panelprev", p->PanelSpriteList.Prev)
.EndObject();
}
}
arc.EndArray();
}
postSerializePanelSprites(arc);
if (arc.isReading())
{
DoTheCache();

View file

@ -183,13 +183,10 @@ class SWPlayer : CorePlayer native
SECTOR_OBJECTp sop_control; // sector object pointer
SECTOR_OBJECTp sop_riding; // sector object pointer
struct
{
PANEL_SPRITEp Next, Prev;
} PanelSpriteList;
PANEL_SPRITEp CurWpn;
PANEL_SPRITEp Wpn[SW.MAX_WEAPONS];
PANEL_SPRITEp Chops;
PanelSprite PanelSpriteList;
PanelSprite CurWpn;
PanelSprite Wpn[SW.MAX_WEAPONS];
PanelSprite Chops;
*/
native voidptr sop_remote; // the status bar needs to check this - remove once the underlying type can be supported.