CMetroid: More implementation & fixes

This commit is contained in:
Luke Street 2020-05-21 12:50:17 -04:00
parent 56d31254cd
commit e0866ebdd4
2 changed files with 172 additions and 92 deletions

View File

@ -86,7 +86,7 @@ CMetroid::CMetroid(TUniqueId uid, std::string_view name, EFlavorType flavor, con
, x7e8_scale3(GetModelData()->GetScale()) , x7e8_scale3(GetModelData()->GetScale())
, x81c_patternedInfo(pInfo) , x81c_patternedInfo(pInfo)
, x954_actParams(aParms) , x954_actParams(aParms)
, x9bc_(other) { , x9bc_parent(other) {
x808_loopAttackDistance = x808_loopAttackDistance =
GetAnimationDistance(CPASAnimParmData{9, CPASAnimParm::FromEnum(2), CPASAnimParm::FromEnum(3)}); GetAnimationDistance(CPASAnimParmData{9, CPASAnimParm::FromEnum(2), CPASAnimParm::FromEnum(3)});
UpdateTouchBounds(); UpdateTouchBounds();
@ -115,6 +115,7 @@ void CMetroid::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateMa
SwarmRemove(mgr); SwarmRemove(mgr);
break; break;
case EScriptObjectMessage::Damage: case EScriptObjectMessage::Damage:
case EScriptObjectMessage::InvulnDamage:
if (TCastToConstPtr<CGameProjectile> projectile = mgr.GetObjectById(uid)) { if (TCastToConstPtr<CGameProjectile> projectile = mgr.GetObjectById(uid)) {
const CDamageInfo& damageInfo = projectile->GetDamageInfo(); const CDamageInfo& damageInfo = projectile->GetDamageInfo();
if (GetDamageVulnerability()->WeaponHits(damageInfo.GetWeaponMode(), false)) { if (GetDamageVulnerability()->WeaponHits(damageInfo.GetWeaponMode(), false)) {
@ -160,11 +161,9 @@ void CMetroid::DoUserAnimEvent(CStateManager& mgr, const CInt32POINode& node, EU
EWeaponCollisionResponseTypes CMetroid::GetCollisionResponseType(const zeus::CVector3f& vec1, EWeaponCollisionResponseTypes CMetroid::GetCollisionResponseType(const zeus::CVector3f& vec1,
const zeus::CVector3f& vec2, const CWeaponMode& mode, const zeus::CVector3f& vec2, const CWeaponMode& mode,
EProjectileAttrib attribute) const { EProjectileAttrib attribute) const {
EWeaponCollisionResponseTypes types = EWeaponCollisionResponseTypes::Unknown33; return !GetDamageVulnerability()->WeaponHurts(mode, false) && x450_bodyController->GetPercentageFrozen() <= 0.f
if (!GetDamageVulnerability()->WeaponHurts(mode, false) && x450_bodyController->GetPercentageFrozen() <= 0.f) { ? EWeaponCollisionResponseTypes::Unknown58
types = EWeaponCollisionResponseTypes::Unknown58; : EWeaponCollisionResponseTypes::Unknown33;
}
return types;
} }
const CDamageVulnerability* CMetroid::GetDamageVulnerability() const { const CDamageVulnerability* CMetroid::GetDamageVulnerability() const {
@ -174,7 +173,7 @@ const CDamageVulnerability* CMetroid::GetDamageVulnerability() const {
} }
return &skNormalDamageVulnerability; return &skNormalDamageVulnerability;
} }
if (x9bf_25_ && !x450_bodyController->IsFrozen()) { if (x9bf_25_growing && !x450_bodyController->IsFrozen()) {
return &x56c_data.GetEnergyDrainVulnerability(); return &x56c_data.GetEnergyDrainVulnerability();
} }
if (x450_bodyController->GetPercentageFrozen() > 0.f) { if (x450_bodyController->GetPercentageFrozen() > 0.f) {
@ -349,7 +348,7 @@ void CMetroid::SuckEnergyFromTarget(CStateManager& mgr, float dt) {
if (x7b0_attackTarget == kInvalidUniqueId) { if (x7b0_attackTarget == kInvalidUniqueId) {
return; return;
} }
if (x7c8_ == EUnknown::One) { if (x7c8_attackState == EAttackState::Attached) {
InterpolateToPosRot(mgr, 0.4f); InterpolateToPosRot(mgr, 0.4f);
CPlayer& player = mgr.GetPlayer(); CPlayer& player = mgr.GetPlayer();
if (x7b0_attackTarget == player.GetUniqueId()) { if (x7b0_attackTarget == player.GetUniqueId()) {
@ -357,14 +356,14 @@ void CMetroid::SuckEnergyFromTarget(CStateManager& mgr, float dt) {
x504_damageDur = 0.2f; x504_damageDur = 0.2f;
mgr.SendScriptMsg(&player, GetUniqueId(), EScriptObjectMessage::Damage); mgr.SendScriptMsg(&player, GetUniqueId(), EScriptObjectMessage::Damage);
} }
x7c0_ = 0.f; x7c0_energyDrainTime = 0.f;
} else if (x7c8_ == EUnknown::Two) { } else if (x7c8_attackState == EAttackState::Draining) {
CPlayer& player = mgr.GetPlayer(); CPlayer& player = mgr.GetPlayer();
if (TCastToPtr<CActor> actor = mgr.ObjectById(x7b0_attackTarget)) { if (TCastToPtr<CActor> actor = mgr.ObjectById(x7b0_attackTarget)) {
CHealthInfo* healthInfo = actor->HealthInfo(mgr); CHealthInfo* healthInfo = actor->HealthInfo(mgr);
if (healthInfo != nullptr) { if (healthInfo != nullptr) {
const float damage = dt * x56c_data.GetEnergyDrainPerSec() * GetDamageMultiplier(); const float damage = dt * x56c_data.GetEnergyDrainPerSec() * GetDamageMultiplier();
x7bc_ += damage; x7bc_energyDrained += damage;
if (x7b0_attackTarget == player.GetUniqueId()) { if (x7b0_attackTarget == player.GetUniqueId()) {
player.SetNoDamageLoopSfx(true); player.SetNoDamageLoopSfx(true);
constexpr auto filter = CMaterialFilter::MakeInclude({EMaterialTypes::Solid}); constexpr auto filter = CMaterialFilter::MakeInclude({EMaterialTypes::Solid});
@ -373,7 +372,8 @@ void CMetroid::SuckEnergyFromTarget(CStateManager& mgr, float dt) {
info.SetNoImmunity(true); info.SetNoImmunity(true);
mgr.ApplyDamage(GetUniqueId(), x7b0_attackTarget, GetUniqueId(), info, filter, zeus::skZero3f); mgr.ApplyDamage(GetUniqueId(), x7b0_attackTarget, GetUniqueId(), info, filter, zeus::skZero3f);
player.SetNoDamageLoopSfx(false); player.SetNoDamageLoopSfx(false);
x9c0_24_isEnergyDrainVulnerable = player.GetMorphballTransitionState() == CPlayer::EPlayerMorphBallState::Morphed; x9c0_24_isEnergyDrainVulnerable =
player.GetMorphballTransitionState() == CPlayer::EPlayerMorphBallState::Morphed;
} else { } else {
x9c0_24_isEnergyDrainVulnerable = true; x9c0_24_isEnergyDrainVulnerable = true;
constexpr auto filter = CMaterialFilter::MakeInclude({EMaterialTypes::Solid}); constexpr auto filter = CMaterialFilter::MakeInclude({EMaterialTypes::Solid});
@ -397,7 +397,7 @@ void CMetroid::SuckEnergyFromTarget(CStateManager& mgr, float dt) {
arg = 0.4f; arg = 0.4f;
} }
if (morphBallState == CPlayer::EPlayerMorphBallState::Unmorphed) { if (morphBallState == CPlayer::EPlayerMorphBallState::Unmorphed) {
const float magnitude = std::clamp(std::abs(std::sin(zeus::degToRad(90.f) * x7c0_)), 0.f, 1.f); const float magnitude = std::clamp(std::abs(std::sin(zeus::degToRad(90.f) * x7c0_energyDrainTime)), 0.f, 1.f);
mgr.GetPlayerState()->GetStaticInterference().AddSource(GetUniqueId(), magnitude, 0.2f); mgr.GetPlayerState()->GetStaticInterference().AddSource(GetUniqueId(), magnitude, 0.2f);
if (player.GetStaticTimer() < 0.2f) { if (player.GetStaticTimer() < 0.2f) {
player.SetHudDisable(0.2f, 0.5f, 2.5f); player.SetHudDisable(0.2f, 0.5f, 2.5f);
@ -407,8 +407,8 @@ void CMetroid::SuckEnergyFromTarget(CStateManager& mgr, float dt) {
x504_damageDur = 0.2f; x504_damageDur = 0.2f;
} }
InterpolateToPosRot(mgr, arg); InterpolateToPosRot(mgr, arg);
x7c0_ += dt; x7c0_energyDrainTime += dt;
} else if (x7c8_ == EUnknown::Three) { } else if (x7c8_attackState == EAttackState::Over) {
const zeus::CQuaternion zRot = zeus::CQuaternion::fromAxisAngle({0.0f, 0.0f, 1.0f}, GetYaw()); const zeus::CQuaternion zRot = zeus::CQuaternion::fromAxisAngle({0.0f, 0.0f, 1.0f}, GetYaw());
const zeus::CQuaternion rot = zeus::CQuaternion::slerpShort(GetTransform().basis, zRot, 0.95f); const zeus::CQuaternion rot = zeus::CQuaternion::slerpShort(GetTransform().basis, zRot, 0.95f);
SetRotation(rot.normalized()); SetRotation(rot.normalized());
@ -418,22 +418,22 @@ void CMetroid::SuckEnergyFromTarget(CStateManager& mgr, float dt) {
void CMetroid::RestoreSolidCollision(CStateManager& mgr) { void CMetroid::RestoreSolidCollision(CStateManager& mgr) {
constexpr auto filter = CMaterialFilter::MakeInclude({EMaterialTypes::Solid, EMaterialTypes::AIBlock}); constexpr auto filter = CMaterialFilter::MakeInclude({EMaterialTypes::Solid, EMaterialTypes::AIBlock});
const zeus::CVector3f& pos = GetTranslation(); const zeus::CVector3f& pos = GetTranslation();
if (x9bf_30_ && !CGameCollision::DetectStaticCollisionBoolean(mgr, x6a0_collisionPrimitive, GetTransform(), filter)) { if (x9bf_30_restoreSolidCollision &&
!CGameCollision::DetectStaticCollisionBoolean(mgr, x6a0_collisionPrimitive, GetTransform(), filter)) {
bool add = true; bool add = true;
if (!x80c_.isZero()) { if (!x80c_detachPos.isZero()) {
const zeus::CVector3f dir = pos - x80c_; const zeus::CVector3f dir = pos - x80c_detachPos;
float mag = dir.magnitude(); float mag = dir.magnitude();
if (mag > 0.f) { if (mag > 0.f) {
// TODO double check bool add = mgr.RayStaticIntersection(x80c_detachPos, (1.f / mag) * dir, mag, filter).IsInvalid();
add = mgr.RayStaticIntersection(x80c_, (1.f / mag) * dir, mag, filter).IsInvalid();
} }
} }
if (add) { if (add) {
AddMaterial(EMaterialTypes::Solid, mgr); AddMaterial(EMaterialTypes::Solid, mgr);
x9bf_30_ = false; x9bf_30_restoreSolidCollision = false;
} }
} }
if (x9bf_31_) { if (x9bf_31_restoreCharacterCollision) {
constexpr auto nearFilter = constexpr auto nearFilter =
CMaterialFilter::MakeInclude({EMaterialTypes::Solid, EMaterialTypes::Player, EMaterialTypes::Character}); CMaterialFilter::MakeInclude({EMaterialTypes::Solid, EMaterialTypes::Player, EMaterialTypes::Character});
float radius = x808_loopAttackDistance * GetModelData()->GetScale().y(); float radius = x808_loopAttackDistance * GetModelData()->GetScale().y();
@ -441,7 +441,7 @@ void CMetroid::RestoreSolidCollision(CStateManager& mgr) {
rstl::reserved_vector<TUniqueId, 1024> nearList; rstl::reserved_vector<TUniqueId, 1024> nearList;
mgr.BuildNearList(nearList, box, nearFilter, this); mgr.BuildNearList(nearList, box, nearFilter, this);
if (!CGameCollision::DetectDynamicCollisionBoolean(x6a0_collisionPrimitive, GetTransform(), nearList, mgr)) { if (!CGameCollision::DetectDynamicCollisionBoolean(x6a0_collisionPrimitive, GetTransform(), nearList, mgr)) {
x9bf_31_ = false; x9bf_31_restoreCharacterCollision = false;
CMaterialFilter matFilter = GetMaterialFilter(); CMaterialFilter matFilter = GetMaterialFilter();
matFilter.ExcludeList().Remove({EMaterialTypes::Character, EMaterialTypes::Player}); matFilter.ExcludeList().Remove({EMaterialTypes::Character, EMaterialTypes::Player});
SetMaterialFilter(matFilter); SetMaterialFilter(matFilter);
@ -457,19 +457,19 @@ void CMetroid::PreventWorldCollisions(CStateManager& mgr, float dt) {
// why not use mgr.GetPlayer()? :thonking: // why not use mgr.GetPlayer()? :thonking:
float mass = 300.f; float mass = 300.f;
if (mgr.GetPlayer().GetMorphballTransitionState() == CPlayer::EPlayerMorphBallState::Unmorphed) { if (mgr.GetPlayer().GetMorphballTransitionState() == CPlayer::EPlayerMorphBallState::Unmorphed) {
float scale = std::min(1.f, 1.33f * x7c0_); float scale = std::min(1.f, 1.33f * x7c0_energyDrainTime);
mass = 300.f * (1.f - scale) + 7500.f * scale; mass = 300.f * (1.f - scale) + 7500.f * scale;
} }
CGameCollision::AvoidStaticCollisionWithinRadius(mgr, *actor, 8, dt, 0.25f, size, mass, 0.5f); CGameCollision::AvoidStaticCollisionWithinRadius(mgr, *actor, 8, dt, 0.25f, size, mass, 0.5f);
} }
} }
x7c4_ = 0.f; x7c4_ = 0.f;
} else if (!x9bf_30_ && !x9bf_31_) { } else if (!x9bf_30_restoreSolidCollision && !x9bf_31_restoreCharacterCollision) {
x7c4_ = 0.f; x7c4_ = 0.f;
} else { } else {
x7c4_ += dt; x7c4_ += dt;
if (x7c4_ <= 6.f) { if (x7c4_ <= 6.f) {
if (x9bf_30_ && 0.25f < x7c4_) { if (x9bf_30_restoreSolidCollision && 0.25f < x7c4_) {
RemoveMaterial(EMaterialTypes::Solid, mgr); RemoveMaterial(EMaterialTypes::Solid, mgr);
} }
} else { } else {
@ -503,21 +503,23 @@ void CMetroid::SwarmAdd(CStateManager& mgr) {
} }
void CMetroid::ApplyGrowth(float arg) { void CMetroid::ApplyGrowth(float arg) {
x7f8_ += arg; x7f8_growthEnergy += arg;
const float energy = std::clamp(x7f8_ / x56c_data.GetStage2GrowthEnergy(), 0.f, 1.f); const float energy = std::clamp(x7f8_growthEnergy / x56c_data.GetStage2GrowthEnergy(), 0.f, 1.f);
const float scale = x56c_data.GetStage2GrowthScale() - x7e8_scale3.y(); const float scale = x56c_data.GetStage2GrowthScale() - x7e8_scale3.y();
x7d0_scale1 = zeus::CVector3f{energy * scale + x7e8_scale3.y()}; x7d0_scale1 = zeus::CVector3f{energy * scale + x7e8_scale3.y()};
TakeDamage(zeus::skZero3f, 0.f); TakeDamage(zeus::skZero3f, 0.f);
} }
bool CMetroid::IsSuckingEnergy() const { return x7c8_ == EUnknown::Two && !x450_bodyController->IsFrozen(); } bool CMetroid::IsSuckingEnergy() const {
return x7c8_attackState == EAttackState::Draining && !x450_bodyController->IsFrozen();
}
void CMetroid::UpdateVolume() { void CMetroid::UpdateVolume() {
// TODO // TODO
} }
void CMetroid::UpdateTouchBounds() { void CMetroid::UpdateTouchBounds() {
const zeus::CTransform& locXf = GetLocatorTransform("lockon_target_LCTR"sv); const zeus::CTransform locXf = GetLocatorTransform("lockon_target_LCTR"sv);
x6a0_collisionPrimitive.SetSphereCenter(locXf * GetModelData()->GetScale()); x6a0_collisionPrimitive.SetSphereCenter(locXf * GetModelData()->GetScale());
} }
@ -525,8 +527,8 @@ void CMetroid::Attack(CStateManager& mgr, EStateMsg msg, float dt) {
if (msg == EStateMsg::Activate) { if (msg == EStateMsg::Activate) {
if (AttachToTarget(mgr)) { if (AttachToTarget(mgr)) {
x568_state = EState::One; x568_state = EState::One;
x7bc_ = 0.f; x7bc_energyDrained = 0.f;
x7c8_ = EUnknown::One; x7c8_attackState = EAttackState::Attached;
x9bf_29_isAttacking = true; x9bf_29_isAttacking = true;
RemoveMaterial(EMaterialTypes::Orbit, EMaterialTypes::Target, mgr); RemoveMaterial(EMaterialTypes::Orbit, EMaterialTypes::Target, mgr);
mgr.GetPlayer().SetOrbitRequestForTarget(GetUniqueId(), CPlayer::EPlayerOrbitRequest::ActivateOrbitSource, mgr); mgr.GetPlayer().SetOrbitRequestForTarget(GetUniqueId(), CPlayer::EPlayerOrbitRequest::ActivateOrbitSource, mgr);
@ -544,7 +546,7 @@ void CMetroid::Attack(CStateManager& mgr, EStateMsg msg, float dt) {
} }
} else if (x568_state == EState::Two) { } else if (x568_state == EState::Two) {
if (GetModelData()->GetAnimationData()->GetIsLoop()) { if (GetModelData()->GetAnimationData()->GetIsLoop()) {
x7c8_ = EUnknown::Two; x7c8_attackState = EAttackState::Draining;
} }
const CPlayer& player = mgr.GetPlayer(); const CPlayer& player = mgr.GetPlayer();
if (x7b0_attackTarget == player.GetUniqueId() && player.GetAttachedActor() == GetUniqueId() && if (x7b0_attackTarget == player.GetUniqueId() && player.GetAttachedActor() == GetUniqueId() &&
@ -555,7 +557,7 @@ void CMetroid::Attack(CStateManager& mgr, EStateMsg msg, float dt) {
if (ShouldReleaseFromTarget(mgr)) { if (ShouldReleaseFromTarget(mgr)) {
GetBodyController()->GetCommandMgr().DeliverCmd(CBodyStateCmd(EBodyStateCmd::ExitState)); GetBodyController()->GetCommandMgr().DeliverCmd(CBodyStateCmd(EBodyStateCmd::ExitState));
DetachFromTarget(mgr); DetachFromTarget(mgr);
x7c8_ = EUnknown::Three; x7c8_attackState = EAttackState::Over;
} }
} else { } else {
x568_state = EState::Over; x568_state = EState::Over;
@ -564,7 +566,7 @@ void CMetroid::Attack(CStateManager& mgr, EStateMsg msg, float dt) {
} else if (msg == EStateMsg::Deactivate) { } else if (msg == EStateMsg::Deactivate) {
CTeamAiMgr::ResetTeamAiRole(CTeamAiMgr::EAttackType::Melee, mgr, x698_teamAiMgrId, GetUniqueId(), false); CTeamAiMgr::ResetTeamAiRole(CTeamAiMgr::EAttackType::Melee, mgr, x698_teamAiMgrId, GetUniqueId(), false);
x7b4_attackChance = x308_attackTimeVariation * mgr.GetActiveRandom()->Float() + x304_averageAttackTime; x7b4_attackChance = x308_attackTimeVariation * mgr.GetActiveRandom()->Float() + x304_averageAttackTime;
x7c8_ = EUnknown::Zero; x7c8_attackState = EAttackState::None;
DetachFromTarget(mgr); DetachFromTarget(mgr);
x9bf_29_isAttacking = false; x9bf_29_isAttacking = false;
SetTransform({zeus::CQuaternion::fromAxisAngle({0.f, 0.f, 1.f}, GetYaw()), GetTranslation()}); SetTransform({zeus::CQuaternion::fromAxisAngle({0.f, 0.f, 1.f}, GetYaw()), GetTranslation()});
@ -604,7 +606,7 @@ void CMetroid::DetachFromTarget(CStateManager& mgr) {
xf = player.GetTransform(); xf = player.GetTransform();
} }
mgr.GetPlayer().GetEnergyDrain().RemoveEnergyDrainSource(GetUniqueId()); mgr.GetPlayer().GetEnergyDrain().RemoveEnergyDrainSource(GetUniqueId());
x80c_ = player.GetAimPosition(mgr, 0.f); x80c_detachPos = player.GetAimPosition(mgr, 0.f);
target = &player; target = &player;
} }
} else if (x7b0_attackTarget != kInvalidUniqueId) { } else if (x7b0_attackTarget != kInvalidUniqueId) {
@ -613,14 +615,14 @@ void CMetroid::DetachFromTarget(CStateManager& mgr) {
pirate->DetachActorFromPirate(); pirate->DetachActorFromPirate();
vec = pirate->GetTransform().frontVector(); vec = pirate->GetTransform().frontVector();
xf = pirate->GetTransform(); xf = pirate->GetTransform();
x80c_ = GetTranslation(); x80c_detachPos = GetTranslation();
target = pirate; target = pirate;
} }
} }
} }
SetupExitFaceHugDirection(target, mgr, vec, xf); SetupExitFaceHugDirection(target, mgr, vec, xf);
x9bf_31_ = true; x9bf_31_restoreCharacterCollision = true;
x9bf_30_ = true; x9bf_30_restoreSolidCollision = true;
} }
bool CMetroid::ShouldReleaseFromTarget(CStateManager& mgr) { bool CMetroid::ShouldReleaseFromTarget(CStateManager& mgr) {
@ -629,7 +631,7 @@ bool CMetroid::ShouldReleaseFromTarget(CStateManager& mgr) {
} }
CPlayer& player = mgr.GetPlayer(); CPlayer& player = mgr.GetPlayer();
if (x7b0_attackTarget == player.GetUniqueId()) { if (x7b0_attackTarget == player.GetUniqueId()) {
if (x7bc_ >= x56c_data.GetMaxEnergyDrainAllowed() * GetDamageMultiplier() || IsPlayerUnderwater(mgr)) { if (x7bc_energyDrained >= x56c_data.GetMaxEnergyDrainAllowed() * GetDamageMultiplier() || IsPlayerUnderwater(mgr)) {
return true; return true;
} }
if (player.GetMorphballTransitionState() != CPlayer::EPlayerMorphBallState::Unmorphed) { if (player.GetMorphballTransitionState() != CPlayer::EPlayerMorphBallState::Unmorphed) {
@ -673,7 +675,7 @@ bool CMetroid::IsHunterAttacking(CStateManager& mgr) {
} }
float CMetroid::GetGrowthStage() { float CMetroid::GetGrowthStage() {
const float energy = x7f8_; const float energy = x7f8_growthEnergy;
const float stage2GrowthEnergy = x56c_data.GetStage2GrowthEnergy(); const float stage2GrowthEnergy = x56c_data.GetStage2GrowthEnergy();
if (energy < stage2GrowthEnergy) { if (energy < stage2GrowthEnergy) {
return 1.f + energy / stage2GrowthEnergy; return 1.f + energy / stage2GrowthEnergy;
@ -784,9 +786,9 @@ void CMetroid::SetUpPathFindBehavior(CStateManager& mgr) {
const zeus::CVector3f dir = GetDestPos() - targetPos; const zeus::CVector3f dir = GetDestPos() - targetPos;
if (dir.canBeNormalized()) { if (dir.canBeNormalized()) {
constexpr auto filter = CMaterialFilter::MakeInclude({EMaterialTypes::Solid, EMaterialTypes::AIBlock}); constexpr auto filter = CMaterialFilter::MakeInclude({EMaterialTypes::Solid, EMaterialTypes::AIBlock});
float mag = dir.magnitude(); const float length = dir.magnitude();
const zeus::CVector3f dirScaled = (1.f / mag) * dir; const zeus::CVector3f dirScaled = (1.f / length) * dir;
const auto result = mgr.RayStaticIntersection(targetPos, dirScaled, mag, filter); const auto result = mgr.RayStaticIntersection(targetPos, dirScaled, length, filter);
if (result.IsValid()) { if (result.IsValid()) {
SetDestPos(targetPos + 0.5f * result.GetT() * dirScaled); SetDestPos(targetPos + 0.5f * result.GetT() * dirScaled);
x9bf_28_ = true; x9bf_28_ = true;
@ -870,18 +872,18 @@ void CMetroid::Generate(CStateManager& mgr, EStateMsg msg, float arg) {
if (msg == EStateMsg::Activate) { if (msg == EStateMsg::Activate) {
if (ShouldSpawnGammaMetroid()) { if (ShouldSpawnGammaMetroid()) {
SpawnGammaMetroid(mgr); SpawnGammaMetroid(mgr);
} else if (x7f8_ >= x56c_data.GetExplosionGrowthEnergy()) { } else if (x7f8_growthEnergy >= x56c_data.GetExplosionGrowthEnergy()) {
MassiveDeath(mgr); MassiveDeath(mgr);
} }
x568_state = EState::One; x568_state = EState::One;
x7dc_scale2 = GetModelData()->GetScale(); x7dc_scale2 = GetModelData()->GetScale();
x9bf_25_ = true; x9bf_25_growing = true;
} else if (msg == EStateMsg::Update) { } else if (msg == EStateMsg::Update) {
CBodyController* bodyController = GetBodyController(); CBodyController* bodyController = GetBodyController();
if (x568_state == EState::One) { if (x568_state == EState::One) {
if (bodyController->GetCurrentStateId() == pas::EAnimationState::Generate) { if (bodyController->GetCurrentStateId() == pas::EAnimationState::Generate) {
x7f4_ = bodyController->GetAnimTimeRemaining(); x7f4_growthDuration = bodyController->GetAnimTimeRemaining();
x568_state = x7f4_ > 0.f ? EState::Two : EState::Over; x568_state = x7f4_growthDuration > 0.f ? EState::Two : EState::Over;
} else if (Attacked(mgr, 0.f)) { } else if (Attacked(mgr, 0.f)) {
bodyController->GetCommandMgr().DeliverCmd(CBCGenerateCmd(pas::EGenerateType::Two)); bodyController->GetCommandMgr().DeliverCmd(CBCGenerateCmd(pas::EGenerateType::Two));
} else { } else {
@ -892,10 +894,10 @@ void CMetroid::Generate(CStateManager& mgr, EStateMsg msg, float arg) {
bool inside = false; bool inside = false;
if (!bodyController->IsFrozen() && ((inside = Inside(mgr, 3.f)) || Attacked(mgr, 0.f))) { if (!bodyController->IsFrozen() && ((inside = Inside(mgr, 3.f)) || Attacked(mgr, 0.f))) {
float timeRem = bodyController->GetAnimTimeRemaining(); float timeRem = bodyController->GetAnimTimeRemaining();
float clamp = std::clamp(1.f - (timeRem / x7f4_), 0.f, 1.f); float clamp = std::clamp(1.f - (timeRem / x7f4_growthDuration), 0.f, 1.f);
zeus::CVector3f scale; zeus::CVector3f scale;
if (0.25f <= clamp) { if (0.25f <= clamp) {
float dVar13 = 0.75f * x7f4_; float dVar13 = 0.75f * x7f4_growthDuration;
const zeus::CVector3f v = 0.5f * x7dc_scale2; const zeus::CVector3f v = 0.5f * x7dc_scale2;
scale = v + (dVar13 - timeRem) * (1.f / dVar13) * (x7d0_scale1 - v); scale = v + (dVar13 - timeRem) * (1.f / dVar13) * (x7d0_scale1 - v);
} else { } else {
@ -912,10 +914,10 @@ void CMetroid::Generate(CStateManager& mgr, EStateMsg msg, float arg) {
} }
} }
} else if (msg == EStateMsg::Deactivate) { } else if (msg == EStateMsg::Deactivate) {
x7f4_ = 0.f; x7f4_growthDuration = 0.f;
x9bf_25_ = false; x9bf_25_growing = false;
if (Attacked(mgr, 0.f)) { if (Attacked(mgr, 0.f)) {
x7fc_ = x7f8_; x7fc_lastGrowthEnergy = x7f8_growthEnergy;
GetModelData()->SetScale(x7d0_scale1); GetModelData()->SetScale(x7d0_scale1);
} }
UpdateVolume(); UpdateVolume();
@ -932,7 +934,7 @@ void CMetroid::SpawnGammaMetroid(CStateManager& mgr) {
} }
void CMetroid::ApplySplitGammas(CStateManager& mgr, float arg) { void CMetroid::ApplySplitGammas(CStateManager& mgr, float arg) {
auto* metroid = CPatterned::CastTo<CMetroid>(mgr.ObjectById(x9bc_)); auto* metroid = CPatterned::CastTo<CMetroid>(mgr.ObjectById(x9bc_parent));
if (metroid == nullptr) { if (metroid == nullptr) {
return; return;
} }
@ -947,9 +949,9 @@ void CMetroid::KnockBack(const zeus::CVector3f& dir, CStateManager& mgr, const C
const CDamageVulnerability* vulnerability = GetDamageVulnerability(); const CDamageVulnerability* vulnerability = GetDamageVulnerability();
float percentFrozen = GetBodyController()->GetPercentageFrozen(); float percentFrozen = GetBodyController()->GetPercentageFrozen();
const CWeaponMode& mode = info.GetWeaponMode(); const CWeaponMode& mode = info.GetWeaponMode();
if (x7c8_ == EUnknown::Two) { if (x7c8_attackState == EAttackState::Draining) {
if (vulnerability->WeaponHits(mode, false)) { if (vulnerability->WeaponHits(mode, false)) {
x7bc_ = x56c_data.GetMaxEnergyDrainAllowed() * GetDamageMultiplier(); x7bc_energyDrained = x56c_data.GetMaxEnergyDrainAllowed() * GetDamageMultiplier();
} }
} else if (vulnerability->WeaponHurts(mode, false)) { } else if (vulnerability->WeaponHurts(mode, false)) {
x7b4_attackChance = x308_attackTimeVariation * mgr.GetActiveRandom()->Float() + x304_averageAttackTime; x7b4_attackChance = x308_attackTimeVariation * mgr.GetActiveRandom()->Float() + x304_averageAttackTime;
@ -961,16 +963,16 @@ void CMetroid::KnockBack(const zeus::CVector3f& dir, CStateManager& mgr, const C
(mode.IsCharged() || mode.IsComboed() || mode.GetType() == EWeaponType::Missile) && (mode.IsCharged() || mode.IsComboed() || mode.GetType() == EWeaponType::Missile) &&
!ShouldSpawnGammaMetroid()) { !ShouldSpawnGammaMetroid()) {
CPatterned::KnockBack(dir, mgr, info, type, inDeferred, magnitude); CPatterned::KnockBack(dir, mgr, info, type, inDeferred, magnitude);
x800_ = x804_; x800_seekTime = x804_maxSeekTime;
} }
} }
bool CMetroid::Attacked(CStateManager& mgr, float arg) { bool CMetroid::Attacked(CStateManager& mgr, float arg) {
if (x7f8_ - x7fc_ > 0.f) { if (x7f8_growthEnergy - x7fc_lastGrowthEnergy > 0.f) {
if (x7fc_ < x56c_data.GetStage2GrowthEnergy()) { if (x7fc_lastGrowthEnergy < x56c_data.GetStage2GrowthEnergy()) {
return x56c_data.GetStage2GrowthEnergy() <= x7f8_; return x56c_data.GetStage2GrowthEnergy() <= x7f8_growthEnergy;
} }
if (x56c_data.GetExplosionGrowthEnergy() <= x7f8_) { if (x56c_data.GetExplosionGrowthEnergy() <= x7f8_growthEnergy) {
return true; return true;
} }
} }
@ -1035,7 +1037,7 @@ bool CMetroid::InAttackPosition(CStateManager& mgr, float arg) {
bool CMetroid::InDetectionRange(CStateManager& mgr, float arg) { bool CMetroid::InDetectionRange(CStateManager& mgr, float arg) {
if (x7b0_attackTarget == kInvalidUniqueId) { if (x7b0_attackTarget == kInvalidUniqueId) {
if ((x9bf_24_alert || CPatterned::InDetectionRange(mgr, arg)) && !IsPlayerUnderwater(mgr) && if ((x9bf_24_alert || CPatterned::InDetectionRange(mgr, arg)) && !IsPlayerUnderwater(mgr) &&
mgr.GetPlayer().GetAreaIdAlways() != GetAreaIdAlways()) { mgr.GetPlayer().GetAreaIdAlways() == GetAreaIdAlways()) {
return true; return true;
} }
// TODO attack pirates // TODO attack pirates
@ -1055,7 +1057,7 @@ void CMetroid::TelegraphAttack(CStateManager& mgr, EStateMsg msg, float dt) {
if (msg == EStateMsg::Activate) { if (msg == EStateMsg::Activate) {
x568_state = EState::Zero; x568_state = EState::Zero;
x7b8_telegraphAttackTime = x56c_data.GetTelegraphAttackTime(); x7b8_telegraphAttackTime = x56c_data.GetTelegraphAttackTime();
x800_ = 0.f; x800_seekTime = 0.f;
GetBodyController()->GetCommandMgr().ClearLocomotionCmds(); GetBodyController()->GetCommandMgr().ClearLocomotionCmds();
GetBodyController()->SetLocomotionType(pas::ELocomotionType::Combat); GetBodyController()->SetLocomotionType(pas::ELocomotionType::Combat);
} else if (msg == EStateMsg::Update) { } else if (msg == EStateMsg::Update) {
@ -1072,11 +1074,11 @@ void CMetroid::TelegraphAttack(CStateManager& mgr, EStateMsg msg, float dt) {
x568_state = EState::Two; x568_state = EState::Two;
const float distance = 1.25f * (GetAttackTargetPos(mgr) - GetTranslation()).magnitude(); const float distance = 1.25f * (GetAttackTargetPos(mgr) - GetTranslation()).magnitude();
const float speed = x3b4_speed > 0.f ? 1.15f / x3b4_speed : 0.f; const float speed = x3b4_speed > 0.f ? 1.15f / x3b4_speed : 0.f;
x804_ = speed + (distance / GetBodyController()->GetBodyStateInfo().GetMaxSpeed()); x804_maxSeekTime = speed + (distance / GetBodyController()->GetBodyStateInfo().GetMaxSpeed());
GetBodyController()->SetTurnSpeed(x3b4_speed > 0.f ? 20.f / x3b4_speed : 20.f); GetBodyController()->SetTurnSpeed(x3b4_speed > 0.f ? 20.f / x3b4_speed : 20.f);
} }
} else if (x568_state == EState::Two) { } else if (x568_state == EState::Two) {
x800_ += dt; x800_seekTime += dt;
const zeus::CVector3f move = x45c_steeringBehaviors.Seek(*this, GetAttackTargetPos(mgr)); const zeus::CVector3f move = x45c_steeringBehaviors.Seek(*this, GetAttackTargetPos(mgr));
GetBodyController()->GetCommandMgr().DeliverCmd(CBCLocomotionCmd(move, zeus::skZero3f, 1.f)); GetBodyController()->GetCommandMgr().DeliverCmd(CBCLocomotionCmd(move, zeus::skZero3f, 1.f));
} }
@ -1207,10 +1209,10 @@ bool CMetroid::InRange(CStateManager& mgr, float arg) {
} }
bool CMetroid::Inside(CStateManager& mgr, float arg) { bool CMetroid::Inside(CStateManager& mgr, float arg) {
if (x9bc_ == kInvalidUniqueId) { if (x9bc_parent == kInvalidUniqueId) {
return false; return false;
} }
if (const auto* other = CPatterned::CastTo<CMetroid>(mgr.GetObjectById(x9bc_))) { if (const auto* other = CPatterned::CastTo<CMetroid>(mgr.GetObjectById(x9bc_parent))) {
float radius = x6a0_collisionPrimitive.GetSphere().radius; float radius = x6a0_collisionPrimitive.GetSphere().radius;
if (arg > 0.f) { if (arg > 0.f) {
radius *= arg; radius *= arg;
@ -1268,14 +1270,47 @@ bool CMetroid::PatternShagged(CStateManager& mgr, float arg) {
return true; return true;
} }
if (x568_state == EState::Two) { if (x568_state == EState::Two) {
return x804_ <= x800_; return x800_seekTime >= x804_maxSeekTime;
} }
return false; return false;
} }
bool CMetroid::ShouldDodge(CStateManager& mgr, float arg) { bool CMetroid::ShouldDodge(CStateManager& mgr, float arg) {
// TODO CPlayer& player = mgr.GetPlayer();
return CAi::ShouldDodge(mgr, arg); if (x3fc_flavor == CPatterned::EFlavorType::Two || x7b0_attackTarget != player.GetUniqueId() ||
GetAreaIdAlways() != player.GetAreaIdAlways()) {
return false;
}
const CTeamAiRole* const aiRole = CTeamAiMgr::GetTeamAiRole(mgr, x698_teamAiMgrId, GetUniqueId());
if (aiRole == nullptr || aiRole->GetTeamAiRole() != CTeamAiRole::ETeamAiRole::Melee) {
return false;
}
const auto& xf = GetTransform();
rstl::reserved_vector<TUniqueId, 1024> nearList;
mgr.BuildNearList(nearList, zeus::CAABox{xf.origin - 9.f, xf.origin + 9.f},
CMaterialFilter::MakeInclude({EMaterialTypes::Projectile}), nullptr);
if (nearList.empty()) {
return false;
}
const auto front = xf.frontVector();
for (const auto id : nearList) {
if (TCastToConstPtr<CGameProjectile> projectile = mgr.GetObjectById(id)) {
if (!projectile->HasAttrib(EProjectileAttrib::Ice)) {
continue;
}
const auto dir = projectile->GetTranslation() - xf.origin;
if (zeus::CVector3f::getAngleDiff(front, dir) >= zeus::degToRad(10.f)) {
continue;
}
pas::EStepDirection dodgeDirection = pas::EStepDirection::Right;
if (xf.rightVector().dot(dir) <= 0.f) {
dodgeDirection = pas::EStepDirection::Left;
}
x818_dodgeDirection = dodgeDirection;
return true;
}
}
return false;
} }
bool CMetroid::ShouldTurn(CStateManager& mgr, float arg) { bool CMetroid::ShouldTurn(CStateManager& mgr, float arg) {
@ -1327,8 +1362,28 @@ void CMetroid::Patrol(CStateManager& mgr, EStateMsg msg, float arg) {
} }
void CMetroid::TargetPatrol(CStateManager& mgr, EStateMsg msg, float dt) { void CMetroid::TargetPatrol(CStateManager& mgr, EStateMsg msg, float dt) {
// TODO if (msg == EStateMsg::Activate) {
CPatterned::TargetPatrol(mgr, msg, dt); GetBodyController()->SetLocomotionType(pas::ELocomotionType::Relaxed);
x7b0_attackTarget = kInvalidUniqueId;
x9bf_26_shotAt = false;
if (HasPatrolPath(mgr, 0.f)) {
CPatterned::Patrol(mgr, msg, dt);
CPatterned::UpdateDest(mgr);
} else {
CPatterned::SetDestPos(x3a0_latestLeashPosition);
}
x7a4_ = GetDestPos();
if (GetSearchPath() != nullptr) {
CPatterned::PathFind(mgr, msg, dt);
}
} else if (msg == EStateMsg::Update) {
if (GetSearchPath() == nullptr || PathShagged(mgr, 0.f)) {
CPatterned::Patrol(mgr, msg, dt);
} else {
CPatterned::PathFind(mgr, msg, dt);
}
ApplySeparationBehavior(mgr, 9.f);
}
} }
void CMetroid::TurnAround(CStateManager& mgr, EStateMsg msg, float dt) { void CMetroid::TurnAround(CStateManager& mgr, EStateMsg msg, float dt) {
@ -1344,8 +1399,33 @@ void CMetroid::TurnAround(CStateManager& mgr, EStateMsg msg, float dt) {
} }
void CMetroid::WallHang(CStateManager& mgr, EStateMsg msg, float dt) { void CMetroid::WallHang(CStateManager& mgr, EStateMsg msg, float dt) {
// TODO if (msg == EStateMsg::Activate) {
CAi::WallHang(mgr, msg, dt); GetBodyController()->SetLocomotionType(pas::ELocomotionType::Crouch);
x568_state = EState::Zero;
RemoveMaterial(EMaterialTypes::Solid, mgr);
x9bf_30_restoreSolidCollision = false;
} else if (msg == EStateMsg::Update) {
if (x568_state == EState::Zero) {
if (x9bf_24_alert) {
x568_state = EState::One;
x9bf_30_restoreSolidCollision = true;
x80c_detachPos.zeroOut();
}
} else if (x568_state == EState::One) {
if (GetBodyController()->GetCurrentStateId() == pas::EAnimationState::Generate) {
x568_state = EState::Two;
} else {
GetBodyController()->GetCommandMgr().DeliverCmd(CBCGenerateCmd(pas::EGenerateType::Zero, zeus::skZero3f));
}
} else if (x568_state == EState::Two) {
if (GetBodyController()->GetCurrentStateId() != pas::EAnimationState::Generate) {
x568_state = EState::Over;
}
}
} else if (msg == EStateMsg::Deactivate) {
GetBodyController()->SetLocomotionType(pas::ELocomotionType::Relaxed);
x9bf_27_ = true;
}
} }
} // namespace urde::MP1 } // namespace urde::MP1

View File

@ -61,15 +61,15 @@ private:
TUniqueId x7b0_attackTarget = kInvalidUniqueId; TUniqueId x7b0_attackTarget = kInvalidUniqueId;
float x7b4_attackChance = 0.f; float x7b4_attackChance = 0.f;
float x7b8_telegraphAttackTime = 0.f; float x7b8_telegraphAttackTime = 0.f;
float x7bc_ = 0.f; float x7bc_energyDrained = 0.f;
float x7c0_ = 0.f; float x7c0_energyDrainTime = 0.f;
float x7c4_ = 0.f; float x7c4_ = 0.f;
enum class EUnknown { enum class EAttackState {
Zero, None,
One, Attached,
Two, Draining,
Three, Over,
} x7c8_ = EUnknown::Zero; } x7c8_attackState = EAttackState::None;
enum class EGammaType { enum class EGammaType {
Invalid = -1, Invalid = -1,
Normal, Normal,
@ -81,26 +81,26 @@ private:
zeus::CVector3f x7d0_scale1; zeus::CVector3f x7d0_scale1;
zeus::CVector3f x7dc_scale2; zeus::CVector3f x7dc_scale2;
zeus::CVector3f x7e8_scale3; zeus::CVector3f x7e8_scale3;
float x7f4_ = 0.f; float x7f4_growthDuration = 0.f;
float x7f8_ = 0.f; float x7f8_growthEnergy = 0.f;
float x7fc_ = 0.f; float x7fc_lastGrowthEnergy = 0.f;
float x800_ = 0.f; float x800_seekTime = 0.f;
float x804_ = 0.f; float x804_maxSeekTime = 0.f;
float x808_loopAttackDistance = 0.f; float x808_loopAttackDistance = 0.f;
zeus::CVector3f x80c_; zeus::CVector3f x80c_detachPos;
pas::EStepDirection x818_dodgeDirection = pas::EStepDirection::Invalid; pas::EStepDirection x818_dodgeDirection = pas::EStepDirection::Invalid;
CPatternedInfo x81c_patternedInfo; CPatternedInfo x81c_patternedInfo;
CActorParameters x954_actParams; CActorParameters x954_actParams;
TUniqueId x9bc_; TUniqueId x9bc_parent;
u8 x9be_ = 0; u8 x9be_ = 0;
bool x9bf_24_alert : 1 = false; bool x9bf_24_alert : 1 = false;
bool x9bf_25_ : 1 = false; bool x9bf_25_growing : 1 = false;
bool x9bf_26_shotAt : 1 = false; bool x9bf_26_shotAt : 1 = false;
bool x9bf_27_ : 1 = false; bool x9bf_27_ : 1 = false;
bool x9bf_28_ : 1 = false; bool x9bf_28_ : 1 = false;
bool x9bf_29_isAttacking : 1 = false; bool x9bf_29_isAttacking : 1 = false;
bool x9bf_30_ : 1 = false; bool x9bf_30_restoreSolidCollision : 1 = false;
bool x9bf_31_ : 1 = false; bool x9bf_31_restoreCharacterCollision : 1 = false;
bool x9c0_24_isEnergyDrainVulnerable : 1 = false; bool x9c0_24_isEnergyDrainVulnerable : 1 = false;
public: public: