Finish CSpacePirate implementation

This commit is contained in:
Jack Andersen 2018-12-12 21:39:16 -10:00
parent 14747e39e1
commit ec1cb75b25
37 changed files with 2337 additions and 503 deletions

View File

@ -12,6 +12,25 @@
<option name="SPACE_AFTER_REFERENCE_IN_DECLARATION" value="true" />
</Objective-C>
<Objective-C-extensions>
<file>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" />
</file>
<class>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" />
</class>
<extensions>
<pair source="cpp" header="hpp" fileNamingConvention="NONE" />
<pair source="c" header="h" fileNamingConvention="NONE" />

View File

@ -268,7 +268,7 @@ struct PatternedInfo : BigDNA {
Value<float> intoFreezeDur;
Value<float> outOfFreezeDur;
Value<float> unknown10;
Value<atUint32> particle1Frames;
Value<atUint32> pathfindingIndex;
Value<atVec3f> particle1Scale;
UniqueID32 particle1;
UniqueID32 electric;

View File

@ -14,57 +14,76 @@ struct SpacePirate : IScriptObject {
Value<atVec3f> scale;
PatternedInfo patternedInfo;
ActorParameters actorParameters;
Value<float> unknown1;
Value<float> unknown2;
Value<float> unknown3;
Value<float> unknown4;
Value<float> unknown5;
Value<float> unknown6;
Value<atUint32> unknown7;
Value<float> AggressionCheck;
Value<float> CoverCheck;
Value<float> SearchRadius;
Value<float> FallBackCheck;
Value<float> FallBackRadius;
Value<float> HearingRadius;
/*
* 0x1: pendingAmbush
* 0x2: ceilingAmbush
* 0x4: nonAggressive
* 0x8: melee
* 0x10: noShuffleCloseCheck
* 0x20: onlyAttackInRange
* 0x40: unk
* 0x80: noKnockbackImpulseReset
* 0x200: noMeleeAttack
* 0x400: breakAttack
* 0x1000: seated
* 0x2000: shadowPirate
* 0x4000: alertBeforeCloak
* 0x8000: noBreakDodge
* 0x10000: floatingCorpse
* 0x20000: ragdollNoAiCollision
* 0x40000: trooper
*/
Value<atUint32> flags;
Value<bool> unknown8;
UniqueID32 wpsc1;
DamageInfo damageInfo1;
Value<atUint32> soundID1;
DamageInfo damageInfo2;
Value<float> unknown9;
UniqueID32 wpsc2;
DamageInfo damageInfo3;
Value<float> unknown10;
Value<atUint32> soundID2;
Value<float> unknown11;
Value<float> unknown12;
Value<atUint32> soundID3;
Value<float> unknown13;
Value<atUint32> unknown14;
Value<float> unknown15;
Value<float> unknown16;
Value<float> unknown17;
Value<float> unknown18;
Value<atUint32> soundID4;
Value<atUint32> soundID5;
UniqueID32 Projectile;
DamageInfo ProjectileDamage;
Value<atUint32> Sound_Projectile;
DamageInfo BladeDamage;
Value<float> KneelAttackChance;
UniqueID32 KneelAttackShot;
DamageInfo KneelAttackDamage;
Value<float> DodgeCheck;
Value<atUint32> Sound_Impact;
Value<float> averageNextShotTime;
Value<float> nextShotTimeVariation;
Value<atUint32> Sound_Alert;
Value<float> GunTrackDelay;
Value<atUint32> firstBurstCount;
Value<float> CloakOpacity;
Value<float> MaxCloakOpacity;
Value<float> dodgeDelayTimeMin;
Value<float> dodgeDelayTimeMax;
Value<atUint32> Sound_Hurled;
Value<atUint32> Sound_Death;
Value<float> unknown19;
Value<float> unknown20;
Value<float> AvoidDistance;
void addCMDLRigPairs(PAKRouter<PAKBridge>& pakRouter, CharacterAssociations<UniqueID32>& charAssoc) const {
actorParameters.addCMDLRigPairs(pakRouter, charAssoc, patternedInfo.animationParameters);
}
void nameIDs(PAKRouter<PAKBridge>& pakRouter) const {
if (wpsc1) {
PAK::Entry* ent = (PAK::Entry*)pakRouter.lookupEntry(wpsc1);
ent->name = name + "_wpsc1";
if (Projectile) {
PAK::Entry* ent = (PAK::Entry*)pakRouter.lookupEntry(Projectile);
ent->name = name + "_Projectile";
}
if (wpsc2) {
PAK::Entry* ent = (PAK::Entry*)pakRouter.lookupEntry(wpsc2);
ent->name = name + "_wpsc2";
if (KneelAttackShot) {
PAK::Entry* ent = (PAK::Entry*)pakRouter.lookupEntry(KneelAttackShot);
ent->name = name + "_KneelAttackShot";
}
patternedInfo.nameIDs(pakRouter, name + "_patterned");
actorParameters.nameIDs(pakRouter, name + "_actp");
}
void gatherDependencies(std::vector<hecl::ProjectPath>& pathsOut, std::vector<hecl::ProjectPath>& lazyOut) const {
g_curSpec->flattenDependencies(wpsc1, pathsOut);
g_curSpec->flattenDependencies(wpsc2, pathsOut);
g_curSpec->flattenDependencies(Projectile, pathsOut);
g_curSpec->flattenDependencies(KneelAttackShot, pathsOut);
patternedInfo.depIDs(pathsOut);
actorParameters.depIDs(pathsOut, lazyOut);
}

View File

@ -11,20 +11,20 @@ class CRandom16 {
public:
CRandom16(u32 p = 99) : m_seed(p) {}
inline u32 Next() {
u32 Next() {
m_seed = (m_seed * 0x41c64e6d) + 0x00003039;
return m_seed >> 16;
}
inline u32 GetSeed() const { return m_seed; }
u32 GetSeed() const { return m_seed; }
inline void SetSeed(u32 p) { m_seed = p; }
void SetSeed(u32 p) { m_seed = p; }
inline float Float() { return Next() * 0.000015259022f; }
float Float() { return Next() * 0.000015259022f; }
inline float Range(float min, float max) { return min + Float() * (max - min); }
float Range(float min, float max) { return min + Float() * (max - min); }
inline s32 Range(s32 min, s32 max) { return min + (Next() % ((max - min) + 1)); }
s32 Range(s32 min, s32 max) { return min + (Next() % ((max - min) + 1)); }
static CRandom16* GetRandomNumber() { return g_randomNumber; }
static void SetRandomNumber(CRandom16* rnd) { g_randomNumber = rnd; }

View File

@ -2281,6 +2281,14 @@ CRayCastResult CStateManager::RayWorldIntersection(TUniqueId& idOut, const zeus:
return CGameCollision::RayWorldIntersection(*this, idOut, pos, dir, length, filter, list);
}
zeus::CVector3f CStateManager::Random2f(float scaleMin, float scaleMax) {
zeus::CVector3f ret(x900_activeRandom->Float() - 0.5f, x900_activeRandom->Float() - 0.5f, 0.f);
if (std::fabs(ret.x()) < 0.001f)
ret.x() = 0.001f;
ret.normalize();
return ret * ((scaleMax - scaleMin) * x900_activeRandom->Float() + scaleMin);
}
void CStateManager::UpdateObjectInLists(CEntity& ent) {
for (auto& list : x808_objLists) {
if (list->GetValidObjectById(ent.GetUniqueId()))

View File

@ -363,6 +363,7 @@ public:
const std::shared_ptr<CPlayerState>& GetPlayerState() const { return x8b8_playerState; }
CRandom16* GetActiveRandom() { return x900_activeRandom; }
zeus::CVector3f Random2f(float scaleMin, float scaleMax);
void SetActiveRandomToDefault() { x900_activeRandom = &x8fc_random; }
void ClearActiveRandom() { x900_activeRandom = nullptr; }
CRumbleManager& GetRumbleManager() { return *x88c_rumbleManager; }

View File

@ -6,7 +6,7 @@ namespace urde {
CBodyStateCmdMgr::CBodyStateCmdMgr() {
x40_commandTable.push_back(&xb8_getup);
x40_commandTable.push_back(&xc4_step);
x40_commandTable.push_back(&xd4_);
x40_commandTable.push_back(&xd4_die);
x40_commandTable.push_back(&xdc_knockDown);
x40_commandTable.push_back(&xf4_knockBack);
x40_commandTable.push_back(&x10c_meleeAttack);
@ -14,10 +14,10 @@ CBodyStateCmdMgr::CBodyStateCmdMgr() {
x40_commandTable.push_back(&x144_loopAttack);
x40_commandTable.push_back(&x154_loopReaction);
x40_commandTable.push_back(&x160_loopHitReaction);
x40_commandTable.push_back(&x16c_);
x40_commandTable.push_back(&x174_);
x40_commandTable.push_back(&x17c_);
x40_commandTable.push_back(&x184_);
x40_commandTable.push_back(&x16c_exitState);
x40_commandTable.push_back(&x174_leanFromCover);
x40_commandTable.push_back(&x17c_nextState);
x40_commandTable.push_back(&x184_maintainVelocity);
x40_commandTable.push_back(&x18c_generate);
x40_commandTable.push_back(&x1ac_hurled);
x40_commandTable.push_back(&x1d0_jump);
@ -26,12 +26,12 @@ CBodyStateCmdMgr::CBodyStateCmdMgr() {
x40_commandTable.push_back(&x21c_scripted);
x40_commandTable.push_back(&x230_cover);
x40_commandTable.push_back(&x254_wallHang);
x40_commandTable.push_back(&x260_);
x40_commandTable.push_back(&x268_);
x40_commandTable.push_back(&x260_locomotion);
x40_commandTable.push_back(&x268_additiveIdle);
x40_commandTable.push_back(&x270_additiveAim);
x40_commandTable.push_back(&x278_additiveFlinch);
x40_commandTable.push_back(&x284_additiveReaction);
x40_commandTable.push_back(&x298_);
x40_commandTable.push_back(&x298_stopReaction);
}
void CBodyStateCmdMgr::DeliverCmd(const CBCLocomotionCmd& cmd) {

View File

@ -315,7 +315,7 @@ class CBodyStateCmdMgr {
u32 xb4_deliveredCmdMask = 0;
CBCGetupCmd xb8_getup;
CBCStepCmd xc4_step;
CBodyStateCmd xd4_ = {EBodyStateCmd::Die};
CBodyStateCmd xd4_die = {EBodyStateCmd::Die};
CBCKnockDownCmd xdc_knockDown;
CBCKnockBackCmd xf4_knockBack;
CBCMeleeAttackCmd x10c_meleeAttack;
@ -323,10 +323,10 @@ class CBodyStateCmdMgr {
CBCLoopAttackCmd x144_loopAttack;
CBCLoopReactionCmd x154_loopReaction;
CBCLoopHitReactionCmd x160_loopHitReaction;
CBodyStateCmd x16c_ = {EBodyStateCmd::ExitState};
CBodyStateCmd x174_ = {EBodyStateCmd::LeanFromCover};
CBodyStateCmd x17c_ = {EBodyStateCmd::NextState};
CBodyStateCmd x184_ = {EBodyStateCmd::MaintainVelocity};
CBodyStateCmd x16c_exitState = {EBodyStateCmd::ExitState};
CBodyStateCmd x174_leanFromCover = {EBodyStateCmd::LeanFromCover};
CBodyStateCmd x17c_nextState = {EBodyStateCmd::NextState};
CBodyStateCmd x184_maintainVelocity = {EBodyStateCmd::MaintainVelocity};
CBCGenerateCmd x18c_generate;
CBCHurledCmd x1ac_hurled;
CBCJumpCmd x1d0_jump;
@ -335,12 +335,12 @@ class CBodyStateCmdMgr {
CBCScriptedCmd x21c_scripted;
CBCCoverCmd x230_cover;
CBCWallHangCmd x254_wallHang;
CBodyStateCmd x260_ = {EBodyStateCmd::Locomotion};
CBodyStateCmd x268_ = {EBodyStateCmd::AdditiveIdle};
CBodyStateCmd x260_locomotion = {EBodyStateCmd::Locomotion};
CBodyStateCmd x268_additiveIdle = {EBodyStateCmd::AdditiveIdle};
CBCAdditiveAimCmd x270_additiveAim;
CBCAdditiveFlinchCmd x278_additiveFlinch;
CBCAdditiveReactionCmd x284_additiveReaction;
CBodyStateCmd x298_ = {EBodyStateCmd::StopReaction};
CBodyStateCmd x298_stopReaction = {EBodyStateCmd::StopReaction};
void DeliverCmd(EBodyStateCmd cmd) { xb4_deliveredCmdMask |= (1 << int(cmd)); }
public:

View File

@ -9,16 +9,15 @@
namespace urde {
CBoneTracking::CBoneTracking(const CAnimData& animData, std::string_view bone, float f1, float f2, bool b1)
CBoneTracking::CBoneTracking(const CAnimData& animData, std::string_view bone,
float maxTrackingAngle, float angSpeed, bool parentIk)
: x14_segId(animData.GetCharLayoutInfo().GetSegIdFromString(bone))
, x1c_(f1)
, x20_(f2)
, x36_24_active(false)
, x36_25_(false)
, x36_26_(b1)
, x36_27_(b1)
, x36_28_(b1)
, x36_29_(b1) {}
, x1c_maxTrackingAngle(maxTrackingAngle)
, x20_angSpeed(angSpeed)
, x36_26_noParent(parentIk)
, x36_27_noParentOrigin(parentIk)
, x36_28_noHorizontalAim(parentIk)
, x36_29_parentIk(parentIk) {}
void CBoneTracking::Update(float dt) { x18_time += dt; }
@ -30,11 +29,71 @@ void CBoneTracking::PreRender(const CStateManager& mgr, CAnimData& animData, con
(bodyController.GetBodyStateInfo().ApplyHeadTracking() && patterned && patterned->ApplyBoneTracking()));
}
void CBoneTracking::PreRender(const CStateManager& mgr, CAnimData& animData, const zeus::CTransform& xf,
const zeus::CVector3f& vec, bool b) {
void CBoneTracking::PreRender(const CStateManager& mgr, CAnimData& animData, const zeus::CTransform& worldXf,
const zeus::CVector3f& localOffsetScale, bool tracking) {
if (x14_segId == 0)
return;
CHierarchyPoseBuilder& pb = animData.PoseBuilder();
TCastToConstPtr<CPatterned> targetAct = mgr.GetObjectById(x34_target);
if (x36_24_active && tracking && (targetAct || x24_targetPosition)) {
x36_25_hasTrackedRotation = true;
auto layoutInfo = pb.CharLayoutInfo();
CSegId bone;
if (x36_26_noParent)
bone = x14_segId;
else
bone = layoutInfo->GetRootNode()->GetBoneMap()[x14_segId].x0_parentId;
zeus::CTransform parentBoneXf;
pb.BuildTransform(bone, parentBoneXf);
zeus::CVector3f pos = parentBoneXf.origin;
if (x36_27_noParentOrigin && !x36_26_noParent) {
zeus::CTransform thisBoneXf;
pb.BuildTransform(x14_segId, thisBoneXf);
pos = thisBoneXf.origin;
}
parentBoneXf.origin = pos * localOffsetScale;
zeus::CTransform finalXf = worldXf * parentBoneXf;
zeus::CVector3f localDir = finalXf.transposeRotate(
(targetAct ? targetAct->GetAimPosition(mgr, 0.f) : *x24_targetPosition) - finalXf.origin).normalized();
if (x36_28_noHorizontalAim)
localDir = zeus::CVector3f(0.f, localDir.toVec2f().magnitude(), localDir.z());
if (x36_29_parentIk) {
float negElev = -parentBoneXf.basis[1].z();
zeus::CVector3f ikBase(0.f, std::sqrt(1.f - negElev * negElev), negElev);
float angle = zeus::CVector3f::getAngleDiff(ikBase, localDir);
angle = std::min(angle, x1c_maxTrackingAngle);
localDir = zeus::CVector3f::slerp(ikBase, localDir, angle);
} else {
float angle = zeus::CVector3f::getAngleDiff(zeus::CVector3f::skForward, localDir);
angle = std::min(angle, x1c_maxTrackingAngle);
localDir = zeus::CVector3f::slerp(zeus::CVector3f::skForward, localDir, angle);
}
float angle = zeus::CVector3f::getAngleDiff(x0_curRotation.transform(zeus::CVector3f::skForward), localDir);
float clampedAngle = std::min(angle, x18_time * x20_angSpeed);
if (clampedAngle > 1.0e-05f) {
x0_curRotation = zeus::CQuaternion::slerpShort(x0_curRotation,
zeus::CQuaternion::lookAt(zeus::CVector3f::skForward, zeus::CUnitVector3f(localDir), 2.f * M_PIF),
clampedAngle / angle);
}
pb.GetTreeMap()[x14_segId].x4_rotation = x0_curRotation;
animData.MarkPoseDirty();
} else if (x36_25_hasTrackedRotation) {
zeus::CQuaternion qb = pb.GetTreeMap()[x14_segId].x4_rotation;
float angle = zeus::CVector3f::getAngleDiff(x0_curRotation.transform(zeus::CVector3f::skForward),
qb.transform(zeus::CVector3f::skForward));
float maxAngDelta = x18_time * x20_angSpeed;
float clampedAngle = std::min(angle, maxAngDelta);
if (clampedAngle > 0.5f * maxAngDelta) {
x0_curRotation = zeus::CQuaternion::slerpShort(x0_curRotation, qb, clampedAngle / angle);
pb.GetTreeMap()[x14_segId].x4_rotation = x0_curRotation;
animData.MarkPoseDirty();
} else {
x36_25_hasTrackedRotation = false;
x0_curRotation = qb;
}
} else {
x0_curRotation = pb.GetTreeMap()[x14_segId].x4_rotation;
}
x18_time = 0.f;
}
@ -42,5 +101,9 @@ void CBoneTracking::SetActive(bool) { x36_24_active = true; }
void CBoneTracking::SetTarget(TUniqueId target) { x34_target = target; }
void CBoneTracking::UnsetTarget() { x34_target = kInvalidUniqueId; }
void CBoneTracking::SetTargetPosition(const zeus::CVector3f& targetPos) { x24_targetPosition = targetPos; }
void CBoneTracking::SetNoHorizontalAim(bool b) { x36_28_noHorizontalAim = b; }
} // namespace urde

View File

@ -12,28 +12,38 @@ class CAnimData;
class CStateManager;
class CBodyController;
class CBoneTracking {
zeus::CQuaternion x0_ = zeus::CQuaternion::skNoRotation;
zeus::CQuaternion x0_curRotation = zeus::CQuaternion::skNoRotation;
float x10_ = 0.f;
CSegId x14_segId;
float x18_time = 0.f;
float x1c_;
float x20_;
float x1c_maxTrackingAngle;
float x20_angSpeed;
std::experimental::optional<zeus::CVector3f> x24_targetPosition;
TUniqueId x34_target = kInvalidUniqueId;
union {
struct {
bool x36_24_active : 1;
bool x36_25_ : 1;
bool x36_26_ : 1;
bool x36_27_ : 1;
bool x36_28_ : 1;
bool x36_29_ : 1;
bool x36_25_hasTrackedRotation : 1;
bool x36_26_noParent : 1;
bool x36_27_noParentOrigin : 1;
bool x36_28_noHorizontalAim : 1;
bool x36_29_parentIk : 1;
};
u32 _dummy = 0;
};
public:
CBoneTracking(const CAnimData&, std::string_view, float, float, bool);
CBoneTracking(const CAnimData& animData, std::string_view bone,
float maxTrackingAngle, float angSpeed, bool parentIk);
void Update(float dt);
void PreRender(const CStateManager&, CAnimData&, const zeus::CTransform&, const zeus::CVector3f&,
const CBodyController&);
void PreRender(const CStateManager&, CAnimData&, const zeus::CTransform&, const zeus::CVector3f&, bool);
void SetActive(bool);
void SetTarget(TUniqueId);
void SetTargetPosition(const zeus::CVector3f&);
void PreRender(const CStateManager& mgr, CAnimData& animData, const zeus::CTransform& xf,
const zeus::CVector3f& vec, const CBodyController& bodyController);
void PreRender(const CStateManager& mgr, CAnimData& animData, const zeus::CTransform& worldXf,
const zeus::CVector3f& localOffsetScale, bool tracking);
void SetActive(bool b);
void SetTarget(TUniqueId id);
void UnsetTarget();
void SetTargetPosition(const zeus::CVector3f& pos);
void SetNoHorizontalAim(bool b);
};
} // namespace urde

View File

@ -76,11 +76,11 @@ enum class EJumpState { Invalid = -1, IntoJump, AmbushJump, Loop, OutOfJump, Wal
enum class EStepDirection { Invalid = -1, Forward = 0, Backward = 1, Left = 2, Right = 3, Up = 4, Down = 5 };
enum class EStepType { Normal = 0, Dodge = 1 };
enum class EStepType { Normal = 0, Dodge = 1, BreakDodge = 2, RollDodge = 3 };
enum class ESeverity { Invalid = -1, Zero = 0, One = 1 };
enum class ESeverity { Invalid = -1, Zero = 0, One = 1, Two = 2 };
enum class EGetupType { Invalid = -1 };
enum class EGetupType { Invalid = -1, Zero = 0 };
enum class ELoopState { Invalid = -1, Begin, Loop, End };
@ -90,7 +90,7 @@ enum class EGenerateType { Invalid = -1, Zero, One, Two, Three, Four };
enum class ESlideType { Invalid = -1 };
enum class ETauntType { Invalid = -1 };
enum class ETauntType { Invalid = -1, Zero, One, Two };
enum class ECoverState { Invalid = -1, IntoCover, Cover, Lean, OutOfCover };

View File

@ -143,12 +143,12 @@ void CEyeball::Cover(CStateManager&, EStateMsg msg, float) {
void CEyeball::Flinch(CStateManager& mgr, EStateMsg msg, float arg) {
if (msg == EStateMsg::Activate) {
x32c_animState = EAnimState::One;
x32c_animState = EAnimState::Ready;
x330_stateMachineState.SetDelay(x568_attackDelay);
} else if (msg == EStateMsg::Update)
TryCommand(mgr, pas::EAnimationState::KnockBack, CPatternedTryFunc(&CEyeball::TryFlinch), 0);
else if (msg == EStateMsg::Deactivate)
x32c_animState = EAnimState::Zero;
x32c_animState = EAnimState::NotReady;
}
void CEyeball::TryFlinch(CStateManager&, int arg) {

View File

@ -25,11 +25,18 @@ public:
};
class CMetroid : public CPatterned {
union {
struct {
bool x9bf_29_ : 1;
};
u32 _dummy = 0;
};
public:
DEFINE_PATTERNED(Metroid)
CMetroid(TUniqueId uid, std::string_view name, EFlavorType flavor, const CEntityInfo& info,
const zeus::CTransform& xf, CModelData&& mData, const CPatternedInfo& pInfo, const CActorParameters& aParms,
const CMetroidData& metroidData);
bool GetX9BF_29() const { return x9bf_29_; }
};
} // namespace urde::MP1

View File

@ -554,7 +554,7 @@ void CParasite::Halt(CStateManager& mgr, EStateMsg msg, float) {
switch (msg) {
case EStateMsg::Activate:
x330_stateMachineState.SetDelay(x710_haltDelay);
x32c_animState = EAnimState::One;
x32c_animState = EAnimState::Ready;
x743_24_halted = true;
x5d6_24_alignToFloor = true;
if (x5d0_walkerType == EWalkerType::Geemer)
@ -567,7 +567,7 @@ void CParasite::Halt(CStateManager& mgr, EStateMsg msg, float) {
break;
case EStateMsg::Deactivate:
x450_bodyController->GetCommandMgr().DeliverCmd(CBodyStateCmd(EBodyStateCmd::ExitState));
x32c_animState = EAnimState::Zero;
x32c_animState = EAnimState::NotReady;
x743_24_halted = false;
x5d6_24_alignToFloor = false;
break;

View File

@ -179,18 +179,18 @@ void CSeedling::Enraged(CStateManager&, EStateMsg msg, float) {
void CSeedling::ProjectileAttack(CStateManager& mgr, EStateMsg msg, float) {
if (msg == EStateMsg::Activate)
x32c_animState = EAnimState::One;
x32c_animState = EAnimState::Ready;
else if (msg == EStateMsg::Update)
TryCommand(mgr, pas::EAnimationState::ProjectileAttack, &CPatterned::TryProjectileAttack, 0);
else if (msg == EStateMsg::Deactivate) {
x32c_animState = EAnimState::Zero;
x32c_animState = EAnimState::NotReady;
x71c_attackCoolOff = (x300_maxAttackRange * mgr.GetActiveRandom()->Float()) + x304_averageAttackTime;
}
}
void CSeedling::Generate(CStateManager& mgr, EStateMsg msg, float) {
if (msg == EStateMsg::Activate)
x32c_animState = EAnimState::One;
x32c_animState = EAnimState::Ready;
else if (msg == EStateMsg::Update)
TryCommand(mgr, pas::EAnimationState::Generate, &CPatterned::TryGenerate, 0);
}

File diff suppressed because it is too large Load Diff

View File

@ -32,40 +32,58 @@ public:
class CSpacePirate : public CPatterned {
friend class CPirateRagDoll;
public:
DEFINE_PATTERNED(SpacePirate)
private:
class CSpacePirateData {
friend class CSpacePirate;
float x0_;
float x4_;
float x8_;
float xc_;
float x10_;
float x14_hearNoiseRange;
float x0_AggressionCheck;
float x4_CoverCheck;
float x8_SearchRadius;
float xc_FallBackCheck;
float x10_FallBackRadius;
float x14_HearingRadius;
/*
* 0x1: pendingAmbush
* 0x2: ceilingAmbush
* 0x4: nonAggressive
* 0x8: melee
* 0x10: noShuffleCloseCheck
* 0x20: onlyAttackInRange
* 0x40: unk
* 0x80: noKnockbackImpulseReset
* 0x200: noMeleeAttack
* 0x400: breakAttack
* 0x1000: seated
* 0x2000: shadowPirate
* 0x4000: alertBeforeCloak
* 0x8000: noBreakDodge
* 0x10000: floatingCorpse
* 0x20000: ragdollNoAiCollision
* 0x40000: trooper
*/
u32 x18_flags;
bool x1c_;
CProjectileInfo x20_mainProjectileInfo;
u16 x48_;
CDamageInfo x4c_;
float x68_;
CProjectileInfo x6c_;
float x94_;
u16 x98_ragdollThudSfx;
CProjectileInfo x20_Projectile;
u16 x48_Sound_Projectile;
CDamageInfo x4c_BladeDamage;
float x68_KneelAttackChance;
CProjectileInfo x6c_KneelAttackShot;
float x94_DodgeCheck;
u16 x98_Sound_Impact;
float x9c_averageNextShotTime;
float xa0_nextShotTimeVariation;
u16 xa4_;
float xa8_aimDelayTime;
u16 xa4_Sound_Alert;
float xa8_GunTrackDelay;
u32 xac_firstBurstCount;
float xb0_minCloakAlpha;
float xb4_maxCloakAlpha;
float xb8_;
float xbc_;
u16 xc0_;
u16 xc2_;
float xb0_CloakOpacity;
float xb4_MaxCloakOpacity;
float xb8_dodgeDelayTimeMin;
float xbc_dodgeDelayTimeMax;
u16 xc0_Sound_Hurled;
u16 xc2_Sound_Death;
float xc4_;
float xc8_;
float xc8_AvoidDistance;
public:
CSpacePirateData(CInputStream&, u32);
@ -76,94 +94,94 @@ private:
struct {
bool x634_24_pendingAmbush : 1;
bool x634_25_ceilingAmbush : 1;
bool x634_26_ : 1;
bool x634_26_nonAggressive : 1;
bool x634_27_melee : 1;
bool x634_28_ : 1;
bool x634_28_noShuffleCloseCheck : 1;
bool x634_29_onlyAttackInRange : 1;
bool x634_30_ : 1;
bool x634_31_ : 1;
bool x635_24_ : 1;
bool x635_25_ : 1;
bool x635_26_ : 1;
bool x634_31_noKnockbackImpulseReset : 1;
bool x635_24_noMeleeAttack : 1;
bool x635_25_breakAttack : 1;
bool x635_26_seated : 1;
bool x635_27_shadowPirate : 1;
bool x635_28_ : 1;
bool x635_29_ : 1;
bool x635_28_alertBeforeCloak : 1;
bool x635_29_noBreakDodge : 1;
bool x635_30_floatingCorpse : 1;
bool x635_31_ragdollNoAiCollision : 1;
bool x636_24_trooper : 1;
bool x636_25_hearNoise : 1;
bool x636_26_ : 1;
bool x636_26_enableMeleeAttack : 1;
bool x636_27_ : 1;
bool x636_28_ : 1;
bool x636_29_ : 1;
bool x636_30_ : 1;
bool x636_31_ : 1;
bool x637_24_ : 1;
bool x637_25_ : 1;
bool x636_29_enableRetreat : 1;
bool x636_30_shuffleClose : 1;
bool x636_31_inAttackState : 1;
bool x637_24_enablePatrol : 1;
bool x637_25_enableAim : 1;
bool x637_26_hearPlayerFire : 1;
bool x637_27_inProjectilePath : 1;
bool x637_28_ : 1;
bool x637_29_ : 1;
bool x637_30_ : 1;
bool x637_28_noPlayerLos : 1;
bool x637_29_inWallHang : 1;
bool x637_30_jumpVelSet : 1;
bool x637_31_prevInCineCam : 1;
bool x638_24_pendingFrenzyChance : 1;
bool x638_25_ : 1;
bool x638_26_ : 1;
bool x638_27_ : 1;
bool x638_28_ : 1;
bool x638_29_ : 1;
bool x638_25_appliedBladeDamage : 1;
bool x638_26_alwaysAggressive : 1;
bool x638_27_coverCheck : 1;
bool x638_28_enableDodge : 1;
bool x638_29_noPlayerDodge : 1;
bool x638_30_ragdollOver : 1;
bool x638_31_ : 1;
bool x638_31_mayStartAttack : 1;
bool x639_24_ : 1;
bool x639_25_ : 1;
bool x639_25_useJumpBackJump : 1;
bool x639_26_started : 1;
bool x639_27_ : 1;
bool x639_28_ : 1;
bool x639_29_ : 1;
bool x639_30_ : 1;
bool x639_31_ : 1;
bool x63a_24_ : 1;
bool x639_27_inRange : 1;
bool x639_28_satUp : 1;
bool x639_29_enableBreakDodge : 1;
bool x639_30_closeMelee : 1;
bool x639_31_sentAttackMsg : 1;
bool x63a_24_normalDodge : 1;
};
u64 _dummy = 0;
};
s32 x63c_frenzyFrames = 0;
TUniqueId x640_ = kInvalidUniqueId;
TUniqueId x642_ = kInvalidUniqueId;
float x644_ = 1.f;
zeus::CVector3f x648_ = zeus::CVector3f::skForward;
zeus::CVector3f x654_;
TUniqueId x640_coverPoint = kInvalidUniqueId;
TUniqueId x642_previousCoverPoint = kInvalidUniqueId;
float x644_steeringSpeed = 1.f;
zeus::CVector3f x648_targetDelta = zeus::CVector3f::skForward;
zeus::CVector3f x654_coverPointRearDir;
CPathFindSearch x660_pathFindSearch;
float x744_ = 0.f;
float x748_ = 0.f;
float x744_unkTimer = 0.f;
float x748_steeringDelayTimer = 0.f;
u32 x74c_ = 0;
float x750_initialHP;
float x754_ = 0.f;
float x754_fsmRange = 0.f;
CSegId x758_headSeg;
u32 x75c_ = 0;
s32 x760_ = -1;
pas::ETauntType x760_taunt = pas::ETauntType::Invalid;
CBoneTracking x764_boneTracking;
s32 x79c_ = -1;
pas::ECoverDirection x79c_coverDir = pas::ECoverDirection::Invalid;
float x7a4_intoJumpDist = 1.f;
float x7a8_ = 2.f;
float x7ac_ = 0.f;
u32 x7b0_ = 0;
TUniqueId x7b4_ = kInvalidUniqueId;
float x7a8_eyeHeight = 2.f;
float x7ac_timeNoPlayerLos = 0.f;
u32 x7b0_cantSeePlayerCycleCounter = 0;
TUniqueId x7b4_attachedActor = kInvalidUniqueId;
CSegId x7b6_gunSeg;
CSegId x7b7_elbowSeg;
CSegId x7b8_wristSeg;
CSegId x7b9_swooshSeg;
float x7bc_ = 1.f;
float x7bc_attackRemTime = 1.f;
TUniqueId x7c0_targetId = kInvalidUniqueId;
CBurstFire x7c4_burstFire;
float x824_ = 3.f;
zeus::CVector3f x828_;
s32 x834_ = -1;
float x838_ = 0.f;
s32 x83c_ = -1;
TUniqueId x840_ = kInvalidUniqueId;
s32 x844_ = -1;
float x824_jumpHeight = 3.f;
zeus::CVector3f x828_patrolDestPos;
pas::EStepDirection x834_skidDir = pas::EStepDirection::Invalid;
float x838_strafeDelayTimer = 0.f;
pas::ESeverity x83c_meleeSeverity = pas::ESeverity::Invalid;
TUniqueId x840_jumpPoint = kInvalidUniqueId;
pas::EStepDirection x844_dodgeDir = pas::EStepDirection::Invalid;
float x848_dodgeDist = 3.f;
float x84c_breakDodgeDist = 3.f;
float x850_timeSinceHitByPlayer = FLT_MAX;
@ -177,13 +195,13 @@ private:
float x8b4_shadowPirateAlpha = 0.5f;
float x8b8_minCloakAlpha;
float x8bc_maxCloakAlpha;
float x8c0_;
float x8c0_dodgeDelayTimer;
float x8c4_aimDelayTimer;
TUniqueId x8c8_teamAiMgrId = kInvalidUniqueId;
zeus::CColor x8cc_trooperColor = zeus::CColor::skWhite;
zeus::CVector2f x8d0_;
float x8d8_ = 0.f;
float x8dc_ = 0.f;
zeus::CVector2f x8d0_heldPosition;
float x8d8_holdPositionTime = 0.f;
float x8dc_leashTimer = 0.f;
static const SBurst skBurstsSeatedOOV[];
static const SBurst skBurstsInjuredOOV[];
@ -207,7 +225,7 @@ private:
void AssignTeamAiRole(CStateManager& mgr);
void RemoveTeamAiRole(CStateManager& mgr);
bool CheckTargetable(CStateManager& mgr);
void FireProjectile(float dt, CStateManager& mgr);
bool FireProjectile(float dt, CStateManager& mgr);
void UpdateAttacks(float dt, CStateManager& mgr);
zeus::CVector3f GetTargetPos(CStateManager& mgr);
void UpdateAimBodyState(float dt, CStateManager& mgr);
@ -216,6 +234,15 @@ private:
void CheckForProjectiles(CStateManager& mgr);
void SetEyeParticleActive(CStateManager& mgr, bool active);
void SetVelocityForJump();
void AvoidActors(CStateManager& mgr);
void UpdateCantSeePlayer(CStateManager& mgr);
bool LineOfSightTest(CStateManager& mgr, const zeus::CVector3f& eyePos, const zeus::CVector3f& targetPos,
const CMaterialList& excludeList) const;
void UpdateHeldPosition(CStateManager& mgr, float dt);
void CheckBlade(CStateManager& mgr);
bool CantJumpBack(CStateManager& mgr, const zeus::CVector3f& dir, float dist) const;
void UpdateLeashTimer(float dt);
pas::EStepDirection GetStrafeDir(CStateManager& mgr, float dist) const;
public:
CSpacePirate(TUniqueId, std::string_view, const CEntityInfo&, const zeus::CTransform&, CModelData&&,
@ -237,10 +264,13 @@ public:
bool IsListening() const;
bool Listen(const zeus::CVector3f&, EListenNoiseType);
zeus::CVector3f GetOrigin(const CStateManager& mgr, const CTeamAiRole& role) const;
void DetachActorFromPirate() { x7b4_attachedActor = kInvalidUniqueId; }
bool AttachActorToPirate(TUniqueId id);
void SetAttackTarget(TUniqueId id);
void Patrol(CStateManager&, EStateMsg, float);
void Dead(CStateManager&, EStateMsg, float);
void PathFind(CStateManager&, EStateMsg, float);
void PathFind(CStateManager& mgr, EStateMsg msg, float dt);
void TargetPatrol(CStateManager&, EStateMsg, float);
void TargetCover(CStateManager&, EStateMsg, float);
void Halt(CStateManager&, EStateMsg, float);
@ -279,7 +309,7 @@ public:
bool PatternShagged(CStateManager&, float);
bool AnimOver(CStateManager&, float);
bool ShouldAttack(CStateManager&, float);
bool ShouldJumpBack(CStateManager&, float);
bool ShouldJumpBack(CStateManager& mgr, float arg);
bool Stuck(CStateManager&, float);
bool Landed(CStateManager&, float);
bool HearShot(CStateManager&, float);
@ -300,10 +330,10 @@ public:
bool ShouldWallHang(CStateManager&, float);
bool StartAttack(CStateManager&, float);
bool BreakAttack(CStateManager&, float);
bool ShouldStrafe(CStateManager&, float);
bool ShouldStrafe(CStateManager& mgr, float arg);
bool ShouldSpecialAttack(CStateManager&, float);
bool LostInterest(CStateManager&, float);
bool BounceFind(CStateManager&, float);
bool BounceFind(CStateManager& mgr, float arg);
CPathFindSearch* GetSearchPath();
u8 GetModelAlphau8(const CStateManager& mgr) const;

View File

@ -1,6 +1,9 @@
#include "CProjectileInfo.hpp"
#include "World/CDamageInfo.hpp"
#include "GameGlobalObjects.hpp"
#include "CProjectileWeapon.hpp"
#include "World/CPlayer.hpp"
#include "Character/CSteeringBehaviors.hpp"
#include "CSimplePool.hpp"
namespace urde {
@ -11,9 +14,56 @@ CProjectileInfo::CProjectileInfo(urde::CInputStream& in)
CProjectileInfo::CProjectileInfo(CAssetId proj, const CDamageInfo& dInfo)
: x0_weaponDescription(g_SimplePool->GetObj({SBIG('WPSC'), proj})), xc_damageInfo(dInfo) {}
zeus::CVector3f CProjectileInfo::PredictInterceptPos(const zeus::CVector3f&, const zeus::CVector3f&, const CPlayer&,
bool) {
return {};
zeus::CVector3f CProjectileInfo::PredictInterceptPos(const zeus::CVector3f& gunPos, const zeus::CVector3f& aimPos,
const CPlayer& player, bool gravity, float speed, float dt) {
zeus::CVector3f ret;
zeus::CVector3f playerVel = player.GetDampedClampedVelocityWR();
zeus::CVector3f gravVec(0.f, 0.f, player.GetGravity());
bool result;
switch (player.GetOrbitState()) {
case CPlayer::EPlayerOrbitState::OrbitObject:
case CPlayer::EPlayerOrbitState::OrbitPoint:
case CPlayer::EPlayerOrbitState::OrbitCarcass:
case CPlayer::EPlayerOrbitState::ForcedOrbitObject:
case CPlayer::EPlayerOrbitState::Grapple: {
if (gravity && player.GetPlayerMovementState() == CPlayer::EPlayerMovementState::ApplyJump) {
result = CSteeringBehaviors::ProjectOrbitalIntersection(gunPos, speed, dt, aimPos, playerVel, gravVec,
player.GetOrbitPoint(), ret);
break;
}
zeus::CVector3f vel;
if (playerVel.canBeNormalized())
vel = playerVel.normalized() * player.GetAverageSpeed();
else
vel = playerVel;
result = CSteeringBehaviors::ProjectOrbitalIntersection(gunPos, speed, dt, aimPos, vel,
player.GetOrbitPoint(), ret);
break;
}
case CPlayer::EPlayerOrbitState::NoOrbit:
if (gravity && player.GetPlayerMovementState() == CPlayer::EPlayerMovementState::ApplyJump)
result = CSteeringBehaviors::ProjectLinearIntersection(gunPos, speed, aimPos, playerVel, gravVec, ret);
else
result = CSteeringBehaviors::ProjectLinearIntersection(gunPos, speed, aimPos, playerVel, ret);
}
if (!result)
ret = playerVel * 1.5f + aimPos;
return ret;
}
float CProjectileInfo::GetProjectileSpeed() const {
auto wpsc = x0_weaponDescription;
if (wpsc->x4_IVEC) {
zeus::CVector3f vec;
wpsc->x4_IVEC->GetValue(0, vec);
return vec.magnitude() / CProjectileWeapon::GetTickPeriod();
}
return 45000.0f;
}
zeus::CVector3f CProjectileInfo::PredictInterceptPos(const zeus::CVector3f& gunPos, const zeus::CVector3f& aimPos,
const CPlayer& player, bool gravity, float dt) {
return PredictInterceptPos(gunPos, aimPos, player, gravity, GetProjectileSpeed(), dt);
}
} // namespace urde

View File

@ -15,7 +15,11 @@ public:
CProjectileInfo(CInputStream&);
CProjectileInfo(CAssetId, const CDamageInfo&);
zeus::CVector3f PredictInterceptPos(const zeus::CVector3f&, const zeus::CVector3f&, const CPlayer&, bool);
float GetProjectileSpeed() const;
static zeus::CVector3f PredictInterceptPos(const zeus::CVector3f& gunPos, const zeus::CVector3f& aimPos,
const CPlayer& player, bool gravity, float speed, float dt);
zeus::CVector3f PredictInterceptPos(const zeus::CVector3f& gunPos, const zeus::CVector3f& aimPos,
const CPlayer& player, bool gravity, float dt);
CDamageInfo GetDamage() const { return xc_damageInfo; }
const TToken<CWeaponDescription>& Token() { return x0_weaponDescription; }

View File

@ -96,5 +96,6 @@ public:
static void SetGlobalSeed(u16 seed) { g_GlobalSeed = seed; }
CElementGen* GetAttachedPS1() const { return xfc_APSMGen.get(); }
double GameTime() const { return xd0_curTime; }
static float GetTickPeriod() { return 0.0166667f; }
};
} // namespace urde

View File

@ -264,7 +264,7 @@ void CActor::Render(const CStateManager& mgr) const {
}
if (xe5_31_pointGeneratorParticles) {
CSkinnedModel::ClearPointGeneratorFunc();
mgr.GetActorModelParticles()->Render(*this);
mgr.GetActorModelParticles()->Render(mgr, *this);
}
}

View File

@ -192,5 +192,6 @@ public:
void SetPointGeneratorParticles(bool s) { xe5_31_pointGeneratorParticles = s; }
CSimpleShadow* Shadow() { return x94_simpleShadow.get(); }
void MoveScannableObjectInfoToActor(CActor*, CStateManager&);
const zeus::CAABox& GetRenderBounds() const { return x9c_renderBounds; }
};
} // namespace urde

View File

@ -22,124 +22,114 @@ static bool IsMediumOrLarge(CActor& act) {
CActorModelParticles::CItem::CItem(const CEntity& ent, CActorModelParticles& parent)
: x0_id(ent.GetUniqueId()), x4_areaId(ent.GetAreaIdAlways()), xdc_ashy(parent.x48_ashy), x128_parent(parent) {
x8_thermalHotParticles.resize(8);
x8_onFireGens.resize(8);
}
u32 GetNextBestPt(s32 start, const std::vector<std::pair<zeus::CVector3f, zeus::CVector3f>>& vn, CRandom16& rnd) {
static s32 GetNextBestPt(s32 start, const std::vector<std::pair<zeus::CVector3f, zeus::CVector3f>>& vn,
CRandom16& rnd) {
const zeus::CVector3f& startVec = vn[start].first;
u32 ret;
float lastMag = 0.f;
s32 ret = start;
float maxMag = 0.f;
for (s32 i = 0; i < 10; ++i) {
u32 idx = u32(rnd.Range(0, s32(vn.size()) - 1));
s32 idx = rnd.Range(0, s32(vn.size()) - 1);
const zeus::CVector3f& rndVec = vn[idx].first;
float mag = (startVec - rndVec).magSquared();
if (mag > lastMag) {
if (mag > maxMag) {
ret = idx;
lastMag = mag;
maxMag = mag;
}
}
return ret;
}
void CActorModelParticles::CItem::GeneratePoints(const std::vector<std::pair<zeus::CVector3f, zeus::CVector3f>>& vn) {
for (std::pair<std::unique_ptr<CElementGen>, u32>& pair : x8_thermalHotParticles) {
for (std::pair<std::unique_ptr<CElementGen>, u32>& pair : x8_onFireGens) {
if (pair.first) {
CRandom16 rnd(pair.second);
const zeus::CVector3f& vec = vn[u32(rnd.Float() * (vn.size() - 1))].first;
pair.first->SetTranslation(xec_ * vec);
const zeus::CVector3f& vec = vn[rnd.Float() * (vn.size() - 1)].first;
pair.first->SetTranslation(xec_particleOffsetScale * vec);
}
}
if (x84_ > 0) {
CRandom16 rnd(x88_seed1);
u32 count = (x84_ >= 16 ? 16 : x84_);
u32 idx = x80_;
if (x84_ashMaxParticles > 0) {
CRandom16 rnd(x88_ashSeed);
s32 count = (x84_ashMaxParticles >= 16 ? 16 : x84_ashMaxParticles);
s32 idx = x80_ashPointIterator;
for (u32 i = 0; i < count; ++i) {
idx = GetNextBestPt(idx, vn, rnd);
x78_->SetTranslation(xec_ * vn[idx].first);
x78_ashGen->SetTranslation(xec_particleOffsetScale * vn[idx].first);
zeus::CVector3f v = vn[idx].second;
if (v.canBeNormalized()) {
v.normalize();
x78_->SetOrientation(
zeus::CTransform{zeus::CVector3f::skUp.cross(v), v, zeus::CVector3f::skUp, zeus::CVector3f::skZero});
x78_ashGen->SetOrientation(
zeus::CTransform{v.cross(zeus::CVector3f::skUp), v, zeus::CVector3f::skUp, zeus::CVector3f::skZero});
}
x78_->ForceParticleCreation(1);
x78_ashGen->ForceParticleCreation(1);
}
x84_ -= count;
x88_seed1 = rnd.GetSeed();
x84_ashMaxParticles -= count;
x88_ashSeed = rnd.GetSeed();
x80_ashPointIterator = idx;
}
if (xb0_ != -1) {
CRandom16 rnd(xb4_seed2);
if (xb0_icePointIterator != -1) {
CRandom16 rnd(xb4_iceSeed);
std::unique_ptr<CElementGen> iceGen = x128_parent.MakeIceGen();
iceGen->SetGlobalOrientAndTrans(xf8_);
iceGen->SetGlobalOrientAndTrans(xf8_iceXf);
u32 next = GetNextBestPt(xb0_, vn, rnd);
iceGen->SetTranslation(xec_ * vn[next].first);
s32 idx = GetNextBestPt(xb0_icePointIterator, vn, rnd);
iceGen->SetTranslation(xec_particleOffsetScale * vn[idx].first);
iceGen->SetOrientation(zeus::CTransform::MakeRotationsBasedOnY(zeus::CUnitVector3f(vn[next].second)));
iceGen->SetOrientation(zeus::CTransform::MakeRotationsBasedOnY(zeus::CUnitVector3f(vn[idx].second)));
x8c_thermalColdParticles.push_back(std::move(iceGen));
xb0_ = (x8c_thermalColdParticles.size() == 4 ? -1 : next);
x8c_iceGens.push_back(std::move(iceGen));
xb0_icePointIterator = (x8c_iceGens.size() == 4 ? -1 : idx);
}
// TODO: Verify behavior
if (xc0_particleElectric && xc0_particleElectric->GetParticleEmission()) {
CRandom16 rnd(xcc_seed3);
if (xc0_electricGen && xc0_electricGen->GetParticleEmission()) {
CRandom16 rnd(xcc_electricSeed);
u32 end = 1;
#if 0
if (4 < 1)
end = 4;
#endif
u32 lastRnd;
s32 idx = xc8_electricPointIterator;
for (u32 i = 0; i < end; ++i) {
xc0_particleElectric->SetOverrideIPos(vn[u32(rnd.Range(0, s32(vn.size()) - 1))].first * xec_);
lastRnd = u32(rnd.Range(0, s32(vn.size()) - 1));
xc0_particleElectric->SetOverrideFPos(vn[lastRnd].first * xec_);
xc0_particleElectric->ForceParticleCreation(1);
xc0_electricGen->SetOverrideIPos(vn[rnd.Range(0, s32(vn.size()) - 1)].first * xec_particleOffsetScale);
idx = rnd.Range(0, s32(vn.size()) - 1);
xc0_electricGen->SetOverrideFPos(vn[idx].first * xec_particleOffsetScale);
xc0_electricGen->ForceParticleCreation(1);
}
xcc_seed3 = rnd.GetSeed();
xc8_ = lastRnd;
xcc_electricSeed = rnd.GetSeed();
xc8_electricPointIterator = idx;
}
// TODO: Finish
#if 0
if (xd4_)
{
xd4_->sub_8026A5E0(v1, v2, w1);
}
#endif
}
void CActorModelParticles::CItem::sub_801e59a8(EDependency i) {
if (x134_lockDeps & (1 << int(i))) {
// x128_parent.sub_801e3a94(i);
x134_lockDeps &= ~(1 << int(i));
}
if (xd4_rainSplashGen)
xd4_rainSplashGen->GeneratePoints(vn);
}
bool CActorModelParticles::CItem::UpdateOnFire(float dt, CActor* actor, CStateManager& mgr) {
bool r30 = false;
bool r31 = false;
bool effectActive = false;
bool sfxActive = false;
x6c_onFireDelayTimer -= dt;
if (x6c_onFireDelayTimer < 0.f)
x6c_onFireDelayTimer = 0.f;
if (x134_lockDeps & 0x1) {
if (x128_parent.xe6_bits2 & 0x1) {
if (x128_parent.xe6_loadedDeps & 0x1) {
if (x70_onFire && actor) {
bool r26 = true;
if (x78_ || xdc_ashy) {
r26 = false;
bool doCreate = true;
if (x78_ashGen || xdc_ashy) {
doCreate = false;
} else if (!IsMediumOrLarge(*actor)) {
int r3 = 0;
for (const auto& p : x8_thermalHotParticles)
int activeParts = 0;
for (const auto& p : x8_onFireGens)
if (p.first)
++r3;
if (r3 >= 4)
r26 = false;
++activeParts;
if (activeParts >= 4)
doCreate = false;
}
if (r26) {
for (auto& p : x8_thermalHotParticles) {
if (doCreate) {
for (auto& p : x8_onFireGens) {
if (!p.first) {
p.second = mgr.GetActiveRandom()->Next();
p.first = x128_parent.MakeOnFireGen();
@ -154,83 +144,203 @@ bool CActorModelParticles::CItem::UpdateOnFire(float dt, CActor* actor, CStateMa
}
x70_onFire = false;
}
for (auto& p : x8_thermalHotParticles) {
for (auto& p : x8_onFireGens) {
if (p.first) {
if (p.first->IsSystemDeletable())
p.first.reset();
else if (actor)
p.first->SetGlobalOrientAndTrans(actor->GetTransform());
p.first->Update(dt);
r30 = true;
r31 = true;
effectActive = true;
sfxActive = true;
}
}
} else {
r30 = true;
effectActive = true;
}
}
if (x74_sfx) {
if (r31) {
CSfxManager::UpdateEmitter(x74_sfx, xf8_.origin, zeus::CVector3f::skZero, 1.f);
if (sfxActive) {
CSfxManager::UpdateEmitter(x74_sfx, xf8_iceXf.origin, zeus::CVector3f::skZero, 1.f);
} else {
CSfxManager::RemoveEmitter(x74_sfx);
x74_sfx.reset();
}
}
if (!r30) {
if (!effectActive)
Unlock(EDependency::OnFire);
}
return r30;
return effectActive;
}
bool CActorModelParticles::CItem::UpdateAsh(float dt, CActor* actor, CStateManager& mgr) { return false; }
bool CActorModelParticles::CItem::UpdateAshGen(float dt, CActor* actor, CStateManager& mgr) {
if (x78_ashGen) {
if (x84_ashMaxParticles == 0 && x78_ashGen->IsSystemDeletable()) {
x78_ashGen.reset();
} else {
if (actor)
x78_ashGen->SetGlobalOrientAndTrans(actor->GetTransform());
x78_ashGen->Update(dt);
return true;
}
} else if (x134_lockDeps & 0x4 && actor) {
if (x128_parent.xe6_loadedDeps & 0x4) {
x78_ashGen = x128_parent.MakeAshGen();
x80_ashPointIterator = 0;
x78_ashGen->SetGlobalOrientAndTrans(actor->GetTransform());
x84_ashMaxParticles = s32((IsMediumOrLarge(*actor) ? 1.f : 0.3f) * x78_ashGen->GetMaxParticles());
x88_ashSeed = mgr.GetActiveRandom()->Next();
}
return true;
}
Unlock(EDependency::Ash);
return false;
}
bool CActorModelParticles::CItem::sub_801e65bc(float dt, CActor* actor, CStateManager& mgr) { return false; }
bool CActorModelParticles::CItem::UpdateIceGen(float dt, CActor* actor, CStateManager& mgr) {
if (xb0_icePointIterator != -1)
return true;
if (!x8c_iceGens.empty()) {
bool active = false;
for (auto& p : x8c_iceGens) {
if (!p->IsSystemDeletable())
active = true;
p->Update(dt);
}
if (!active)
x8c_iceGens.clear();
else
return true;
} else if (x134_lockDeps & 0x2 && actor) {
if (x128_parent.xe6_loadedDeps & 0x2) {
xb0_icePointIterator = 0;
xb4_iceSeed = mgr.GetActiveRandom()->Next();
}
return true;
}
Unlock(EDependency::Ice);
return false;
}
bool CActorModelParticles::CItem::UpdateFirePop(float dt, CActor* actor, CStateManager& mgr) { return false; }
bool CActorModelParticles::CItem::UpdateFirePop(float dt, CActor* actor, CStateManager& mgr) {
if (xb8_firePopGen) {
if (xb8_firePopGen->IsSystemDeletable()) {
xb8_firePopGen.reset();
} else {
xb8_firePopGen->Update(dt);
return true;
}
} else if (x134_lockDeps & 0x8 && actor) {
if (x128_parent.xe6_loadedDeps & 0x8) {
xb8_firePopGen = x128_parent.MakeFirePopGen();
xb8_firePopGen->SetGlobalOrientation(actor->GetTransform());
xb8_firePopGen->SetGlobalTranslation(actor->GetRenderBounds().center());
}
return true;
}
Unlock(EDependency::FirePop);
return false;
}
bool CActorModelParticles::CItem::UpdateElectric(float dt, CActor* actor, CStateManager& mgr) { return false; }
bool CActorModelParticles::CItem::UpdateElectric(float dt, CActor* actor, CStateManager& mgr) {
if (xc0_electricGen) {
if (xc0_electricGen->IsSystemDeletable()) {
xc0_electricGen.reset();
} else {
if (actor && actor->GetActive()) {
xc0_electricGen->SetGlobalOrientation(actor->GetTransform().getRotation());
xc0_electricGen->SetGlobalTranslation(actor->GetTranslation());
}
if (!actor || actor->GetActive()) {
xc0_electricGen->SetModulationColor(xd0_electricColor);
xc0_electricGen->Update(dt);
return true;
}
}
} else if (x134_lockDeps & 0x10) {
if (x128_parent.xe6_loadedDeps & 0x10) {
xc0_electricGen = x128_parent.MakeElectricGen();
xc0_electricGen->SetModulationColor(xd0_electricColor);
xc8_electricPointIterator = 0;
xcc_electricSeed = mgr.GetActiveRandom()->Next();
}
return true;
}
Unlock(EDependency::Electric);
return false;
}
bool CActorModelParticles::CItem::sub_801e69f0(float dt, CActor* actor, CStateManager& mgr) { return false; }
bool CActorModelParticles::CItem::UpdateRainSplash(float dt, CActor* actor, CStateManager& mgr) {
if (xd4_rainSplashGen) {
if (!xd4_rainSplashGen->IsRaining()) {
xd4_rainSplashGen.reset();
} else {
xd4_rainSplashGen->Update(dt, mgr);
return true;
}
}
return false;
}
bool CActorModelParticles::CItem::sub_801e5e98(float dt, CActor* actor, CStateManager& mgr) { return false; }
bool CActorModelParticles::CItem::UpdateBurn(float dt, CActor* actor, CStateManager& mgr) {
if (!actor)
xdc_ashy.Unlock();
return xdc_ashy.IsLocked();
}
bool CActorModelParticles::CItem::UpdateIcePop(float dt, CActor* actor, CStateManager& mgr) { return false; }
bool CActorModelParticles::CItem::UpdateIcePop(float dt, CActor* actor, CStateManager& mgr) {
if (xe4_icePopGen) {
if (xe4_icePopGen->IsSystemDeletable()) {
xe4_icePopGen.reset();
} else {
xe4_icePopGen->Update(dt);
return true;
}
} else if (x134_lockDeps & 0x20 && actor) {
if (x128_parent.xe6_loadedDeps & 0x20) {
xe4_icePopGen = x128_parent.MakeIcePopGen();
xe4_icePopGen->SetGlobalOrientation(actor->GetTransform());
xe4_icePopGen->SetGlobalTranslation(actor->GetRenderBounds().center());
}
return true;
}
Unlock(EDependency::IcePop);
return false;
}
bool CActorModelParticles::CItem::Update(float dt, CStateManager& mgr) {
CActor* act = static_cast<CActor*>(mgr.ObjectById(x0_id));
if (act && act->HasModelData() && !act->ModelData()->IsNull()) {
xec_ = act->ModelData()->GetScale();
xf8_ = act->GetTransform();
xec_particleOffsetScale = act->ModelData()->GetScale();
xf8_iceXf = act->GetTransform();
x4_areaId = act->GetAreaIdAlways();
} else {
x0_id = kInvalidUniqueId;
x84_ = 0;
xb0_ = -1;
if (xc0_particleElectric)
xc0_particleElectric->SetParticleEmission(false);
x84_ashMaxParticles = 0;
xb0_icePointIterator = -1;
if (xc0_electricGen)
xc0_electricGen->SetParticleEmission(false);
if (x74_sfx) {
CSfxManager::RemoveEmitter(x74_sfx);
x74_sfx.reset();
}
x130_ -= dt;
if (x130_ <= 0.f)
x130_remTime -= dt;
if (x130_remTime <= 0.f)
return false;
}
bool ret = false;
if (UpdateOnFire(dt, act, mgr))
ret = true;
if (UpdateAsh(dt, act, mgr))
if (UpdateAshGen(dt, act, mgr))
ret = true;
if (sub_801e65bc(dt, act, mgr))
if (UpdateIceGen(dt, act, mgr))
ret = true;
if (UpdateFirePop(dt, act, mgr))
ret = true;
if (UpdateElectric(dt, act, mgr))
ret = true;
if (sub_801e69f0(dt, act, mgr))
if (UpdateRainSplash(dt, act, mgr))
ret = true;
if (sub_801e5e98(dt, act, mgr))
if (UpdateBurn(dt, act, mgr))
ret = true;
if (UpdateIcePop(dt, act, mgr))
ret = true;
@ -255,21 +365,21 @@ void CActorModelParticles::DecrementDependency(EDependency d) {
Dependency& dep = x50_dgrps[int(d)];
dep.Decrement();
if (dep.x10_refCount == 0) {
xe4_bits &= ~(1 << int(d));
xe6_bits2 &= ~(1 << int(d));
xe5_bits1 &= ~(1 << int(d));
xe4_loadingDeps &= ~(1 << int(d));
xe6_loadedDeps &= ~(1 << int(d));
xe5_justLoadedDeps &= ~(1 << int(d));
}
}
void CActorModelParticles::IncrementDependency(EDependency d) {
x50_dgrps[int(d)].Increment();
if (!(xe6_bits2 & (1 << int(d))))
xe4_bits |= (1 << int(d));
if (!(xe6_loadedDeps & (1 << int(d))))
xe4_loadingDeps |= (1 << int(d));
}
static const char* ParticleDGRPs[] = {
"Effect_OnFire_DGRP", "Effect_Ash_DGRP", "Effect_IceBreak_DGRP",
"Effect_FirePop_DGRP", "Effect_IcePop_DGRP", "Effect_Electric_DGRP",
"Effect_OnFire_DGRP", "Effect_IceBreak_DGRP", "Effect_Ash_DGRP",
"Effect_FirePop_DGRP", "Effect_Electric_DGRP", "Effect_IcePop_DGRP",
};
CActorModelParticles::Dependency CActorModelParticles::GetParticleDGRPTokens(const char* name) {
@ -291,7 +401,9 @@ std::unique_ptr<CElementGen> CActorModelParticles::MakeOnFireGen() const {
return std::make_unique<CElementGen>(x18_onFire);
}
std::unique_ptr<CElementGen> CActorModelParticles::MakeAshGen() const { return std::make_unique<CElementGen>(x20_ash); }
std::unique_ptr<CElementGen> CActorModelParticles::MakeAshGen() const {
return std::make_unique<CElementGen>(x20_ash);
}
std::unique_ptr<CElementGen> CActorModelParticles::MakeIceGen() const {
return std::make_unique<CElementGen>(x28_iceBreak);
@ -342,23 +454,23 @@ void CActorModelParticles::AddStragglersToRenderer(const CStateManager& mgr) {
if (isNotCold) {
/* Hot Draw */
for (int i = 0; i < 8; ++i) {
std::unique_ptr<CElementGen>& gen = item.x8_thermalHotParticles[i].first;
std::unique_ptr<CElementGen>& gen = item.x8_onFireGens[i].first;
if (gen)
g_Renderer->AddParticleGen(*gen);
}
if (mgr.GetThermalDrawFlag() != EThermalDrawFlag::Hot && item.x78_)
g_Renderer->AddParticleGen(*item.x78_);
if (item.xb8_)
g_Renderer->AddParticleGen(*item.xb8_);
if (item.xc0_particleElectric)
g_Renderer->AddParticleGen(*item.xc0_particleElectric);
if (mgr.GetThermalDrawFlag() != EThermalDrawFlag::Hot && item.x78_ashGen)
g_Renderer->AddParticleGen(*item.x78_ashGen);
if (item.xb8_firePopGen)
g_Renderer->AddParticleGen(*item.xb8_firePopGen);
if (item.xc0_electricGen)
g_Renderer->AddParticleGen(*item.xc0_electricGen);
}
if (isNotHot) {
/* Cold Draw */
for (std::unique_ptr<CElementGen>& gen : item.x8c_thermalColdParticles)
for (std::unique_ptr<CElementGen>& gen : item.x8c_iceGens)
g_Renderer->AddParticleGen(*gen);
if (item.xe4_)
g_Renderer->AddParticleGen(*item.xe4_);
if (item.xe4_icePopGen)
g_Renderer->AddParticleGen(*item.xe4_icePopGen);
}
if (isNotCold) {
/* Thermal Reset */
@ -368,7 +480,34 @@ void CActorModelParticles::AddStragglersToRenderer(const CStateManager& mgr) {
}
}
void CActorModelParticles::Update(float dt, CStateManager& mgr) {}
void CActorModelParticles::UpdateLoad() {
if (xe4_loadingDeps) {
xe5_justLoadedDeps = 0;
for (int i = 0; i < 6; ++i) {
if (xe4_loadingDeps & (1 << i)) {
x50_dgrps[i].UpdateLoad();
if (x50_dgrps[i].x14_loaded) {
xe5_justLoadedDeps |= (1 << i);
xe4_loadingDeps &= ~(1 << i);
}
}
}
xe6_loadedDeps |= xe5_justLoadedDeps;
}
}
void CActorModelParticles::Update(float dt, CStateManager& mgr) {
UpdateLoad();
for (auto it = x0_items.begin(); it != x0_items.end();) {
if (!it->Update(dt, mgr)) {
if (CActor* act = static_cast<CActor*>(mgr.ObjectById(it->x0_id)))
act->SetPointGeneratorParticles(false);
it = x0_items.erase(it);
continue;
}
++it;
}
}
void CActorModelParticles::PointGenerator(void* ctx,
const std::vector<std::pair<zeus::CVector3f, zeus::CVector3f>>& vn) {
@ -401,30 +540,30 @@ std::list<CActorModelParticles::CItem>::iterator CActorModelParticles::FindOrCre
void CActorModelParticles::StartIce(CActor& act) {
auto iter = FindOrCreateSystem(act);
iter->Lock(EDependency::Ash);
iter->Lock(EDependency::Ice);
}
void CActorModelParticles::StartElectric(CActor& act) {
auto iter = FindOrCreateSystem(act);
if (iter->xc0_particleElectric && !iter->xc0_particleElectric->GetParticleEmission())
iter->xc0_particleElectric->SetParticleEmission(true);
if (iter->xc0_electricGen && !iter->xc0_electricGen->GetParticleEmission())
iter->xc0_electricGen->SetParticleEmission(true);
}
void CActorModelParticles::StopElectric(CActor& act) {
if (act.GetPointGeneratorParticles()) {
auto iter = FindSystem(act.GetUniqueId());
if (iter != x0_items.cend() && iter->xc0_particleElectric)
iter->xc0_particleElectric->SetParticleEmission(false);
if (iter != x0_items.cend() && iter->xc0_electricGen)
iter->xc0_electricGen->SetParticleEmission(false);
}
}
void CActorModelParticles::sub_801e51d0(CActor& act) {
void CActorModelParticles::LoadAndStartElectric(CActor& act) {
auto iter = FindOrCreateSystem(act);
if (!iter->xc0_particleElectric)
iter->Lock(EDependency::IcePop);
if (!iter->xc0_electricGen)
iter->Lock(EDependency::Electric);
else {
if (!iter->xc0_particleElectric->GetParticleEmission())
iter->xc0_particleElectric->SetParticleEmission(true);
if (!iter->xc0_electricGen->GetParticleEmission())
iter->xc0_electricGen->SetParticleEmission(true);
}
}
@ -432,7 +571,7 @@ void CActorModelParticles::StopThermalHotParticles(CActor& act) {
if (act.GetPointGeneratorParticles()) {
auto iter = FindSystem(act.GetUniqueId());
if (iter != x0_items.cend()) {
for (auto& part : iter->x8_thermalHotParticles)
for (auto& part : iter->x8_onFireGens)
if (part.first)
part.first->SetParticleEmission(false);
}
@ -448,7 +587,7 @@ void CActorModelParticles::StartBurnDeath(CActor& act) {
void CActorModelParticles::EnsureElectricLoaded(CActor& act) {
auto iter = FindOrCreateSystem(act);
iter->Lock(EDependency::Electric);
iter->Lock(EDependency::IcePop);
}
void CActorModelParticles::EnsureFirePopLoaded(CActor& act) {
@ -458,7 +597,7 @@ void CActorModelParticles::EnsureFirePopLoaded(CActor& act) {
void CActorModelParticles::EnsureIceBreakLoaded(CActor& act) {
auto iter = FindOrCreateSystem(act);
iter->Lock(EDependency::IceBreak);
iter->Lock(EDependency::Ash);
}
void CActorModelParticles::LightDudeOnFire(CActor& act) {
@ -480,19 +619,52 @@ const CTexture* CActorModelParticles::GetAshyTexture(const CActor& act) {
void CActorModelParticles::AddRainSplashGenerator(CActor& act, CStateManager& mgr, u32 maxSplashes, u32 genRate,
float minZ) {
auto it = FindOrCreateSystem(act);
if (it->xd4_rainSplashGenerator)
if (it->xd4_rainSplashGen)
return;
if (act.GetModelData() && !act.GetModelData()->IsNull())
it->xd4_rainSplashGenerator =
it->xd4_rainSplashGen =
std::make_unique<CRainSplashGenerator>(act.GetModelData()->GetScale(), maxSplashes, genRate, minZ, 0.1875f);
}
void CActorModelParticles::RemoveRainSplashGenerator(CActor& act) {
auto it = FindOrCreateSystem(act);
it->xd4_rainSplashGenerator.reset();
it->xd4_rainSplashGen.reset();
}
void CActorModelParticles::Render(const CActor& actor) const {}
void CActorModelParticles::Render(const CStateManager& mgr, const CActor& actor) const {
zeus::CTransform backupModel = CGraphics::g_GXModelMatrix;
auto search = FindSystem(actor.GetUniqueId());
if (search == x0_items.end())
return;
if (search->x4_areaId != kInvalidAreaId) {
const CGameArea* area = mgr.GetWorld()->GetAreaAlways(search->x4_areaId);
if (!area->IsPostConstructed())
return;
if (area->GetOcclusionState() == CGameArea::EOcclusionState::Occluded)
return;
}
if (mgr.GetThermalDrawFlag() != EThermalDrawFlag::Cold) {
for (const auto& gen : search->x8_onFireGens)
gen.first->Render();
if (mgr.GetThermalDrawFlag() != EThermalDrawFlag::Hot && search->x78_ashGen)
search->x78_ashGen->Render();
if (search->xb8_firePopGen)
search->xb8_firePopGen->Render();
if (search->xc0_electricGen)
search->xc0_electricGen->Render();
search->x134_lockDeps |= 0x80;
}
if (mgr.GetThermalDrawFlag() != EThermalDrawFlag::Hot) {
for (const auto& gen : search->x8c_iceGens)
gen->Render();
if (search->xd4_rainSplashGen && actor.GetModelData() && !actor.GetModelData()->IsNull())
search->xd4_rainSplashGen->Draw(actor.GetTransform());
if (search->xe4_icePopGen)
search->xe4_icePopGen->Render();
search->x134_lockDeps |= 0x40;
}
CGraphics::SetModelMatrix(backupModel);
}
} // namespace urde

View File

@ -19,33 +19,33 @@ class CScriptPlayerActor;
class CActorModelParticles {
public:
enum class EDependency { OnFire, Ash, IceBreak, FirePop, IcePop, Electric };
enum class EDependency { OnFire, Ice, Ash, FirePop, Electric, IcePop };
class CItem {
friend class CActorModelParticles;
TUniqueId x0_id;
TAreaId x4_areaId;
rstl::reserved_vector<std::pair<std::unique_ptr<CElementGen>, u32>, 8> x8_thermalHotParticles;
rstl::reserved_vector<std::pair<std::unique_ptr<CElementGen>, u32>, 8> x8_onFireGens;
float x6c_onFireDelayTimer = 0.f;
bool x70_onFire = false;
CSfxHandle x74_sfx;
std::unique_ptr<CElementGen> x78_;
u32 x80_ = 0;
s32 x84_ = -1;
u32 x88_seed1 = 99;
rstl::reserved_vector<std::unique_ptr<CElementGen>, 4> x8c_thermalColdParticles;
s32 xb0_ = -1;
u32 xb4_seed2 = 99;
std::unique_ptr<CElementGen> xb8_;
std::unique_ptr<CParticleElectric> xc0_particleElectric;
u32 xc8_ = 0;
u32 xcc_seed3 = 99;
zeus::CColor xd0_;
std::unique_ptr<CRainSplashGenerator> xd4_rainSplashGenerator;
std::unique_ptr<CElementGen> x78_ashGen;
s32 x80_ashPointIterator = 0;
s32 x84_ashMaxParticles = -1;
u32 x88_ashSeed = 99;
rstl::reserved_vector<std::unique_ptr<CElementGen>, 4> x8c_iceGens;
s32 xb0_icePointIterator = -1;
u32 xb4_iceSeed = 99;
std::unique_ptr<CElementGen> xb8_firePopGen;
std::unique_ptr<CParticleElectric> xc0_electricGen;
s32 xc8_electricPointIterator = 0;
u32 xcc_electricSeed = 99;
zeus::CColor xd0_electricColor;
std::unique_ptr<CRainSplashGenerator> xd4_rainSplashGen;
TToken<CTexture> xdc_ashy;
std::unique_ptr<CElementGen> xe4_;
zeus::CVector3f xec_ = zeus::CVector3f::skOne;
zeus::CTransform xf8_;
std::unique_ptr<CElementGen> xe4_icePopGen;
zeus::CVector3f xec_particleOffsetScale = zeus::CVector3f::skOne;
zeus::CTransform xf8_iceXf;
CActorModelParticles& x128_parent;
union {
struct {
@ -54,16 +54,15 @@ public:
};
u16 _dummy = 0;
};
float x130_ = 10.f;
u8 x134_lockDeps = 0;
void sub_801e59a8(EDependency i);
float x130_remTime = 10.f;
mutable u8 x134_lockDeps = 0;
bool UpdateOnFire(float dt, CActor* actor, CStateManager& mgr);
bool UpdateAsh(float dt, CActor* actor, CStateManager& mgr);
bool sub_801e65bc(float dt, CActor* actor, CStateManager& mgr);
bool UpdateAshGen(float dt, CActor* actor, CStateManager& mgr);
bool UpdateIceGen(float dt, CActor* actor, CStateManager& mgr);
bool UpdateFirePop(float dt, CActor* actor, CStateManager& mgr);
bool UpdateElectric(float dt, CActor* actor, CStateManager& mgr);
bool sub_801e69f0(float dt, CActor* actor, CStateManager& mgr);
bool sub_801e5e98(float dt, CActor* actor, CStateManager& mgr);
bool UpdateRainSplash(float dt, CActor* actor, CStateManager& mgr);
bool UpdateBurn(float dt, CActor* actor, CStateManager& mgr);
bool UpdateIcePop(float dt, CActor* actor, CStateManager& mgr);
public:
@ -113,11 +112,22 @@ private:
tok.Unlock();
x14_loaded = false;
}
void UpdateLoad() {
if (x14_loaded || x10_refCount == 0)
return;
bool loading = false;
for (CToken& tok : x0_tokens) {
if (!tok.IsLoaded())
loading = true;
}
if (!loading)
x14_loaded = true;
}
};
rstl::reserved_vector<Dependency, 6> x50_dgrps;
u8 xe4_bits = 0;
u8 xe5_bits1 = 0;
u8 xe6_bits2 = 0;
u8 xe4_loadingDeps = 0;
u8 xe5_justLoadedDeps = 0;
u8 xe6_loadedDeps = 0;
Dependency GetParticleDGRPTokens(const char* name);
void LoadParticleDGRPs();
@ -132,6 +142,8 @@ private:
void DecrementDependency(EDependency d);
void IncrementDependency(EDependency d);
void UpdateLoad();
public:
CActorModelParticles();
static void PointGenerator(void* item, const std::vector<std::pair<zeus::CVector3f, zeus::CVector3f>>& vn);
@ -143,10 +155,10 @@ public:
void StartIce(CActor& actor);
void AddRainSplashGenerator(CActor& act, CStateManager& mgr, u32 maxSplashes, u32 genRate, float minZ);
void RemoveRainSplashGenerator(CActor& act);
void Render(const CActor& actor) const;
void Render(const CStateManager& mgr, const CActor& actor) const;
void StartElectric(CActor& act);
void StopElectric(CActor& act);
void sub_801e51d0(CActor& act);
void LoadAndStartElectric(CActor& act);
void StopThermalHotParticles(CActor& act);
void StartBurnDeath(CActor& act);
void EnsureElectricLoaded(CActor& act);

View File

@ -137,6 +137,8 @@ public:
const KnockBackParms& GetActiveParms() const { return x4_activeParms; }
EKnockBackVariant GetVariant() const { return x0_variant; }
float GetFlinchRemTime() const { return x64_flinchRemTime; }
void SetAvailableState(EKnockBackAnimationState s, bool b) { x80_availableStates.set(size_t(s), b); }
bool TestAvailableState(EKnockBackAnimationState s) const { return x80_availableStates.test(size_t(s)); }
};
} // namespace urde

View File

@ -40,6 +40,9 @@ public:
void GetSplinePoint(zeus::CVector3f& pOut, const zeus::CVector3f& p1) const;
void GetSplinePointWithLookahead(zeus::CVector3f& pOut, const zeus::CVector3f& p1, float lookahead) const;
void SetArea(CPFArea* area) { x0_area = area; }
float GetCharacterHeight() const { return xd0_chHeight; }
void SetCharacterHeight(float h) { xd0_chHeight = h; }
float RemainingPathDistance(const zeus::CVector3f& pos) const;
};
} // namespace urde

View File

@ -59,4 +59,15 @@ void CPathFindSearch::GetSplinePointWithLookahead(zeus::CVector3f& pOut, const z
GetSplinePointWithLookahead(pOut, p1, xc8_curWaypoint, lookahead);
}
float CPathFindSearch::RemainingPathDistance(const zeus::CVector3f& pos) const {
float f31 = 0.f;
if (xc8_curWaypoint < x4_waypoints.size() - 1) {
f31 += (x4_waypoints[xc8_curWaypoint + 1] - pos).magnitude();
for (int i = xc8_curWaypoint + 1; i < x4_waypoints.size() - 1; ++i) {
f31 += (x4_waypoints[i + 1] - x4_waypoints[i]).magnitude();
}
}
return f31;
}
} // namespace urde

View File

@ -20,6 +20,7 @@
#include "World/CScriptWaypoint.hpp"
#include "World/CScriptActorKeyframe.hpp"
#include "Weapon/CEnergyProjectile.hpp"
#include "World/CScriptCoverPoint.hpp"
namespace urde {
@ -822,7 +823,7 @@ void CPatterned::Patrol(CStateManager& mgr, EStateMsg msg, float dt) {
void CPatterned::TryCommand(CStateManager& mgr, pas::EAnimationState state, CPatternedTryFunc func, int arg) {
if (state == x450_bodyController->GetCurrentStateId())
x32c_animState = EAnimState::Repeat;
else if (x32c_animState == EAnimState::One)
else if (x32c_animState == EAnimState::Ready)
(this->*func)(mgr, arg);
else
x32c_animState = EAnimState::Over;
@ -840,6 +841,54 @@ void CPatterned::TryGenerate(CStateManager& mgr, int arg) {
x450_bodyController->GetCommandMgr().DeliverCmd(CBCGenerateCmd(pas::EGenerateType(arg), x2e0_destPos, true));
}
void CPatterned::TryJump(CStateManager& mgr, int arg) {
x450_bodyController->GetCommandMgr().DeliverCmd(CBCJumpCmd(x2e0_destPos, pas::EJumpType(arg)));
}
void CPatterned::TryMeleeAttack(CStateManager& mgr, int arg) {
x450_bodyController->GetCommandMgr().DeliverCmd(CBCMeleeAttackCmd(pas::ESeverity(arg)));
}
void CPatterned::TryTurn(CStateManager& mgr, int arg) {
x450_bodyController->GetCommandMgr().DeliverCmd(
CBCLocomotionCmd(zeus::CVector3f::skZero, (x2e0_destPos - GetTranslation()).normalized(), 1.f));
}
void CPatterned::TryGetUp(CStateManager& mgr, int arg) {
x450_bodyController->GetCommandMgr().DeliverCmd(CBCGetupCmd(pas::EGetupType(arg)));
}
void CPatterned::TryTaunt(CStateManager& mgr, int arg) {
x450_bodyController->GetCommandMgr().DeliverCmd(CBCTauntCmd(pas::ETauntType(arg)));
}
void CPatterned::TryJumpInLoop(CStateManager& mgr, int arg) {
x450_bodyController->GetCommandMgr().DeliverCmd(CBCJumpCmd(x2e0_destPos, pas::EJumpType(arg), true));
}
void CPatterned::TryDodge(CStateManager& mgr, int arg) {
x450_bodyController->GetCommandMgr().DeliverCmd(CBCStepCmd(pas::EStepDirection(arg), pas::EStepType::Dodge));
}
void CPatterned::TryRollingDodge(CStateManager& mgr, int arg) {
x450_bodyController->GetCommandMgr().DeliverCmd(CBCStepCmd(pas::EStepDirection(arg), pas::EStepType::RollDodge));
}
void CPatterned::TryBreakDodge(CStateManager& mgr, int arg) {
x450_bodyController->GetCommandMgr().DeliverCmd(CBCStepCmd(pas::EStepDirection(arg), pas::EStepType::BreakDodge));
}
void CPatterned::TryCover(CStateManager& mgr, int arg) {
if (CScriptCoverPoint* cp = GetCoverPoint(mgr, x2dc_destObj)) {
x450_bodyController->GetCommandMgr().DeliverCmd(CBCCoverCmd(pas::ECoverDirection(arg), cp->GetTranslation(),
-cp->GetTransform().basis[1]));
}
}
void CPatterned::TryWallHang(CStateManager& mgr, int arg) {
x450_bodyController->GetCommandMgr().DeliverCmd(CBCWallHangCmd(x2dc_destObj));
}
void CPatterned::BuildBodyController(EBodyType bodyType) {
if (x450_bodyController)
return;
@ -1085,6 +1134,26 @@ void CPatterned::UpdateDamageColor(float dt) {
}
}
CScriptCoverPoint* CPatterned::GetCoverPoint(CStateManager& mgr, TUniqueId id) const {
if (id != kInvalidUniqueId) {
if (TCastToPtr<CScriptCoverPoint> cp = mgr.ObjectById(id))
return cp.GetPtr();
}
return nullptr;
}
void CPatterned::SetCoverPoint(CScriptCoverPoint* cp, TUniqueId& id) {
cp->SetInUse(true);
id = cp->GetUniqueId();
}
void CPatterned::ReleaseCoverPoint(CStateManager& mgr, TUniqueId& id) {
if (CScriptCoverPoint* cp = GetCoverPoint(mgr, id)) {
cp->SetInUse(false);
id = kInvalidUniqueId;
}
}
TUniqueId CPatterned::GetWaypointForState(CStateManager& mgr, EScriptObjectState state,
EScriptObjectMessage msg) const {
rstl::reserved_vector<TUniqueId, 12> ids;
@ -1476,7 +1545,7 @@ void CPatterned::Render(const CStateManager& mgr) const {
alpha * (x401_29_laggedBurnDeath ? 0.00787402f : 0.00392157f));
if (xe5_31_pointGeneratorParticles) {
CSkinnedModel::ClearPointGeneratorFunc();
mgr.GetActorModelParticles()->Render(*this);
mgr.GetActorModelParticles()->Render(mgr, *this);
}
} else {
CPhysicsActor::Render(mgr);

View File

@ -75,7 +75,7 @@ public:
enum class EBehaviourOrient { MoveDir, Constant, Destination };
enum class EBehaviourModifiers { Zero };
enum class EPatrolState { Invalid = -1, Patrol, Pause, Done };
enum class EAnimState { Zero, One, Repeat, Over };
enum class EAnimState { NotReady, Ready, Repeat, Over };
class CPatternNode {
zeus::CVector3f x0_pos;
zeus::CVector3f xc_forward;
@ -131,7 +131,7 @@ protected:
u32 _dummy = 0;
};
EAnimState x32c_animState = EAnimState::Zero;
EAnimState x32c_animState = EAnimState::NotReady;
CStateMachineState x330_stateMachineState;
ECharacter x34c_character;
zeus::CVector3f x350_patternStartPos;
@ -319,6 +319,17 @@ public:
void TryLoopReaction(CStateManager& mgr, int arg);
void TryProjectileAttack(CStateManager& mgr, int arg);
void TryGenerate(CStateManager& mgr, int arg);
void TryJump(CStateManager& mgr, int arg);
void TryMeleeAttack(CStateManager& mgr, int arg);
void TryTurn(CStateManager& mgr, int arg);
void TryGetUp(CStateManager& mgr, int arg);
void TryTaunt(CStateManager& mgr, int arg);
void TryJumpInLoop(CStateManager& mgr, int arg);
void TryDodge(CStateManager& mgr, int arg);
void TryRollingDodge(CStateManager& mgr, int arg);
void TryBreakDodge(CStateManager& mgr, int arg);
void TryCover(CStateManager& mgr, int arg);
void TryWallHang(CStateManager& mgr, int arg);
virtual bool KnockbackWhenFrozen() const { return true; }
virtual void MassiveDeath(CStateManager& mgr);
@ -357,6 +368,9 @@ public:
void SetModelAlpha(float a) { x42c_color.a() = a; }
float CalcDyingThinkRate();
void UpdateDamageColor(float dt);
CScriptCoverPoint* GetCoverPoint(CStateManager& mgr, TUniqueId id) const;
void SetCoverPoint(CScriptCoverPoint* cp, TUniqueId& id);
void ReleaseCoverPoint(CStateManager& mgr, TUniqueId& id);
bool CanLongJump() const { return x328_26_longJump; }
bool IsMakingBigStrike() const { return x402_28_isMakingBigStrike; }

View File

@ -5674,4 +5674,10 @@ bool CPlayer::AttachActorToPlayer(TUniqueId id, bool disableGun) {
return false;
}
float CPlayer::GetAverageSpeed() const {
if (auto avg = x4a4_moveSpeedAvg.GetAverage())
return *avg;
return x4f8_moveSpeed;
}
} // namespace urde

View File

@ -610,5 +610,7 @@ public:
bool IsShowingCrosshairs() const { return x9c4_25_showCrosshairs; }
bool IsSidewaysDashing() const { return x37c_sidewaysDashing; }
void Set_X590(bool b) { x590_ = b; }
const zeus::CVector3f& GetOrbitPoint() const { return x314_orbitPoint; }
float GetAverageSpeed() const;
};
} // namespace urde

View File

@ -9,7 +9,7 @@ CScriptAiJumpPoint::CScriptAiJumpPoint(TUniqueId uid, std::string_view name, con
zeus::CTransform& xf, bool active, float f1)
: CActor(uid, active, name, info, xf, CModelData::CModelDataNull(), CMaterialList(EMaterialTypes::NoStepLogic),
CActorParameters::None(), kInvalidUniqueId)
, xe8_(f1)
, xe8_apex(f1)
, xec_touchBounds(xf.origin, xf.origin) {}
void CScriptAiJumpPoint::Accept(IVisitor& visitor) { visitor.Visit(this); }
@ -43,10 +43,7 @@ void CScriptAiJumpPoint::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId oth
std::experimental::optional<zeus::CAABox> CScriptAiJumpPoint::GetTouchBounds() const { return xec_touchBounds; }
bool CScriptAiJumpPoint::GetInUse(TUniqueId uid) const {
if (x108_24 || x110_timeRemaining > 0.f || x10a_occupant != kInvalidUniqueId || uid != kInvalidUniqueId ||
uid != x10a_occupant)
return true;
return false;
return x108_24 || x110_timeRemaining > 0.f || x10a_occupant != kInvalidUniqueId || uid != kInvalidUniqueId ||
uid != x10a_occupant;
}
} // namespace urde

View File

@ -5,7 +5,7 @@
namespace urde {
class CScriptAiJumpPoint : public CActor {
private:
float xe8_;
float xe8_apex;
zeus::CAABox xec_touchBounds;
union {
struct {
@ -28,5 +28,8 @@ public:
void Render(const CStateManager&) const {}
std::experimental::optional<zeus::CAABox> GetTouchBounds() const;
bool GetInUse(TUniqueId uid) const;
TUniqueId GetJumpPoint() const { return x10c_currentWaypoint; }
TUniqueId GetJumpTarget() const { return x10e_nextWaypoint; }
float GetJumpApex() const { return xe8_apex; }
};
} // namespace urde

View File

@ -655,7 +655,7 @@ void CScriptGunTurret::sub80218f50(s32 state, CStateManager& mgr, float dt) {
zeus::CVector3f rotatedBlastVec = GetTransform().rotate(blastXf.origin) + GetTranslation();
x404_ = mgr.GetPlayer().GetAimPosition(mgr, 0.f);
vec = x37c_projectileInfo.PredictInterceptPos(rotatedBlastVec, mgr.GetPlayer().GetAimPosition(mgr, dt),
mgr.GetPlayer(), false);
mgr.GetPlayer(), false, dt);
}
zeus::CVector3f compensated =

View File

@ -106,6 +106,7 @@ public:
float GetTime() const { return x8_time; }
float GetRandom() const { return xc_random; }
float GetDelay() const { return x10_delay; }
void SetCodeTrigger() { x18_24_codeTrigger = true; }
const char* GetName() const {
if (x4_state)

2
hecl

@ -1 +1 @@
Subproject commit 82a7890e99da98fcc9770fb21c73f7837f285f66
Subproject commit 40d23980dec1cf5addab4b0dbd2539d460c37fe0

@ -1 +1 @@
Subproject commit a3a3f90d8ce1d7f4c73c70c690f9bce4da69c50a
Subproject commit f81efb25b53e90cf9e77c06a09095a433929ddb4