raze/source/games/blood/src/bloodactor.h

415 lines
8.3 KiB
C
Raw Normal View History

#pragma once
BEGIN_BLD_NS
class DBloodActor;
// Wrapper around the insane collision info mess from Build.
struct Collision
{
int type;
int index;
int legacyVal; // should be removed later, but needed for converting back for unadjusted code.
DBloodActor* actor;
Collision() = default;
Collision(int legacyval) { setFromEngine(legacyval); }
// need forward declarations of these.
int actorIndex(DBloodActor*);
DBloodActor* Actor(int);
int setNone()
{
type = kHitNone;
index = -1;
legacyVal = 0;
actor = nullptr;
return kHitNone;
}
int setSector(int num)
{
type = kHitSector;
index = num;
legacyVal = type | index;
actor = nullptr;
return kHitSector;
}
int setWall(int num)
{
type = kHitWall;
index = num;
legacyVal = type | index;
actor = nullptr;
return kHitWall;
}
int setSprite(DBloodActor* num)
{
type = kHitSprite;
index = -1;
legacyVal = type | actorIndex(num);
actor = num;
return kHitSprite;
}
int setFromEngine(int value)
{
legacyVal = value;
type = value & kHitTypeMask;
if (type == 0) { index = -1; actor = nullptr; }
else if (type != kHitSprite) { index = value & kHitIndexMask; actor = nullptr; }
else { index = -1; actor = Actor(value & kHitIndexMask); }
return type;
}
walltype* wall()
{
assert(type == kHitWall);
return &::wall[index];
}
sectortype* sector()
{
assert(type == kHitSector);
return &::sector[index];
}
};
struct SPRITEHIT
{
Collision hit, ceilhit, florhit;
};
struct ConditionElement
{
int type;
int index;
DBloodActor* actor;
bool operator==(const ConditionElement& other) const
{
if (type != other.type) return false;
if (type == kCondSerialSprite && actor != other.actor) return false;
if (type != kCondSerialSprite && index != other.index) return false;
return true;
}
bool operator!=(const ConditionElement& other) const
{
return !(operator==(other));
}
};
// Due to the messed up array storage of all the game data we cannot do any direct references here yet. We have to access everything via wrapper functions for now.
// Note that the indexing is very inconsistent - partially by sprite index, partially by xsprite index.
class DBloodActor
{
int index;
DBloodActor* base();
public:
int dudeSlope;
int xvel, yvel, zvel;
bool hasx;
XSPRITE xsprite;
2021-08-29 17:09:29 +00:00
SPRITEHIT hit;
DUDEEXTRA dudeExtra;
2021-09-01 19:53:33 +00:00
SPRITEMASS spriteMass;
GENDUDEEXTRA genDudeExtra;
2021-08-29 13:57:42 +00:00
DBloodActor* prevmarker; // needed by the nnext marker code. This originally hijacked targetX in XSPRITE
2021-11-19 20:19:18 +00:00
DBloodActor* ownerActor; // was previously stored in the sprite's owner field.
2021-09-04 10:23:36 +00:00
POINT3D basePoint;
ConditionElement condition[2];
bool explosionhackflag; // this originally hijacked the target field which is not safe when working with pointers.
2021-09-01 19:53:33 +00:00
// transient data (not written to savegame)
int cumulDamage;
bool interpolated;
DBloodActor() :index(int(this - base())) {}
DBloodActor& operator=(const DBloodActor& other) = default;
void Clear()
{
dudeSlope = 0;
hit = {};
dudeExtra = {};
2021-09-01 19:53:33 +00:00
spriteMass = {};
genDudeExtra = {};
prevmarker = nullptr;
2021-09-04 10:23:36 +00:00
basePoint = {};
xsprite = {};
hasx = false;
interpolated = false;
xvel = yvel = zvel = 0;
explosionhackflag = false;
interpolated = false;
}
bool hasX() { return hasx; }
void addX() { hasx = true; }
spritetype& s() { return sprite[index]; }
XSPRITE& x() { return xsprite; } // calling this does not validate the xsprite!
int GetIndex() { return s().time; } // For error printing only! This is only identical with the sprite index for items spawned at map start.
int GetSpriteIndex() { return index; } // this is only here to mark places that need changing later!
void SetOwner(DBloodActor* own)
{
2021-11-19 20:19:18 +00:00
ownerActor = own;
}
DBloodActor* GetOwner()
{
2021-11-19 20:19:18 +00:00
return ownerActor;
}
2020-12-03 17:00:07 +00:00
void SetTarget(DBloodActor* own)
{
x().target_i = own ? own->GetSpriteIndex() : -1;
2020-12-03 17:00:07 +00:00
}
DBloodActor* GetTarget()
{
if (x().target_i <= -1 || x().target_i == kMaxSprites - 1) return nullptr;
return base() + x().target_i;
2020-12-03 17:00:07 +00:00
}
bool ValidateTarget(const char* func)
{
if (GetTarget() == nullptr)
{
Printf(PRINT_HIGH | PRINT_NOTIFY, "%s: invalid target in calling actor\n", func);
return false;
}
return true;
}
2020-12-03 19:30:30 +00:00
void SetBurnSource(DBloodActor* own)
{
x().burnSource = own ? own->GetSpriteIndex() : -1;
2020-12-03 19:30:30 +00:00
}
DBloodActor* GetBurnSource()
{
if (x().burnSource == -1 || x().burnSource == kMaxSprites - 1) return nullptr;
return base() + x().burnSource;
}
2020-12-02 23:30:19 +00:00
void SetSpecialOwner() // nnext hackery
{
2021-11-19 20:19:18 +00:00
ownerActor = nullptr;
2020-12-02 23:30:19 +00:00
s().owner = kMaxSprites - 1;
}
bool GetSpecialOwner()
{
2021-11-19 20:19:18 +00:00
return ownerActor == nullptr && (s().owner == kMaxSprites - 1);
2020-12-02 23:30:19 +00:00
}
bool IsPlayerActor()
{
return s().type >= kDudePlayer1 && s().type <= kDudePlayer8;
}
bool IsDudeActor()
{
return s().type >= kDudeBase && s().type < kDudeMax;
}
bool IsItemActor()
{
return s().type >= kItemBase && s().type < kItemMax;
}
bool IsWeaponActor()
{
return s().type >= kItemWeaponBase && s().type < kItemWeaponMax;
}
bool IsAmmoActor()
{
return s().type >= kItemAmmoBase && s().type < kItemAmmoMax;
}
2020-12-03 19:30:30 +00:00
bool isActive()
{
if (!hasX())
return false;
switch (x().aiState->stateType)
{
case kAiStateIdle:
case kAiStateGenIdle:
case kAiStateSearch:
case kAiStateMove:
case kAiStateOther:
return false;
default:
return true;
}
}
};
extern DBloodActor bloodActors[kMaxSprites];
inline DBloodActor* DBloodActor::base() { return bloodActors; }
// Iterator wrappers that return an actor pointer, not an index.
class BloodStatIterator : public StatIterator
{
public:
BloodStatIterator(int stat) : StatIterator(stat)
{
}
DBloodActor* Next()
{
int n = NextIndex();
return n >= 0 ? &bloodActors[n] : nullptr;
}
DBloodActor* Peek()
{
int n = PeekIndex();
return n >= 0 ? &bloodActors[n] : nullptr;
}
};
class BloodSectIterator : public SectIterator
{
public:
BloodSectIterator(int stat) : SectIterator(stat)
{
}
DBloodActor* Next()
{
int n = NextIndex();
return n >= 0 ? &bloodActors[n] : nullptr;
}
DBloodActor* Peek()
{
int n = PeekIndex();
return n >= 0 ? &bloodActors[n] : nullptr;
}
};
// An iterator to iterate over all sprites.
class BloodSpriteIterator
{
BloodStatIterator it;
int stat = kStatDecoration;
public:
BloodSpriteIterator() : it(kStatDecoration) {}
DBloodActor* Next()
{
while (stat < kStatFree)
{
auto ac = it.Next();
if (ac) return ac;
stat++;
if (stat < kStatFree) it.Reset(stat);
}
return nullptr;
}
};
// For iterating linearly over map spawned sprites.
class BloodLinearSpriteIterator
{
int index = 0;
public:
2021-09-05 06:27:34 +00:00
void Reset()
{
index = 0;
}
DBloodActor* Next()
{
while (index < MAXSPRITES)
{
auto p = &bloodActors[index++];
if (p->s().statnum != kStatFree) return p;
}
return nullptr;
}
};
inline int DeleteSprite(DBloodActor* nSprite)
{
if (nSprite) return DeleteSprite(nSprite->GetSpriteIndex());
return 0;
}
2020-12-02 22:39:38 +00:00
inline void GetActorExtents(DBloodActor* actor, int* top, int* bottom)
{
GetSpriteExtents(&actor->s(), top, bottom);
}
inline DBloodActor* getUpperLink(int sect)
{
return gUpperLink[sect];
}
inline DBloodActor* getLowerLink(int sect)
{
return gLowerLink[sect];
}
inline FSerializer& Serialize(FSerializer& arc, const char* keyname, DBloodActor*& w, DBloodActor** def)
{
int index = w? int(w - bloodActors) : -1;
Serialize(arc, keyname, index, nullptr);
if (arc.isReading()) w = index == -1? nullptr : &bloodActors[index];
return arc;
}
2021-09-15 22:12:28 +00:00
inline void sfxPlay3DSound(DBloodActor* pSprite, int soundId, int a3 = -1, int a4 = 0)
{
sfxPlay3DSound(&pSprite->s(), soundId, a3, a4);
}
inline void sfxPlay3DSoundCP(DBloodActor* pSprite, int soundId, int a3 = -1, int a4 = 0, int pitch = 0, int volume = 0)
{
sfxPlay3DSoundCP(&pSprite->s(), soundId, a3, a4, pitch, volume);
}
inline void sfxKill3DSound(DBloodActor* pSprite, int a2 = -1, int a3 = -1)
{
sfxKill3DSound(&pSprite->s(), a2, a3);
}
inline void ChangeActorStat(DBloodActor* actor, int stat)
2021-08-27 14:38:53 +00:00
{
ChangeSpriteStat(actor->GetSpriteIndex(), stat);
2021-08-27 14:38:53 +00:00
}
inline void ChangeActorSect(DBloodActor* actor, int stat)
2021-08-27 14:38:53 +00:00
{
ChangeSpriteSect(actor->GetSpriteIndex(), stat);
2021-08-27 14:38:53 +00:00
}
inline int Collision::actorIndex(DBloodActor* actor)
{
return int(actor - bloodActors);
}
inline DBloodActor* Collision::Actor(int a)
{
return &bloodActors[a];
}
inline void setActorPos(DBloodActor* actor, vec3_t* pos)
{
setsprite(actor->GetSpriteIndex(), pos);
}
END_BLD_NS