- extended walltype to directly manage Blood's XWALL.

Unfortunately this had to be done in the base class so that we can still maintain the walls in a global array.
The tradeoffs of better abstractions would be far too costly here than the added 16 bytes to the wall struct.
This commit is contained in:
Christoph Oelckers 2021-11-20 17:01:59 +01:00
parent 6217623c24
commit 94a37dfcdc
11 changed files with 301 additions and 262 deletions

View file

@ -153,6 +153,10 @@ struct walltype
uint8_t portalflags;
uint16_t portalnum;
// Blood is the only game which extends the wall struct.
Blood::XWALL* _xw;
vec2_t baseWall;
int xpan() const { return int(xpan_); }
int ypan() const { return int(ypan_); }
void setxpan(float add) { xpan_ = fmodf(add + 512, 256); } // +512 is for handling negative offsets
@ -168,9 +172,9 @@ struct walltype
int deltay() const { return point2Wall()->y - y; }
bool twoSided() const { return nextsector >= 0; }
// These will unfortunately have to be within the base struct to refactor Blood properly. They can later be removed again, once everything is done.
Blood::XWALL& xw() const;
bool hasX() const { return extra > 0; } // 0 is invalid!
Blood::XWALL& xw() const { return *_xw; }
bool hasX() const { return _xw != nullptr; }
void allocX();
#if 0
// make sure we do not accidentally copy this

View file

@ -290,6 +290,28 @@ bool FSerializer::BeginObject(const char *name)
//
//==========================================================================
bool FSerializer::HasObject(const char* name)
{
if (isReading())
{
auto val = r->FindKey(name);
if (val != nullptr)
{
if (val->IsObject())
{
return true;
}
}
}
return false;
}
//==========================================================================
//
//
//
//==========================================================================
void FSerializer::EndObject()
{
if (isWriting())

View file

@ -85,6 +85,7 @@ public:
void ReadObjects(bool hubtravel);
bool BeginObject(const char *name);
void EndObject();
bool HasObject(const char* name);
bool BeginArray(const char *name);
void EndArray();
unsigned GetSize(const char *group);

View file

@ -46,6 +46,7 @@
#include "render.h"
#include "hw_sections.h"
#include "interpolate.h"
#include "games/blood/src/mapstructs.h"
// needed for skipping over to get the map size first.
enum
@ -58,6 +59,16 @@ enum
wallsize7 = 32,
};
// This arena stores the larger allocated game-specific extension data. Since this can be freed in bulk a memory arena is better suited than malloc.
static FMemArena mapDataArena;
void walltype::allocX()
{
using XWALL = BLD_NS::XWALL;
_xw = (XWALL*)mapDataArena.Alloc(sizeof(XWALL));
memset(_xw, 0, sizeof(XWALL));
}
static void ReadSectorV7(FileReader& fr, sectortype& sect)
{

View file

@ -2,35 +2,27 @@
#ifndef NO_NAMESPACE
#define BEGIN_DUKE_NS namespace Duke3d {
#define DUKE_NS Duke3d
#define BEGIN_DUKE_NS namespace DUKE_NS {
#define END_DUKE_NS }
#define BEGIN_EDUKE_NS namespace Duke {
#define END_EDUKE_NS }
#define BEGIN_RR_NS namespace Redneck {
#define END_RR_NS }
#define BEGIN_BLD_NS namespace Blood {
#define BLD_NS Blood
#define BEGIN_BLD_NS namespace BLD_NS {
#define END_BLD_NS }
#define BEGIN_SW_NS namespace ShadowWarrior {
#define SW_NS ShadowWarrior
#define BEGIN_SW_NS namespace SW_NS {
#define END_SW_NS }
#define BEGIN_PS_NS namespace Exhumed {
#define PS_NS Exhumed
#define BEGIN_PS_NS namespace PS_NS {
#define END_PS_NS }
#else
#define BEGIN_EDUKE_NS
#define END_EDUKE_NS
#define BEGIN_DUKE_NS
#define END_DUKE_NS
#define BEGIN_RR_NS
#define END_RR_NS
#define BEGIN_BLD_NS
#define END_BLD_NS

View file

@ -60,6 +60,8 @@
#include "hw_sections.h"
#include "sectorgeometry.h"
#include "d_net.h"
#include "ns.h"
#include "games/blood/src/mapstructs.h"
#include <zlib.h>
@ -77,6 +79,12 @@ FixedBitArray<MAXSPRITES> activeSprites;
CVAR(String, cl_savedir, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
BEGIN_BLD_NS
FSerializer& Serialize(FSerializer& arc, const char* keyname, XWALL& w, XWALL* def);
END_BLD_NS
//=============================================================================
//
//
@ -555,8 +563,30 @@ FSerializer &Serialize(FSerializer &arc, const char *key, walltype &c, walltype
("hitag", c.hitag, def->hitag)
("extra", c.extra, def->extra)
("portalflags", c.portalflags, def->portalflags)
("portalnum", c.portalnum, def->portalnum)
.EndObject();
("portalnum", c.portalnum, def->portalnum);
// Save the blood-specific extensions only when playing Blood
if (isBlood())
{
arc("wallbase", c.baseWall, def->baseWall);
if (arc.isWriting())
{
if (c.hasX())
{
BLD_NS::Serialize(arc, "xwall", *c._xw, nullptr);
}
}
else
{
if (arc.HasObject("xwall"))
{
c.allocX();
BLD_NS::Serialize(arc, "xwall", *c._xw, nullptr);
}
}
}
arc.EndObject();
}
return arc;
}

View file

@ -556,7 +556,6 @@ void viewProcessSprites(spritetype* tsprite, int& spritesortcnt, int32_t cX, int
int nAnim = 0;
switch (picanm[nTile].extra & 7) {
case 0:
//assert(nXSprite > 0 && nXSprite < kMaxXSprites);
if (pTXSprite == nullptr) break;
switch (pTSprite->type) {
case kSwitchToggle:

View file

@ -45,9 +45,7 @@ bool gModernMap = false;
unsigned int gStatCount[kMaxStatus + 1];
XSECTOR xsector[kMaxXSectors];
XWALL xwall[kMaxXWalls];
int XWallsUsed, XSectorsUsed;
int XSectorsUsed;
@ -252,18 +250,6 @@ void InitFreeList(unsigned short* pList, int nCount)
}
unsigned int dbInsertXWall(int nWall)
{
int nXWall = XWallsUsed++;
if (nXWall >= kMaxXWalls)
{
I_Error("Out of free XWalls");
}
memset(&xwall[nXWall], 0, sizeof(XWALL));
wall[nWall].extra = nXWall;
return nXWall;
}
unsigned int dbInsertXSector(int nSector)
{
int nXSector = XSectorsUsed++;
@ -278,7 +264,7 @@ unsigned int dbInsertXSector(int nSector)
void dbInit(void)
{
XWallsUsed = XSectorsUsed = 1; // 0 is not usable because it's the default for 'extra' and some code actually uses it to clobber the contents in here. :(
XSectorsUsed = 1; // 0 is not usable because it's the default for 'extra' and some code actually uses it to clobber the contents in here. :(
initspritelists();
for (int i = 0; i < kMaxSprites; i++)
{
@ -715,12 +701,11 @@ void dbLoadMap(const char* pPath, int* pX, int* pY, int* pZ, short* pAngle, int*
pWall->yrepeat = load.yrepeat;
pWall->ypan_ = load.ypanning;
if (wall[i].extra > 0)
if (pWall->extra > 0)
{
char pBuffer[nXWallSize];
int nXWall = dbInsertXWall(i);
XWALL* pXWall = &xwall[nXWall];
memset(pXWall, 0, sizeof(XWALL));
pWall->allocX();
XWALL* pXWall = &pWall->xw();
int nCount;
if (!encrypted)
{

View file

@ -22,13 +22,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//-------------------------------------------------------------------------
#pragma once
#include "mapstructs.h"
BEGIN_BLD_NS
enum
{
kMaxXSprites = 16384,
kMaxXWalls = 512,
kMaxXSectors = 512
};
@ -44,218 +44,10 @@ enum
};
// by NoOne: functions to quckly check range of specifical arrays
inline bool xsectRangeIsFine(int nXindex) {
return (nXindex >= 0 && nXindex < kMaxXSectors);
}
inline bool xwallRangeIsFine(int nXindex) {
return (nXindex >= 0 && nXindex < kMaxXWalls);
}
#pragma pack(push, 1)
struct AISTATE;
struct XSPRITE {
AISTATE* aiState; // ai
union
{
uint32_t flags;
struct {
unsigned int state : 1; // State 0
unsigned int triggerOn : 1; // going ON
unsigned int triggerOff : 1; // going OFF
unsigned int restState : 1; // restState
unsigned int Interrutable : 1; // Interruptable
unsigned int Decoupled : 1; // Decoupled
unsigned int triggerOnce : 1; // 1-shot
unsigned int isTriggered : 1; // works in case if triggerOnce selected
unsigned int Push : 1; // Push
unsigned int Vector : 1; // Vector
unsigned int Impact : 1; // Impact
unsigned int Pickup : 1; // Pickup
unsigned int Touch : 1; // Touch
unsigned int Sight : 1; // Sight
unsigned int Proximity : 1; // Proximity
unsigned int lS : 1; // Single
unsigned int lB : 1; // Bloodbath
unsigned int lT : 1; // Launch Team
unsigned int lC : 1; // Coop
unsigned int DudeLockout : 1; // DudeLockout
unsigned int locked : 1; // Locked
unsigned int dudeDeaf : 1; // dudeDeaf
unsigned int dudeAmbush : 1; // dudeAmbush
unsigned int dudeGuard : 1; // dudeGuard
unsigned int dudeFlag4 : 1; // unused
unsigned int wave : 2; // Wave
unsigned int medium : 2; // medium
unsigned int respawn : 2; // Respawn option
unsigned int unused2 : 1; // (new) patrol state
};
};
DBloodActor* target; // target sprite
int32_t targetX; // target x
int32_t targetY; // target y
int32_t targetZ; // target z
int32_t sysData1; // used to keep here various system data, so user can't change it in map editor
int32_t sysData2; //
int32_t scale; // used for scaling SEQ size on sprites
uint32_t physAttr; // currently used by additional physics sprites to keep it's attributes.
uint32_t health;
uint32_t busy;
int16_t data1; // Data 1
int16_t data2; // Data 2
int16_t data3; // Data 3
int16_t burnSource;
uint16_t txID; // TX ID
uint16_t rxID; // RX ID
uint16_t command; // Cmd
uint16_t busyTime; // busyTime
uint16_t waitTime; // waitTime
uint16_t data4; // Data 4
uint16_t goalAng; // Dude goal ang
uint16_t burnTime;
uint16_t height;
uint16_t stateTimer; // ai timer
uint8_t respawnPending; // respawnPending
uint8_t dropMsg; // Drop Item
uint8_t key; // Key
uint8_t lSkill; // Launch 12345
uint8_t lockMsg; // Lock msg
int8_t dodgeDir; // Dude dodge direction
uint8_t unused1; // modern flags
uint8_t unused3; // something about sight checks
uint8_t unused4; // patrol turn delay
};
struct XSECTOR {
union
{
uint64_t flags;
struct {
unsigned int state : 1; // State
unsigned int triggerOn : 1; // Send at ON
unsigned int triggerOff : 1; // Send at OFF
unsigned int restState : 1;
unsigned int interruptable : 1; // Interruptable
unsigned int reTriggerA : 1; // OFF->ON wait
unsigned int reTriggerB : 1; // ON->OFF wait
unsigned int shadeAlways : 1; // Lighting shadeAlways
unsigned int shadeFloor : 1; // Lighting floor
unsigned int shadeCeiling : 1; // Lighting ceiling
unsigned int shadeWalls : 1; // Lighting walls
unsigned int panAlways : 1; // Pan always
unsigned int panFloor : 1; // Pan floor
unsigned int panCeiling : 1; // Pan ceiling
unsigned int Drag : 1; // Pan drag
unsigned int Underwater : 1; // Underwater
unsigned int decoupled : 1; // Decoupled
unsigned int triggerOnce : 1; // 1-shot
unsigned int isTriggered : 1;
unsigned int Push : 1; // Push
unsigned int Vector : 1; // Vector
unsigned int Reserved : 1; // Reserved
unsigned int Enter : 1; // Enter
unsigned int Exit : 1; // Exit
unsigned int Wallpush : 1; // WallPush
unsigned int color : 1; // Color Lights
unsigned int stopOn : 1;
unsigned int stopOff : 1;
unsigned int Crush : 1; // Crush
unsigned int locked : 1; // Locked
unsigned int windAlways : 1; // Wind always
unsigned int dudeLockout : 1;
unsigned int bobAlways : 1; // Motion always
unsigned int bobFloor : 1; // Motion bob floor
unsigned int bobCeiling : 1; // Motion bob ceiling
unsigned int bobRotate : 1; // Motion rotate
unsigned int unused1 : 1; // (new) pause motion
};
};
uint32_t busy;
int32_t offCeilZ;
int32_t onCeilZ;
int32_t offFloorZ;
int32_t onFloorZ;
uint32_t windVel; // Wind vel (changed from 10 bit to use higher velocity values)
uint16_t data; // Data
uint16_t txID; // TX ID
uint16_t rxID; // RX ID
uint16_t busyTimeA; // OFF->ON busyTime
uint16_t waitTimeA; // OFF->ON waitTime
uint16_t panAngle; // Motion angle
uint16_t busyTimeB; // ON->OFF busyTime
uint16_t waitTimeB; // ON->OFF waitTime
DBloodActor* marker0;
DBloodActor* marker1;
DBloodActor* basePath;
DBloodActor* actordata;
uint16_t windAng; // Wind ang
uint16_t bobTheta; // Motion Theta
int16_t bobSpeed; // Motion speed
uint8_t busyWaveA; // OFF->ON wave
uint8_t busyWaveB; // ON->OFF wave
uint8_t command; // Cmd
int8_t amplitude; // Lighting amplitude
uint8_t freq; // Lighting freq
uint8_t phase; // Lighting phase
uint8_t wave; // Lighting wave
int8_t shade; // Lighting value
uint8_t panVel; // Motion speed
uint8_t Depth; // Depth
uint8_t Key; // Key
uint8_t ceilpal; // Ceil pal2
uint8_t damageType; // DamageType
uint8_t floorpal; // Floor pal2
uint8_t bobZRange; // Motion Z range
};
struct XWALL {
union
{
uint32_t flags;
struct {
unsigned int state : 1; // State
unsigned int triggerOn : 1; // going ON
unsigned int triggerOff : 1; // going OFF
unsigned int restState : 1; // restState
unsigned int interruptable : 1; // Interruptable
unsigned int panAlways : 1; // panAlways
unsigned int decoupled : 1; // Decoupled
unsigned int triggerOnce : 1; // 1-shot
unsigned int isTriggered : 1;
unsigned int triggerPush : 1; // Push
unsigned int triggerVector : 1; // Vector
unsigned int triggerTouch : 1; // by NoOne: renamed from Reserved to Touch as it works with Touch now.
unsigned int locked : 1; // Locked
unsigned int dudeLockout : 1; // DudeLockout
};
};
uint32_t busy;
int16_t data; // Data
uint16_t txID; // TX ID
uint16_t rxID; // RX ID
uint16_t busyTime; // busyTime
uint16_t waitTime; // waitTime
uint8_t command; // Cmd
int8_t panXVel; // panX
int8_t panYVel; // panY
uint8_t key; // Key
};
struct MAPSIGNATURE {
char signature[4];
@ -294,7 +86,6 @@ extern bool drawtile2048, encrypted;
extern MAPHEADER2 byte_19AE44;
extern XSECTOR xsector[kMaxXSectors];
extern XWALL xwall[kMaxXWalls];
extern uint8_t qsector_filler[kMaxSectors];
@ -304,7 +95,7 @@ extern const char *gItemText[];
extern const char *gAmmoText[];
extern const char *gWeaponText[];
extern int XWallsUsed, XSectorsUsed;
extern int XSectorsUsed;
static inline int GetWallType(int nWall)
{
@ -358,11 +149,6 @@ void dbLoadMap(const char* pPath, int* pX, int* pY, int* pZ, short* pAngle, int*
END_BLD_NS
// refactoring aids.
inline Blood::XWALL& walltype::xw() const
{
return Blood::xwall[extra];
}
inline Blood::XSECTOR& sectortype::xs() const
{
return Blood::xsector[extra];

View file

@ -710,7 +710,6 @@ void SerializeState(FSerializer& arc)
.Array("velceil", velCeil, numsectors)
("hitinfo", gHitInfo)
.Array("statcount", gStatCount, kMaxStatus + 1)
("xwallsused", XWallsUsed)
("xsectorsused", XSectorsUsed)
("fogmode", gFogMode)
#ifdef NOONE_EXTENSIONS
@ -725,7 +724,6 @@ void SerializeState(FSerializer& arc)
("numtiles", pSky->lognumtiles)
("gameoptions", gGameOptions)
.Array("xwall", xwall, XWallsUsed) // todo
.Array("xsector", xsector, XSectorsUsed)
.SparseArray("actors", bloodActors, kMaxSprites, activeSprites);

View file

@ -0,0 +1,211 @@
// This is separate because the map loader needs knowledge about these types to allocate their instances.
#pragma once
#include "ns.h"
BEGIN_BLD_NS
class DBloodActor;
struct AISTATE;
struct XSPRITE {
AISTATE* aiState; // ai
union
{
uint32_t flags;
struct {
unsigned int state : 1; // State 0
unsigned int triggerOn : 1; // going ON
unsigned int triggerOff : 1; // going OFF
unsigned int restState : 1; // restState
unsigned int Interrutable : 1; // Interruptable
unsigned int Decoupled : 1; // Decoupled
unsigned int triggerOnce : 1; // 1-shot
unsigned int isTriggered : 1; // works in case if triggerOnce selected
unsigned int Push : 1; // Push
unsigned int Vector : 1; // Vector
unsigned int Impact : 1; // Impact
unsigned int Pickup : 1; // Pickup
unsigned int Touch : 1; // Touch
unsigned int Sight : 1; // Sight
unsigned int Proximity : 1; // Proximity
unsigned int lS : 1; // Single
unsigned int lB : 1; // Bloodbath
unsigned int lT : 1; // Launch Team
unsigned int lC : 1; // Coop
unsigned int DudeLockout : 1; // DudeLockout
unsigned int locked : 1; // Locked
unsigned int dudeDeaf : 1; // dudeDeaf
unsigned int dudeAmbush : 1; // dudeAmbush
unsigned int dudeGuard : 1; // dudeGuard
unsigned int dudeFlag4 : 1; // unused
unsigned int wave : 2; // Wave
unsigned int medium : 2; // medium
unsigned int respawn : 2; // Respawn option
unsigned int unused2 : 1; // (new) patrol state
};
};
DBloodActor* target; // target sprite
int32_t targetX; // target x
int32_t targetY; // target y
int32_t targetZ; // target z
int32_t sysData1; // used to keep here various system data, so user can't change it in map editor
int32_t sysData2; //
int32_t scale; // used for scaling SEQ size on sprites
uint32_t physAttr; // currently used by additional physics sprites to keep its attributes.
uint32_t health;
uint32_t busy;
int16_t data1; // Data 1
int16_t data2; // Data 2
int16_t data3; // Data 3
int16_t burnSource;
uint16_t txID; // TX ID
uint16_t rxID; // RX ID
uint16_t command; // Cmd
uint16_t busyTime; // busyTime
uint16_t waitTime; // waitTime
uint16_t data4; // Data 4
uint16_t goalAng; // Dude goal ang
uint16_t burnTime;
uint16_t height;
uint16_t stateTimer; // ai timer
uint8_t respawnPending; // respawnPending
uint8_t dropMsg; // Drop Item
uint8_t key; // Key
uint8_t lSkill; // Launch 12345
uint8_t lockMsg; // Lock msg
int8_t dodgeDir; // Dude dodge direction
uint8_t unused1; // modern flags
uint8_t unused3; // something about sight checks
uint8_t unused4; // patrol turn delay
};
struct XSECTOR {
union
{
uint64_t flags;
struct {
unsigned int state : 1; // State
unsigned int triggerOn : 1; // Send at ON
unsigned int triggerOff : 1; // Send at OFF
unsigned int restState : 1;
unsigned int interruptable : 1; // Interruptable
unsigned int reTriggerA : 1; // OFF->ON wait
unsigned int reTriggerB : 1; // ON->OFF wait
unsigned int shadeAlways : 1; // Lighting shadeAlways
unsigned int shadeFloor : 1; // Lighting floor
unsigned int shadeCeiling : 1; // Lighting ceiling
unsigned int shadeWalls : 1; // Lighting walls
unsigned int panAlways : 1; // Pan always
unsigned int panFloor : 1; // Pan floor
unsigned int panCeiling : 1; // Pan ceiling
unsigned int Drag : 1; // Pan drag
unsigned int Underwater : 1; // Underwater
unsigned int decoupled : 1; // Decoupled
unsigned int triggerOnce : 1; // 1-shot
unsigned int isTriggered : 1;
unsigned int Push : 1; // Push
unsigned int Vector : 1; // Vector
unsigned int Reserved : 1; // Reserved
unsigned int Enter : 1; // Enter
unsigned int Exit : 1; // Exit
unsigned int Wallpush : 1; // WallPush
unsigned int color : 1; // Color Lights
unsigned int stopOn : 1;
unsigned int stopOff : 1;
unsigned int Crush : 1; // Crush
unsigned int locked : 1; // Locked
unsigned int windAlways : 1; // Wind always
unsigned int dudeLockout : 1;
unsigned int bobAlways : 1; // Motion always
unsigned int bobFloor : 1; // Motion bob floor
unsigned int bobCeiling : 1; // Motion bob ceiling
unsigned int bobRotate : 1; // Motion rotate
unsigned int unused1 : 1; // (new) pause motion
};
};
DBloodActor* marker0;
DBloodActor* marker1;
DBloodActor* basePath;
DBloodActor* actordata;
uint32_t busy;
int32_t offCeilZ;
int32_t onCeilZ;
int32_t offFloorZ;
int32_t onFloorZ;
uint32_t windVel; // Wind vel (changed from 10 bit to use higher velocity values)
uint16_t data; // Data
uint16_t txID; // TX ID
uint16_t rxID; // RX ID
uint16_t busyTimeA; // OFF->ON busyTime
uint16_t waitTimeA; // OFF->ON waitTime
uint16_t panAngle; // Motion angle
uint16_t busyTimeB; // ON->OFF busyTime
uint16_t waitTimeB; // ON->OFF waitTime
uint16_t windAng; // Wind ang
uint16_t bobTheta; // Motion Theta
int16_t bobSpeed; // Motion speed
uint8_t busyWaveA; // OFF->ON wave
uint8_t busyWaveB; // ON->OFF wave
uint8_t command; // Cmd
int8_t amplitude; // Lighting amplitude
uint8_t freq; // Lighting freq
uint8_t phase; // Lighting phase
uint8_t wave; // Lighting wave
int8_t shade; // Lighting value
uint8_t panVel; // Motion speed
uint8_t Depth; // Depth
uint8_t Key; // Key
uint8_t ceilpal; // Ceil pal2
uint8_t damageType; // DamageType
uint8_t floorpal; // Floor pal2
uint8_t bobZRange; // Motion Z range
};
struct XWALL {
union
{
uint32_t flags;
struct {
unsigned int state : 1; // State
unsigned int triggerOn : 1; // going ON
unsigned int triggerOff : 1; // going OFF
unsigned int restState : 1; // restState
unsigned int interruptable : 1; // Interruptable
unsigned int panAlways : 1; // panAlways
unsigned int decoupled : 1; // Decoupled
unsigned int triggerOnce : 1; // 1-shot
unsigned int isTriggered : 1;
unsigned int triggerPush : 1; // Push
unsigned int triggerVector : 1; // Vector
unsigned int triggerTouch : 1; // by NoOne: renamed from Reserved to Touch as it works with Touch now.
unsigned int locked : 1; // Locked
unsigned int dudeLockout : 1; // DudeLockout
};
};
uint32_t busy;
int16_t data; // Data
uint16_t txID; // TX ID
uint16_t rxID; // RX ID
uint16_t busyTime; // busyTime
uint16_t waitTime; // waitTime
uint8_t command; // Cmd
int8_t panXVel; // panX
int8_t panYVel; // panY
uint8_t key; // Key
};
END_BLD_NS