mirror of https://github.com/AxioDL/metaforce.git
Merge branch 'master' of ssh://git.axiodl.com:6431/AxioDL/urde
This commit is contained in:
commit
41ae32be31
|
@ -93,6 +93,8 @@ public:
|
|||
s32 GetShadowLightIndex() const { return x2a0_shadowLightIdx; }
|
||||
u32 GetAreaUpdateFramePeriod() const { return x2a8_areaUpdateFramePeriod; }
|
||||
void SetAreaUpdateFramePeriod(u32 p) { x2a8_areaUpdateFramePeriod = p; }
|
||||
zeus::CVector3f GetActorPositionBias() const { return x2ac_actorPosBias; }
|
||||
void SetActorPositionBias(const zeus::CVector3f& bias) { x2ac_actorPosBias = bias; }
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -91,9 +91,9 @@ public:
|
|||
CBCGenerateCmd(pas::EGenerateType type, s32 animId = -1)
|
||||
: CBodyStateCmd(EBodyStateCmd::Generate), x8_type(type), x18_animId(animId)
|
||||
{ x1c_24_targetTransform = false; x1c_25_overrideAnim = false; }
|
||||
CBCGenerateCmd(pas::EGenerateType type, const zeus::CVector3f& vec)
|
||||
CBCGenerateCmd(pas::EGenerateType type, const zeus::CVector3f& vec, bool targetTransform = false, bool overrideAnim = false)
|
||||
: CBodyStateCmd(EBodyStateCmd::Generate), x8_type(type), xc_targetPos(vec)
|
||||
{ x1c_24_targetTransform = false; x1c_25_overrideAnim = false; }
|
||||
{ x1c_24_targetTransform = targetTransform; x1c_25_overrideAnim = overrideAnim; }
|
||||
pas::EGenerateType GetGenerateType() const { return x8_type; }
|
||||
const zeus::CVector3f& GetExitTargetPos() const { return xc_targetPos; }
|
||||
bool HasExitTargetPos() const { return x1c_24_targetTransform; }
|
||||
|
|
|
@ -7,21 +7,21 @@ namespace pas
|
|||
enum class ELocomotionType
|
||||
{
|
||||
Invalid = -1,
|
||||
Crouch,
|
||||
Relaxed,
|
||||
Lurk,
|
||||
Combat,
|
||||
Internal4,
|
||||
Internal5,
|
||||
Internal6,
|
||||
Internal7,
|
||||
Internal8,
|
||||
Internal9,
|
||||
Internal10,
|
||||
Internal11,
|
||||
Internal12,
|
||||
Internal13,
|
||||
Internal14
|
||||
Crouch = 0,
|
||||
Relaxed = 1,
|
||||
Lurk = 2,
|
||||
Combat = 3,
|
||||
Internal4 = 4,
|
||||
Internal5 = 5,
|
||||
Internal6 = 6,
|
||||
Internal7 = 7,
|
||||
Internal8 = 8,
|
||||
Internal9 = 9,
|
||||
Internal10 = 10,
|
||||
Internal11 = 11,
|
||||
Internal12 = 12,
|
||||
Internal13 = 13,
|
||||
Internal14 = 14
|
||||
};
|
||||
|
||||
enum class ELocomotionAnim
|
||||
|
|
|
@ -5,6 +5,19 @@
|
|||
|
||||
namespace urde
|
||||
{
|
||||
struct SOBBJointDescription
|
||||
{
|
||||
const char* from;
|
||||
const char* to;
|
||||
zeus::CVector3f bounds;
|
||||
};
|
||||
|
||||
struct SSphereJointDescription
|
||||
{
|
||||
const char* name;
|
||||
float radius;
|
||||
};
|
||||
|
||||
class CJointCollisionDescription
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -111,7 +111,7 @@ public:
|
|||
|
||||
void Add(EMaterialTypes type)
|
||||
{
|
||||
x0_list |= (1ull << u32(type));
|
||||
x0_list |= (1ull << u64(type));
|
||||
}
|
||||
|
||||
void Add(const CMaterialList& l)
|
||||
|
@ -121,7 +121,7 @@ public:
|
|||
|
||||
void Remove(EMaterialTypes type)
|
||||
{
|
||||
x0_list &= ~(1ull << u32(type));
|
||||
x0_list &= ~(1ull << u64(type));
|
||||
}
|
||||
|
||||
void Remove(const CMaterialList& other)
|
||||
|
@ -131,7 +131,7 @@ public:
|
|||
|
||||
bool HasMaterial(EMaterialTypes type) const
|
||||
{
|
||||
return (x0_list & (1ull << u32(type))) != 0;
|
||||
return (x0_list & (1ull << u64(type))) != 0;
|
||||
}
|
||||
|
||||
bool SharesMaterials(const CMaterialList& other)
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
#include "Weapon/CGameProjectile.hpp"
|
||||
#include "Weapon/CPlasmaProjectile.hpp"
|
||||
#include "World/CPlayer.hpp"
|
||||
#include "World/CWorld.hpp"
|
||||
#include "World/CGameArea.hpp"
|
||||
#include "CStateManager.hpp"
|
||||
#include "TCastTo.hpp"
|
||||
namespace urde::MP1
|
||||
|
@ -13,13 +15,18 @@ CEyeball::CEyeball(TUniqueId uid, std::string_view name, CPatterned::EFlavorType
|
|||
u32 w1, u32 w2, u32 w3, u32 w4, u32 w5,
|
||||
bool b1, const CActorParameters& actParms)
|
||||
: CPatterned(ECharacter::EyeBall, uid, name, flavor, info, xf, std::move(mData), pInfo, EMovementType::Flyer,
|
||||
EColliderType::Zero, EBodyType::Restricted, actParms, EKnockBackVariant::Medium), x568_(f1), x56c_(f2),
|
||||
EColliderType::Zero, EBodyType::Restricted, actParms, EKnockBackVariant::Medium), x568_attackDelay(f1), x56c_maxAttackDelay(f2),
|
||||
x570_boneTracking(*GetModelData()->GetAnimationData(), "Eye"sv, zeus::degToRad(45.f),
|
||||
zeus::degToRad(180.f), true), x5b4_projectileInfo(aId1, dInfo), x5dc_(aId2), x5e0_(aId3),
|
||||
x5e4_(aId4),
|
||||
x5e8_(aId5), x5f4_(w1), x5f8_(w2), x5fc_(w3), x600_(w4), x604_(CSfxManager::TranslateSFXID(w5)), x60c_24_(false),
|
||||
x60c_25_(false), x60c_26_alert(false), x60c_27_(b1), x60c_28_(false)
|
||||
x5e8_(aId5), x604_beamSfxId(CSfxManager::TranslateSFXID(w5)), x60c_24_canAttack(false),
|
||||
x60c_25_playerInRange(false), x60c_26_alert(false), x60c_27_attackDisabled(b1), x60c_28_firingBeam(false)
|
||||
{
|
||||
x5f4_animIdxs[0] = w1;
|
||||
x5f4_animIdxs[1] = w2;
|
||||
x5f4_animIdxs[2] = w3;
|
||||
x5f4_animIdxs[3] = w4;
|
||||
|
||||
x460_knockBackController.SetAutoResetImpulse(false);
|
||||
}
|
||||
|
||||
|
@ -61,10 +68,10 @@ void CEyeball::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateMa
|
|||
if (x5ec_projectileId != kInvalidUniqueId)
|
||||
{
|
||||
mgr.FreeScriptObject(x5ec_projectileId);
|
||||
if (x608_)
|
||||
if (x608_beamSfx)
|
||||
{
|
||||
CSfxManager::RemoveEmitter(x608_);
|
||||
x608_.reset();
|
||||
CSfxManager::RemoveEmitter(x608_beamSfx);
|
||||
x608_beamSfx.reset();
|
||||
}
|
||||
}
|
||||
x5ec_projectileId = kInvalidUniqueId;
|
||||
|
@ -76,6 +83,47 @@ void CEyeball::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateMa
|
|||
CPatterned::AcceptScriptMsg(msg, uid, mgr);
|
||||
}
|
||||
|
||||
static float kMinAngle = std::cos(zeus::degToRad(45.f));
|
||||
void CEyeball::Think(float dt, CStateManager& mgr)
|
||||
{
|
||||
CPatterned::Think(dt, mgr);
|
||||
if (!GetActive())
|
||||
return;
|
||||
|
||||
CPlayer& player = mgr.GetPlayer();
|
||||
zeus::CVector3f direction = (player.GetTranslation() - GetTranslation()).normalized();
|
||||
|
||||
x60c_25_playerInRange = (player.GetMorphballTransitionState() == CPlayer::EPlayerMorphBallState::Morphed &&
|
||||
direction.dot(GetTransform().frontVector()) > kMinAngle);
|
||||
|
||||
if (x60c_25_playerInRange)
|
||||
{
|
||||
x570_boneTracking.SetActive(true);
|
||||
x5a8_targetPosition = player.GetTranslation() - (0.5f * player.GetVelocity());
|
||||
x570_boneTracking.SetTargetPosition(x5a8_targetPosition);
|
||||
x570_boneTracking.Update(dt);
|
||||
ModelData()->AnimationData()->PreRender();
|
||||
x570_boneTracking.PreRender(mgr, *ModelData()->AnimationData(), GetTransform(), GetModelData()->GetScale(),
|
||||
*x450_bodyController.get());
|
||||
} else
|
||||
x570_boneTracking.SetActive(false);
|
||||
|
||||
if (GetActive())
|
||||
{
|
||||
CPlasmaProjectile* projectile = static_cast<CPlasmaProjectile*>(mgr.ObjectById(x5ec_projectileId));
|
||||
if (projectile && projectile->GetActive())
|
||||
projectile->UpdateFX(GetLctrTransform(skEyeLocator), dt, mgr);
|
||||
}
|
||||
|
||||
if (x60c_28_firingBeam)
|
||||
{
|
||||
const CGameArea* area = mgr.GetWorld()->GetAreaAlways(GetAreaIdAlways());
|
||||
if (area->GetActive() && area->IsPostConstructed() &&
|
||||
area->GetPostConstructed()->x10dc_occlusionState == CGameArea::EOcclusionState::Occluded)
|
||||
ResetBeamState(mgr);
|
||||
}
|
||||
}
|
||||
|
||||
void CEyeball::CreateBeam(CStateManager& mgr)
|
||||
{
|
||||
if (x5ec_projectileId != kInvalidUniqueId)
|
||||
|
@ -102,8 +150,8 @@ void CEyeball::Cover(CStateManager&, EStateMsg msg, float)
|
|||
if (msg == EStateMsg::Activate)
|
||||
{
|
||||
x450_bodyController->SetLocomotionType(pas::ELocomotionType::Lurk);
|
||||
x60c_24_ = false;
|
||||
x330_stateMachineState.SetDelay(x568_);
|
||||
x60c_24_canAttack = false;
|
||||
x330_stateMachineState.SetDelay(x568_attackDelay);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -112,7 +160,7 @@ void CEyeball::Flinch(CStateManager& mgr, EStateMsg msg, float arg)
|
|||
if (msg == EStateMsg::Activate)
|
||||
{
|
||||
x32c_animState = EAnimState::One;
|
||||
x330_stateMachineState.SetDelay(x568_);
|
||||
x330_stateMachineState.SetDelay(x568_attackDelay);
|
||||
}
|
||||
else if (msg == EStateMsg::Update)
|
||||
TryCommand(mgr, pas::EAnimationState::KnockBack, CPatternedTryFunc(&CEyeball::TryFlinch), 0);
|
||||
|
@ -131,31 +179,99 @@ void CEyeball::Active(CStateManager& mgr, EStateMsg msg, float)
|
|||
{
|
||||
x400_24_hitByPlayerProjectile = 0;
|
||||
x450_bodyController->SetLocomotionType(pas::ELocomotionType::Combat);
|
||||
x60c_24_ = false;
|
||||
x60c_24_canAttack = false;
|
||||
}
|
||||
else if (msg == EStateMsg::Update)
|
||||
{
|
||||
if (x330_stateMachineState.GetDelay() > x56c_)
|
||||
x60c_24_ = true;
|
||||
if (x330_stateMachineState.GetDelay() > x56c_maxAttackDelay)
|
||||
x60c_24_canAttack = true;
|
||||
|
||||
sub802249c8();
|
||||
UpdateAnimation();
|
||||
}
|
||||
else if (msg == EStateMsg::Deactivate)
|
||||
{
|
||||
x330_stateMachineState.SetDelay(x568_);
|
||||
x330_stateMachineState.SetDelay(x568_attackDelay);
|
||||
if (CPlasmaProjectile* proj = static_cast<CPlasmaProjectile*>(mgr.ObjectById(x5ec_projectileId)))
|
||||
proj->ResetBeam(mgr, true);
|
||||
|
||||
x60c_24_ = false;
|
||||
x60c_24_canAttack = false;
|
||||
|
||||
CSfxManager::RemoveEmitter(x608_);
|
||||
x608_.reset();
|
||||
CSfxManager::RemoveEmitter(x608_beamSfx);
|
||||
x608_beamSfx.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void CEyeball::sub802249c8()
|
||||
void CEyeball::UpdateAnimation()
|
||||
{
|
||||
if (std::fabs(GetModelData()->GetAnimationData()->GetAnimTimeRemaining("Whole Body"sv) - 0.f) >= 0.00001f)
|
||||
return;
|
||||
|
||||
x5f0_currentAnim = (x5f0_currentAnim + 1) & 3;
|
||||
for (u32 i=0 ; i<4 ; ++i)
|
||||
{
|
||||
if (x5f4_animIdxs[x5f0_currentAnim] != -1)
|
||||
break;
|
||||
|
||||
x5f0_currentAnim = (x5f0_currentAnim + 1) & 3;
|
||||
}
|
||||
s32 animIdx = x5f4_animIdxs[x5f0_currentAnim];
|
||||
if (animIdx != -1)
|
||||
x450_bodyController->GetCommandMgr().DeliverCmd(CBCScriptedCmd(animIdx, false, false, 0.f));
|
||||
}
|
||||
|
||||
void CEyeball::ResetBeamState(CStateManager& mgr)
|
||||
{
|
||||
if (CPlasmaProjectile* projectile = static_cast<CPlasmaProjectile*>(mgr.ObjectById(x5ec_projectileId)))
|
||||
projectile->ResetBeam(mgr, true);
|
||||
|
||||
x60c_28_firingBeam = false;
|
||||
if (x608_beamSfx)
|
||||
{
|
||||
CSfxManager::RemoveEmitter(x608_beamSfx);
|
||||
x608_beamSfx.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void CEyeball::DoUserAnimEvent(CStateManager& mgr, const CInt32POINode& node, EUserEventType type, float dt)
|
||||
{
|
||||
if (type == EUserEventType::DamageOff)
|
||||
ResetBeamState(mgr);
|
||||
else if (type == EUserEventType::DamageOn && x60c_24_canAttack)
|
||||
FireBeam(mgr, GetLctrTransform(node.GetLocatorName()));
|
||||
else
|
||||
CPatterned::DoUserAnimEvent(mgr, node, type, dt);
|
||||
}
|
||||
|
||||
void CEyeball::FireBeam(CStateManager& mgr, const zeus::CTransform& xf)
|
||||
{
|
||||
if (CPlasmaProjectile* projectile = static_cast<CPlasmaProjectile*>(mgr.ObjectById(x5ec_projectileId)))
|
||||
{
|
||||
if (!projectile->GetActive())
|
||||
{
|
||||
projectile->Fire(xf, mgr, false);
|
||||
x60c_28_firingBeam = true;
|
||||
if (!x608_beamSfx)
|
||||
{
|
||||
CAudioSys::C3DEmitterParmData
|
||||
parmData{GetTranslation(), {}, 50.f, 0.1f, 0x1, x604_beamSfxId, 1.f /* 127 */, 0.15f /* 20 / 127 */,
|
||||
false, 127};
|
||||
x608_beamSfx = CSfxManager::AddEmitter(parmData, true, 127, true, GetAreaIdAlways());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CEyeball::PreRender(CStateManager& mgr, const zeus::CFrustum& frustum)
|
||||
{
|
||||
CPatterned::PreRender(mgr, frustum);
|
||||
x570_boneTracking.PreRender(mgr, *ModelData()->AnimationData(), GetTransform(), GetModelData()->GetScale(),
|
||||
*x450_bodyController);
|
||||
}
|
||||
|
||||
void CEyeball::Death(CStateManager& mgr, const zeus::CVector3f& pos, EScriptObjectState state)
|
||||
{
|
||||
zeus::CTransform oldXf = GetTransform();
|
||||
CPatterned::Death(mgr, pos, state);
|
||||
SetTransform(oldXf);
|
||||
}
|
||||
}
|
|
@ -8,33 +8,32 @@ namespace urde::MP1
|
|||
{
|
||||
class CEyeball : public CPatterned
|
||||
{
|
||||
float x568_;
|
||||
float x56c_;
|
||||
static constexpr std::string_view skEyeLocator="Laser_LCTR"sv;
|
||||
float x568_attackDelay;
|
||||
float x56c_maxAttackDelay;
|
||||
CBoneTracking x570_boneTracking;
|
||||
zeus::CVector3f x5a8_;
|
||||
zeus::CVector3f x5a8_targetPosition;
|
||||
CProjectileInfo x5b4_projectileInfo;
|
||||
CAssetId x5dc_;
|
||||
CAssetId x5e0_;
|
||||
CAssetId x5e4_;
|
||||
CAssetId x5e8_;
|
||||
TUniqueId x5ec_projectileId = kInvalidUniqueId;
|
||||
u32 x5f0_ = 0;
|
||||
u32 x5f4_;
|
||||
u32 x5f8_;
|
||||
u32 x5fc_;
|
||||
u32 x600_;
|
||||
s16 x604_;
|
||||
CSfxHandle x608_ = 0;
|
||||
bool x60c_24_ : 1;
|
||||
bool x60c_25_ : 1;
|
||||
u32 x5f0_currentAnim = 0;
|
||||
s32 x5f4_animIdxs[4];
|
||||
u16 x604_beamSfxId;
|
||||
CSfxHandle x608_beamSfx = 0;
|
||||
bool x60c_24_canAttack : 1;
|
||||
bool x60c_25_playerInRange : 1;
|
||||
bool x60c_26_alert : 1;
|
||||
bool x60c_27_ : 1;
|
||||
bool x60c_28_ : 1;
|
||||
bool x60c_27_attackDisabled : 1;
|
||||
bool x60c_28_firingBeam : 1;
|
||||
|
||||
void CreateBeam(CStateManager&);
|
||||
|
||||
void FireBeam(CStateManager&, const zeus::CTransform&);
|
||||
void TryFlinch(CStateManager&, int);
|
||||
void sub802249c8();
|
||||
void UpdateAnimation();
|
||||
void ResetBeamState(CStateManager&);
|
||||
public:
|
||||
DEFINE_PATTERNED(EyeBall)
|
||||
|
||||
|
@ -43,8 +42,13 @@ public:
|
|||
CAssetId, CAssetId, u32, u32, u32, u32, u32, bool, const CActorParameters&);
|
||||
|
||||
void Accept(IVisitor& visitor);
|
||||
void PreRender(CStateManager&, const zeus::CFrustum&);
|
||||
void Touch(CActor&, CStateManager&) {};
|
||||
void Death(CStateManager&, const zeus::CVector3f&, EScriptObjectState);
|
||||
|
||||
void AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr);
|
||||
void DoUserAnimEvent(CStateManager&, const CInt32POINode&, EUserEventType, float);
|
||||
void Think(float, CStateManager&);
|
||||
void Flinch(CStateManager&, EStateMsg, float);
|
||||
void Active(CStateManager&, EStateMsg, float);
|
||||
void InActive(CStateManager&, EStateMsg, float);
|
||||
|
@ -52,6 +56,6 @@ public:
|
|||
void Cover(CStateManager&, EStateMsg, float);
|
||||
|
||||
bool ShouldAttack(CStateManager&, float) { return x60c_26_alert; }
|
||||
bool ShouldFire(CStateManager&, float) { return !x60c_27_; }
|
||||
bool ShouldFire(CStateManager&, float) { return !x60c_27_attackDisabled; }
|
||||
};
|
||||
}
|
|
@ -28,6 +28,7 @@ set(MP1_WORLD_SOURCES
|
|||
CSeedling.hpp CSeedling.cpp
|
||||
CRidley.hpp CRidley.cpp
|
||||
CPuddleToadGamma.hpp CPuddleToadGamma.cpp
|
||||
CFlaahgraProjectile.hpp CFlaahgraProjectile.cpp)
|
||||
CFlaahgraProjectile.hpp CFlaahgraProjectile.cpp
|
||||
CSpankWeed.hpp CSpankWeed.cpp)
|
||||
|
||||
runtime_add_list(World MP1_WORLD_SOURCES)
|
||||
|
|
|
@ -37,24 +37,11 @@ void CNewIntroBoss::Accept(IVisitor &visitor)
|
|||
visitor.Visit(this);
|
||||
}
|
||||
|
||||
struct SSphereJointDescription
|
||||
{
|
||||
const char* name;
|
||||
float radius;
|
||||
};
|
||||
|
||||
static const SSphereJointDescription skSphereJoints[] ={
|
||||
{"Head_1", 1.5f},
|
||||
{"Tail_1", 1.5f}
|
||||
};
|
||||
|
||||
struct SOBBJointDescription
|
||||
{
|
||||
const char* from;
|
||||
const char* to;
|
||||
zeus::CVector3f bounds;
|
||||
};
|
||||
|
||||
static const SOBBJointDescription skOBBJoints[] = {
|
||||
{"Pelvis", "Spine_3", {4.f, 1.f, 4.f}},
|
||||
{"Spine_3", "Tail_1", {2.f, 1.f, 2.f}},
|
||||
|
|
|
@ -1,17 +1,363 @@
|
|||
#include "CPuddleToadGamma.hpp"
|
||||
#include "GameGlobalObjects.hpp"
|
||||
#include "CSimplePool.hpp"
|
||||
#include "CStateManager.hpp"
|
||||
#include "World/CPlayer.hpp"
|
||||
#include "Collision/CGameCollision.hpp"
|
||||
#include "TCastTo.hpp"
|
||||
|
||||
namespace urde::MP1
|
||||
{
|
||||
|
||||
const zeus::CVector3f CPuddleToadGamma::skBellyOffset(0.f, 0.1f, -.3f);
|
||||
|
||||
CPuddleToadGamma::CPuddleToadGamma(TUniqueId uid, std::string_view name, EFlavorType flavor, const CEntityInfo& info,
|
||||
const zeus::CTransform& xf, CModelData&& mData, const CPatternedInfo& pInfo,
|
||||
const CActorParameters& aParms, float f1, float f2, float f3,
|
||||
const zeus::CVector3f& v1,
|
||||
float f4, float f5, float f6, const CDamageInfo& dInfo1, const CDamageInfo& dInfo2)
|
||||
: CPatterned(ECharacter::PuddleToad, uid, name, flavor, info, xf, std::move(mData), pInfo, EMovementType::Flyer,
|
||||
EColliderType::Zero, EBodyType::Restricted, aParms, EKnockBackVariant::Large)
|
||||
const zeus::CVector3f& v1, float f4, float f5, float f6, const CDamageInfo& dInfo1,
|
||||
const CDamageInfo& dInfo2, CAssetId dcln)
|
||||
: CPatterned(ECharacter::PuddleToad, uid, name, flavor, info, xf, std::move(mData), pInfo, EMovementType::Flyer,
|
||||
EColliderType::Zero, EBodyType::Restricted, aParms, EKnockBackVariant::Large), x570_(dInfo1),
|
||||
x58c_(dInfo2), x5a8_(f1), x5ac_(std::cos(zeus::degToRad(f2 * 0.5f))), x5b0_(f3), x5b4_(v1), x5c0_(f4), x5c4_(f5),
|
||||
x5c8_(f6), x5e8_24_(false), x5e8_25_(false), x5e8_26_(false)
|
||||
{
|
||||
x401_26_disableMove = true;
|
||||
x460_knockBackController.SetEnableBurn(false);
|
||||
x460_knockBackController.SetEnableLaggedBurnDeath(false);
|
||||
x460_knockBackController.SetEnableShock(false);
|
||||
x460_knockBackController.SetX81_31(false);
|
||||
SetMovable(false);
|
||||
if (dcln.IsValid() && g_ResFactory->GetResourceTypeById(dcln) != 0)
|
||||
{
|
||||
TLockedToken<CCollidableOBBTreeGroupContainer> container = g_SimplePool->GetObj({FOURCC('DCLN'), dcln});
|
||||
x5e4_collisionTreePrim.reset(new CCollidableOBBTreeGroup(container.GetObj(), GetMaterialList()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void CPuddleToadGamma::SetSolid(CStateManager& mgr, bool solid)
|
||||
{
|
||||
if (solid)
|
||||
{
|
||||
AddMaterial(EMaterialTypes::Solid, mgr);
|
||||
RemoveMaterial(EMaterialTypes::NonSolidDamageable, mgr);
|
||||
} else
|
||||
{
|
||||
RemoveMaterial(EMaterialTypes::Solid, mgr);
|
||||
AddMaterial(EMaterialTypes::NonSolidDamageable, mgr);
|
||||
}
|
||||
}
|
||||
|
||||
const CCollisionPrimitive* CPuddleToadGamma::GetCollisionPrimitive() const
|
||||
{
|
||||
if (!x5e4_collisionTreePrim)
|
||||
return CPhysicsActor::GetCollisionPrimitive();
|
||||
return x5e4_collisionTreePrim.get();
|
||||
}
|
||||
|
||||
zeus::CTransform CPuddleToadGamma::GetPrimitiveTransform() const
|
||||
{
|
||||
zeus::CTransform xf = GetTransform();
|
||||
xf.origin += GetPrimitiveOffset();
|
||||
return xf;
|
||||
}
|
||||
|
||||
void CPuddleToadGamma::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr)
|
||||
{
|
||||
CPatterned::AcceptScriptMsg(msg, uid, mgr);
|
||||
|
||||
if (msg == EScriptObjectMessage::Registered)
|
||||
{
|
||||
x450_bodyController->Activate(mgr);
|
||||
zeus::CTransform bellyXf = GetLctrTransform(mBellyLocatorName);
|
||||
zeus::CVector3f bellyOffset = GetTransform().rotate(skBellyOffset);
|
||||
x5d8_ = x5cc_ = bellyXf.origin + bellyOffset;
|
||||
RemoveMaterial(EMaterialTypes::Target, EMaterialTypes::Orbit, mgr);
|
||||
AddMaterial(EMaterialTypes::Immovable, mgr);
|
||||
AddMaterial(EMaterialTypes::SolidCharacter);
|
||||
}
|
||||
}
|
||||
|
||||
void CPuddleToadGamma::Think(float dt, CStateManager& mgr)
|
||||
{
|
||||
CPatterned::Think(dt, mgr);
|
||||
if (x5e8_25_)
|
||||
x56c_ += dt;
|
||||
}
|
||||
|
||||
std::experimental::optional<zeus::CAABox> CPuddleToadGamma::GetTouchBounds() const
|
||||
{
|
||||
if (!GetActive())
|
||||
return {};
|
||||
|
||||
return (x5e4_collisionTreePrim ? x5e4_collisionTreePrim->CalculateAABox(GetTransform()) : GetBoundingBox());
|
||||
}
|
||||
|
||||
void CPuddleToadGamma::CenterPlayer(CStateManager& mgr, const zeus::CVector3f& pos, float dt)
|
||||
{
|
||||
zeus::CVector3f dir = (mgr.GetPlayer().GetTranslation() - pos).normalized();
|
||||
mgr.GetPlayer().SetVelocityWR((1.f / (2.f * dt)) * dir);
|
||||
}
|
||||
|
||||
const CDamageVulnerability* CPuddleToadGamma::GetDamageVulnerability(const zeus::CVector3f& pos,
|
||||
const zeus::CVector3f& dir,
|
||||
const CDamageInfo& dInfo) const
|
||||
{
|
||||
if (x5e8_24_ && (x5d8_ - pos).magSquared() < 4.f)
|
||||
return CAi::GetDamageVulnerability();
|
||||
|
||||
return &CDamageVulnerability::ImmuneVulnerabilty();
|
||||
}
|
||||
|
||||
void CPuddleToadGamma::DoUserAnimEvent(CStateManager& mgr, const CInt32POINode& node, EUserEventType type, float dt)
|
||||
{
|
||||
if (type == EUserEventType::Projectile)
|
||||
{
|
||||
ShootPlayer(mgr, x5c0_);
|
||||
return;
|
||||
}
|
||||
|
||||
CPatterned::DoUserAnimEvent(mgr, node, type, dt);
|
||||
}
|
||||
|
||||
bool CPuddleToadGamma::SpotPlayer(CStateManager&, float arg)
|
||||
{
|
||||
return x56c_ >= x5c8_;
|
||||
}
|
||||
|
||||
bool CPuddleToadGamma::ShouldAttack(CStateManager&, float)
|
||||
{
|
||||
return x56c_ >= x5c4_;
|
||||
}
|
||||
|
||||
bool CPuddleToadGamma::LostInterest(CStateManager& mgr, float)
|
||||
{
|
||||
zeus::CAABox box = *GetTouchBounds();
|
||||
zeus::CAABox plBox = mgr.GetPlayer().GetBoundingBox();
|
||||
return !box.intersects(plBox);
|
||||
}
|
||||
|
||||
void CPuddleToadGamma::ShootPlayer(CStateManager&, float)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool CPuddleToadGamma::InAttackPosition(CStateManager& mgr, float)
|
||||
{
|
||||
return mgr.GetPlayer().GetMorphballTransitionState() == CPlayer::EPlayerMorphBallState::Morphed &&
|
||||
PlayerInVortexArea(mgr);
|
||||
}
|
||||
|
||||
static CMaterialFilter kSolidFilter = CMaterialFilter::MakeIncludeExclude({EMaterialTypes::Solid},
|
||||
{EMaterialTypes::Character,
|
||||
EMaterialTypes::Player,
|
||||
EMaterialTypes::ProjectilePassthrough});
|
||||
|
||||
bool CPuddleToadGamma::PlayerInVortexArea(const CStateManager& mgr)
|
||||
{
|
||||
CPlayer& player = mgr.GetPlayer();
|
||||
zeus::CTransform xf = GetLctrTransform(mMouthLocatorName);
|
||||
|
||||
zeus::CVector3f playerOffset =
|
||||
player.GetTranslation() + zeus::CVector3f{0.f, 0.f, player.GetMorphBall()->GetBallRadius()};
|
||||
zeus::CVector3f rotatedOffset = GetTransform().rotate(zeus::CVector3f::skForward);
|
||||
|
||||
zeus::CVector3f vec1 = (playerOffset - (xf.origin - (1.f * rotatedOffset)));
|
||||
float f31 = vec1.normalized().dot(rotatedOffset);
|
||||
float f28 = vec1.magnitude();
|
||||
float f26 = (player.GetTranslation() - (xf.origin - (4.f * rotatedOffset))).normalized().dot(rotatedOffset);
|
||||
if (f28 > 2.f)
|
||||
{
|
||||
CRayCastResult result = mgr.RayStaticIntersection(vec1, 1.f / f28 * vec1,
|
||||
f28 - player.GetMorphBall()->GetBallRadius(), kSolidFilter);
|
||||
if (result.IsValid())
|
||||
return false;
|
||||
}
|
||||
|
||||
return (f28 < x5b0_ && f31 > 0.f && f26 > x5ac_);
|
||||
}
|
||||
|
||||
void CPuddleToadGamma::InActive(CStateManager& mgr, EStateMsg msg, float)
|
||||
{
|
||||
if (msg == EStateMsg::Activate)
|
||||
{
|
||||
x450_bodyController->SetLocomotionType(pas::ELocomotionType::Relaxed);
|
||||
SetSolid(mgr, true);
|
||||
mgr.GetPlayer().Set_X590(true);
|
||||
x330_stateMachineState.SetDelay(2.f);
|
||||
}
|
||||
}
|
||||
|
||||
void CPuddleToadGamma::Active(CStateManager& mgr, EStateMsg msg, float)
|
||||
{
|
||||
if (msg == EStateMsg::Activate)
|
||||
{
|
||||
x450_bodyController->SetLocomotionType(pas::ELocomotionType::Lurk);
|
||||
zeus::CTransform xf = GetLctrTransform(mBellyLocatorName);
|
||||
x5cc_ = xf.origin + GetTransform().rotate(skBellyOffset);
|
||||
x56c_ = 0.f;
|
||||
x5e8_25_ = true;
|
||||
SetSolid(mgr, true);
|
||||
mgr.GetPlayer().Set_X590(true);
|
||||
} else if (msg == EStateMsg::Deactivate)
|
||||
{
|
||||
x5e8_25_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
void CPuddleToadGamma::Suck(CStateManager& mgr, EStateMsg msg, float arg)
|
||||
{
|
||||
return;
|
||||
if (msg == EStateMsg::Activate)
|
||||
{
|
||||
SetSolid(mgr, false);
|
||||
mgr.GetPlayer().Set_X590(false);
|
||||
mgr.GetPlayer().GetMorphBall()->DisableHalfPipeStatus();
|
||||
} else if (msg == EStateMsg::Update)
|
||||
{
|
||||
if (x568_ == 0)
|
||||
{
|
||||
if (x450_bodyController->GetBodyStateInfo().GetCurrentStateId() == pas::EAnimationState::LoopReaction)
|
||||
{
|
||||
x568_ = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
x450_bodyController->GetCommandMgr().DeliverCmd(CBCLoopReactionCmd(pas::EReactionType::Zero));
|
||||
} else if (x568_ == 1)
|
||||
SuckPlayer(mgr, arg);
|
||||
} else if (msg == EStateMsg::Deactivate)
|
||||
{
|
||||
x450_bodyController->GetCommandMgr().DeliverCmd(CBodyStateCmd(EBodyStateCmd::ExitState));
|
||||
}
|
||||
}
|
||||
|
||||
void CPuddleToadGamma::SuckPlayer(CStateManager& mgr, float arg)
|
||||
{
|
||||
CPlayer& player = mgr.GetPlayer();
|
||||
if (player.GetMorphballTransitionState() != CPlayer::EPlayerMorphBallState::Morphed)
|
||||
return;
|
||||
|
||||
zeus::CVector3f posDiff = player.GetTranslation() - x5cc_;
|
||||
if (posDiff.magnitude() < 3.f)
|
||||
{
|
||||
player.Stop();
|
||||
CenterPlayer(mgr, x5cc_, arg);
|
||||
return;
|
||||
}
|
||||
|
||||
float d = x5a8_ * (x5b0_ / (posDiff.magnitude() * posDiff.magnitude()));
|
||||
zeus::CVector3f force = d * (player.GetMass() * -posDiff);
|
||||
player.ApplyForceWR(force, zeus::CAxisAngle::sIdentity);
|
||||
}
|
||||
|
||||
void CPuddleToadGamma::Attack(CStateManager& mgr, EStateMsg msg, float)
|
||||
{
|
||||
return;
|
||||
if (msg == EStateMsg::Activate)
|
||||
{
|
||||
mgr.GetPlayer().Stop();
|
||||
mgr.GetPlayer().SetVelocityWR({});
|
||||
x450_bodyController->GetCommandMgr().DeliverCmd(CBCMeleeAttackCmd(pas::ESeverity::One));
|
||||
x5e8_26_ = false;
|
||||
mgr.GetPlayer().GetMorphBall()->SetBombJumpState(CMorphBall::EBombJumpState::BombJumpDisabled);
|
||||
} else if (msg == EStateMsg::Update)
|
||||
{
|
||||
if (!x5e8_26_)
|
||||
{
|
||||
zeus::CTransform xf = GetLctrTransform(mBellyLocatorName);
|
||||
x5cc_ = xf.origin + GetTransform().rotate(skBellyOffset);
|
||||
SetPlayerPosition(mgr, x5cc_);
|
||||
} else if (LostInterest(mgr, 0.f))
|
||||
SetSolid(mgr, true);
|
||||
} else if (msg == EStateMsg::Deactivate)
|
||||
{
|
||||
SetSolid(mgr, true);
|
||||
mgr.GetPlayer().Set_X590(true);
|
||||
mgr.GetPlayer().GetMorphBall()->SetBombJumpState(CMorphBall::EBombJumpState::BombJumpAvailable);
|
||||
x5e8_24_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
void CPuddleToadGamma::SetPlayerPosition(CStateManager& mgr, const zeus::CVector3f& targetPos)
|
||||
{
|
||||
float preThinkDt = x500_preThinkDt;
|
||||
CPlayer& player = mgr.GetPlayer();
|
||||
player.Stop();
|
||||
player.SetVelocityWR({});
|
||||
bool hadPlayerMaterial = player.GetMaterialList().HasMaterial(EMaterialTypes::Player);
|
||||
|
||||
if (hadPlayerMaterial)
|
||||
player.RemoveMaterial(EMaterialTypes::GroundCollider, mgr);
|
||||
player.RemoveMaterial(EMaterialTypes::Player, mgr);
|
||||
|
||||
bool hadSolidMaterial = GetMaterialList().HasMaterial(EMaterialTypes::Solid);
|
||||
if (hadSolidMaterial)
|
||||
RemoveMaterial(EMaterialTypes::Solid, mgr);
|
||||
|
||||
CPhysicsState physState = player.GetPhysicsState();
|
||||
player.Stop();
|
||||
player.MoveToWR(targetPos, preThinkDt);
|
||||
CGameCollision::Move(mgr, player, preThinkDt, nullptr);
|
||||
physState.SetTranslation(player.GetTranslation());
|
||||
player.SetPhysicsState(physState);
|
||||
if (hadPlayerMaterial)
|
||||
player.AddMaterial(EMaterialTypes::GroundCollider, mgr);
|
||||
player.AddMaterial(EMaterialTypes::Player, mgr);
|
||||
if (hadSolidMaterial)
|
||||
AddMaterial(EMaterialTypes::Solid, mgr);
|
||||
}
|
||||
|
||||
bool CPuddleToadGamma::Inside(CStateManager& mgr, float)
|
||||
{
|
||||
if (mgr.GetPlayer().GetMorphballTransitionState() != CPlayer::EPlayerMorphBallState::Morphed)
|
||||
return false;
|
||||
|
||||
zeus::CVector3f posDiff = mgr.GetPlayer().GetTranslation() - x5cc_;
|
||||
return posDiff.dot(GetTransform().frontVector()) <= 0.f &&
|
||||
posDiff.magSquared() < 2.f;
|
||||
}
|
||||
|
||||
void CPuddleToadGamma::Crouch(CStateManager& mgr, EStateMsg msg, float)
|
||||
{
|
||||
return;
|
||||
if (msg == EStateMsg::Activate)
|
||||
{
|
||||
x568_ = 0;
|
||||
x56c_ = 0.f;
|
||||
x5e8_25_ = true;
|
||||
x5e8_24_ = true;
|
||||
mgr.GetPlayer().Stop();
|
||||
mgr.GetPlayer().SetVelocityWR({});
|
||||
SendScriptMsgs(EScriptObjectState::Inside, mgr, EScriptObjectMessage::None);
|
||||
if (!mgr.GetPlayer().AttachActorToPlayer(GetUniqueId(), false))
|
||||
x56c_ = 100.f;
|
||||
|
||||
SetSolid(mgr, false);
|
||||
mgr.GetPlayer().Set_X590(false);
|
||||
mgr.GetPlayer().GetMorphBall()->DisableHalfPipeStatus();
|
||||
SetSolid(mgr, false);
|
||||
}
|
||||
else if (msg == EStateMsg::Update)
|
||||
{
|
||||
zeus::CTransform xf = GetLctrTransform(mBellyLocatorName);
|
||||
x5cc_ = xf.origin + GetTransform().rotate(skBellyOffset);
|
||||
SetPlayerPosition(mgr, x5cc_);
|
||||
if (x568_ == 0)
|
||||
{
|
||||
if (x450_bodyController->GetBodyStateInfo().GetCurrentStateId() == pas::EAnimationState::Locomotion)
|
||||
x568_ = 1;
|
||||
else
|
||||
x450_bodyController->SetLocomotionType(pas::ELocomotionType::Crouch);
|
||||
}
|
||||
}
|
||||
else if (msg == EStateMsg::Deactivate)
|
||||
{
|
||||
if (mgr.GetPlayer().GetAttachedActor() == GetUniqueId())
|
||||
mgr.GetPlayer().DetachActorFromPlayer();
|
||||
mgr.GetPlayer().Set_X590(true);
|
||||
x5e8_25_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,18 +1,74 @@
|
|||
#pragma once
|
||||
|
||||
#include "World/CPatterned.hpp"
|
||||
#include "Collision/CCollidableOBBTreeGroup.hpp"
|
||||
|
||||
namespace urde::MP1
|
||||
{
|
||||
|
||||
class CPuddleToadGamma : public CPatterned
|
||||
class CPuddleToadGamma final : public CPatterned
|
||||
{
|
||||
static constexpr std::string_view mMouthLocatorName = "MOUTH_LCTR_SDK"sv;
|
||||
static constexpr std::string_view mBellyLocatorName = "SAMUS_POS_LCTR_SDK"sv;
|
||||
static const zeus::CVector3f skBellyOffset;
|
||||
u32 x568_ = 0;
|
||||
float x56c_ = 0.f;
|
||||
CDamageInfo x570_;
|
||||
CDamageInfo x58c_;
|
||||
float x5a8_;
|
||||
float x5ac_;
|
||||
float x5b0_;
|
||||
zeus::CVector3f x5b4_;
|
||||
float x5c0_;
|
||||
float x5c4_;
|
||||
float x5c8_;
|
||||
zeus::CVector3f x5cc_;
|
||||
zeus::CVector3f x5d8_;
|
||||
std::unique_ptr<CCollidableOBBTreeGroup> x5e4_collisionTreePrim;
|
||||
bool x5e8_24_ : 1;
|
||||
bool x5e8_25_ : 1;
|
||||
bool x5e8_26_ : 1;
|
||||
|
||||
void SetSolid(CStateManager&, bool);
|
||||
|
||||
static void CenterPlayer(CStateManager&, const zeus::CVector3f&, float);
|
||||
void ShootPlayer(CStateManager&, float);
|
||||
void SuckPlayer(CStateManager&, float);
|
||||
bool PlayerInVortexArea(const CStateManager&);
|
||||
void SetPlayerPosition(CStateManager&, const zeus::CVector3f&);
|
||||
|
||||
public:
|
||||
DEFINE_PATTERNED(PuddleToad)
|
||||
|
||||
CPuddleToadGamma(TUniqueId uid, std::string_view name, EFlavorType flavor, const CEntityInfo& info,
|
||||
const zeus::CTransform& xf, CModelData&& mData, const CPatternedInfo& pInfo,
|
||||
const CActorParameters& aParms, float f1, float f2, float f3, const zeus::CVector3f& v1,
|
||||
float f4, float f5, float f6, const CDamageInfo& dInfo1, const CDamageInfo& dInfo2);
|
||||
float f4, float f5, float f6, const CDamageInfo& dInfo1, const CDamageInfo& dInfo2, CAssetId dcln);
|
||||
|
||||
void AcceptScriptMsg(EScriptObjectMessage, TUniqueId, CStateManager&);
|
||||
void Think(float dt, CStateManager& mgr);
|
||||
void DoUserAnimEvent(CStateManager& mgr, const CInt32POINode& node, EUserEventType type, float dt);
|
||||
std::experimental::optional<zeus::CAABox> GetTouchBounds() const;
|
||||
|
||||
const CDamageVulnerability*
|
||||
GetDamageVulnerability(const zeus::CVector3f&, const zeus::CVector3f&, const CDamageInfo&) const;
|
||||
|
||||
const CDamageVulnerability* GetDamageVulnerability() const { return &CDamageVulnerability::ImmuneVulnerabilty(); }
|
||||
|
||||
const CCollisionPrimitive* GetCollisionPrimitive() const;
|
||||
|
||||
zeus::CTransform GetPrimitiveTransform() const;
|
||||
|
||||
void InActive(CStateManager&, EStateMsg, float);
|
||||
void Active(CStateManager&, EStateMsg, float);
|
||||
void Suck(CStateManager&, EStateMsg, float);
|
||||
void Attack(CStateManager&, EStateMsg, float);
|
||||
void Crouch(CStateManager&, EStateMsg, float);
|
||||
bool InAttackPosition(CStateManager&, float);
|
||||
bool SpotPlayer(CStateManager&, float);
|
||||
bool ShouldAttack(CStateManager&, float);
|
||||
bool LostInterest(CStateManager&, float);
|
||||
bool Inside(CStateManager&, float);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
#include "MP1/World/CSeedling.hpp"
|
||||
#include "World/CPatternedInfo.hpp"
|
||||
#include "World/CWorld.hpp"
|
||||
#include "World/CGameArea.hpp"
|
||||
#include "World/CPlayer.hpp"
|
||||
#include "CStateManager.hpp"
|
||||
#include "TCastTo.hpp"
|
||||
#include "CSeedling.hpp"
|
||||
|
||||
|
||||
namespace urde
|
||||
{
|
||||
|
@ -8,12 +15,21 @@ namespace MP1
|
|||
|
||||
CSeedling::CSeedling(TUniqueId uid, std::string_view name, const CEntityInfo& info, const zeus::CTransform& xf,
|
||||
CModelData&& mData, const CPatternedInfo& pInfo, const CActorParameters& actParms,
|
||||
CAssetId, CAssetId, const CDamageInfo&, const CDamageInfo&, float f1, float f2, float f3, float f4)
|
||||
CAssetId needleId, CAssetId weaponId, const CDamageInfo& dInfo1, const CDamageInfo& dInfo2,
|
||||
float f1, float f2, float f3, float f4)
|
||||
: CWallWalker(ECharacter::Seedling, uid, name, EFlavorType::Zero, info, xf, std::move(mData), pInfo,
|
||||
EMovementType::Ground, EColliderType::Zero, EBodyType::WallWalker, actParms, f1, f2,
|
||||
EKnockBackVariant::Small, f3, EWalkerType::Seedling, f4, false)
|
||||
, x5d8_searchPath(nullptr, 1, pInfo.GetPathfindingIndex(), 1.f, 1.f)
|
||||
, x6bc_spikeData(new CModelData(CStaticRes(needleId, GetModelData()->GetScale())))
|
||||
, x6c0_projectileInfo(weaponId, dInfo1)
|
||||
, x6e8_deathDamage(dInfo2)
|
||||
, x722_24_renderOnlyClusterA(true)
|
||||
, x722_25_curNeedleCluster(false)
|
||||
{
|
||||
|
||||
const_cast<TToken<CWeaponDescription>*>(&x6c0_projectileInfo.Token())->Lock();
|
||||
CreateShadow(false);
|
||||
SetKeepInThermalVisor();
|
||||
}
|
||||
|
||||
void CSeedling::Accept(IVisitor& visitor)
|
||||
|
@ -21,5 +37,228 @@ void CSeedling::Accept(IVisitor& visitor)
|
|||
visitor.Visit(this);
|
||||
}
|
||||
|
||||
const std::string CSeedling::skNeedleLocators[2][6] =
|
||||
{
|
||||
{
|
||||
"A_spike1_LCTR_SDK",
|
||||
"A_spike2_LCTR_SDK",
|
||||
"A_spike3_LCTR_SDK",
|
||||
"A_spike4_LCTR_SDK",
|
||||
"A_spike5_LCTR_SDK",
|
||||
"A_spike6_LCTR_SDK",
|
||||
},
|
||||
{
|
||||
"B_spike1_LCTR_SDK",
|
||||
"B_spike2_LCTR_SDK",
|
||||
"B_spike3_LCTR_SDK",
|
||||
"B_spike4_LCTR_SDK",
|
||||
"B_spike5_LCTR_SDK",
|
||||
"B_spike6_LCTR_SDK",
|
||||
}
|
||||
};
|
||||
|
||||
void CSeedling::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr)
|
||||
{
|
||||
CPatterned::AcceptScriptMsg(msg, uid, mgr);
|
||||
|
||||
if (msg == EScriptObjectMessage::Activate)
|
||||
{
|
||||
x5d6_27_disableMove = false;
|
||||
TUniqueId id = GetWaypointForState(mgr, EScriptObjectState::Patrol, EScriptObjectMessage::Follow);
|
||||
if (id != kInvalidUniqueId)
|
||||
x2dc_destObj = id;
|
||||
}
|
||||
else if (msg == EScriptObjectMessage::Registered)
|
||||
{
|
||||
x450_bodyController->Activate(mgr);
|
||||
x704_modelBounds = GetModelData()->GetBounds();
|
||||
}
|
||||
else if (msg == EScriptObjectMessage::InitializedInArea)
|
||||
{
|
||||
x5d8_searchPath.SetArea(mgr.GetWorld()->GetAreaAlways(GetAreaIdAlways())->GetPostConstructed()->x10bc_pathArea);
|
||||
}
|
||||
}
|
||||
|
||||
void CSeedling::Think(float dt, CStateManager& mgr)
|
||||
{
|
||||
if (!GetActive())
|
||||
return;
|
||||
|
||||
++x5d4_thinkCounter;
|
||||
x5d6_26_playerObstructed = false;
|
||||
const CGameArea* area = mgr.GetWorld()->GetAreaAlways(GetAreaIdAlways());
|
||||
CGameArea::EOcclusionState occlusionState = CGameArea::EOcclusionState::Occluded;
|
||||
if (area && area->IsPostConstructed())
|
||||
occlusionState = area->GetPostConstructed()->x10dc_occlusionState;
|
||||
|
||||
if (occlusionState == CGameArea::EOcclusionState::Occluded)
|
||||
x5d6_26_playerObstructed = true;
|
||||
|
||||
if (!x5d6_26_playerObstructed)
|
||||
{
|
||||
zeus::CVector3f playerPos = mgr.GetPlayer().GetTranslation();
|
||||
float distance = (playerPos - GetTranslation()).magnitude();
|
||||
if (distance > x5c4_playerObstructionMinDist)
|
||||
{
|
||||
zeus::CVector3f direction = (playerPos - GetTranslation()).normalized();
|
||||
CRayCastResult result = mgr.RayStaticIntersection(playerPos, direction, distance,
|
||||
CMaterialFilter::skPassEverything);
|
||||
if (result.IsValid())
|
||||
x5d6_26_playerObstructed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (x5d6_26_playerObstructed)
|
||||
xf8_24_movable = false;
|
||||
|
||||
xf8_24_movable = !x5d6_24_alignToFloor;
|
||||
CWallWalker::Think(dt, mgr);
|
||||
|
||||
if (!x5d6_25_hasAlignSurface && x450_bodyController->GetPercentageFrozen() < 0.00001f && x5d6_24_alignToFloor)
|
||||
AlignToFloor(mgr, x590_colSphere.GetSphere().radius, GetTranslation() + (2.f * (dt * GetVelocity())), dt);
|
||||
|
||||
if (x71c_attackCoolOff > 0.f)
|
||||
x71c_attackCoolOff -= dt;
|
||||
}
|
||||
|
||||
void CSeedling::Render(const CStateManager& mgr) const
|
||||
{
|
||||
if (x400_25_alive && x6bc_spikeData)
|
||||
{
|
||||
u32 index = x722_24_renderOnlyClusterA ? 0 : u32(x722_25_curNeedleCluster);
|
||||
CModelFlags flags;
|
||||
flags.x2_flags = 3;
|
||||
flags.x4_color = zeus::CColor::skWhite;
|
||||
|
||||
for (const std::string& sv : skNeedleLocators[index])
|
||||
x6bc_spikeData->Render(mgr, GetLctrTransform(sv), x90_actorLights.get(), flags);
|
||||
}
|
||||
|
||||
CWallWalker::Render(mgr);
|
||||
}
|
||||
|
||||
void CSeedling::DoUserAnimEvent(CStateManager& mgr, const CInt32POINode& node, EUserEventType type, float dt)
|
||||
{
|
||||
if (type == EUserEventType::Projectile)
|
||||
LaunchNeedles(mgr);
|
||||
else if (type == EUserEventType::BeginAction)
|
||||
x722_24_renderOnlyClusterA = true;
|
||||
else
|
||||
CPatterned::DoUserAnimEvent(mgr, node, type, dt);
|
||||
}
|
||||
|
||||
std::experimental::optional<zeus::CAABox> CSeedling::GetTouchBounds() const
|
||||
{
|
||||
return x704_modelBounds.getTransformedAABox(GetTransform());
|
||||
}
|
||||
|
||||
void CSeedling::Touch(CActor& act, CStateManager& mgr)
|
||||
{
|
||||
if (x400_25_alive)
|
||||
{
|
||||
if (TCastToPtr<CPlayer> pl = act)
|
||||
MassiveDeath(mgr);
|
||||
}
|
||||
|
||||
CPatterned::Touch(act, mgr);
|
||||
}
|
||||
|
||||
void CSeedling::Patrol(CStateManager& mgr, EStateMsg msg, float)
|
||||
{
|
||||
if (msg == EStateMsg::Activate)
|
||||
{
|
||||
x450_bodyController->SetLocomotionType(pas::ELocomotionType::Relaxed);
|
||||
x5d6_24_alignToFloor = true;
|
||||
x150_momentum.zeroOut();
|
||||
x5d6_25_hasAlignSurface = false;
|
||||
xf8_24_movable = false;
|
||||
|
||||
TUniqueId id = (x720_prevObj != kInvalidUniqueId ? x720_prevObj :
|
||||
GetWaypointForState(mgr, EScriptObjectState::Patrol,
|
||||
EScriptObjectMessage::Follow));
|
||||
|
||||
if (id != kInvalidUniqueId)
|
||||
x2dc_destObj = id;
|
||||
}
|
||||
else if (msg == EStateMsg::Update)
|
||||
{
|
||||
UpdateWPDestination(mgr);
|
||||
zeus::CVector3f upVec = GetTransform().upVector();
|
||||
x450_bodyController->GetCommandMgr().DeliverCmd(
|
||||
CBCLocomotionCmd(ProjectVectorToPlane((x2e0_destPos - GetTranslation()).normalized(), upVec), {}, 0.f));
|
||||
x450_bodyController->GetCommandMgr().DeliverCmd(CBCLocomotionCmd(
|
||||
ProjectVectorToPlane(ProjectVectorToPlane(x45c_steeringBehaviors.Seek(*this, x2e0_destPos), upVec), upVec),
|
||||
{}, 1.f));
|
||||
x450_bodyController->GetCommandMgr().DeliverCmd(CBCLocomotionCmd(1.f * GetTransform().frontVector(), {}, 0.f));
|
||||
}
|
||||
else if (msg == EStateMsg::Deactivate)
|
||||
{
|
||||
x720_prevObj = x2dc_destObj;
|
||||
}
|
||||
}
|
||||
|
||||
void CSeedling::Active(CStateManager& mgr, EStateMsg msg, float arg)
|
||||
{
|
||||
if (msg == EStateMsg::Activate)
|
||||
x450_bodyController->SetLocomotionType(pas::ELocomotionType::Lurk);
|
||||
CPatterned::Patrol(mgr, msg, arg);
|
||||
}
|
||||
|
||||
void CSeedling::Enraged(CStateManager&, EStateMsg msg, float)
|
||||
{
|
||||
if (msg == EStateMsg::Activate)
|
||||
x450_bodyController->SetLocomotionType(pas::ELocomotionType::Internal8);
|
||||
}
|
||||
|
||||
void CSeedling::ProjectileAttack(CStateManager& mgr, EStateMsg msg, float)
|
||||
{
|
||||
if (msg == EStateMsg::Activate)
|
||||
x32c_animState = EAnimState::One;
|
||||
else if (msg == EStateMsg::Update)
|
||||
TryCommand(mgr, pas::EAnimationState::ProjectileAttack, &CPatterned::TryProjectileAttack, 0);
|
||||
else if (msg == EStateMsg::Deactivate)
|
||||
{
|
||||
x32c_animState = EAnimState::Zero;
|
||||
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;
|
||||
else if (msg == EStateMsg::Update)
|
||||
TryCommand(mgr, pas::EAnimationState::Generate, &CPatterned::TryGenerate, 0);
|
||||
}
|
||||
|
||||
bool CSeedling::ShouldAttack(CStateManager& mgr, float)
|
||||
{
|
||||
if (x71c_attackCoolOff > 0.f)
|
||||
return false;
|
||||
|
||||
return mgr.CanCreateProjectile(GetUniqueId(), EWeaponType::AI, 6);
|
||||
}
|
||||
|
||||
void CSeedling::LaunchNeedles(CStateManager& mgr)
|
||||
{
|
||||
for (const std::string& needle : skNeedleLocators[u32(x722_25_curNeedleCluster)])
|
||||
LaunchProjectile(GetLctrTransform(needle), mgr, 6, EProjectileAttrib::None, true, {}, 0xFFFF, false,
|
||||
GetModelData()->GetScale());
|
||||
|
||||
x722_25_curNeedleCluster = !x722_25_curNeedleCluster;
|
||||
x722_24_renderOnlyClusterA = false;
|
||||
}
|
||||
|
||||
void CSeedling::MassiveDeath(CStateManager& mgr)
|
||||
{
|
||||
if (x400_25_alive)
|
||||
{
|
||||
mgr.ApplyDamageToWorld(GetUniqueId(), *this, GetTranslation(), x6e8_deathDamage,
|
||||
CMaterialFilter::MakeIncludeExclude({EMaterialTypes::Solid}, {}));
|
||||
LaunchNeedles(mgr);
|
||||
}
|
||||
CPatterned::MassiveDeath(mgr);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "World/CWallWalker.hpp"
|
||||
#include "World/CPathFindSearch.hpp"
|
||||
#include "Weapon/CProjectileInfo.hpp"
|
||||
|
||||
namespace urde
|
||||
{
|
||||
|
@ -8,6 +10,17 @@ namespace MP1
|
|||
{
|
||||
class CSeedling : public CWallWalker
|
||||
{
|
||||
static const std::string skNeedleLocators[2][6];
|
||||
CPathFindSearch x5d8_searchPath;
|
||||
std::unique_ptr<CModelData> x6bc_spikeData;
|
||||
CProjectileInfo x6c0_projectileInfo;
|
||||
CDamageInfo x6e8_deathDamage;
|
||||
zeus::CAABox x704_modelBounds = zeus::CAABox::skNullBox;
|
||||
float x71c_attackCoolOff = 0.f;
|
||||
TUniqueId x720_prevObj = kInvalidUniqueId;
|
||||
bool x722_24_renderOnlyClusterA : 1;
|
||||
bool x722_25_curNeedleCluster : 1;
|
||||
void LaunchNeedles(CStateManager&);
|
||||
public:
|
||||
DEFINE_PATTERNED(Seedling)
|
||||
CSeedling(TUniqueId, std::string_view, const CEntityInfo&, const zeus::CTransform&,
|
||||
|
@ -16,6 +29,21 @@ public:
|
|||
float, float, float, float);
|
||||
|
||||
void Accept(IVisitor&);
|
||||
void AcceptScriptMsg(EScriptObjectMessage, TUniqueId, CStateManager&);
|
||||
void Think(float, CStateManager&);
|
||||
void Render(const CStateManager&) const;
|
||||
void DoUserAnimEvent(CStateManager& mgr, const CInt32POINode& node, EUserEventType type, float dt);
|
||||
CProjectileInfo* GetProjectileInfo() { return &x6c0_projectileInfo; }
|
||||
std::experimental::optional<zeus::CAABox> GetTouchBounds() const;
|
||||
void Touch(CActor&, CStateManager&);
|
||||
CPathFindSearch* GetSearchPath() { return &x5d8_searchPath; }
|
||||
void Patrol(CStateManager&, EStateMsg, float);
|
||||
void Active(CStateManager&, EStateMsg, float);
|
||||
void Enraged(CStateManager&, EStateMsg, float);
|
||||
void ProjectileAttack(CStateManager&, EStateMsg, float);
|
||||
void Generate(CStateManager&, EStateMsg, float);
|
||||
bool ShouldAttack(CStateManager&, float);
|
||||
void MassiveDeath(CStateManager&);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,415 @@
|
|||
#include "CSpankWeed.hpp"
|
||||
#include "World/CPatternedInfo.hpp"
|
||||
#include "World/CPlayer.hpp"
|
||||
#include "Collision/CCollisionActor.hpp"
|
||||
#include "CStateManager.hpp"
|
||||
#include <logvisor/logvisor.hpp>
|
||||
|
||||
namespace urde::MP1
|
||||
{
|
||||
logvisor::Module SpankLog("urde::MP1::SpankWeed");
|
||||
CSpankWeed::CSpankWeed(TUniqueId uid, std::string_view name, const CEntityInfo& info, const zeus::CTransform& xf,
|
||||
CModelData&& mData, const CActorParameters& actParms, const CPatternedInfo& pInfo, float maxDetectionRange,
|
||||
float maxHearingRange, float maxSightRange, float hideTime)
|
||||
: CPatterned(ECharacter::SpankWeed, uid, name, EFlavorType::Zero, info, xf, std::move(mData), pInfo,
|
||||
EMovementType::Flyer, EColliderType::One, EBodyType::Restricted, actParms, EKnockBackVariant::Medium)
|
||||
, x568_maxDetectionRange(maxDetectionRange)
|
||||
, x56c_detectionHeightRange(pInfo.GetDetectionHeightRange())
|
||||
, x570_maxHearingRange(maxHearingRange)
|
||||
, x574_maxSightRange(maxSightRange)
|
||||
, x578_hideTime(hideTime)
|
||||
, x584_retreatOrigin(xf.origin)
|
||||
{
|
||||
SetCallTouch(false);
|
||||
CreateShadow(false);
|
||||
|
||||
zeus::CVector3f modelScale = GetModelData()->GetScale();
|
||||
if (modelScale.x != modelScale.y || modelScale.x != modelScale.z)
|
||||
{
|
||||
float scale = modelScale.magnitude() / std::sqrt(3.f);
|
||||
|
||||
ModelData()->SetScale(zeus::CVector3f(scale));
|
||||
SpankLog.report(logvisor::Level::Warning, "WARNING: Non-uniform scale (%.2f, %.2f, %.2f) applied to Spank Weed"
|
||||
"...changing scale to (%.2f, %.2f, %.2f)\n",
|
||||
modelScale.x, modelScale.y, modelScale.z,
|
||||
scale, scale, scale);
|
||||
}
|
||||
CMaterialList list = GetMaterialFilter().GetExcludeList();
|
||||
list.Add(EMaterialTypes::Character);
|
||||
list.Add(EMaterialTypes::Player);
|
||||
SetMaterialFilter(CMaterialFilter::MakeIncludeExclude(GetMaterialFilter().GetIncludeList(), list));
|
||||
|
||||
CSegId segId = GetModelData()->GetAnimationData()->GetLocatorSegId("lockon_target_LCTR"sv);
|
||||
if (segId != 0xFF)
|
||||
{
|
||||
zeus::CTransform locatorXf = GetTransform() * zeus::CTransform::Scale(GetModelData()->GetScale()) *
|
||||
GetModelData()->GetAnimationData()->GetLocatorTransform(segId, nullptr);
|
||||
x5a8_lockonTarget = locatorXf.origin;
|
||||
x59c_lockonOffset = locatorXf.origin - GetTranslation();
|
||||
}
|
||||
x460_knockBackController.SetAutoResetImpulse(false);
|
||||
}
|
||||
|
||||
static const SSphereJointDescription kArmCollision[]=
|
||||
{
|
||||
{"Arm_4", 1.5f},
|
||||
{"Arm_6", 1.f},
|
||||
{"Arm_7", 1.f},
|
||||
{"Arm_8", 1.f},
|
||||
{"Arm_9", 1.f},
|
||||
{"Arm_11", 1.f},
|
||||
{"Swoosh_LCTR", 1.5f}
|
||||
};
|
||||
|
||||
void CSpankWeed::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr)
|
||||
{
|
||||
bool oldActive = GetActive();
|
||||
if (msg == EScriptObjectMessage::Activate)
|
||||
{
|
||||
if (x90_actorLights)
|
||||
x90_actorLights->SetDirty();
|
||||
}
|
||||
else if (msg == EScriptObjectMessage::Decrement)
|
||||
{
|
||||
if (x5b4_ != 0 && x5b4_ != 5 && x5b4_ != 6 && x5b4_ != 4)
|
||||
{
|
||||
x400_24_hitByPlayerProjectile = true;
|
||||
x428_damageCooldownTimer = x424_damageWaitTime;
|
||||
}
|
||||
}
|
||||
else if (msg == EScriptObjectMessage::Registered)
|
||||
{
|
||||
if (!x450_bodyController->GetActive())
|
||||
{
|
||||
x450_bodyController->Activate(mgr);
|
||||
zeus::CVector3f extents = GetBoundingBox().extents();
|
||||
|
||||
SetBoundingBox({-extents, extents});
|
||||
}
|
||||
|
||||
std::vector<CJointCollisionDescription> joints;
|
||||
joints.reserve(12);
|
||||
|
||||
for (const SSphereJointDescription& joint : kArmCollision)
|
||||
{
|
||||
CSegId id = GetModelData()->GetAnimationData()->GetLocatorSegId(joint.name);
|
||||
if (id != 0xFF)
|
||||
joints.push_back(CJointCollisionDescription::SphereCollision(id, joint.radius, joint.name, 0.001f));
|
||||
}
|
||||
|
||||
x594_collisionMgr.reset(new CCollisionActorManager(mgr, GetUniqueId(), GetAreaIdAlways(), joints, GetActive()));
|
||||
CMaterialList list;
|
||||
list.Add(EMaterialTypes::CameraPassthrough);
|
||||
list.Add(EMaterialTypes::Immovable);
|
||||
x594_collisionMgr->AddMaterial(mgr, list);
|
||||
if (x90_actorLights)
|
||||
{
|
||||
x90_actorLights->SetDirty();
|
||||
zeus::CVector3f swooshOrigin = GetScaledLocatorTransform("swoosh_LCTR"sv).origin;
|
||||
x90_actorLights->SetActorPositionBias(GetTransform().buildMatrix3f() * swooshOrigin);
|
||||
}
|
||||
}
|
||||
else if (msg == EScriptObjectMessage::Touched)
|
||||
{
|
||||
if (TCastToPtr<CCollisionActor> colAct = mgr.ObjectById(uid))
|
||||
{
|
||||
if (TCastToPtr<CPlayer> player = mgr.ObjectById(colAct->GetLastTouchedObject()))
|
||||
{
|
||||
if (x420_curDamageRemTime <= 0.f && x5b4_ != 4 && x5b4_ != 6)
|
||||
{
|
||||
mgr.ApplyDamage(GetUniqueId(), player->GetUniqueId(), GetUniqueId(), GetContactDamage(),
|
||||
CMaterialFilter::MakeIncludeExclude({EMaterialTypes::Solid}, {}), {});
|
||||
x420_curDamageRemTime = x424_damageWaitTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (msg == EScriptObjectMessage::Deleted)
|
||||
{
|
||||
mgr.FreeScriptObject(x590_);
|
||||
x594_collisionMgr->Destroy(mgr);
|
||||
}
|
||||
else if (msg == EScriptObjectMessage::SuspendedMove)
|
||||
{
|
||||
x594_collisionMgr->SetMovable(mgr, false);
|
||||
}
|
||||
|
||||
CPatterned::AcceptScriptMsg(msg, uid, mgr);
|
||||
|
||||
if (GetActive() != oldActive)
|
||||
x594_collisionMgr.reset();
|
||||
}
|
||||
|
||||
void CSpankWeed::Think(float dt, CStateManager& mgr)
|
||||
{
|
||||
if (!GetActive())
|
||||
return;
|
||||
|
||||
HealthInfo(mgr)->SetHP(1000000.0f);
|
||||
|
||||
if (!x598_isHiding)
|
||||
{
|
||||
zeus::CVector3f eyeOrigin = GetLocatorTransform("Eye"sv).origin;
|
||||
MoveCollisionPrimitive(GetModelData()->GetScale() * eyeOrigin);
|
||||
x594_collisionMgr->Update(dt, mgr, CCollisionActorManager::EUpdateOptions::ObjectSpace);
|
||||
xe4_27_notInSortedLists = true;
|
||||
}
|
||||
|
||||
CPatterned::Think(dt, mgr);
|
||||
}
|
||||
|
||||
zeus::CVector3f CSpankWeed::GetOrbitPosition(const CStateManager& mgr) const
|
||||
{
|
||||
zeus::CVector3f ret = CPatterned::GetOrbitPosition(mgr);
|
||||
float delay = std::max(1.f, x330_stateMachineState.GetDelay());
|
||||
if (x5b4_ == 3 && x5b8_ == 2)
|
||||
{
|
||||
return (ret * (1.f - delay) + ((GetTranslation() + x59c_lockonOffset) * delay));
|
||||
}
|
||||
else if (x5b4_ == 2 && x5b8_ == 3)
|
||||
{
|
||||
return (GetTranslation() + x59c_lockonOffset) * (1.f - delay) + (ret * delay);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
zeus::CVector3f CSpankWeed::GetAimPosition(const CStateManager&, float dt) const
|
||||
{
|
||||
zeus::CVector3f pos = (dt > 0.f ? PredictMotion(dt).x0_translation : zeus::CVector3f::skZero);
|
||||
|
||||
CSegId id = GetModelData()->GetAnimationData()->GetLocatorSegId("lockon_target_LCTR"sv);
|
||||
if (id != 0xFF)
|
||||
{
|
||||
zeus::CVector3f lockonOff = GetModelData()->GetAnimationData()->GetLocatorTransform(id, nullptr).origin;
|
||||
return pos + (GetTransform() * (GetModelData()->GetScale() * lockonOff));
|
||||
}
|
||||
|
||||
return pos + GetBoundingBox().center();
|
||||
}
|
||||
|
||||
void CSpankWeed::Flinch(CStateManager& mgr, EStateMsg msg, float)
|
||||
{
|
||||
if (msg == EStateMsg::Activate)
|
||||
{
|
||||
x5bc_ = 0;
|
||||
x5b4_ = 0;
|
||||
RemoveMaterial(EMaterialTypes::Orbit, EMaterialTypes::Target, mgr);
|
||||
}
|
||||
else if (msg == EStateMsg::Update)
|
||||
{
|
||||
if (x5bc_ == 0)
|
||||
{
|
||||
if (x450_bodyController->GetBodyStateInfo().GetCurrentStateId() == pas::EAnimationState::KnockBack)
|
||||
x5bc_ = 2;
|
||||
else
|
||||
x450_bodyController->GetCommandMgr().DeliverCmd(CBCKnockBackCmd({}, pas::ESeverity::Zero));
|
||||
}
|
||||
else if (x5bc_ == 2 && x450_bodyController->GetBodyStateInfo().GetCurrentStateId() != pas::EAnimationState::KnockBack)
|
||||
x5bc_ = 3;
|
||||
}
|
||||
else if (msg == EStateMsg::Deactivate)
|
||||
{
|
||||
x5b8_ = 4;
|
||||
}
|
||||
}
|
||||
|
||||
bool CSpankWeed::Delay(CStateManager&, float)
|
||||
{
|
||||
if (x400_24_hitByPlayerProjectile)
|
||||
{
|
||||
if (x330_stateMachineState.GetTime() > x578_hideTime)
|
||||
{
|
||||
x400_24_hitByPlayerProjectile = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSpankWeed::InRange(CStateManager& mgr, float)
|
||||
{
|
||||
float playerDist = GetPlayerDistance(mgr);
|
||||
if (x56c_detectionHeightRange > 0.f)
|
||||
{
|
||||
return std::fabs(mgr.GetPlayer().GetTranslation().z - GetTranslation().z) < x56c_detectionHeightRange &&
|
||||
playerDist < (x574_maxSightRange * x574_maxSightRange);
|
||||
}
|
||||
|
||||
return playerDist < (x574_maxSightRange * x574_maxSightRange);
|
||||
}
|
||||
|
||||
bool CSpankWeed::HearPlayer(CStateManager& mgr, float)
|
||||
{
|
||||
float playerDist = GetPlayerDistance(mgr);
|
||||
if (x56c_detectionHeightRange > 0.f)
|
||||
{
|
||||
return std::fabs(mgr.GetPlayer().GetTranslation().z - GetTranslation().z) < x56c_detectionHeightRange &&
|
||||
playerDist < (x570_maxHearingRange * x570_maxHearingRange);
|
||||
}
|
||||
|
||||
return playerDist < (x570_maxHearingRange * x570_maxHearingRange);
|
||||
}
|
||||
|
||||
bool CSpankWeed::InDetectionRange(CStateManager& mgr, float)
|
||||
{
|
||||
float playerDist = GetPlayerDistance(mgr);
|
||||
if (x56c_detectionHeightRange > 0.f)
|
||||
{
|
||||
return std::fabs(mgr.GetPlayer().GetTranslation().z - GetTranslation().z) < x56c_detectionHeightRange &&
|
||||
playerDist < (x568_maxDetectionRange * x568_maxDetectionRange);
|
||||
}
|
||||
|
||||
return playerDist < (x568_maxDetectionRange * x568_maxDetectionRange);
|
||||
}
|
||||
|
||||
void CSpankWeed::Attack(CStateManager&, EStateMsg msg, float)
|
||||
{
|
||||
if (msg == EStateMsg::Activate)
|
||||
{
|
||||
x450_bodyController->GetCommandMgr().DeliverCmd(CBCMeleeAttackCmd(pas::ESeverity::Zero));
|
||||
}
|
||||
else if (msg == EStateMsg::Update)
|
||||
{
|
||||
if (x450_bodyController->GetBodyStateInfo().GetCurrentStateId() == pas::EAnimationState::MeleeAttack)
|
||||
return;
|
||||
|
||||
x450_bodyController->GetCommandMgr().DeliverCmd(CBCMeleeAttackCmd(pas::ESeverity::Zero));
|
||||
}
|
||||
else if (msg == EStateMsg::Deactivate)
|
||||
{
|
||||
x5b8_ = 3;
|
||||
}
|
||||
}
|
||||
|
||||
void CSpankWeed::TargetPatrol(CStateManager& mgr, EStateMsg msg, float)
|
||||
{
|
||||
if (msg == EStateMsg::Activate)
|
||||
{
|
||||
x450_bodyController->SetLocomotionType(pas::ELocomotionType::Combat);
|
||||
RemoveMaterial(EMaterialTypes::Solid, mgr);
|
||||
x5b4_ = 2;
|
||||
}
|
||||
else if (msg == EStateMsg::Deactivate)
|
||||
{
|
||||
x5b8_ = 2;
|
||||
}
|
||||
}
|
||||
|
||||
void CSpankWeed::Lurk(CStateManager& mgr, EStateMsg msg, float)
|
||||
{
|
||||
if (msg == EStateMsg::Activate)
|
||||
{
|
||||
x460_knockBackController.SetEnableFreeze(true);
|
||||
x450_bodyController->SetLocomotionType(pas::ELocomotionType::Lurk);
|
||||
RemoveMaterial(EMaterialTypes::Solid, mgr);
|
||||
x5b4_ = 1;
|
||||
}
|
||||
else if (msg == EStateMsg::Deactivate)
|
||||
{
|
||||
x5b8_ = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void CSpankWeed::FadeOut(CStateManager&, EStateMsg msg, float)
|
||||
{
|
||||
if (msg == EStateMsg::Activate)
|
||||
{
|
||||
x5bc_ = 0;
|
||||
x57c_canKnockBack = false;
|
||||
x5b4_ = 6;
|
||||
}
|
||||
else if (msg == EStateMsg::Update)
|
||||
{
|
||||
if (x5bc_ == 0)
|
||||
{
|
||||
if (x450_bodyController->GetBodyStateInfo().GetCurrentStateId() == pas::EAnimationState::Step)
|
||||
x5bc_ = 2;
|
||||
else
|
||||
x450_bodyController->GetCommandMgr().DeliverCmd(
|
||||
CBCStepCmd(pas::EStepDirection::Backward, pas::EStepType::Normal));
|
||||
|
||||
}
|
||||
else if (x5bc_ == 2)
|
||||
{
|
||||
if (x450_bodyController->GetBodyStateInfo().GetCurrentStateId() != pas::EAnimationState::Step)
|
||||
x5bc_ = 3;
|
||||
}
|
||||
}
|
||||
else if (msg == EStateMsg::Deactivate)
|
||||
{
|
||||
x5b8_ = 6;
|
||||
}
|
||||
}
|
||||
|
||||
void CSpankWeed::FadeIn(CStateManager& mgr, EStateMsg msg, float)
|
||||
{
|
||||
if (msg == EStateMsg::Activate)
|
||||
{
|
||||
x5bc_ = 0;
|
||||
x57c_canKnockBack = true;
|
||||
x5b4_ = 5;
|
||||
}
|
||||
else if (msg == EStateMsg::Update)
|
||||
{
|
||||
if (x5bc_ == 0)
|
||||
{
|
||||
if (x450_bodyController->GetBodyStateInfo().GetCurrentStateId() == pas::EAnimationState::Step)
|
||||
x5bc_ = 2;
|
||||
else
|
||||
x450_bodyController->GetCommandMgr().DeliverCmd(
|
||||
CBCStepCmd(pas::EStepDirection::Forward, pas::EStepType::Normal));
|
||||
|
||||
}
|
||||
else if (x5bc_ == 2)
|
||||
{
|
||||
if (x450_bodyController->GetBodyStateInfo().GetCurrentStateId() != pas::EAnimationState::Step)
|
||||
x5bc_ = 3;
|
||||
}
|
||||
}
|
||||
else if (msg == EStateMsg::Deactivate)
|
||||
{
|
||||
x5b8_ = 5;
|
||||
}
|
||||
|
||||
xe7_28_worldLightingDirty = true;
|
||||
}
|
||||
|
||||
void CSpankWeed::Patrol(CStateManager& mgr, EStateMsg msg, float)
|
||||
{
|
||||
if (msg == EStateMsg::Activate)
|
||||
{
|
||||
x460_knockBackController.SetEnableFreeze(false);
|
||||
x450_bodyController->SetLocomotionType(pas::ELocomotionType::Relaxed);
|
||||
RemoveMaterial(EMaterialTypes::Solid, EMaterialTypes::Scannable, mgr);
|
||||
RemoveMaterial(EMaterialTypes::Orbit, EMaterialTypes::Target, mgr);
|
||||
x594_collisionMgr->SetActive(mgr, false);
|
||||
x598_isHiding = true;
|
||||
x5b4_ = 0;
|
||||
}
|
||||
else if (msg == EStateMsg::Deactivate)
|
||||
{
|
||||
AddMaterial(EMaterialTypes::Orbit, EMaterialTypes::Target, EMaterialTypes::Scannable, mgr);
|
||||
SetTranslation(x584_retreatOrigin);
|
||||
x594_collisionMgr->SetActive(mgr, true);
|
||||
x598_isHiding = false;
|
||||
x460_knockBackController.SetEnableFreeze(true);
|
||||
x5b8_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void CSpankWeed::KnockBack(const zeus::CVector3f& backVec, CStateManager& mgr, const CDamageInfo& info,
|
||||
EKnockBackType type, bool inDeferred, float magnitude)
|
||||
{
|
||||
if (!x57c_canKnockBack)
|
||||
return;
|
||||
CPatterned::KnockBack(backVec, mgr, info, type, inDeferred, magnitude);
|
||||
x57c_canKnockBack = false;
|
||||
}
|
||||
|
||||
float CSpankWeed::GetPlayerDistance(CStateManager& mgr) const
|
||||
{
|
||||
return (mgr.GetPlayer().GetTranslation() - x5a8_lockonTarget).magSquared();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
#pragma once
|
||||
|
||||
#include "World/CPatterned.hpp"
|
||||
#include "Collision/CCollisionActorManager.hpp"
|
||||
|
||||
namespace urde::MP1
|
||||
{
|
||||
class CSpankWeed : public CPatterned
|
||||
{
|
||||
float x568_maxDetectionRange;
|
||||
float x56c_detectionHeightRange;
|
||||
float x570_maxHearingRange;
|
||||
float x574_maxSightRange;
|
||||
float x578_hideTime;
|
||||
bool x57c_canKnockBack = false;
|
||||
/* float x580_ = 0.f; unused */
|
||||
zeus::CVector3f x584_retreatOrigin;
|
||||
TUniqueId x590_ = kInvalidUniqueId;
|
||||
std::unique_ptr<CCollisionActorManager> x594_collisionMgr;
|
||||
bool x598_isHiding = true;
|
||||
zeus::CVector3f x59c_lockonOffset;
|
||||
zeus::CVector3f x5a8_lockonTarget;
|
||||
s32 x5b4_ = -1;
|
||||
s32 x5b8_ = -1;
|
||||
s32 x5bc_ = -1;
|
||||
|
||||
float GetPlayerDistance(CStateManager&) const;
|
||||
public:
|
||||
DEFINE_PATTERNED(SpankWeed)
|
||||
|
||||
CSpankWeed(TUniqueId, std::string_view, const CEntityInfo&, const zeus::CTransform&, CModelData&&,
|
||||
const CActorParameters&, const CPatternedInfo&, float, float, float, float);
|
||||
|
||||
void AcceptScriptMsg(EScriptObjectMessage, TUniqueId, CStateManager&);
|
||||
void Think(float, CStateManager&);
|
||||
zeus::CVector3f GetOrbitPosition(const CStateManager&) const;
|
||||
zeus::CVector3f GetAimPosition(const CStateManager&, float) const;
|
||||
bool AnimOver(CStateManager&, float) { return x5bc_ == 3; }
|
||||
void Flinch(CStateManager&, EStateMsg, float);
|
||||
bool Delay(CStateManager&, float);
|
||||
bool InRange(CStateManager&, float);
|
||||
bool HearPlayer(CStateManager&, float);
|
||||
bool InDetectionRange(CStateManager&, float);
|
||||
void Attack(CStateManager&, EStateMsg, float);
|
||||
void TargetPatrol(CStateManager&, EStateMsg, float);
|
||||
void Lurk(CStateManager&, EStateMsg, float);
|
||||
void FadeOut(CStateManager&, EStateMsg, float);
|
||||
void FadeIn(CStateManager&, EStateMsg, float);
|
||||
void Patrol(CStateManager&, EStateMsg, float);
|
||||
void KnockBack(const zeus::CVector3f&, CStateManager&, const CDamageInfo& info,
|
||||
EKnockBackType type, bool inDeferred, float magnitude);
|
||||
};
|
||||
}
|
|
@ -136,7 +136,7 @@ void CBomb::AddToRenderer(const zeus::CFrustum& frustum, const urde::CStateManag
|
|||
zeus::CAABox aabox(origin - (0.9f * ballRadius), origin + (0.9f * ballRadius));
|
||||
zeus::CVector3f closestPoint = aabox.closestPointAlongVector(CGraphics::g_ViewMatrix.frontVector());
|
||||
|
||||
if (x190_24_isNotDetonated&& x17c_fuseTime > 0.5f)
|
||||
if (x190_24_isNotDetonated && x17c_fuseTime > 0.5f)
|
||||
g_Renderer->AddParticleGen(*x180_particle1, closestPoint, aabox);
|
||||
else
|
||||
g_Renderer->AddParticleGen(*x184_particle2, closestPoint, aabox);
|
||||
|
|
|
@ -18,4 +18,9 @@ void CPlasmaProjectile::Accept(IVisitor& visitor)
|
|||
visitor.Visit(this);
|
||||
}
|
||||
|
||||
void CPlasmaProjectile::Fire(const zeus::CTransform&, CStateManager&, bool)
|
||||
{
|
||||
SetActive(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ public:
|
|||
void Accept(IVisitor& visitor);
|
||||
|
||||
void UpdateFx(const zeus::CTransform&, float, CStateManager&) {}
|
||||
void Fire(const zeus::CTransform&, CStateManager&, bool) {}
|
||||
void Fire(const zeus::CTransform&, CStateManager&, bool);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ CAi::CAi(TUniqueId uid, bool active, std::string_view name, const CEntityInfo& i
|
|||
}
|
||||
|
||||
if (x90_actorLights)
|
||||
x260_damageVulnerability.SetX38_25(true);
|
||||
x90_actorLights->SetCastShadows(true);
|
||||
}
|
||||
|
||||
void CAi::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr)
|
||||
|
|
|
@ -34,9 +34,7 @@ class CDamageVulnerability
|
|||
EVulnerability x2c_enemyWp3Lava;
|
||||
EVulnerability x30_enemyWp4;
|
||||
EVulnerability x34_unk1;
|
||||
/* FIXME: What's going on here? */
|
||||
EVulnerability x38_unk2;
|
||||
bool x38_25 : 1;
|
||||
|
||||
EVulnerability x3c_chargedPower;
|
||||
EVulnerability x40_chargedIce;
|
||||
|
@ -80,7 +78,6 @@ public:
|
|||
static const CDamageVulnerability& ImmuneVulnerabilty() { return sImmuneVulnerability; }
|
||||
static const CDamageVulnerability& ReflectVulnerabilty() { return sReflectVulnerability; }
|
||||
static const CDamageVulnerability& PasshThroughVulnerabilty() { return sPassThroughVulnerability; }
|
||||
void SetX38_25(bool) { x38_25 = true; }
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -154,6 +154,7 @@ public:
|
|||
void SetEnableBurnDeath(bool b) { x81_28_enableBurnDeath = b; }
|
||||
void SetEnableExplodeDeath(bool b) { x81_29_enableExplodeDeath = b; }
|
||||
void SetEnableLaggedBurnDeath(bool b) { x81_30_enableLaggedBurnDeath = b; }
|
||||
void SetX81_31(bool b) { x81_31_ = b; }
|
||||
void SetX82_24(bool b) { x82_24_ = b; }
|
||||
void SetLocomotionDuringElectrocution(bool b) { x82_26_locomotionDuringElectrocution = b; }
|
||||
const KnockBackParms& GetActiveParms() const { return x4_activeParms; }
|
||||
|
|
|
@ -1026,6 +1026,16 @@ void CPatterned::TryLoopReaction(CStateManager& mgr, int arg)
|
|||
x450_bodyController->GetCommandMgr().DeliverCmd(CBCLoopReactionCmd(pas::EReactionType(arg)));
|
||||
}
|
||||
|
||||
void CPatterned::TryProjectileAttack(CStateManager&, int arg)
|
||||
{
|
||||
x450_bodyController->GetCommandMgr().DeliverCmd(CBCProjectileAttackCmd(pas::ESeverity(arg), x2e0_destPos, false));
|
||||
}
|
||||
|
||||
void CPatterned::TryGenerate(CStateManager& mgr, int arg)
|
||||
{
|
||||
x450_bodyController->GetCommandMgr().DeliverCmd(CBCGenerateCmd(pas::EGenerateType(arg), x2e0_destPos, true));
|
||||
}
|
||||
|
||||
void CPatterned::BuildBodyController(EBodyType bodyType)
|
||||
{
|
||||
if (x450_bodyController)
|
||||
|
|
|
@ -381,6 +381,8 @@ public:
|
|||
|
||||
void TryCommand(CStateManager& mgr, pas::EAnimationState state, CPatternedTryFunc func, int arg);
|
||||
void TryLoopReaction(CStateManager& mgr, int arg);
|
||||
void TryProjectileAttack(CStateManager& mgr, int arg);
|
||||
void TryGenerate(CStateManager& mgr, int arg);
|
||||
|
||||
virtual bool KnockbackWhenFrozen() const { return true; }
|
||||
virtual void MassiveDeath(CStateManager& mgr);
|
||||
|
@ -422,6 +424,12 @@ public:
|
|||
bool CanLongJump() const { return x328_26_longJump; }
|
||||
bool IsMakingBigStrike() const { return x402_28_isMakingBigStrike; }
|
||||
|
||||
void SetKeepInThermalVisor()
|
||||
{
|
||||
x403_24_keepThermalVisorState = true;
|
||||
xe6_27_thermalVisorFlags = 1 | 2;
|
||||
}
|
||||
|
||||
//region Casting Functions
|
||||
|
||||
template <class T>
|
||||
|
|
|
@ -59,13 +59,13 @@ public:
|
|||
CPatternedInfo(CInputStream& in, u32 pcount);
|
||||
static std::pair<bool, u32> HasCorrectParameterCount(CInputStream& in);
|
||||
|
||||
CAnimationParameters& GetAnimationParameters() { return xec_animParams; }
|
||||
const CAnimationParameters& GetAnimationParameters() const { return xec_animParams; }
|
||||
|
||||
float GetDetectionHeightRange() const { return x10_detectionHeightRange; }
|
||||
float GetHalfExtent() const { return xc4_halfExtent; }
|
||||
float GetHeight() const { return xc8_height; }
|
||||
u32 GetPathfindingIndex() const { return x10c_pathfindingIndex; }
|
||||
const CHealthInfo& GetHealthInfo() const { return x54_healthInfo; }
|
||||
CAnimationParameters& GetAnimationParameters() { return xec_animParams; }
|
||||
const CAnimationParameters& GetAnimationParameters() const { return xec_animParams; }
|
||||
u32 GetPathfindingIndex() const { return x10c_pathfindingIndex; }
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -689,6 +689,7 @@ public:
|
|||
EPlayerOrbitRequest GetOrbitRequest() const { return x30c_orbitRequest; }
|
||||
bool IsShowingCrosshairs() const { return x9c4_25_showCrosshairs; }
|
||||
bool IsSidewaysDashing() const { return x37c_sidewaysDashing; }
|
||||
void Set_X590(bool b) { x590_ = b; }
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
#include "CScriptSound.hpp"
|
||||
#include "CScriptSpawnPoint.hpp"
|
||||
#include "CScriptSpecialFunction.hpp"
|
||||
#include "MP1/World/CSpankWeed.hpp"
|
||||
#include "MP1/World/CBabygoth.hpp"
|
||||
#include "MP1/World/CEyeball.hpp"
|
||||
#include "CScriptSteam.hpp"
|
||||
|
@ -86,6 +87,7 @@
|
|||
#include "CScriptWorldTeleporter.hpp"
|
||||
#include "CScriptDebugCameraWaypoint.hpp"
|
||||
#include "CScriptSpiderBallAttractionSurface.hpp"
|
||||
#include "MP1/World/CPuddleToadGamma.hpp"
|
||||
#include "CScriptSpindleCamera.hpp"
|
||||
#include "MP1/World/CAtomicAlpha.hpp"
|
||||
#include "CSimplePool.hpp"
|
||||
|
@ -1723,7 +1725,34 @@ CEntity* ScriptLoader::LoadSpiderBallAttractionSurface(CStateManager& mgr, CInpu
|
|||
|
||||
CEntity* ScriptLoader::LoadPuddleToadGamma(CStateManager& mgr, CInputStream& in, int propCount, const CEntityInfo& info)
|
||||
{
|
||||
if (!EnsurePropertyCount(propCount, 17, "PuddleToadGamma"))
|
||||
return nullptr;
|
||||
|
||||
std::string name = mgr.HashInstanceName(in);
|
||||
CPatterned::EFlavorType flavor = CPatterned::EFlavorType(in.readUint32Big());
|
||||
zeus::CTransform xf = LoadEditorTransform(in);
|
||||
zeus::CVector3f scale = zeus::CVector3f::ReadBig(in);
|
||||
auto pair = CPatternedInfo::HasCorrectParameterCount(in);
|
||||
if (!pair.first)
|
||||
return nullptr;
|
||||
|
||||
CPatternedInfo pInfo(in, pair.second);
|
||||
CActorParameters actParms = LoadActorParameters(in);
|
||||
float f1 = in.readFloatBig();
|
||||
float f2 = in.readFloatBig();
|
||||
float f3 = in.readFloatBig();
|
||||
zeus::CVector3f vec = zeus::CVector3f::ReadBig(in);
|
||||
float f4 = in.readFloatBig();
|
||||
float f5 = in.readFloatBig();
|
||||
float f6 = in.readFloatBig();
|
||||
CDamageInfo dInfo1(in);
|
||||
CDamageInfo dInfo2(in);
|
||||
CAssetId collisionData(in);
|
||||
const CAnimationParameters& animParms = pInfo.GetAnimationParameters();
|
||||
CModelData mData(CAnimRes(animParms.GetACSFile(), animParms.GetCharacter(), scale,
|
||||
animParms.GetInitialAnimation(), true));
|
||||
return new MP1::CPuddleToadGamma(mgr.AllocateUniqueId(), name, flavor, info, xf, std::move(mData), pInfo, actParms,
|
||||
f1, f2, f3, vec, f4, f5, f6, dInfo1, dInfo2, collisionData);
|
||||
}
|
||||
|
||||
CEntity* ScriptLoader::LoadDistanceFog(CStateManager& mgr, CInputStream& in, int propCount, const CEntityInfo& info)
|
||||
|
@ -1879,7 +1908,29 @@ CEntity* ScriptLoader::LoadSpecialFunction(CStateManager& mgr, CInputStream& in,
|
|||
|
||||
CEntity* ScriptLoader::LoadSpankWeed(CStateManager& mgr, CInputStream& in, int propCount, const CEntityInfo& info)
|
||||
{
|
||||
if (!EnsurePropertyCount(propCount, 11, "SpankWeed"))
|
||||
return nullptr;
|
||||
SScaledActorHead aHead = LoadScaledActorHead(in, mgr);
|
||||
auto pair = CPatternedInfo::HasCorrectParameterCount(in);
|
||||
if (!pair.first)
|
||||
return nullptr;
|
||||
|
||||
CPatternedInfo pInfo(in, pair.second);
|
||||
CActorParameters actParms = LoadActorParameters(in);
|
||||
in.readBool();
|
||||
float f1 = in.readFloatBig();
|
||||
float f2 = in.readFloatBig();
|
||||
float f3 = in.readFloatBig();
|
||||
float f4 = in.readFloatBig();
|
||||
|
||||
const CAnimationParameters& animParms = pInfo.GetAnimationParameters();
|
||||
if (!animParms.GetACSFile().IsValid())
|
||||
return nullptr;
|
||||
|
||||
CModelData mData(CAnimRes(animParms.GetACSFile(), animParms.GetCharacter(), aHead.x40_scale,
|
||||
animParms.GetInitialAnimation(), true));
|
||||
return new MP1::CSpankWeed(mgr.AllocateUniqueId(), aHead.x0_name, info, aHead.x10_transform, std::move(mData),
|
||||
actParms, pInfo, f1, f2, f3, f4);
|
||||
}
|
||||
|
||||
CEntity* ScriptLoader::LoadParasite(CStateManager& mgr, CInputStream& in, int propCount, const CEntityInfo& info)
|
||||
|
|
|
@ -231,7 +231,7 @@ vertex VertToFrag vmain(constant VertData* va [[ buffer(1) ]],
|
|||
vtf.color = v.colorIn * particle.moduColor;
|
||||
vtf.uvFlake = v.uvsIn[vertId].xy;
|
||||
float4 pos = float4(v.posIn[vertId].xyz, 1.0);
|
||||
vtf.uvEnv = (envMtx * pos).xy;
|
||||
vtf.uvEnv = (particle.envMtx * pos).xy;
|
||||
vtf.mvPos = particle.mv * pos;
|
||||
vtf.position = particle.proj * vtf.mvPos;
|
||||
return vtf;
|
||||
|
@ -258,7 +258,7 @@ struct FogUniform
|
|||
float4 MainPostFunc(thread VertToFrag& vtf, constant FogUniform& fu, float4 colorIn)
|
||||
{
|
||||
float fogZ, temp;
|
||||
switch (lu.mode)
|
||||
switch (fu.mode)
|
||||
{
|
||||
case 2:
|
||||
fogZ = (-vtf.mvPos.z - fu.start) * fu.rangeScale;
|
||||
|
|
Loading…
Reference in New Issue