2020-12-02 11:46:44 +00:00
|
|
|
#pragma once
|
|
|
|
|
2021-11-25 20:42:49 +00:00
|
|
|
#include "coreactor.h"
|
|
|
|
|
2020-12-02 11:46:44 +00:00
|
|
|
BEGIN_BLD_NS
|
|
|
|
|
2021-09-02 18:23:51 +00:00
|
|
|
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;
|
|
|
|
}
|
2021-11-23 23:18:14 +00:00
|
|
|
int setSector(sectortype* num)
|
|
|
|
{
|
|
|
|
type = kHitSector;
|
|
|
|
index = sectnum(num);
|
|
|
|
legacyVal = type | index;
|
|
|
|
actor = nullptr;
|
|
|
|
return kHitSector;
|
|
|
|
}
|
2021-09-02 18:23:51 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2021-11-21 08:45:50 +00:00
|
|
|
walltype* wall() const
|
2021-09-02 18:23:51 +00:00
|
|
|
{
|
|
|
|
assert(type == kHitWall);
|
|
|
|
return &::wall[index];
|
|
|
|
}
|
|
|
|
|
2021-11-21 08:45:50 +00:00
|
|
|
sectortype* sector() const
|
2021-09-02 18:23:51 +00:00
|
|
|
{
|
|
|
|
assert(type == kHitSector);
|
|
|
|
return &::sector[index];
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
struct SPRITEHIT
|
|
|
|
{
|
|
|
|
Collision hit, ceilhit, florhit;
|
|
|
|
};
|
|
|
|
|
2021-11-25 20:42:49 +00:00
|
|
|
class DBloodActor : public DCoreActor
|
2020-12-02 11:46:44 +00:00
|
|
|
{
|
2021-05-05 08:12:31 +00:00
|
|
|
DBloodActor* base();
|
2020-12-02 11:46:44 +00:00
|
|
|
|
|
|
|
public:
|
2021-05-05 08:12:31 +00:00
|
|
|
int dudeSlope;
|
2021-09-05 08:09:59 +00:00
|
|
|
int xvel, yvel, zvel;
|
|
|
|
bool hasx;
|
|
|
|
XSPRITE xsprite;
|
2021-08-29 17:09:29 +00:00
|
|
|
SPRITEHIT hit;
|
2020-12-04 22:21:42 +00:00
|
|
|
DUDEEXTRA dudeExtra;
|
2021-09-01 19:53:33 +00:00
|
|
|
SPRITEMASS spriteMass;
|
2021-08-29 07:27:03 +00:00
|
|
|
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;
|
2021-11-23 18:37:38 +00:00
|
|
|
EventObject condition[2];
|
2021-09-05 08:09:59 +00:00
|
|
|
bool explosionhackflag; // this originally hijacked the target field which is not safe when working with pointers.
|
2021-09-01 19:53:33 +00:00
|
|
|
|
2021-08-28 13:43:34 +00:00
|
|
|
// transient data (not written to savegame)
|
|
|
|
int cumulDamage;
|
2021-09-05 10:35:13 +00:00
|
|
|
bool interpolated;
|
2020-11-07 15:26:14 +00:00
|
|
|
|
2021-11-25 20:42:49 +00:00
|
|
|
DBloodActor()
|
|
|
|
{
|
|
|
|
index = (int(this - base()));
|
|
|
|
}
|
|
|
|
|
2021-05-05 08:12:31 +00:00
|
|
|
DBloodActor& operator=(const DBloodActor& other) = default;
|
|
|
|
|
2020-12-02 19:22:13 +00:00
|
|
|
void Clear()
|
|
|
|
{
|
|
|
|
dudeSlope = 0;
|
2021-09-04 17:53:31 +00:00
|
|
|
hit = {};
|
2020-12-04 22:21:42 +00:00
|
|
|
dudeExtra = {};
|
2021-09-01 19:53:33 +00:00
|
|
|
spriteMass = {};
|
2021-09-04 17:53:31 +00:00
|
|
|
genDudeExtra = {};
|
|
|
|
prevmarker = nullptr;
|
2021-09-04 10:23:36 +00:00
|
|
|
basePoint = {};
|
2021-09-05 08:09:59 +00:00
|
|
|
xsprite = {};
|
|
|
|
hasx = false;
|
2021-09-05 10:35:13 +00:00
|
|
|
interpolated = false;
|
2021-09-04 10:52:02 +00:00
|
|
|
xvel = yvel = zvel = 0;
|
2021-09-04 17:53:31 +00:00
|
|
|
explosionhackflag = false;
|
|
|
|
interpolated = false;
|
2020-12-02 19:22:13 +00:00
|
|
|
}
|
2021-09-05 08:09:59 +00:00
|
|
|
bool hasX() { return hasx; }
|
|
|
|
void addX() { hasx = true; }
|
|
|
|
|
|
|
|
XSPRITE& x() { return xsprite; } // calling this does not validate the xsprite!
|
2020-12-02 11:46:44 +00:00
|
|
|
|
2020-12-02 19:22:13 +00:00
|
|
|
void SetOwner(DBloodActor* own)
|
|
|
|
{
|
2021-11-19 20:19:18 +00:00
|
|
|
ownerActor = own;
|
2020-12-02 19:22:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
DBloodActor* GetOwner()
|
|
|
|
{
|
2021-11-19 20:19:18 +00:00
|
|
|
return ownerActor;
|
2020-12-02 19:22:13 +00:00
|
|
|
}
|
|
|
|
|
2020-12-03 17:00:07 +00:00
|
|
|
void SetTarget(DBloodActor* own)
|
|
|
|
{
|
2021-11-19 19:54:13 +00:00
|
|
|
x().target = own;
|
2020-12-03 17:00:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
DBloodActor* GetTarget()
|
|
|
|
{
|
2021-11-19 19:54:13 +00:00
|
|
|
return x().target;
|
2020-12-03 17:00:07 +00:00
|
|
|
}
|
|
|
|
|
2021-05-05 08:12:31 +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)
|
|
|
|
{
|
2021-09-05 17:05:06 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2020-12-02 19:22:13 +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;
|
|
|
|
}
|
|
|
|
}
|
2020-12-02 11:46:44 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
extern DBloodActor bloodActors[kMaxSprites];
|
|
|
|
|
|
|
|
inline DBloodActor* DBloodActor::base() { return bloodActors; }
|
|
|
|
|
2020-12-02 16:10:00 +00:00
|
|
|
// 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)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2021-11-23 17:55:20 +00:00
|
|
|
BloodSectIterator(sectortype* stat) : SectIterator(stat)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2020-12-02 16:10:00 +00:00
|
|
|
DBloodActor* Next()
|
|
|
|
{
|
|
|
|
int n = NextIndex();
|
|
|
|
return n >= 0 ? &bloodActors[n] : nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
DBloodActor* Peek()
|
|
|
|
{
|
|
|
|
int n = PeekIndex();
|
|
|
|
return n >= 0 ? &bloodActors[n] : nullptr;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-08-29 18:47:51 +00:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2021-08-29 18:47:51 +00:00
|
|
|
DBloodActor* Next()
|
|
|
|
{
|
|
|
|
while (index < MAXSPRITES)
|
|
|
|
{
|
|
|
|
auto p = &bloodActors[index++];
|
|
|
|
if (p->s().statnum != kStatFree) return p;
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
2020-12-02 19:05:53 +00:00
|
|
|
inline int DeleteSprite(DBloodActor* nSprite)
|
|
|
|
{
|
2021-09-05 17:05:06 +00:00
|
|
|
if (nSprite) return DeleteSprite(nSprite->GetSpriteIndex());
|
2020-12-02 19:05:53 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-12-02 22:39:38 +00:00
|
|
|
inline void GetActorExtents(DBloodActor* actor, int* top, int* bottom)
|
|
|
|
{
|
|
|
|
GetSpriteExtents(&actor->s(), top, bottom);
|
|
|
|
}
|
|
|
|
|
2020-12-04 23:08:51 +00:00
|
|
|
inline DBloodActor* getUpperLink(int sect)
|
|
|
|
{
|
2021-11-20 17:42:19 +00:00
|
|
|
auto pSect = §or[sect];
|
|
|
|
return pSect->upperLink;
|
2020-12-04 23:08:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
inline DBloodActor* getLowerLink(int sect)
|
|
|
|
{
|
2021-11-20 17:42:19 +00:00
|
|
|
auto pSect = §or[sect];
|
|
|
|
return pSect->lowerLink;
|
2020-12-04 23:08:51 +00:00
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2021-09-02 18:23:51 +00:00
|
|
|
inline void ChangeActorStat(DBloodActor* actor, int stat)
|
2021-08-27 14:38:53 +00:00
|
|
|
{
|
2021-09-05 17:05:06 +00:00
|
|
|
ChangeSpriteStat(actor->GetSpriteIndex(), stat);
|
2021-08-27 14:38:53 +00:00
|
|
|
}
|
|
|
|
|
2021-09-02 18:23:51 +00:00
|
|
|
inline void ChangeActorSect(DBloodActor* actor, int stat)
|
2021-08-27 14:38:53 +00:00
|
|
|
{
|
2021-09-05 17:05:06 +00:00
|
|
|
ChangeSpriteSect(actor->GetSpriteIndex(), stat);
|
2021-08-27 14:38:53 +00:00
|
|
|
}
|
2021-09-02 18:23:51 +00:00
|
|
|
|
2021-11-23 23:16:02 +00:00
|
|
|
inline void ChangeActorSect(DBloodActor* actor, sectortype* stat)
|
|
|
|
{
|
|
|
|
ChangeSpriteSect(actor->GetSpriteIndex(), sectnum(stat));
|
|
|
|
}
|
|
|
|
|
2021-09-02 18:23:51 +00:00
|
|
|
inline int Collision::actorIndex(DBloodActor* actor)
|
|
|
|
{
|
|
|
|
return int(actor - bloodActors);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline DBloodActor* Collision::Actor(int a)
|
|
|
|
{
|
|
|
|
return &bloodActors[a];
|
|
|
|
}
|
|
|
|
|
2021-08-28 11:59:29 +00:00
|
|
|
inline void setActorPos(DBloodActor* actor, vec3_t* pos)
|
|
|
|
{
|
2021-09-05 17:05:06 +00:00
|
|
|
setsprite(actor->GetSpriteIndex(), pos);
|
2021-08-28 11:59:29 +00:00
|
|
|
}
|
|
|
|
|
2020-12-02 11:46:44 +00:00
|
|
|
END_BLD_NS
|