diff --git a/Runtime/CStateManager.cpp b/Runtime/CStateManager.cpp index 7b4d6ac25..d64d0929e 100644 --- a/Runtime/CStateManager.cpp +++ b/Runtime/CStateManager.cpp @@ -970,6 +970,14 @@ void CStateManager::DrawWorldCubeFaces() const { } } +void CStateManager::SetupFogForArea3XRange(TAreaId area) const { + if (area == kInvalidAreaId) + area = x8cc_nextAreaId; + const CGameArea* areaObj = x850_world->GetAreaAlways(area); + if (areaObj->IsPostConstructed()) + SetupFogForArea3XRange(*areaObj); +} + void CStateManager::SetupFogForArea(TAreaId area) const { if (area == kInvalidAreaId) area = x8cc_nextAreaId; @@ -986,6 +994,15 @@ void CStateManager::SetupFogForAreaNonCurrent(TAreaId area) const { SetupFogForAreaNonCurrent(*areaObj); } +void CStateManager::SetupFogForArea3XRange(const CGameArea& area) const { + if (x8b8_playerState->GetActiveVisor(*this) == CPlayerState::EPlayerVisor::XRay) { + float fogDist = area.GetXRayFogDistance(); + float farz = (g_tweakGui->GetXRayFogNearZ() * (1.f - fogDist) + g_tweakGui->GetXRayFogFarZ() * fogDist) * 3.f; + g_Renderer->SetWorldFog(ERglFogMode(g_tweakGui->GetXRayFogMode()), g_tweakGui->GetXRayFogNearZ(), farz, + g_tweakGui->GetXRayFogColor()); + } +} + void CStateManager::SetupFogForArea(const CGameArea& area) const { if (SetupFogForDraw()) return; @@ -1180,7 +1197,7 @@ void CStateManager::SendScriptMsgAlways(TUniqueId dest, TUniqueId src, EScriptOb } void CStateManager::SendScriptMsg(TUniqueId src, TEditorId dest, EScriptObjectMessage msg, EScriptObjectState state) { - //CEntity* ent = GetObjectById(src); + // CEntity* ent = GetObjectById(src); auto search = GetIdListForScript(dest); if (search.first != x890_scriptIdMap.cend()) { for (auto it = search.first; it != search.second; ++it) { diff --git a/Runtime/CStateManager.hpp b/Runtime/CStateManager.hpp index 24b645b73..001a952cc 100644 --- a/Runtime/CStateManager.hpp +++ b/Runtime/CStateManager.hpp @@ -261,8 +261,10 @@ public: void DrawWorld() const; void DrawActorCubeFaces(CActor& actor, int& cubeInst) const; void DrawWorldCubeFaces() const; + void SetupFogForArea3XRange(TAreaId area) const; void SetupFogForArea(TAreaId area) const; void SetupFogForAreaNonCurrent(TAreaId area) const; + void SetupFogForArea3XRange(const CGameArea& area) const; void SetupFogForArea(const CGameArea& area) const; void SetupFogForAreaNonCurrent(const CGameArea& area) const; bool SetupFogForDraw() const; diff --git a/Runtime/Character/CCharAnimTime.cpp b/Runtime/Character/CCharAnimTime.cpp index 3cffef350..f64512ea7 100644 --- a/Runtime/Character/CCharAnimTime.cpp +++ b/Runtime/Character/CCharAnimTime.cpp @@ -2,21 +2,18 @@ #include #include -#include namespace urde { CCharAnimTime CCharAnimTime::Infinity() { - CCharAnimTime ret(1.f); - ret.x4_type = EType::Infinity; - return ret; + return {EType::Infinity, 1.f}; } bool CCharAnimTime::EqualsZero() const { if (x4_type == EType::ZeroIncreasing || x4_type == EType::ZeroSteady || x4_type == EType::ZeroDecreasing) return true; - return (x0_time == 0.f); + return x0_time == 0.f; } bool CCharAnimTime::EpsilonZero() const { return (std::fabs(x0_time) < 0.00001f); } @@ -24,7 +21,7 @@ bool CCharAnimTime::EpsilonZero() const { return (std::fabs(x0_time) < 0.00001f) bool CCharAnimTime::GreaterThanZero() const { if (EqualsZero()) return false; - return (x0_time > 0.f); + return x0_time > 0.f; } bool CCharAnimTime::operator==(const CCharAnimTime& other) const { @@ -69,14 +66,14 @@ bool CCharAnimTime::operator>=(const CCharAnimTime& other) const { if (*this == other) return true; - return (*this > other); + return *this > other; } bool CCharAnimTime::operator<=(const CCharAnimTime& other) const { if (*this == other) return true; - return (*this < other); + return *this < other; } bool CCharAnimTime::operator>(const CCharAnimTime& other) const { return (!(*this == other) && !(*this < other)); } @@ -123,19 +120,17 @@ bool CCharAnimTime::operator<(const CCharAnimTime& other) const { } CCharAnimTime& CCharAnimTime::operator*=(const CCharAnimTime& other) { - *this = *this * other; - return *this; + return *this = *this * other; } CCharAnimTime& CCharAnimTime::operator+=(const CCharAnimTime& other) { - *this = *this + other; - return *this; + return *this = *this + other; } CCharAnimTime CCharAnimTime::operator+(const CCharAnimTime& other) const { if (x4_type == EType::Infinity && other.x4_type == EType::Infinity) { if (other.x0_time != x0_time) - return CCharAnimTime(); + return {}; return *this; } else if (x4_type == EType::Infinity) return *this; @@ -143,58 +138,46 @@ CCharAnimTime CCharAnimTime::operator+(const CCharAnimTime& other) const { return other; if (!EqualsZero() || !other.EqualsZero()) - return CCharAnimTime(x0_time + other.x0_time); + return {x0_time + other.x0_time}; int type = -1; if (x4_type != EType::ZeroDecreasing) { - if (x4_type != EType::ZeroSteady) - type = 1; - else - type = 0; + type = x4_type == EType::ZeroSteady ? 0 : 1; } int otherType = -1; if (other.x4_type != EType::ZeroDecreasing) { - if (other.x4_type != EType::ZeroSteady) - otherType = 1; - else - otherType = 0; + otherType = other.x4_type == EType::ZeroSteady ? 0 : 1; } type += otherType; otherType = std::max(-1, std::min(type, 1)); - CCharAnimTime ret; if (otherType == -1) - ret.x4_type = EType::ZeroDecreasing; + return {EType::ZeroDecreasing, 0.f}; else if (otherType == 0) - ret.x4_type = EType::ZeroSteady; + return {EType::ZeroSteady, 0.f}; else - ret.x4_type = EType::ZeroIncreasing; - - return ret; + return {EType::ZeroIncreasing, 0.f}; } CCharAnimTime& CCharAnimTime::operator-=(const CCharAnimTime& other) { - *this = *this - other; - return *this; + return *this = *this - other; } CCharAnimTime CCharAnimTime::operator-(const CCharAnimTime& other) const { if (x4_type == EType::Infinity && other.x4_type == EType::Infinity) { if (other.x0_time == x0_time) - return CCharAnimTime(); + return {}; return *this; } else if (x4_type == EType::Infinity) return *this; else if (other.x4_type == EType::Infinity) { - CCharAnimTime ret(-other.x0_time); - ret.x4_type = EType::Infinity; - return ret; + return {EType::Infinity, -other.x0_time}; } if (!EqualsZero() || !other.EqualsZero()) - return CCharAnimTime(x0_time - other.x0_time); + return {x0_time - other.x0_time}; int type = -1; if (x4_type != EType::ZeroDecreasing) { @@ -212,22 +195,19 @@ CCharAnimTime CCharAnimTime::operator-(const CCharAnimTime& other) const { otherType = 0; } - CCharAnimTime ret; type -= otherType; if (type == -1) - ret.x4_type = EType::ZeroDecreasing; + return {EType::ZeroDecreasing, 0.f}; else if (type == 0) - ret.x4_type = EType::ZeroSteady; + return {EType::ZeroSteady, 0.f}; else - ret.x4_type = EType::ZeroIncreasing; - - return ret; + return {EType::ZeroIncreasing, 0.f}; } CCharAnimTime CCharAnimTime::operator*(const CCharAnimTime& other) const { if (x4_type == EType::Infinity && other.x4_type == EType::Infinity) { if (other.x0_time != x0_time) - return CCharAnimTime(); + return {}; return *this; } else if (x4_type == EType::Infinity) return *this; @@ -235,7 +215,7 @@ CCharAnimTime CCharAnimTime::operator*(const CCharAnimTime& other) const { return other; if (!EqualsZero() || !other.EqualsZero()) - return CCharAnimTime(x0_time * other.x0_time); + return {x0_time * other.x0_time}; int type = -1; if (x4_type != EType::ZeroDecreasing) { @@ -256,31 +236,31 @@ CCharAnimTime CCharAnimTime::operator*(const CCharAnimTime& other) const { type += otherType; otherType = std::max(-1, std::min(type, 1)); - CCharAnimTime ret; if (otherType == -1) - ret.x4_type = EType::ZeroDecreasing; + return {EType::ZeroDecreasing, 0.f}; else if (otherType == 0) - ret.x4_type = EType::ZeroSteady; + return {EType::ZeroSteady, 0.f}; else - ret.x4_type = EType::ZeroIncreasing; - return ret; + return {EType::ZeroIncreasing, 0.f}; } CCharAnimTime CCharAnimTime::operator*(const float& other) const { - CCharAnimTime ret; if (other == 0.f) - return ret; + return {}; if (!EqualsZero()) - return CCharAnimTime(x0_time * other); + return {x0_time * other}; if (other > 0.f) return *this; - else if (other == 0.f) - return ret; - ret.x4_type = x4_type; - return ret; + if (x4_type == EType::ZeroDecreasing) { + return {EType::ZeroIncreasing, 0.f}; + } else if (x4_type == EType::ZeroSteady) { + return {EType::ZeroSteady, 0.f}; + } else { + return {EType::ZeroDecreasing, 0.f}; + } } float CCharAnimTime::operator/(const CCharAnimTime& other) const { diff --git a/Runtime/Collision/CCollisionResponseData.hpp b/Runtime/Collision/CCollisionResponseData.hpp index 36ce52ddc..019426945 100644 --- a/Runtime/Collision/CCollisionResponseData.hpp +++ b/Runtime/Collision/CCollisionResponseData.hpp @@ -54,7 +54,7 @@ enum class EWeaponCollisionResponseTypes { Unknown35, Unknown36, Unknown37, - Unknown38, + ChozoGhost, Unknown39, Unknown40, Unknown41, diff --git a/Runtime/MP1/World/CChozoGhost.cpp b/Runtime/MP1/World/CChozoGhost.cpp index 6bc381343..56ead1af0 100644 --- a/Runtime/MP1/World/CChozoGhost.cpp +++ b/Runtime/MP1/World/CChozoGhost.cpp @@ -1,105 +1,771 @@ #include "Runtime/MP1/World/CChozoGhost.hpp" +#include "Runtime/GameGlobalObjects.hpp" #include "Runtime/CStateManager.hpp" +#include "Runtime/CSimplePool.hpp" #include "Runtime/CRandom16.hpp" +#include "Runtime/Character/CPASAnimParmData.hpp" +#include "Runtime/Weapon/CGameProjectile.hpp" +#include "Runtime/World/CPlayer.hpp" +#include "Runtime/World/CScriptCoverPoint.hpp" +#include "Runtime/World/CScriptWaypoint.hpp" +#include "Runtime/World/CTeamAiMgr.hpp" #include "TCastTo.hpp" // Generated file, do not modify include path + namespace urde::MP1 { CChozoGhost::CBehaveChance::CBehaveChance(CInputStream& in) : x0_propertyCount(in.readUint32Big()) -, x4_(in.readFloatBig()) -, x8_(in.readFloatBig()) -, xc_(in.readFloatBig()) -, x10_(in.readFloatBig()) -, x14_(in.readFloatBig()) -, x18_(x0_propertyCount <= 5 ? 0.5f : in.readFloatBig() * .01f) -, x1c_(x0_propertyCount <= 6 ? 2 : in.readUint32Big()) { - float f2 = 1.f / (x10_ + xc_ + x4_ + x8_); - x4_ *= f2; - x8_ *= f2; - xc_ *= f2; - x10_ *= f2; +, x4_lurk(in.readFloatBig()) +, x8_taunt(in.readFloatBig()) +, xc_attack(in.readFloatBig()) +, x10_move(in.readFloatBig()) +, x14_lurkTime(in.readFloatBig()) +, x18_chargeAttack(x0_propertyCount < 6 ? 0.5f : in.readFloatBig() * .01f) +, x1c_numBolts(x0_propertyCount < 7 ? 2 : in.readUint32Big()) { + float f2 = 1.f / (x10_move + xc_attack + x4_lurk + x8_taunt); + x4_lurk *= f2; + x8_taunt *= f2; + xc_attack *= f2; + x10_move *= f2; } -u32 CChozoGhost::CBehaveChance::GetBehave(EBehaveType type, CStateManager& mgr) const { - float dVar5 = x4_; - float dVar4 = x8_; - float dVar3 = xc_; - if (type == EBehaveType::Zero) { - float dVar2 = dVar5 / 3.f; - dVar5 = 0.f; - dVar4 += dVar2; - dVar3 += dVar2; - } else if (type == EBehaveType::One) { - float dVar2 = dVar4 / 3.f; - dVar4 = 0.f; - dVar5 += dVar2; - dVar3 += dVar2; - } else if (type == EBehaveType::Two) { - float dVar2 = dVar3 / 3.f; - dVar3 = 0.f; - dVar5 += dVar2; - dVar4 += dVar2; - } else if (type == EBehaveType::Three) { - float dVar2 = x10_ / 3.f; - dVar5 += dVar2; - dVar4 += dVar2; - dVar3 += dVar2; +EBehaveType CChozoGhost::CBehaveChance::GetBehave(EBehaveType type, CStateManager& mgr) const { + float lurkChance = x4_lurk; + float tauntChance = x8_taunt; + float attackChance = xc_attack; + if (type == EBehaveType::Lurk) { + float delta = lurkChance / 3.f; + lurkChance = 0.f; + tauntChance += delta; + attackChance += delta; + } else if (type == EBehaveType::Taunt) { + float delta = tauntChance / 3.f; + tauntChance = 0.f; + lurkChance += delta; + attackChance += delta; + } else if (type == EBehaveType::Attack) { + float delta = attackChance / 3.f; + attackChance = 0.f; + lurkChance += delta; + tauntChance += delta; + } else if (type == EBehaveType::Move) { + float delta = x10_move / 3.f; + lurkChance += delta; + tauntChance += delta; + attackChance += delta; } float rnd = mgr.GetActiveRandom()->Float(); - if (dVar5 > rnd) - return 0; - else if (dVar4 > (rnd - dVar5)) - return 1; - else if (dVar3 > (rnd - dVar5) - dVar4) - return 2; - return 3; + if (lurkChance > rnd) + return EBehaveType::Lurk; + else if (tauntChance > rnd - lurkChance) + return EBehaveType::Taunt; + else if (attackChance > rnd - lurkChance - tauntChance) + return EBehaveType::Attack; + return EBehaveType::Move; } CChozoGhost::CChozoGhost(TUniqueId uid, std::string_view name, const CEntityInfo& info, const zeus::CTransform& xf, - CModelData&& mData, const CActorParameters& actParms, const CPatternedInfo& pInfo, float f1, - float f2, float f3, float f4, CAssetId wpsc1, const CDamageInfo& dInfo1, CAssetId wpsc2, - const CDamageInfo& dInfo2, const CBehaveChance& chance1, const CBehaveChance& chance2, - const CBehaveChance& chance3, u16 sId1, float f5, u16 sId2, u16 sId3, u32 w1, float f6, u32 w2, - float f7, CAssetId partId, s16 sId4, float f8, float f9, u32 w3, u32 w4) + CModelData&& mData, const CActorParameters& actParms, const CPatternedInfo& pInfo, + float hearingRadius, float fadeOutDelay, float attackDelay, float freezeTime, CAssetId wpsc1, + const CDamageInfo& dInfo1, CAssetId wpsc2, const CDamageInfo& dInfo2, + const CBehaveChance& chance1, const CBehaveChance& chance2, const CBehaveChance& chance3, + u16 soundImpact, float f5, u16 sId2, u16 sId3, u32 w1, float f6, u32 w2, float hurlRecoverTime, + CAssetId projectileVisorEffect, s16 soundProjectileVisor, float f8, float f9, u32 nearChance, + u32 midChance) : CPatterned(ECharacter::ChozoGhost, uid, name, EFlavorType::Zero, info, xf, std::move(mData), pInfo, EMovementType::Flyer, EColliderType::Zero, EBodyType::BiPedal, actParms, EKnockBackVariant::Medium) -, x568_(f1) -, x56c_(f2) -, x570_(f3) -, x574_(f4) +, x568_hearingRadius(hearingRadius) +, x56c_fadeOutDelay(fadeOutDelay) +, x570_attackDelay(attackDelay) +, x574_freezeTime(freezeTime) , x578_(wpsc1, dInfo1) , x5a0_(wpsc2, dInfo2) , x5c8_(chance1) , x5e8_(chance2) , x608_(chance3) -, x628_(sId1) +, x628_soundImpact(soundImpact) , x62c_(f5) -, x630_(sId2) -, x632_(sId3) +, x630_sfxFadeIn(sId2) +, x632_sfxFadeOut(sId3) , x634_(f6) -, x638_(f7) +, x638_hurlRecoverTime(hurlRecoverTime) , x63c_(w2) -, x650_(sId4) +, x650_sound_ProjectileVisor(soundProjectileVisor) , x654_(f8) , x658_(f9) -, x65c_(w3) -, x660_(w4) -, x664_24_(w1) -, x664_25_(w1) -, x664_26_(false) -, x664_27_(false) +, x65c_nearChance(nearChance) +, x660_midChance(midChance) +, x664_24_behaviorEnabled(w1) +, x664_25_flinch(!w1) +, x664_26_alert(false) +, x664_27_onGround(false) , x664_28_(false) -, x664_29_(false) -, x664_30_(false) +, x664_29_fadedIn(false) +, x664_30_fadedOut(false) , x664_31_(false) , x665_24_(true) , x665_25_(false) -, x665_26_(false) -, x665_27_(false) -, x665_28_(false) -, x665_29_(false) +, x665_26_shouldSwoosh(false) +, x665_27_playerInLeashRange(false) +, x665_28_inRange(false) +, x665_29_aggressive(false) +, x680_behaveType(x664_24_behaviorEnabled ? EBehaveType::Attack : EBehaveType::None) , x68c_boneTracking(*GetModelData()->GetAnimationData(), "Head_1"sv, zeus::degToRad(80.f), zeus::degToRad(180.f), - EBoneTrackingFlags::None) {} -} // namespace urde::MP1 \ No newline at end of file + EBoneTrackingFlags::None) { + x578_.Token().Lock(); + x5a0_.Token().Lock(); + x668_ = GetModelData()->GetScale().z() * + GetAnimationDistance(CPASAnimParmData(13, CPASAnimParm::FromEnum(3), CPASAnimParm::FromEnum(0))); + x66c_ = GetModelData()->GetScale().z() * + GetAnimationDistance(CPASAnimParmData(15, CPASAnimParm::FromEnum(1), CPASAnimParm::FromReal32(90.f))); + x670_ = GetModelData()->GetScale().z() * + GetAnimationDistance(CPASAnimParmData(7, CPASAnimParm::FromEnum(2), CPASAnimParm::FromEnum(1))); + + if (projectileVisorEffect.IsValid()) + x640_projectileVisor = g_SimplePool->GetObj({SBIG('PART'), projectileVisorEffect}); + x460_knockBackController.SetEnableBurn(false); + x460_knockBackController.SetEnableLaggedBurnDeath(false); + x460_knockBackController.SetEnableShock(false); + x460_knockBackController.SetEnableFreeze(false); + CreateShadow(false); + MakeThermalColdAndHot(); +} + +void CChozoGhost::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) { + CPatterned::AcceptScriptMsg(msg, uid, mgr); + + switch (msg) { + case EScriptObjectMessage::Activate: + AddToTeam(mgr); + break; + case EScriptObjectMessage::Deactivate: + case EScriptObjectMessage::Deleted: + RemoveFromTeam(mgr); + break; + case EScriptObjectMessage::Action: + if (x664_25_flinch) + x665_29_aggressive = true; + break; + case EScriptObjectMessage::Alert: + if (x664_26_alert) + break; + x664_26_alert = true; + x400_24_hitByPlayerProjectile = true; + break; + case EScriptObjectMessage::Falling: + case EScriptObjectMessage::Jumped: { + if (!x328_25_verticalMovement) + x150_momentum = {0.f, 0.f, -(GetGravityConstant() * GetMass())}; + break; + } + case EScriptObjectMessage::InitializedInArea: + if (GetActive()) + AddToTeam(mgr); + break; + default: + break; + } +} + +void CChozoGhost::Think(float dt, CStateManager& mgr) { + if (!GetActive()) + return; + + CPatterned::Think(dt, mgr); + UpdateThermalFrozenState(false); + x68c_boneTracking.Update(dt); + x6c8_spaceWarpTime = std::max(0.f, x6c8_spaceWarpTime - dt); + xe7_31_targetable = IsVisibleEnough(mgr); +} + +void CChozoGhost::PreRender(CStateManager& mgr, const zeus::CFrustum& frustum) { + x402_29_drawParticles = mgr.GetPlayerState()->GetActiveVisor(mgr) == CPlayerState::EPlayerVisor::XRay; + if (mgr.GetPlayerState()->GetActiveVisor(mgr) == CPlayerState::EPlayerVisor::Thermal) { + SetCalculateLighting(false); + x90_actorLights->BuildConstantAmbientLighting(zeus::skWhite); + } else { + SetCalculateLighting(true); + } + + u8 alpha = GetModelAlphau8(mgr); + u8 r, g, b, a; + x42c_color.toRGBA8(r, g, b, a); + if (alpha < 255 || r == 0) { + zeus::CColor col; + if (r == 0) { + col = zeus::skWhite; + } else { + float v = std::max(0, r - 255) * (1.f / 255.f); + col.r() = 1.f; + col.g() = v; + col.b() = v; + } + col.a() = alpha * (1.f / 255.f); + xb4_drawFlags = CModelFlags(5, 0, 3, col); + } else { + xb4_drawFlags = CModelFlags(0, 0, 3, zeus::skWhite); + } + CPatterned::PreRender(mgr, frustum); + x68c_boneTracking.PreRender(mgr, *GetModelData()->GetAnimationData(), GetTransform(), GetModelData()->GetScale(), + *GetBodyController()); +} + +void CChozoGhost::Render(const CStateManager& mgr) const { + if (x6c8_spaceWarpTime > 0.f) + mgr.DrawSpaceWarp(x6cc_spaceWarpPosition, std::sin((M_PIF * x6c8_spaceWarpTime) / x56c_fadeOutDelay)); + + if (mgr.GetPlayerState()->GetActiveVisor(mgr) == CPlayerState::EPlayerVisor::XRay) { + CElementGen::SetSubtractBlend(true); + CElementGen::g_ParticleSystemInitialized = true; + CGraphics::SetFog(ERglFogMode::PerspLin, 0.f, 75.f, zeus::skBlack); + mgr.SetupFogForArea3XRange(GetAreaIdAlways()); + } + + CPatterned::Render(mgr); + + if (mgr.GetPlayerState()->GetActiveVisor(mgr) == CPlayerState::EPlayerVisor::XRay) { + CGraphics::SetFog(ERglFogMode::PerspLin, 0.f, 75.f, zeus::skBlack); + GetModelData()->GetAnimationData()->GetParticleDB().RenderSystemsToBeDrawnLast(); + mgr.SetupFogForArea(GetAreaIdAlways()); + CElementGen::SetSubtractBlend(false); + CElementGen::g_ParticleSystemInitialized = false; + } +} + +void CChozoGhost::Touch(CActor& act, CStateManager& mgr) { + if (IsVisibleEnough(mgr)) { + if (TCastToPtr pl = act) { + if (x420_curDamageRemTime <= 0.f) { + mgr.ApplyDamage(GetUniqueId(), pl->GetUniqueId(), GetUniqueId(), GetContactDamage(), + CMaterialFilter::MakeIncludeExclude({EMaterialTypes::Solid}, {}), {}); + x420_curDamageRemTime = x424_damageWaitTime; + } + } + } + CPatterned::Touch(act, mgr); +} + +EWeaponCollisionResponseTypes CChozoGhost::GetCollisionResponseType(const zeus::CVector3f& pos, + const zeus::CVector3f& dir, const CWeaponMode& mode, + EProjectileAttrib attrib) const { + return EWeaponCollisionResponseTypes::ChozoGhost; +} + +void CChozoGhost::DoUserAnimEvent(CStateManager& mgr, const CInt32POINode& node, EUserEventType type, float dt) { + + if (type == EUserEventType::FadeIn) { + if (x664_30_fadedOut) { + x3e8_alphaDelta = 2.f; + CSfxManager::AddEmitter(x630_sfxFadeIn, GetTranslation(), {}, false, false, 127, -1); + } + AddMaterial(EMaterialTypes::Target, mgr); + x664_30_fadedOut = false; + x664_29_fadedIn = true; + return; + } else if (type == EUserEventType::Projectile) { + const zeus::CTransform& xf = + zeus::lookAt(GetLctrTransform(node.GetLocatorName()).origin, mgr.GetPlayer().GetAimPosition(mgr, 0.f)); + if (x67c_attackType == 2) { + CGameProjectile* proj = + LaunchProjectile(xf, mgr, 2, EProjectileAttrib::BigStrike | EProjectileAttrib::StaticInterference, true, + x640_projectileVisor, x650_sound_ProjectileVisor, false, zeus::skOne3f); + if (proj) { + proj->AddAttrib(EProjectileAttrib::BigStrike); + proj->SetDamageDuration(x62c_); + proj->AddAttrib(EProjectileAttrib::StaticInterference); + proj->SetInterferenceDuration(x62c_); + proj->SetMinHomingDistance(x634_); + } + } else { + CGameProjectile* proj = + LaunchProjectile(xf, mgr, 5, EProjectileAttrib::DamageFalloff | EProjectileAttrib::StaticInterference, true, + {x640_projectileVisor}, x650_sound_ProjectileVisor, false, zeus::skOne3f); + if (proj) { + proj->AddAttrib(EProjectileAttrib::BigStrike); + proj->SetDamageDuration(x62c_); + proj->AddAttrib(EProjectileAttrib::StaticInterference); + proj->SetInterferenceDuration(x62c_); + proj->SetMinHomingDistance(x634_); + } + } + return; + } else if (type == EUserEventType::FadeOut) { + if (x664_29_fadedIn) { + x3e8_alphaDelta = -2.f; + CSfxManager::AddEmitter(x632_sfxFadeOut, GetTranslation(), {}, false, false, 127, -1); + } + RemoveMaterial(EMaterialTypes::Target, mgr); + x664_29_fadedIn = false; + x664_30_fadedOut = true; + x665_26_shouldSwoosh = true; + return; + } + + CPatterned::DoUserAnimEvent(mgr, node, type, dt); + + if (type == EUserEventType::Delete) + x3e8_alphaDelta = -1.f; +} + +void CChozoGhost::KnockBack(const zeus::CVector3f& dir, CStateManager& mgr, const CDamageInfo& info, + EKnockBackType type, bool inDeferred, float magnitude) { + if (!IsAlive()) + x460_knockBackController.SetAvailableState(EKnockBackAnimationState::Hurled, false); + else if (!x460_knockBackController.TestAvailableState(EKnockBackAnimationState::KnockBack) && + info.GetWeaponMode().IsCharged()) + x460_knockBackController.SetAnimationStateRange(EKnockBackAnimationState::Hurled, EKnockBackAnimationState::Fall); + + CPatterned::KnockBack(dir, mgr, info, type, inDeferred, magnitude); + if (!IsAlive()) { + Stop(); + x150_momentum.zeroOut(); + } else if (x460_knockBackController.GetActiveParms().x0_animState == EKnockBackAnimationState::Hurled) { + x330_stateMachineState.SetState(mgr, *this, GetStateMachine(), "Hurled"sv); + } +} + +bool CChozoGhost::CanBeShot(const CStateManager& mgr, int) { return IsVisibleEnough(mgr); } + +void CChozoGhost::Dead(CStateManager& mgr, EStateMsg msg, float) { + if (msg == EStateMsg::Activate) { + ReleaseCoverPoint(mgr, x674_coverPoint); + x3e8_alphaDelta = 4.f; + x664_30_fadedOut = false; + x664_29_fadedIn = false; + x68c_boneTracking.SetActive(false); + Stop(); + } +} + +void CChozoGhost::SelectTarget(CStateManager& mgr, EStateMsg msg, float) { + if (msg == EStateMsg::Activate) + FindBestAnchor(mgr); +} + +void CChozoGhost::Run(CStateManager& mgr, EStateMsg msg, float dt) { + if (msg == EStateMsg::Activate) { + GetBodyController()->SetLocomotionType(pas::ELocomotionType::Lurk); + x400_24_hitByPlayerProjectile = false; + x460_knockBackController.SetAvailableState(EKnockBackAnimationState::KnockBack, false); + x665_28_inRange = false; + } else if (msg == EStateMsg::Update) { + GetBodyController()->GetCommandMgr().DeliverCmd(CBCLocomotionCmd(x688_.Seek(*this, x2e0_destPos), {}, 1.f)); + if (x665_26_shouldSwoosh) { + x678_floorLevel = x2e0_destPos.z(); + FloatToLevel(x678_floorLevel, dt); + GetModelData()->GetAnimationData()->SetParticleEffectState("SpeedSwoosh", true, mgr); + x665_24_ = false; + if (!x665_28_inRange) { + const float range = 2.5f * (dt * x138_velocity.magnitude()) + x66c_; + x665_28_inRange = (GetTranslation() - x2e0_destPos).magSquared() < range * range; + } + } + } else if (msg == EStateMsg::Deactivate) { + GetBodyController()->SetLocomotionType(pas::ELocomotionType::Crouch); + SetDestPos(mgr.GetPlayer().GetTranslation()); + GetModelData()->GetAnimationData()->SetParticleEffectState("SpeedSwoosh", false, mgr); + x460_knockBackController.SetAvailableState(EKnockBackAnimationState::KnockBack, true); + x665_28_inRange = false; + } +} + +void CChozoGhost::Generate(CStateManager& mgr, EStateMsg msg, float dt) { + if (msg == EStateMsg::Activate) { + x330_stateMachineState.SetDelay(x56c_fadeOutDelay); + x32c_animState = EAnimState::Ready; + x664_27_onGround = false; + const CRayCastResult& res = mgr.RayStaticIntersection(GetTranslation(), zeus::skDown, 100.f, + CMaterialFilter::MakeInclude({EMaterialTypes::Floor})); + if (res.IsInvalid()) { + x678_floorLevel = mgr.GetPlayer().GetTranslation().z(); + } else { + x678_floorLevel = res.GetPoint().z(); + } + x3e8_alphaDelta = 1.f; + x664_29_fadedIn = true; + if (x56c_fadeOutDelay > 0.f) { + x6c8_spaceWarpTime = x56c_fadeOutDelay; + FindSpaceWarpPosition(mgr, zeus::skDown); + } + } else if (msg == EStateMsg::Update) { + TryCommand(mgr, pas::EAnimationState::Jump, &CPatterned::TryJump, 0); + if (x32c_animState == EAnimState::Over) { + x68c_boneTracking.SetActive(true); + x68c_boneTracking.SetTarget(mgr.GetPlayer().GetUniqueId()); + FloatToLevel(x678_floorLevel, dt); + } else if (x32c_animState == EAnimState::Repeat) { + x450_bodyController->SetLocomotionType(pas::ELocomotionType::Crouch); + if (!x664_27_onGround) { + const zeus::CVector3f& pos = GetTranslation(); + SetTranslation({pos.x(), pos.y(), x678_floorLevel + x668_}); + x664_27_onGround = true; + } + } + } else if (msg == EStateMsg::Deactivate) { + x32c_animState = EAnimState::NotReady; + x665_24_ = false; + x664_27_onGround = false; + } +} + +void CChozoGhost::Deactivate(CStateManager& mgr, EStateMsg msg, float) { + if (msg == EStateMsg::Activate) { + x68c_boneTracking.SetActive(false); + ReleaseCoverPoint(mgr, x674_coverPoint); + x32c_animState = EAnimState::Ready; + x665_24_ = true; + } else if (msg == EStateMsg::Update) { + TryCommand(mgr, pas::EAnimationState::Generate, &CPatterned::TryGenerate, 1); + if (x32c_animState == EAnimState::Repeat) + GetBodyController()->SetLocomotionType(pas::ELocomotionType::Relaxed); + } else if (msg == EStateMsg::Deactivate) { + x32c_animState = EAnimState::NotReady; + } +} + +void CChozoGhost::Attack(CStateManager& mgr, EStateMsg msg, float dt) { + if (msg == EStateMsg::Activate) { + CTeamAiMgr::AddAttacker(CTeamAiMgr::EAttackType::Melee, mgr, x6c4_teamMgr, GetUniqueId()); + x32c_animState = EAnimState::Ready; + if (x6d8_ == 1) + x67c_attackType = 3; + else if (x6d8_ == 2) + x67c_attackType = 4; + else if (x6d8_ == 3) + x67c_attackType = 5; + + const CRayCastResult& res = mgr.RayStaticIntersection(GetTranslation() + (zeus::skUp * 0.5f), zeus::skUp, x670_, + CMaterialFilter::MakeInclude({EMaterialTypes::Solid})); + if (x665_26_shouldSwoosh && res.IsValid()) { + x67c_attackType = 2; + x460_knockBackController.SetAvailableState(EKnockBackAnimationState::KnockBack, false); + } + x150_momentum.zeroOut(); + xfc_constantForce.zeroOut(); + } else if (msg == EStateMsg::Update) { + TryCommand(mgr, pas::EAnimationState::MeleeAttack, &CPatterned::TryMeleeAttack, x67c_attackType); + GetBodyController()->GetCommandMgr().SetTargetVector(mgr.GetPlayer().GetTranslation() - GetTranslation()); + if (x67c_attackType != 2) + FloatToLevel(x678_floorLevel, dt); + } else if (msg == EStateMsg::Deactivate) { + x32c_animState = EAnimState::NotReady; + x665_26_shouldSwoosh = false; + x460_knockBackController.SetAvailableState(EKnockBackAnimationState::KnockBack, true); + CTeamAiMgr::ResetTeamAiRole(CTeamAiMgr::EAttackType::Ranged, mgr, x6c4_teamMgr, GetUniqueId(), true); + } +} + +void CChozoGhost::Shuffle(CStateManager& mgr, EStateMsg msg, float) { + if (msg != EStateMsg::Activate) + return; + + const CBehaveChance& chance1 = ChooseBehaveChanceRange(mgr); + CTeamAiRole* role = CTeamAiMgr::GetTeamAiRole(mgr, x6c4_teamMgr, GetUniqueId()); + if (role && role->GetTeamAiRole() == CTeamAiRole::ETeamAiRole::Ranged && + !CTeamAiMgr::CanAcceptAttacker(CTeamAiMgr::EAttackType::Ranged, mgr, x6c4_teamMgr, GetUniqueId())) { + x680_behaveType = EBehaveType::Attack; + } + + const CBehaveChance& chance2 = ChooseBehaveChanceRange(mgr); + x680_behaveType = chance2.GetBehave(x680_behaveType, mgr); + if (x680_behaveType == EBehaveType::Lurk) + x684_lurkDelay = chance1.GetLurkTime(); + else if (x680_behaveType == EBehaveType::Attack) { + x665_25_ = mgr.GetActiveRandom()->Float() < chance1.GetChargeAttack(); + const int rnd = mgr.GetActiveRandom()->Next(); + x6d8_ = (rnd - (rnd / chance1.GetNumBolts()) * chance1.GetNumBolts()) + 1; + } + x664_31_ = false; + x665_27_playerInLeashRange = false; +} + +void CChozoGhost::InActive(CStateManager& mgr, EStateMsg msg, float) { + if (msg == EStateMsg::Activate) { + if (!x450_bodyController->GetActive()) + x450_bodyController->Activate(mgr); + + if (x63c_ == 3) { + x450_bodyController->SetLocomotionType(pas::ELocomotionType::Crouch); + x42c_color.a() = 1.f; + } else { + x450_bodyController->SetLocomotionType(pas::ELocomotionType::Relaxed); + x42c_color.a() = 0.f; + } + + RemoveMaterial(EMaterialTypes::Solid, mgr); + x150_momentum.zeroOut(); + x665_24_ = true; + } +} + +void CChozoGhost::Taunt(CStateManager& mgr, EStateMsg msg, float dt) { + if (msg == EStateMsg::Activate) { + x32c_animState = EAnimState::Ready; + } else if (msg == EStateMsg::Update) { + TryCommand(mgr, pas::EAnimationState::Taunt, &CPatterned::TryTaunt, 0); + FloatToLevel(x678_floorLevel, dt); + } else { + x32c_animState = EAnimState::NotReady; + x665_26_shouldSwoosh = false; + } +} + +void CChozoGhost::Hurled(CStateManager& mgr, EStateMsg msg, float) { + if (msg == EStateMsg::Activate) { + x328_25_verticalMovement = false; + x664_27_onGround = false; + x665_24_ = true; + } else if (msg == EStateMsg::Update) { + x3e8_alphaDelta = 2.f; + if (x664_27_onGround) + return; + + if (x138_velocity.z() < 0.f) { + const CRayCastResult& res = mgr.RayStaticIntersection(GetTranslation() + zeus::skUp, zeus::skDown, 2.f, + CMaterialFilter::MakeInclude({EMaterialTypes::Floor})); + if (res.IsValid()) { + x664_27_onGround = true; + x150_momentum.zeroOut(); + SetVelocityWR({x138_velocity.x(), x138_velocity.y(), 0.f}); + x678_floorLevel = res.GetPoint().z(); + x330_stateMachineState.SetCodeTrigger(); + } + } + if (!x664_27_onGround && x638_hurlRecoverTime < x330_stateMachineState.GetTime()) { + GetBodyController()->GetCommandMgr().DeliverCmd(CBodyStateCmd(EBodyStateCmd::ExitState)); + GetBodyController()->SetLocomotionType(pas::ELocomotionType::Lurk); + x330_stateMachineState.SetCodeTrigger(); + } + } else if (msg == EStateMsg::Deactivate) { + x328_25_verticalMovement = true; + x150_momentum.zeroOut(); + } +} + +void CChozoGhost::WallDetach(CStateManager& mgr, EStateMsg msg, float) { + if (msg == EStateMsg::Activate) { + x330_stateMachineState.SetDelay(x56c_fadeOutDelay); + x3e8_alphaDelta = 0.f; + x664_29_fadedIn = false; + if (x56c_fadeOutDelay > 0.f) { + x6c8_spaceWarpTime = x56c_fadeOutDelay; + FindSpaceWarpPosition(mgr, GetTransform().basis[1]); + } + TUniqueId wpId = GetWaypointForState(mgr, EScriptObjectState::Attack, EScriptObjectMessage::Follow); + TCastToConstPtr wp; + if (wpId != kInvalidUniqueId) { + wp = TCastToConstPtr(mgr.GetObjectById(wpId)); + } + if (wp) + SetDestPos(wp->GetTranslation()); + else + SetDestPos(GetTranslation() + (2.f * x66c_) * GetTranslation()); + + SendScriptMsgs(EScriptObjectState::Attack, mgr, EScriptObjectMessage::Follow); + } else if (msg == EStateMsg::Deactivate) { + x68c_boneTracking.SetActive(true); + x68c_boneTracking.SetTarget(mgr.GetPlayer().GetUniqueId()); + x665_24_ = false; + x680_behaveType = EBehaveType::Move; + } +} + +void CChozoGhost::Growth(CStateManager& mgr, EStateMsg msg, float) { + if (msg == EStateMsg::Activate) { + x330_stateMachineState.SetDelay(x56c_fadeOutDelay); + GetBodyController()->SetLocomotionType(pas::ELocomotionType::Crouch); + x3e8_alphaDelta = 1.f; + x664_29_fadedIn = true; + if (x56c_fadeOutDelay > 0.f) { + x6c8_spaceWarpTime = x56c_fadeOutDelay; + FindSpaceWarpPosition(mgr, zeus::skUp); + } + } else if (msg == EStateMsg::Deactivate) { + x665_24_ = false; + x68c_boneTracking.SetActive(false); + x68c_boneTracking.SetTarget(mgr.GetPlayer().GetUniqueId()); + } +} + +void CChozoGhost::Land(CStateManager& mgr, EStateMsg msg, float dt) { + if (msg == EStateMsg::Update) { + FloatToLevel(x678_floorLevel, dt); + if (std::fabs(x678_floorLevel - GetTranslation().z()) < 0.05f) { + x330_stateMachineState.SetCodeTrigger(); + } + } +} + +void CChozoGhost::Lurk(CStateManager& mgr, EStateMsg msg, float dt) { + if (msg == EStateMsg::Activate) { + x330_stateMachineState.SetDelay(x684_lurkDelay); + } else if (msg == EStateMsg::Update) { + FloatToLevel(x678_floorLevel, dt); + } +} + +bool CChozoGhost::Leash(CStateManager& mgr, float arg) { + return x665_27_playerInLeashRange || CPatterned::Leash(mgr, arg); +} + +bool CChozoGhost::InRange(CStateManager& mgr, float arg) { return x665_28_inRange; } + +bool CChozoGhost::ShouldAttack(CStateManager& mgr, float arg) { return x680_behaveType == EBehaveType::Attack; } + +bool CChozoGhost::AggressionCheck(CStateManager& mgr, float arg) { return x665_29_aggressive; } + +bool CChozoGhost::ShouldTaunt(CStateManager& mgr, float arg) { return x680_behaveType == EBehaveType::Taunt; } + +bool CChozoGhost::ShouldFlinch(CStateManager& mgr, float arg) { return x664_25_flinch; } + +bool CChozoGhost::ShouldMove(CStateManager& mgr, float arg) { return x680_behaveType == EBehaveType::Move; } + +bool CChozoGhost::AIStage(CStateManager& mgr, float arg) { return arg == x63c_; } + +u8 CChozoGhost::GetModelAlphau8(const CStateManager& mgr) const { + if (mgr.GetPlayerState()->GetActiveVisor(mgr) == CPlayerState::EPlayerVisor::XRay && IsAlive()) + return 255; + return u8(x42c_color.a() * 255); +} + +bool CChozoGhost::IsOnGround() const { return x664_27_onGround; } + +CProjectileInfo* CChozoGhost::GetProjectileInfo() { return x67c_attackType == 2 ? &x578_ : &x5a0_; } + +void CChozoGhost::AddToTeam(CStateManager& mgr) { + if (x6c4_teamMgr == kInvalidUniqueId) + x6c4_teamMgr = CTeamAiMgr::GetTeamAiMgr(*this, mgr); + + if (x6c4_teamMgr == kInvalidUniqueId) + return; + + if (TCastToPtr teamMgr = mgr.ObjectById(x6c4_teamMgr)) + teamMgr->AssignTeamAiRole(*this, CTeamAiRole::ETeamAiRole::Ranged, CTeamAiRole::ETeamAiRole::Unknown, + CTeamAiRole::ETeamAiRole::Invalid); +} + +void CChozoGhost::RemoveFromTeam(CStateManager& mgr) { + if (x6c4_teamMgr == kInvalidUniqueId) + return; + + if (TCastToPtr teamMgr = mgr.ObjectById(x6c4_teamMgr)) { + if (teamMgr->IsPartOfTeam(GetUniqueId())) { + teamMgr->RemoveTeamAiRole(GetUniqueId()); + x6c4_teamMgr = kInvalidUniqueId; + } + } +} + +void CChozoGhost::FloatToLevel(float level, float dt) { + const zeus::CVector3f& pos = GetTranslation(); + SetTranslation({pos.x(), pos.y(), 4.f * (level - pos.z()) * dt + pos.z()}); +} + +const CChozoGhost::CBehaveChance& CChozoGhost::ChooseBehaveChanceRange(CStateManager& mgr) { + const float dist = (GetTranslation() - mgr.GetPlayer().GetTranslation()).magnitude(); + if (x654_ <= dist && x658_ > dist) + return x5e8_; + else if (x658_ <= dist) + return x608_; + else + return x5c8_; +} + +void CChozoGhost::FindSpaceWarpPosition(CStateManager& mgr, const zeus::CVector3f& dir) { + const zeus::CVector3f& center = GetBoundingBox().center(); + const CRayCastResult& res = + mgr.RayStaticIntersection(center + (dir * 8.f), -dir, 8.f, CMaterialFilter::MakeInclude({EMaterialTypes::Solid})); + if (res.IsInvalid()) { + x6cc_spaceWarpPosition = center + dir; + } else { + x6cc_spaceWarpPosition = res.GetPoint(); + } +} + +void CChozoGhost::FindBestAnchor(CStateManager& mgr) { + x665_27_playerInLeashRange = false; + u32 chance = mgr.GetActiveRandom()->Next() % 100; + chance = chance < x65c_nearChance ? 0 : (chance < (x65c_nearChance + x660_midChance)) + 2; + float dVar15 = 10.f * x658_; + float dVar14 = dVar15; + float dVar13 = dVar15; + if (chance == 0) { + dVar13 = dVar15 * 10.f; + dVar14 = dVar15 * 5.f; + } else if (chance == 1) { + dVar13 = dVar15 * 5.f; + dVar15 *= 10.f; + } else if (chance == 2) { + dVar14 = dVar15 * 5.f; + dVar15 *= 10.f; + } + + float prevDist = FLT_MAX; + CScriptCoverPoint* target = nullptr; + for (CEntity* ent : mgr.GetAiWaypointObjectList()) { + if (TCastToPtr cover = ent) { + if (cover->GetActive() && !cover->GetInUse(kInvalidUniqueId) && cover->GetAreaIdAlways() == GetAreaId()) { + float fVar17 = (cover->GetTranslation() - GetTranslation()).magnitude(); + if (2.f * x66c_ <= fVar17) { + float dist = std::max(0.f, x654_ - fVar17); + zeus::CVector3f diff = cover->GetTranslation() - mgr.GetPlayer().GetTranslation(); + fVar17 = diff.magnitude(); + if (x2fc_minAttackRange <= fVar17) { + if (std::fabs(diff.z()) / fVar17 < 0.2f) { + dist = (20.f * x658_) * ((std::fabs(diff.z()) / fVar17) - 0.2f) + dist; + } + if (x654_ <= fVar17) { + if (x658_ <= fVar17) { + dist = (dist + dVar13); + } else { + dist = (dist + dVar14); + if (dist < prevDist) { + fVar17 = 1.f / fVar17; + diff = diff * fVar17; + dist += (10.f * x658_) * (1.f - mgr.GetPlayer().GetTransform().basis[1].dot(diff)); + } + } + } else { + dist += dVar15; + if (dist < prevDist) { + fVar17 = 1.f / fVar17; + diff = diff * fVar17; + dist += (10.f * x658_) * (1.f - mgr.GetPlayer().GetTransform().basis[1].dot(diff)); + } + } + if (dist < prevDist) { + dist += x658_ * mgr.GetActiveRandom()->Float(); + if (dist < prevDist) { + x665_27_playerInLeashRange = false; + target = cover; + prevDist = dist; + } + } + } + } + } + } + } + + if (target) { + x2dc_destObj = target->GetUniqueId(); + SetDestPos(target->GetTranslation()); + ReleaseCoverPoint(mgr, x674_coverPoint); + SetCoverPoint(target, x674_coverPoint); + } else if (mgr.GetPlayer().GetAreaIdAlways() == GetAreaIdAlways()) { + x2dc_destObj = mgr.GetPlayer().GetUniqueId(); + zeus::CVector3f destPos = + mgr.GetPlayer().GetTranslation() - x654_ * (mgr.GetPlayer().GetTranslation() - GetTranslation()).normalized(); + const CRayCastResult& res = + mgr.RayStaticIntersection(destPos, zeus::skDown, 8.f, CMaterialFilter::MakeInclude(EMaterialTypes::Floor)); + if (res.IsValid()) + destPos = res.GetPoint(); + SetDestPos(destPos); + } else { + x2dc_destObj = kInvalidUniqueId; + x2e0_destPos = GetTranslation(); + } +} +} // namespace urde::MP1 diff --git a/Runtime/MP1/World/CChozoGhost.hpp b/Runtime/MP1/World/CChozoGhost.hpp index c5b782647..410e69c4d 100644 --- a/Runtime/MP1/World/CChozoGhost.hpp +++ b/Runtime/MP1/World/CChozoGhost.hpp @@ -10,88 +10,93 @@ #include namespace urde::MP1 { -enum class EBehaveType { - Zero, - One, - Two, - Three -}; +enum class EBehaveType { Lurk, Taunt, Attack, Move, None }; class CChozoGhost : public CPatterned { public: class CBehaveChance { u32 x0_propertyCount; - float x4_; - float x8_; - float xc_; - float x10_; - float x14_; - float x18_; - u32 x1c_; + float x4_lurk; + float x8_taunt; + float xc_attack; + float x10_move; + float x14_lurkTime; + float x18_chargeAttack; + u32 x1c_numBolts; public: CBehaveChance(CInputStream&); - u32 GetBehave(EBehaveType type, CStateManager& mgr) const; + EBehaveType GetBehave(EBehaveType type, CStateManager& mgr) const; + float GetLurk() const { return x4_lurk; } + float GetTaunt() const { return x8_taunt; } + float GetAttack() const { return xc_attack; } + float GetMove() const { return x10_move; } + float GetLurkTime() const { return x14_lurkTime; } + float GetChargeAttack() const { return x18_chargeAttack; } + u32 GetNumBolts() const { return x1c_numBolts; } }; private: - float x568_; - float x56c_; - float x570_; - float x574_; + float x568_hearingRadius; + float x56c_fadeOutDelay; + float x570_attackDelay; + float x574_freezeTime; CProjectileInfo x578_; CProjectileInfo x5a0_; CBehaveChance x5c8_; CBehaveChance x5e8_; CBehaveChance x608_; - s16 x628_; + s16 x628_soundImpact; float x62c_; - s16 x630_; - s16 x632_; + s16 x630_sfxFadeIn; + s16 x632_sfxFadeOut; float x634_; - float x638_; + float x638_hurlRecoverTime; u32 x63c_; - TLockedToken x640_; - s16 x650_; + std::optional> x640_projectileVisor; + s16 x650_sound_ProjectileVisor; float x654_; float x658_; - u32 x65c_; - u32 x660_; - union { - struct { - bool x664_24_ : 1; - bool x664_25_ : 1; - bool x664_26_ : 1; - bool x664_27_ : 1; - bool x664_28_ : 1; - bool x664_29_ : 1; - bool x664_30_ : 1; - bool x664_31_ : 1; - bool x665_24_ : 1; - bool x665_25_ : 1; - bool x665_26_ : 1; - bool x665_27_ : 1; - bool x665_28_ : 1; - bool x665_29_ : 1; - }; - u32 _dummy = 0; - }; + u32 x65c_nearChance; + u32 x660_midChance; + bool x664_24_behaviorEnabled : 1; + bool x664_25_flinch : 1; + bool x664_26_alert : 1; + bool x664_27_onGround : 1; + bool x664_28_ : 1; + bool x664_29_fadedIn : 1; + bool x664_30_fadedOut : 1; + bool x664_31_ : 1; + bool x665_24_ : 1; + bool x665_25_ : 1; + bool x665_26_shouldSwoosh : 1; + bool x665_27_playerInLeashRange : 1; + bool x665_28_inRange : 1; + bool x665_29_aggressive : 1; float x668_ = 0.f; float x66c_ = 0.f; float x670_ = 0.f; - TUniqueId x674_ = kInvalidUniqueId; - float x678_ = 0.f; - u32 x67c_ = -1; - u32 x680_ = 0; - float x684_ = 1.f; + TUniqueId x674_coverPoint = kInvalidUniqueId; + float x678_floorLevel = 0.f; + u32 x67c_attackType = -1; + EBehaveType x680_behaveType = EBehaveType::Lurk; + float x684_lurkDelay = 1.f; CSteeringBehaviors x688_; CBoneTracking x68c_boneTracking; - TUniqueId x6c4_ = kInvalidUniqueId; - float x6c8_ = 0.f; - zeus::CVector3f x6cc_; + TUniqueId x6c4_teamMgr = kInvalidUniqueId; + float x6c8_spaceWarpTime = 0.f; + zeus::CVector3f x6cc_spaceWarpPosition; u32 x6d8_ = 1; - u32 x6dc_; + + void AddToTeam(CStateManager& mgr); + void RemoveFromTeam(CStateManager& mgr); + void FloatToLevel(float f1, float dt); + const CBehaveChance& ChooseBehaveChanceRange(CStateManager& mgr); + bool IsVisibleEnough(const CStateManager& mgr) const { return GetModelAlphau8(mgr) > 31; } + void FindSpaceWarpPosition(CStateManager& mgr, const zeus::CVector3f& dir); + void FindBestAnchor(CStateManager& mgr); + public: DEFINE_PATTERNED(ChozoGhost) @@ -101,6 +106,47 @@ public: const CBehaveChance&, u16, float, u16, u16, u32, float, u32, float, CAssetId, s16, float, float, u32, u32); - float GetGravityConstant() const { return 60.f; } + void AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) override; + void Think(float dt, CStateManager&) override; + void PreRender(CStateManager& mgr, const zeus::CFrustum& frustum) override; + void Render(const CStateManager& mgr) const override; + void Touch(CActor& act, CStateManager& mgr) override; + EWeaponCollisionResponseTypes GetCollisionResponseType(const zeus::CVector3f& pos, const zeus::CVector3f& dir, + const CWeaponMode& mode, + EProjectileAttrib attrib) const override; + void DoUserAnimEvent(CStateManager& mgr, const CInt32POINode& node, EUserEventType type, float dt) override; + void KnockBack(const zeus::CVector3f& dir, CStateManager& mgr, const CDamageInfo& info, EKnockBackType type, + bool inDeferred, float magnitude) override; + bool CanBeShot(const CStateManager& mgr, int w1) override; + zeus::CVector3f GetOrigin(const CStateManager& mgr, const CTeamAiRole& role, + const zeus::CVector3f& aimPos) const override { + return x34_transform.origin; + } + void Dead(CStateManager& mgr, EStateMsg msg, float arg) override; + void SelectTarget(CStateManager& mgr, EStateMsg msg, float arg) override; + void Run(CStateManager& mgr, EStateMsg msg, float dt) override; + void Generate(CStateManager& mgr, EStateMsg msg, float dt) override; + void Deactivate(CStateManager& mgr, EStateMsg msg, float arg) override; + void Attack(CStateManager& mgr, EStateMsg msg, float dt) override; + void Shuffle(CStateManager& mgr, EStateMsg msg, float arg) override; + void InActive(CStateManager& mgr, EStateMsg msg, float arg) override; + void Taunt(CStateManager& mgr, EStateMsg msg, float dt) override; + void Hurled(CStateManager& mgr, EStateMsg msg, float arg) override; + void WallDetach(CStateManager& mgr, EStateMsg msg, float arg) override; + void Growth(CStateManager& mgr, EStateMsg msg, float dt) override; + void Land(CStateManager& mgr, EStateMsg msg, float dt) override; + void Lurk(CStateManager& mgr, EStateMsg msg, float dt) override; + bool Leash(CStateManager& mgr, float arg) override; + bool InRange(CStateManager& mgr, float arg) override; + bool ShouldAttack(CStateManager& mgr, float arg) override; + bool AggressionCheck(CStateManager& mgr, float arg) override; + bool ShouldTaunt(CStateManager& mgr, float arg) override; + bool ShouldFlinch(CStateManager& mgr, float arg) override; + bool ShouldMove(CStateManager& mgr, float arg) override; + bool AIStage(CStateManager& mgr, float arg) override; + u8 GetModelAlphau8(const CStateManager&) const override; + bool IsOnGround() const override; + float GetGravityConstant() const override { return 60.f; } + CProjectileInfo* GetProjectileInfo() override; }; -} // namespace urde::MP1 \ No newline at end of file +} // namespace urde::MP1 diff --git a/Runtime/Weapon/CGameProjectile.hpp b/Runtime/Weapon/CGameProjectile.hpp index 31f482089..752b097cf 100644 --- a/Runtime/Weapon/CGameProjectile.hpp +++ b/Runtime/Weapon/CGameProjectile.hpp @@ -92,5 +92,6 @@ public: const CProjectileWeapon& GetProjectileWeapon() const { return x170_projectile; } TUniqueId GetHomingTargetId() const { return x2c0_homingTargetId; } zeus::CVector3f GetPreviousPos() const { return x298_previousPos; } + void SetMinHomingDistance(float dist) { x2e0_minHomingDist = dist; } }; } // namespace urde diff --git a/Runtime/Weapon/CWeapon.hpp b/Runtime/Weapon/CWeapon.hpp index 672ee2002..025e89ab6 100644 --- a/Runtime/Weapon/CWeapon.hpp +++ b/Runtime/Weapon/CWeapon.hpp @@ -30,6 +30,7 @@ public: void Accept(IVisitor& visitor) override; bool HasAttrib(EProjectileAttrib attrib) const { return (int(xe8_projectileAttribs) & int(attrib)) == int(attrib); } EProjectileAttrib GetAttribField() const { return xe8_projectileAttribs; } + void AddAttrib(EProjectileAttrib attrib) { xe8_projectileAttribs |= attrib; } const CMaterialFilter& GetFilter() const { return xf8_filter; } void SetFilter(const CMaterialFilter& filter) { xf8_filter = filter; } TUniqueId GetOwnerId() const { return xec_ownerId; } @@ -39,7 +40,9 @@ public: CDamageInfo& DamageInfo() { return x12c_curDamageInfo; } void SetDamageInfo(const CDamageInfo& dInfo) { x12c_curDamageInfo = dInfo; } float GetDamageDuration() const { return x150_damageDuration; } + void SetDamageDuration(float dur) { x150_damageDuration = dur; } float GetInterferenceDuration() const { return x154_interferenceDuration; } + void SetInterferenceDuration(float dur) { x154_interferenceDuration = dur; } void Think(float, CStateManager&) override; void Render(const CStateManager&) const override; diff --git a/Runtime/World/CPatterned.cpp b/Runtime/World/CPatterned.cpp index 88fcb6a28..100fc1b27 100644 --- a/Runtime/World/CPatterned.cpp +++ b/Runtime/World/CPatterned.cpp @@ -1081,7 +1081,7 @@ void CPatterned::SetupPlayerCollision(bool v) { SetMaterialFilter(CMaterialFilter::MakeIncludeExclude(include, exclude)); } -void CPatterned::LaunchProjectile(const zeus::CTransform& gunXf, CStateManager& mgr, int maxAllowed, +CGameProjectile* CPatterned::LaunchProjectile(const zeus::CTransform& gunXf, CStateManager& mgr, int maxAllowed, EProjectileAttrib attrib, bool playerHoming, const std::optional>& visorParticle, u16 visorSfx, bool sendCollideMsg, const zeus::CVector3f& scale) { @@ -1094,8 +1094,10 @@ void CPatterned::LaunchProjectile(const zeus::CTransform& gunXf, CStateManager& pInfo->GetDamage(), mgr.AllocateUniqueId(), GetAreaIdAlways(), GetUniqueId(), homingId, attrib, false, scale, visorParticle, visorSfx, sendCollideMsg); mgr.AddObject(newProjectile); + return newProjectile; } } + return nullptr; } void CPatterned::DoUserAnimEvent(CStateManager& mgr, const CInt32POINode& node, EUserEventType type, float dt) { diff --git a/Runtime/World/CPatterned.hpp b/Runtime/World/CPatterned.hpp index e8a6bb9a4..612eec1be 100644 --- a/Runtime/World/CPatterned.hpp +++ b/Runtime/World/CPatterned.hpp @@ -373,9 +373,10 @@ public: CBodyController* GetBodyController() { return x450_bodyController.get(); } const CKnockBackController& GetKnockBackController() const { return x460_knockBackController; } void SetupPlayerCollision(bool); - void LaunchProjectile(const zeus::CTransform& gunXf, CStateManager& mgr, int maxAllowed, EProjectileAttrib attrib, - bool playerHoming, const std::optional>& visorParticle, - u16 visorSfx, bool sendCollideMsg, const zeus::CVector3f& scale); + CGameProjectile* LaunchProjectile(const zeus::CTransform& gunXf, CStateManager& mgr, int maxAllowed, + EProjectileAttrib attrib, bool playerHoming, + const std::optional>& visorParticle, u16 visorSfx, + bool sendCollideMsg, const zeus::CVector3f& scale); void DoUserAnimEvent(CStateManager& mgr, const CInt32POINode& node, EUserEventType type, float dt) override; void SetDestPos(const zeus::CVector3f& pos) { x2e0_destPos = pos; } diff --git a/Runtime/World/CScriptCoverPoint.cpp b/Runtime/World/CScriptCoverPoint.cpp index 20bbf4eb9..44af6ac16 100644 --- a/Runtime/World/CScriptCoverPoint.cpp +++ b/Runtime/World/CScriptCoverPoint.cpp @@ -45,10 +45,7 @@ bool CScriptCoverPoint::GetInUse(TUniqueId uid) const { if (xf8_25_inUse || x11c_timeLeft > 0.f) return true; - if (xfa_occupant == kInvalidUniqueId || uid == kInvalidUniqueId || xfa_occupant == uid) - return false; - - return true; + return !(xfa_occupant == kInvalidUniqueId || uid == kInvalidUniqueId || xfa_occupant == uid); } bool CScriptCoverPoint::Blown(const zeus::CVector3f& point) const { diff --git a/Runtime/World/CStateMachine.cpp b/Runtime/World/CStateMachine.cpp index 74c261f7f..c45e53bcf 100644 --- a/Runtime/World/CStateMachine.cpp +++ b/Runtime/World/CStateMachine.cpp @@ -111,7 +111,7 @@ void CStateMachineState::SetState(CStateManager& mgr, CAi& ai, const CStateMachi return; if (!x0_machine) - x0_machine = machine; + Setup(machine); s32 idx = machine->GetStateIndex(state); SetState(mgr, ai, idx); diff --git a/Runtime/World/CStateMachine.hpp b/Runtime/World/CStateMachine.hpp index 51470b73b..1c2ee71a5 100644 --- a/Runtime/World/CStateMachine.hpp +++ b/Runtime/World/CStateMachine.hpp @@ -27,7 +27,7 @@ public: bool CallFunc(CStateManager& mgr, CAi& ai) const { if (x0_func) { bool ret = (ai.*x0_func)(mgr, xc_arg); - return x18_lNot ? !ret : ret; + return x18_lNot == !ret; } return true; } diff --git a/Runtime/World/ScriptLoader.cpp b/Runtime/World/ScriptLoader.cpp index bc5c6121d..ae2b1bb69 100644 --- a/Runtime/World/ScriptLoader.cpp +++ b/Runtime/World/ScriptLoader.cpp @@ -1434,7 +1434,7 @@ CEntity* ScriptLoader::LoadMetroidBeta(CStateManager& mgr, CInputStream& in, int } CEntity* ScriptLoader::LoadChozoGhost(CStateManager& mgr, CInputStream& in, int propCount, const CEntityInfo& info) { - if (!EnsurePropertyCount(propCount, 32, "ChozoGhost")) + if (!EnsurePropertyCount(propCount, 31, "ChozoGhost")) return nullptr; SScaledActorHead actorHead = LoadScaledActorHead(in, mgr);