mirror of https://github.com/AxioDL/metaforce.git
Merge pull request #287 from AxioDL/elitepirate
Elite Pirate implementation
This commit is contained in:
commit
a4a7888338
|
@ -0,0 +1 @@
|
|||
Checks: '*,-misc-unused-parameters,-modernize-use-trailing-return-type,-readability-named-parameter,-readability-convert-member-functions-to-static,-readability-uppercase-literal-suffix,-readability-magic-numbers,-hicpp-uppercase-literal-suffix,-hicpp-signed-bitwise,-cppcoreguidelines-avoid-magic-numbers,-cppcoreguidelines-pro-type-static-cast-downcast,-cppcoreguidelines-pro-bounds-constant-array-index,-cppcoreguidelines-owning-memory,-cppcoreguidelines-pro-type-union-access,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-cppcoreguidelines-non-private-member-variables-in-classes,-fuchsia-*,-google-runtime-references'
|
|
@ -68,7 +68,7 @@ enum class EFallState { Invalid = -1, Zero, One , Two};
|
|||
|
||||
enum class EReactionType { Invalid = -1, Zero, One, Two, Three };
|
||||
|
||||
enum class EAdditiveReactionType { Invalid = -1, Electrocution, One, Two, IceBreakout };
|
||||
enum class EAdditiveReactionType { Invalid = -1, Electrocution, One, Two, IceBreakout, Four, Five, Six, Seven };
|
||||
|
||||
enum class EJumpType { Normal, One, Ambush };
|
||||
|
||||
|
@ -96,7 +96,7 @@ enum class ELoopState { Invalid = -1, Begin, Loop, End };
|
|||
|
||||
enum class ELoopAttackType { Invalid = -1 };
|
||||
|
||||
enum class EGenerateType { Invalid = -1, Zero, One, Two, Three, Four };
|
||||
enum class EGenerateType { Invalid = -1, Zero, One, Two, Three, Four, Five };
|
||||
|
||||
enum class ESlideType { Invalid = -1, Zero = 0 };
|
||||
|
||||
|
|
|
@ -0,0 +1,208 @@
|
|||
#include "Runtime/MP1/World/CBouncyGrenade.hpp"
|
||||
|
||||
#include "Runtime/CPlayerState.hpp"
|
||||
#include "Runtime/CSimplePool.hpp"
|
||||
#include "Runtime/CStateManager.hpp"
|
||||
#include "Runtime/GameGlobalObjects.hpp"
|
||||
#include "Runtime/Graphics/CBooRenderer.hpp"
|
||||
#include "Runtime/World/CPlayer.hpp"
|
||||
#include "Runtime/Collision/CCollisionActor.hpp"
|
||||
|
||||
namespace urde::MP1 {
|
||||
CBouncyGrenade::CBouncyGrenade(TUniqueId uid, std::string_view name, const CEntityInfo& info,
|
||||
const zeus::CTransform& xf, CModelData&& mData, const CActorParameters& actParams,
|
||||
TUniqueId parentId, const SBouncyGrenadeData& data, float velocity,
|
||||
float explodePlayerDistance)
|
||||
: CPhysicsActor(uid, true, name, info, xf, std::move(mData), {EMaterialTypes::Projectile, EMaterialTypes::Solid},
|
||||
mData.GetBounds(), SMoverData{data.GetUnkStruct().GetMass()}, actParams, 0.3f, 0.1f)
|
||||
, x258_data(data)
|
||||
, x294_numBounces(data.GetNumBounces())
|
||||
, x298_parentId(parentId)
|
||||
, x2a0_elementGen1(std::make_unique<CElementGen>(g_SimplePool->GetObj({'PART', data.GetElementGenId1()})))
|
||||
, x2a4_elementGen2(std::make_unique<CElementGen>(g_SimplePool->GetObj({'PART', data.GetElementGenId2()})))
|
||||
, x2a8_elementGen3(std::make_unique<CElementGen>(g_SimplePool->GetObj({'PART', data.GetElementGenId3()})))
|
||||
, x2ac_elementGen4(std::make_unique<CElementGen>(g_SimplePool->GetObj({'PART', data.GetElementGenId4()})))
|
||||
, x2b0_explodePlayerDistance(explodePlayerDistance)
|
||||
, x2b4_24_exploded(false)
|
||||
, x2b4_25_(false) {
|
||||
SetMomentumWR({0.f, 0.f, -GravityConstant() * GetMass()});
|
||||
SetVelocityWR(velocity * xf.frontVector());
|
||||
x2a0_elementGen1->SetParticleEmission(false);
|
||||
x2a4_elementGen2->SetParticleEmission(false);
|
||||
x2a8_elementGen3->SetParticleEmission(false);
|
||||
x2ac_elementGen4->SetParticleEmission(true);
|
||||
CMaterialFilter filter = GetMaterialFilter();
|
||||
filter.ExcludeList().Add(EMaterialTypes::Character);
|
||||
SetMaterialFilter(CMaterialFilter::MakeIncludeExclude(filter.IncludeList(), filter.ExcludeList()));
|
||||
}
|
||||
|
||||
void CBouncyGrenade::AddToRenderer(const zeus::CFrustum& frustum, const CStateManager& mgr) const {
|
||||
CActor::AddToRenderer(frustum, mgr);
|
||||
if (!x2b4_24_exploded) {
|
||||
g_Renderer->AddParticleGen(*x2ac_elementGen4);
|
||||
return;
|
||||
}
|
||||
const auto visor = mgr.GetPlayerState()->GetActiveVisor(mgr);
|
||||
if (visor == CPlayerState::EPlayerVisor::Combat || visor == CPlayerState::EPlayerVisor::Scan) {
|
||||
g_Renderer->AddParticleGen(*x2a0_elementGen1);
|
||||
} else if (visor == CPlayerState::EPlayerVisor::XRay || visor == CPlayerState::EPlayerVisor::Thermal) {
|
||||
g_Renderer->AddParticleGen(*x2a8_elementGen3);
|
||||
}
|
||||
}
|
||||
|
||||
void CBouncyGrenade::CollidedWith(TUniqueId id, const CCollisionInfoList& list, CStateManager& mgr) {
|
||||
constexpr auto matList = CMaterialList{
|
||||
EMaterialTypes::Solid,
|
||||
EMaterialTypes::Ceiling,
|
||||
EMaterialTypes::Floor,
|
||||
EMaterialTypes::Character,
|
||||
};
|
||||
|
||||
bool shouldExplode = false;
|
||||
if (x298_parentId != id) {
|
||||
const CEntity* const entity = mgr.GetObjectById(id);
|
||||
if (entity != nullptr) {
|
||||
if (TCastToConstPtr<CCollisionActor> actor = entity) {
|
||||
shouldExplode = actor->GetOwnerId() != x298_parentId;
|
||||
} else {
|
||||
shouldExplode = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (shouldExplode) {
|
||||
Explode(mgr, id);
|
||||
} else {
|
||||
for (const auto& info : list) {
|
||||
if (info.GetMaterialLeft().SharesMaterials(matList)) {
|
||||
if (x294_numBounces == 0) {
|
||||
Explode(mgr, kInvalidUniqueId);
|
||||
} else {
|
||||
const zeus::CVector3f* normal = &info.GetNormalLeft();
|
||||
if (GetVelocity().dot(info.GetNormalLeft()) > 0.f) {
|
||||
normal = &info.GetNormalRight();
|
||||
}
|
||||
const zeus::CVector3f impulse =
|
||||
(x258_data.GetUnkStruct().GetSpeed() * GetConstantForce().magnitude()) * *normal;
|
||||
const zeus::CVector3f angle = -x258_data.GetUnkStruct().GetSpeed() * GetAngularMomentum();
|
||||
ApplyImpulseWR(impulse, angle);
|
||||
CSfxManager::AddEmitter(x258_data.GetBounceSfx(), GetTranslation(), zeus::skUp, false, false, 0x7f,
|
||||
GetAreaIdAlways());
|
||||
--x294_numBounces;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
CPhysicsActor::CollidedWith(id, list, mgr);
|
||||
}
|
||||
|
||||
std::optional<zeus::CAABox> CBouncyGrenade::GetTouchBounds() const { return GetModelData()->GetBounds(GetTransform()); }
|
||||
|
||||
void CBouncyGrenade::Render(const CStateManager& mgr) const {
|
||||
if (!x2b4_24_exploded) {
|
||||
GetModelData()->Render(mgr, GetTransform(), nullptr, {0, 0, 3, zeus::skWhite});
|
||||
} else if (mgr.GetPlayerState()->GetActiveVisor(mgr) == CPlayerState::EPlayerVisor::XRay) {
|
||||
CGraphics::SetFog(ERglFogMode::PerspLin, 0.f, 75.f, zeus::skBlack);
|
||||
x2a4_elementGen2->Render();
|
||||
mgr.SetupFogForArea(GetAreaIdAlways());
|
||||
}
|
||||
}
|
||||
|
||||
void CBouncyGrenade::Think(float dt, CStateManager& mgr) {
|
||||
if (GetActive()) {
|
||||
const zeus::CTransform& orientation = GetTransform().getRotation();
|
||||
const zeus::CVector3f& translation = GetTranslation();
|
||||
const zeus::CVector3f& scale = GetModelData()->GetScale();
|
||||
auto UpdateElementGen = [ orientation, translation, scale, dt ](CElementGen & gen) constexpr {
|
||||
gen.SetOrientation(orientation);
|
||||
gen.SetGlobalTranslation(translation);
|
||||
gen.SetGlobalScale(scale);
|
||||
gen.Update(dt);
|
||||
};
|
||||
if (x2b4_24_exploded) {
|
||||
Stop();
|
||||
UpdateElementGen(*x2a0_elementGen1);
|
||||
UpdateElementGen(*x2a4_elementGen2);
|
||||
UpdateElementGen(*x2a8_elementGen3);
|
||||
} else {
|
||||
UpdateElementGen(*x2ac_elementGen4);
|
||||
}
|
||||
x29c_ += dt;
|
||||
if (x29c_ > 0.3f) {
|
||||
x2b4_25_ = true;
|
||||
}
|
||||
const zeus::CVector3f& playerDistance = mgr.GetPlayer().GetTranslation() +
|
||||
zeus::CVector3f{0.f, 0.f, 0.5f * mgr.GetPlayer().GetEyeHeight()} -
|
||||
translation;
|
||||
if (playerDistance.magSquared() < x2b0_explodePlayerDistance * x2b0_explodePlayerDistance) {
|
||||
Explode(mgr, kInvalidUniqueId);
|
||||
}
|
||||
}
|
||||
if (x2a0_elementGen1->IsSystemDeletable() && x2a4_elementGen2->IsSystemDeletable() &&
|
||||
x2a8_elementGen3->IsSystemDeletable()) {
|
||||
mgr.FreeScriptObject(GetUniqueId());
|
||||
}
|
||||
}
|
||||
|
||||
void CBouncyGrenade::Touch(CActor& act, CStateManager& mgr) { CActor::Touch(act, mgr); }
|
||||
|
||||
void CBouncyGrenade::Explode(CStateManager& mgr, TUniqueId uid) {
|
||||
if (x2b4_24_exploded) {
|
||||
return;
|
||||
}
|
||||
|
||||
x2b4_24_exploded = true;
|
||||
CSfxManager::AddEmitter(x258_data.GetExplodeSfx(), GetTranslation(), zeus::skUp, false, false, 0x7f,
|
||||
GetAreaIdAlways());
|
||||
x2a0_elementGen1->SetParticleEmission(true);
|
||||
x2a4_elementGen2->SetParticleEmission(true);
|
||||
x2a8_elementGen3->SetParticleEmission(true);
|
||||
x2ac_elementGen4->SetParticleEmission(false);
|
||||
|
||||
const CDamageInfo& dInfo = x258_data.GetDamageInfo();
|
||||
{
|
||||
bool isParent = x298_parentId == uid;
|
||||
if (TCastToConstPtr<CCollisionActor> actor = mgr.GetObjectById(uid)) {
|
||||
isParent = x298_parentId == actor->GetOwnerId();
|
||||
}
|
||||
if (uid != kInvalidUniqueId && !isParent) {
|
||||
mgr.ApplyDamage(GetUniqueId(), uid, GetUniqueId(), dInfo, CMaterialFilter::MakeInclude({EMaterialTypes::Solid}),
|
||||
zeus::skZero3f);
|
||||
}
|
||||
}
|
||||
|
||||
const float radius = dInfo.GetRadius();
|
||||
if (radius > 1.f) {
|
||||
const zeus::CVector3f& pos = GetTranslation();
|
||||
const CMaterialFilter filter = CMaterialFilter::MakeInclude({EMaterialTypes::Player, EMaterialTypes::Character});
|
||||
rstl::reserved_vector<TUniqueId, 1024> nearList;
|
||||
mgr.BuildNearList(nearList, {pos - radius, pos + radius}, filter, nullptr);
|
||||
|
||||
for (const auto& id : nearList) {
|
||||
bool isParent = x298_parentId == id;
|
||||
if (TCastToConstPtr<CCollisionActor> cActor = mgr.GetObjectById(id)) {
|
||||
isParent = x298_parentId == cActor->GetOwnerId();
|
||||
}
|
||||
if (isParent) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto* actor = static_cast<const CActor*>(mgr.GetObjectById(id));
|
||||
if (actor == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const float magnitude = (actor->GetTranslation() - GetTranslation()).magnitude();
|
||||
if (radius <= magnitude) {
|
||||
continue;
|
||||
}
|
||||
|
||||
float scale = (radius - magnitude) / radius;
|
||||
const CDamageInfo info{dInfo.GetWeaponMode(), scale * dInfo.GetDamage(), radius,
|
||||
scale * dInfo.GetKnockBackPower()};
|
||||
mgr.ApplyDamage(GetUniqueId(), id, GetUniqueId(), info, CMaterialFilter::MakeInclude({EMaterialTypes::Solid}),
|
||||
zeus::skZero3f);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace urde::MP1
|
|
@ -0,0 +1,90 @@
|
|||
#pragma once
|
||||
|
||||
#include "Runtime/World/CPhysicsActor.hpp"
|
||||
#include "Runtime/World/CDamageInfo.hpp"
|
||||
#include "Runtime/Particle/CElementGen.hpp"
|
||||
|
||||
#include "TCastTo.hpp" // Generated file, do not modify include path
|
||||
|
||||
#include <zeus/CTransform.hpp>
|
||||
|
||||
namespace urde::MP1 {
|
||||
struct SGrenadeUnknownStruct {
|
||||
private:
|
||||
float x0_mass;
|
||||
float x4_speed; // wrong name probably
|
||||
|
||||
public:
|
||||
explicit SGrenadeUnknownStruct(CInputStream& in) : x0_mass(in.readFloatBig()), x4_speed(in.readFloatBig()) {}
|
||||
|
||||
[[nodiscard]] float GetMass() const { return x0_mass; }
|
||||
[[nodiscard]] float GetSpeed() const { return x4_speed; }
|
||||
};
|
||||
|
||||
struct SBouncyGrenadeData {
|
||||
private:
|
||||
SGrenadeUnknownStruct x0_;
|
||||
CDamageInfo x8_damageInfo;
|
||||
CAssetId x24_elementGenId1;
|
||||
CAssetId x28_elementGenId2;
|
||||
CAssetId x2c_elementGenId3;
|
||||
CAssetId x30_elementGenId4;
|
||||
u32 x34_numBounces;
|
||||
u16 x38_bounceSfx;
|
||||
u16 x3a_explodeSfx;
|
||||
|
||||
public:
|
||||
SBouncyGrenadeData(const SGrenadeUnknownStruct& unkStruct, const CDamageInfo& damageInfo, CAssetId w1, CAssetId w2,
|
||||
CAssetId w3, CAssetId w4, u32 w5, u16 s1, u16 s2)
|
||||
: x0_(unkStruct)
|
||||
, x8_damageInfo(damageInfo)
|
||||
, x24_elementGenId1(w1)
|
||||
, x28_elementGenId2(w2)
|
||||
, x2c_elementGenId3(w3)
|
||||
, x30_elementGenId4(w4)
|
||||
, x34_numBounces(w5)
|
||||
, x38_bounceSfx(s1)
|
||||
, x3a_explodeSfx(s2){};
|
||||
|
||||
[[nodiscard]] const SGrenadeUnknownStruct& GetUnkStruct() const { return x0_; }
|
||||
[[nodiscard]] const CDamageInfo& GetDamageInfo() const { return x8_damageInfo; }
|
||||
[[nodiscard]] CAssetId GetElementGenId1() const { return x24_elementGenId1; }
|
||||
[[nodiscard]] CAssetId GetElementGenId2() const { return x28_elementGenId2; }
|
||||
[[nodiscard]] CAssetId GetElementGenId3() const { return x2c_elementGenId3; }
|
||||
[[nodiscard]] CAssetId GetElementGenId4() const { return x30_elementGenId4; }
|
||||
[[nodiscard]] u32 GetNumBounces() const { return x34_numBounces; }
|
||||
[[nodiscard]] u16 GetBounceSfx() const { return x38_bounceSfx; }
|
||||
[[nodiscard]] u16 GetExplodeSfx() const { return x3a_explodeSfx; }
|
||||
};
|
||||
|
||||
class CBouncyGrenade : public CPhysicsActor {
|
||||
private:
|
||||
SBouncyGrenadeData x258_data;
|
||||
u32 x294_numBounces;
|
||||
TUniqueId x298_parentId;
|
||||
float x29c_ = 0.f;
|
||||
std::unique_ptr<CElementGen> x2a0_elementGen1;
|
||||
std::unique_ptr<CElementGen> x2a4_elementGen2;
|
||||
std::unique_ptr<CElementGen> x2a8_elementGen3;
|
||||
std::unique_ptr<CElementGen> x2ac_elementGen4;
|
||||
float x2b0_explodePlayerDistance;
|
||||
bool x2b4_24_exploded : 1;
|
||||
bool x2b4_25_ : 1;
|
||||
|
||||
public:
|
||||
CBouncyGrenade(TUniqueId uid, std::string_view name, const CEntityInfo& info, const zeus::CTransform& xf,
|
||||
CModelData&& mData, const CActorParameters& actParams, TUniqueId parentId,
|
||||
const SBouncyGrenadeData& data, float velocity, float explodePlayerDistance);
|
||||
|
||||
void Accept(IVisitor& visitor) override { visitor.Visit(this); }
|
||||
void AddToRenderer(const zeus::CFrustum& frustum, const CStateManager& mgr) const override;
|
||||
void CollidedWith(TUniqueId id, const CCollisionInfoList& list, CStateManager& mgr) override;
|
||||
[[nodiscard]] std::optional<zeus::CAABox> GetTouchBounds() const override;
|
||||
void Render(const CStateManager& mgr) const override;
|
||||
void Think(float dt, CStateManager& mgr) override;
|
||||
void Touch(CActor& act, CStateManager& mgr) override;
|
||||
|
||||
private:
|
||||
void Explode(CStateManager& mgr, TUniqueId uid);
|
||||
};
|
||||
} // namespace urde::MP1
|
File diff suppressed because it is too large
Load Diff
|
@ -1,59 +1,229 @@
|
|||
#pragma once
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include "Runtime/RetroTypes.hpp"
|
||||
#include "Runtime/Character/CBoneTracking.hpp"
|
||||
#include "Runtime/Collision/CCollisionActorManager.hpp"
|
||||
#include "Runtime/Collision/CJointCollisionDescription.hpp"
|
||||
#include "Runtime/MP1/World/CGrenadeLauncher.hpp"
|
||||
#include "Runtime/MP1/World/CShockWave.hpp"
|
||||
#include "Runtime/World/CActorParameters.hpp"
|
||||
#include "Runtime/World/CAnimationParameters.hpp"
|
||||
#include "Runtime/World/CPathFindSearch.hpp"
|
||||
#include "Runtime/World/CPatterned.hpp"
|
||||
|
||||
namespace urde::MP1 {
|
||||
class CElitePirateData {
|
||||
float x0_;
|
||||
float x4_;
|
||||
private:
|
||||
float x0_tauntInterval;
|
||||
float x4_tauntVariance;
|
||||
float x8_;
|
||||
float xc_;
|
||||
float x10_;
|
||||
float x14_;
|
||||
float x18_;
|
||||
float x10_attackChance;
|
||||
float x14_shotAtTime;
|
||||
float x18_shotAtTimeVariance;
|
||||
float x1c_;
|
||||
CAssetId x20_;
|
||||
s16 x24_;
|
||||
CActorParameters x28_;
|
||||
CAnimationParameters x90_;
|
||||
u16 x24_sfxAbsorb;
|
||||
CActorParameters x28_launcherActParams;
|
||||
CAnimationParameters x90_launcherAnimParams;
|
||||
CAssetId x9c_;
|
||||
s16 xa0_;
|
||||
u16 xa0_;
|
||||
CAssetId xa4_;
|
||||
CDamageInfo xa8_;
|
||||
float xc4_;
|
||||
float xc4_launcherHp;
|
||||
CAssetId xc8_;
|
||||
CAssetId xcc_;
|
||||
CAssetId xd0_;
|
||||
CAssetId xd4_;
|
||||
float xd8_;
|
||||
float xdc_;
|
||||
float xe0_;
|
||||
float xe4_;
|
||||
float xe8_;
|
||||
float xec_;
|
||||
u32 xf0_;
|
||||
u32 xf4_;
|
||||
SGrenadeUnknownStruct xd8_;
|
||||
SGrenadeTrajectoryInfo xe0_trajectoryInfo;
|
||||
u32 xf0_grenadeNumBounces;
|
||||
u16 xf4_;
|
||||
u16 xf6_;
|
||||
CAssetId xf8_;
|
||||
CDamageInfo xfc_;
|
||||
CAssetId x118_;
|
||||
s16 x11c_;
|
||||
u16 x11c_;
|
||||
bool x11e_;
|
||||
bool x11f_;
|
||||
|
||||
public:
|
||||
CElitePirateData(CInputStream&, u32 propCount);
|
||||
|
||||
[[nodiscard]] float GetTauntInterval() const { return x0_tauntInterval; }
|
||||
[[nodiscard]] float GetTauntVariance() const { return x4_tauntVariance; }
|
||||
[[nodiscard]] float GetAttackChance() const { return x10_attackChance; }
|
||||
[[nodiscard]] float GetShotAtTime() const { return x14_shotAtTime; }
|
||||
[[nodiscard]] float GetShotAtTimeVariance() const { return x18_shotAtTimeVariance; }
|
||||
[[nodiscard]] float GetX1C() const { return x1c_; }
|
||||
[[nodiscard]] CAssetId GetX20() const { return x20_; }
|
||||
[[nodiscard]] u16 GetSFXAbsorb() const { return x24_sfxAbsorb; }
|
||||
[[nodiscard]] const CActorParameters& GetLauncherActParams() const { return x28_launcherActParams; }
|
||||
[[nodiscard]] const CAnimationParameters& GetLauncherAnimParams() const { return x90_launcherAnimParams; }
|
||||
[[nodiscard]] float GetLauncherHP() const { return xc4_launcherHp; }
|
||||
[[nodiscard]] const SGrenadeTrajectoryInfo& GetGrenadeTrajectoryInfo() const { return xe0_trajectoryInfo; }
|
||||
[[nodiscard]] CAssetId GetXF8() const { return xf8_; }
|
||||
[[nodiscard]] const CDamageInfo& GetXFC() const { return xfc_; }
|
||||
[[nodiscard]] CAssetId GetX118() const { return x118_; }
|
||||
[[nodiscard]] u16 GetX11C() const { return x11c_; }
|
||||
[[nodiscard]] bool GetX11E() const { return x11e_; }
|
||||
[[nodiscard]] bool GetX11F() const { return x11f_; }
|
||||
|
||||
[[nodiscard]] SBouncyGrenadeData GetBouncyGrenadeData() const {
|
||||
return {xd8_, xa8_, xc8_, xcc_, xd0_, xd4_, xf0_grenadeNumBounces, xf4_, xf6_};
|
||||
}
|
||||
[[nodiscard]] SGrenadeLauncherData GetGrenadeLauncherData() const {
|
||||
return {GetBouncyGrenadeData(), xa4_, x9c_, xa0_, xe0_trajectoryInfo};
|
||||
}
|
||||
};
|
||||
|
||||
class CElitePirate : public CPatterned {
|
||||
private:
|
||||
struct SUnknownStruct {
|
||||
private:
|
||||
float x0_;
|
||||
rstl::reserved_vector<zeus::CVector3f, 16> x4_;
|
||||
|
||||
public:
|
||||
explicit SUnknownStruct(float f) : x0_(f * f) {}
|
||||
zeus::CVector3f GetValue(const zeus::CVector3f& v1, const zeus::CVector3f& v2);
|
||||
void AddValue(const zeus::CVector3f& vec);
|
||||
void Clear() { x4_.clear(); }
|
||||
};
|
||||
|
||||
enum class EState {
|
||||
Invalid = -1,
|
||||
Zero = 0,
|
||||
One = 1,
|
||||
Two = 2,
|
||||
Over = 3,
|
||||
};
|
||||
|
||||
EState x568_state = EState::Invalid;
|
||||
CDamageVulnerability x56c_vulnerability;
|
||||
std::unique_ptr<CCollisionActorManager> x5d4_collisionActorMgr;
|
||||
CElitePirateData x5d8_data;
|
||||
CBoneTracking x6f8_boneTracking;
|
||||
std::unique_ptr<CCollisionActorManager> x730_collisionActorMgrHead;
|
||||
// s32 x734_;
|
||||
CCollidableAABox x738_collisionAabb;
|
||||
std::optional<TLockedToken<CGenDescription>> x760_energyAbsorbDesc;
|
||||
TUniqueId x770_collisionHeadId = kInvalidUniqueId;
|
||||
TUniqueId x772_launcherId = kInvalidUniqueId;
|
||||
rstl::reserved_vector<TUniqueId, 7> x774_collisionRJointIds;
|
||||
rstl::reserved_vector<TUniqueId, 7> x788_collisionLJointIds;
|
||||
TUniqueId x79c_ = kInvalidUniqueId;
|
||||
float x7a0_initialSpeed;
|
||||
float x7a4_steeringSpeed = 1.f;
|
||||
float x7a8_pathShaggedTime = 0.f;
|
||||
float x7ac_energyAbsorbCooldown = 0.f;
|
||||
float x7b0_ = 1.f;
|
||||
float x7b4_hp = 0.f;
|
||||
float x7b8_attackTimer = 0.f;
|
||||
float x7bc_tauntTimer = 0.f;
|
||||
float x7c0_shotAtTimer = 0.f;
|
||||
float x7c4_absorbUpdateTimer = 0.f;
|
||||
s32 x7c8_currAnimId = -1;
|
||||
u32 x7cc_activeMaterialSet = 0;
|
||||
CPathFindSearch x7d0_pathFindSearch;
|
||||
zeus::CVector3f x8b4_targetDestPos;
|
||||
SUnknownStruct x8c0_;
|
||||
bool x988_24_damageOn : 1;
|
||||
bool x988_25_attackingRightClaw : 1;
|
||||
bool x988_26_attackingLeftClaw : 1;
|
||||
bool x988_27_shotAt : 1;
|
||||
bool x988_28_alert : 1;
|
||||
bool x988_29_shockWaveAnim : 1;
|
||||
bool x988_30_calledForBackup : 1;
|
||||
bool x988_31_running : 1;
|
||||
bool x989_24_onPath : 1;
|
||||
|
||||
public:
|
||||
DEFINE_PATTERNED(ElitePirate)
|
||||
|
||||
CElitePirate(TUniqueId, std::string_view, const CEntityInfo&, const zeus::CTransform&, CModelData&&,
|
||||
const CPatternedInfo&, const CActorParameters&, const CElitePirateData&);
|
||||
CElitePirate(TUniqueId uid, std::string_view name, const CEntityInfo& info, const zeus::CTransform& xf,
|
||||
CModelData&& mData, const CPatternedInfo& pInfo, const CActorParameters& actParms,
|
||||
CElitePirateData data);
|
||||
|
||||
void Accept(IVisitor& visitor) override;
|
||||
void Think(float dt, CStateManager& mgr) override;
|
||||
void AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) override;
|
||||
void PreRender(CStateManager& mgr, const zeus::CFrustum& frustum) override;
|
||||
const CDamageVulnerability* GetDamageVulnerability() const override;
|
||||
const CDamageVulnerability* GetDamageVulnerability(const zeus::CVector3f& pos, const zeus::CVector3f& dir,
|
||||
const CDamageInfo& dInfo) const override;
|
||||
zeus::CVector3f GetOrbitPosition(const CStateManager& mgr) const override;
|
||||
zeus::CVector3f GetAimPosition(const CStateManager& mgr, float) const override;
|
||||
void DoUserAnimEvent(CStateManager& mgr, const CInt32POINode& node, EUserEventType type, float dt) override;
|
||||
const CCollisionPrimitive* GetCollisionPrimitive() const override;
|
||||
void KnockBack(const zeus::CVector3f&, CStateManager& mgr, const CDamageInfo& info, EKnockBackType type,
|
||||
bool inDeferred, float magnitude) override;
|
||||
void TakeDamage(const zeus::CVector3f&, float arg) override;
|
||||
void Patrol(CStateManager& mgr, EStateMsg msg, float dt) override;
|
||||
void PathFind(CStateManager& mgr, EStateMsg msg, float dt) override;
|
||||
void TargetPatrol(CStateManager& mgr, EStateMsg msg, float dt) override;
|
||||
void Halt(CStateManager& mgr, EStateMsg msg, float dt) override;
|
||||
void Run(CStateManager& mgr, EStateMsg msg, float dt) override;
|
||||
void Generate(CStateManager& mgr, EStateMsg msg, float dt) override;
|
||||
void Attack(CStateManager& mgr, EStateMsg msg, float dt) override;
|
||||
void Taunt(CStateManager& mgr, EStateMsg msg, float dt) override;
|
||||
void ProjectileAttack(CStateManager& mgr, EStateMsg msg, float dt) override;
|
||||
void Cover(CStateManager& mgr, EStateMsg msg, float dt) override;
|
||||
void SpecialAttack(CStateManager& mgr, EStateMsg msg, float dt) override;
|
||||
void CallForBackup(CStateManager& mgr, EStateMsg msg, float dt) override;
|
||||
bool TooClose(CStateManager& mgr, float arg) override;
|
||||
bool InDetectionRange(CStateManager& mgr, float arg) override;
|
||||
bool SpotPlayer(CStateManager& mgr, float arg) override;
|
||||
bool AnimOver(CStateManager& mgr, float arg) override;
|
||||
bool ShouldAttack(CStateManager& mgr, float arg) override;
|
||||
bool InPosition(CStateManager& mgr, float arg) override;
|
||||
bool ShouldTurn(CStateManager& mgr, float arg) override;
|
||||
bool AggressionCheck(CStateManager& mgr, float arg) override;
|
||||
bool ShouldTaunt(CStateManager& mgr, float arg) override;
|
||||
bool ShouldFire(CStateManager& mgr, float arg) override;
|
||||
bool ShotAt(CStateManager& mgr, float arg) override;
|
||||
bool ShouldSpecialAttack(CStateManager& mgr, float arg) override;
|
||||
bool ShouldCallForBackup(CStateManager& mgr, float arg) override;
|
||||
CPathFindSearch* GetSearchPath() override;
|
||||
virtual bool HasWeakPointHead() const { return true; }
|
||||
virtual bool IsElitePirate() const { return true; }
|
||||
virtual void SetupHealthInfo(CStateManager& mgr);
|
||||
virtual void SetLaunchersActive(CStateManager& mgr, bool val);
|
||||
virtual SShockWaveData GetShockWaveData() const {
|
||||
return {x5d8_data.GetXF8(), x5d8_data.GetXFC(), x5d8_data.GetX118(), x5d8_data.GetX11C()};
|
||||
}
|
||||
|
||||
private:
|
||||
void SetupPathFindSearch();
|
||||
void SetShotAt(bool val, CStateManager& mgr);
|
||||
bool IsArmClawCollider(TUniqueId uid, const rstl::reserved_vector<TUniqueId, 7>& vec) const;
|
||||
void AddSphereCollisionList(const SSphereJointInfo* joints, size_t count,
|
||||
std::vector<CJointCollisionDescription>& outJoints) const;
|
||||
void AddCollisionList(const SJointInfo* joints, size_t count,
|
||||
std::vector<CJointCollisionDescription>& outJoints) const;
|
||||
void SetupCollisionManager(CStateManager& mgr);
|
||||
void SetupCollisionActorInfo(CStateManager& mgr);
|
||||
bool IsArmClawCollider(std::string_view name, std::string_view locator, const SJointInfo* info, size_t infoCount);
|
||||
void CreateGrenadeLauncher(CStateManager& mgr, TUniqueId uid);
|
||||
void ApplyDamageToHead(CStateManager& mgr, TUniqueId uid);
|
||||
void CreateEnergyAbsorb(CStateManager& mgr, const zeus::CTransform& xf);
|
||||
void SetupLauncherHealthInfo(CStateManager& mgr, TUniqueId uid);
|
||||
void SetLauncherActive(CStateManager& mgr, bool val, TUniqueId uid);
|
||||
zeus::CVector3f GetLockOnPosition(const CActor* actor) const;
|
||||
bool CanKnockBack(const CDamageInfo& info) const;
|
||||
void UpdateDestPos(CStateManager& mgr);
|
||||
void CheckAttackChance(CStateManager& mgr);
|
||||
void AttractProjectiles(CStateManager& mgr);
|
||||
void UpdateAbsorbBodyState(CStateManager& mgr, float dt);
|
||||
bool IsAttractingEnergy();
|
||||
void UpdateTimers(float dt);
|
||||
void UpdatePositionHistory();
|
||||
void UpdateActorTransform(CStateManager& mgr, TUniqueId& uid, std::string_view name);
|
||||
void UpdateHealthInfo(CStateManager& mgr);
|
||||
void ExtendTouchBounds(const CStateManager& mgr, const rstl::reserved_vector<TUniqueId, 7>& uids,
|
||||
const zeus::CVector3f& vec) const;
|
||||
bool ShouldFireFromLauncher(CStateManager& mgr, TUniqueId launcherId);
|
||||
bool ShouldCallForBackupFromLauncher(const CStateManager& mgr, TUniqueId uid) const;
|
||||
bool IsClosestEnergyAttractor(const CStateManager& mgr, const rstl::reserved_vector<TUniqueId, 1024>& charNearList,
|
||||
const zeus::CVector3f& projectilePos) const;
|
||||
};
|
||||
} // namespace urde::MP1
|
||||
} // namespace urde
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
namespace urde::MP1 {
|
||||
namespace {
|
||||
constexpr std::array<SBurst, 6> skBurst1{{
|
||||
constexpr std::array<SBurst, 6> skBurstsFlying{{
|
||||
{4, {3, 4, 11, 12, -1, 0, 0, 0}, 0.1f, 0.05f},
|
||||
{20, {2, 3, 4, 5, -1, 0, 0, 0}, 0.1f, 0.05f},
|
||||
{20, {10, 11, 12, 13, -1, 0, 0, 0}, 0.1f, 0.05f},
|
||||
|
@ -30,7 +30,7 @@ constexpr std::array<SBurst, 6> skBurst1{{
|
|||
{0, {0, 0, 0, 0, 0, 0, 0, 0}, 0.000000, 0.000000},
|
||||
}};
|
||||
|
||||
constexpr std::array<SBurst, 6> skBurst2{{
|
||||
constexpr std::array<SBurst, 6> skBurstsFlyingOutOfView{{
|
||||
{5, {3, 4, 8, 12, -1, 0, 0, 0}, 0.1f, 0.05f},
|
||||
{10, {2, 3, 4, 5, -1, 0, 0, 0}, 0.1f, 0.05f},
|
||||
{10, {10, 11, 12, 13, -1, 0, 0, 0}, 0.1f, 0.05f},
|
||||
|
@ -39,7 +39,7 @@ constexpr std::array<SBurst, 6> skBurst2{{
|
|||
{0, {0, 0, 0, 0, 0, 0, 0, 0}, 0.000000, 0.000000},
|
||||
}};
|
||||
|
||||
constexpr std::array<SBurst, 5> skBurst3{{
|
||||
constexpr std::array<SBurst, 5> skBurstsLanded{{
|
||||
{30, {3, 4, 5, 11, 12, 4, -1, 0}, 0.1f, 0.05f},
|
||||
{20, {2, 3, 4, 5, 4, 3, -1, 0}, 0.1f, 0.05f},
|
||||
{20, {5, 4, 3, 13, 12, 11, -1, 0}, 0.1f, 0.05f},
|
||||
|
@ -47,7 +47,7 @@ constexpr std::array<SBurst, 5> skBurst3{{
|
|||
{0, {0, 0, 0, 0, 0, 0, 0, 0}, 0.000000, 0.000000},
|
||||
}};
|
||||
|
||||
constexpr std::array<SBurst, 5> skBurst4{{
|
||||
constexpr std::array<SBurst, 5> skBurstsLandedOutOfView{{
|
||||
{10, {6, 5, 4, 14, 13, 12, -1, 0}, 0.1f, 0.05f},
|
||||
{20, {14, 13, 12, 11, 10, 9, -1, 0}, 0.1f, 0.05f},
|
||||
{20, {14, 15, 16, 11, 10, 9, -1, 0}, 0.1f, 0.05f},
|
||||
|
@ -56,7 +56,11 @@ constexpr std::array<SBurst, 5> skBurst4{{
|
|||
}};
|
||||
|
||||
constexpr std::array<const SBurst*, 5> skBursts{
|
||||
skBurst1.data(), skBurst2.data(), skBurst3.data(), skBurst4.data(), nullptr,
|
||||
skBurstsFlying.data(),
|
||||
skBurstsFlyingOutOfView.data(),
|
||||
skBurstsLanded.data(),
|
||||
skBurstsLandedOutOfView.data(),
|
||||
nullptr,
|
||||
};
|
||||
|
||||
constexpr std::array<std::string_view, 15> skParts{
|
||||
|
|
|
@ -0,0 +1,335 @@
|
|||
#include "Runtime/MP1/World/CGrenadeLauncher.hpp"
|
||||
|
||||
#include "Runtime/Character/CPASAnimParm.hpp"
|
||||
#include "Runtime/Character/CPASAnimParmData.hpp"
|
||||
#include "Runtime/CSimplePool.hpp"
|
||||
#include "Runtime/CStateManager.hpp"
|
||||
#include "Runtime/GameGlobalObjects.hpp"
|
||||
#include "Runtime/Weapon/CGameProjectile.hpp"
|
||||
#include "Runtime/World/CExplosion.hpp"
|
||||
#include "Runtime/World/CPatterned.hpp"
|
||||
#include "Runtime/World/CPlayer.hpp"
|
||||
|
||||
namespace urde::MP1 {
|
||||
CGrenadeLauncher::CGrenadeLauncher(TUniqueId uid, std::string_view name, const CEntityInfo& info,
|
||||
const zeus::CTransform& xf, CModelData&& mData, const zeus::CAABox& bounds,
|
||||
const CHealthInfo& healthInfo, const CDamageVulnerability& vulnerability,
|
||||
const CActorParameters& actParams, TUniqueId parentId,
|
||||
const SGrenadeLauncherData& data, float f1)
|
||||
: CPhysicsActor(uid, true, name, info, xf, std::move(mData), {EMaterialTypes::Character, EMaterialTypes::Solid}, bounds,
|
||||
SMoverData{1000.f}, actParams, 0.3f, 0.1f)
|
||||
, x25c_healthInfo(healthInfo)
|
||||
, x264_vulnerability(vulnerability)
|
||||
, x2cc_parentId(parentId)
|
||||
, x2d0_data(data)
|
||||
, x328_cSphere({{}, mData.GetScale().z()}, {EMaterialTypes::Character, EMaterialTypes::Solid})
|
||||
, x350_grenadeActorParams(actParams)
|
||||
, x3e8_thermalMag(actParams.GetThermalMag())
|
||||
, x3f8_explodePlayerDistance(f1) {
|
||||
if (data.GetExplosionGenDescId().IsValid()) {
|
||||
x3b8_particleGenDesc = g_SimplePool->GetObj({SBIG('PART'), data.GetExplosionGenDescId()});
|
||||
}
|
||||
GetModelData()->EnableLooping(true);
|
||||
const CPASDatabase& pasDatabase = GetModelData()->GetAnimationData()->GetCharacterInfo().GetPASDatabase();
|
||||
for (int i = 0; i < x3c8_animIds.size(); ++i) {
|
||||
const auto result = pasDatabase.FindBestAnimation(CPASAnimParmData{22, CPASAnimParm::FromEnum(i)}, -1);
|
||||
x3c8_animIds[i] = result.second;
|
||||
}
|
||||
}
|
||||
|
||||
zeus::CVector3f CGrenadeLauncher::GrenadeTarget(const CStateManager& mgr) {
|
||||
const zeus::CVector3f& aim = mgr.GetPlayer().GetAimPosition(mgr, 1.f);
|
||||
if (mgr.GetPlayer().GetMorphballTransitionState() == CPlayer::EPlayerMorphBallState::Unmorphed) {
|
||||
return aim - zeus::CVector3f{0.f, 0.f, 0.5f * mgr.GetPlayer().GetEyeHeight()};
|
||||
}
|
||||
return aim;
|
||||
}
|
||||
|
||||
void CGrenadeLauncher::CalculateGrenadeTrajectory(const zeus::CVector3f& target, const zeus::CVector3f& origin,
|
||||
const SGrenadeTrajectoryInfo& info, float& angleOut,
|
||||
float& velocityOut) {
|
||||
float angle = info.GetAngleMin();
|
||||
float velocity = info.GetVelocityMin();
|
||||
float delta = std::max(0.01f, 0.1f * (info.GetAngleMax() - info.GetAngleMin()));
|
||||
zeus::CVector3f dist = target - origin;
|
||||
float distXYMag = dist.toVec2f().magnitude();
|
||||
float velocityMinSq = info.GetVelocityMin() * info.GetVelocityMin();
|
||||
float velocityMaxSq = info.GetVelocityMax() * info.GetVelocityMax();
|
||||
float gravAdj = distXYMag * ((0.5f * CPhysicsActor::GravityConstant()) * distXYMag);
|
||||
float currAngle = info.GetAngleMin();
|
||||
float leastResult = FLT_MAX;
|
||||
while (info.GetAngleMax() >= currAngle) {
|
||||
float cos = std::cos(currAngle);
|
||||
float sin = std::sin(currAngle);
|
||||
float result = (distXYMag * (cos * sin) - (dist.z() * (cos * cos)));
|
||||
if (result > FLT_EPSILON) {
|
||||
float div = gravAdj / result;
|
||||
if (velocityMinSq <= result && result <= velocityMaxSq) {
|
||||
angle = currAngle;
|
||||
velocity = std::sqrt(div);
|
||||
break;
|
||||
}
|
||||
if (result <= velocityMaxSq) {
|
||||
result = velocityMinSq - result;
|
||||
} else {
|
||||
result = result - velocityMaxSq;
|
||||
}
|
||||
if (result < leastResult) {
|
||||
angle = currAngle;
|
||||
velocity = std::sqrt(div);
|
||||
leastResult = result;
|
||||
}
|
||||
}
|
||||
currAngle += delta;
|
||||
}
|
||||
angleOut = angle;
|
||||
velocityOut = velocity;
|
||||
}
|
||||
|
||||
void CGrenadeLauncher::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) {
|
||||
CActor::AcceptScriptMsg(msg, uid, mgr);
|
||||
switch (msg) {
|
||||
case EScriptObjectMessage::Start:
|
||||
if (x2cc_parentId == uid && x258_started != 1) {
|
||||
x258_started = 1;
|
||||
sub_80230438();
|
||||
}
|
||||
break;
|
||||
case EScriptObjectMessage::Stop:
|
||||
if (x2cc_parentId == uid && x258_started != 0) {
|
||||
x258_started = 0;
|
||||
sub_80230438();
|
||||
}
|
||||
break;
|
||||
case EScriptObjectMessage::Action:
|
||||
if (x2cc_parentId == uid && x258_started == 1) {
|
||||
x3fc_launchGrenade = true;
|
||||
}
|
||||
break;
|
||||
case EScriptObjectMessage::Registered:
|
||||
sub_80230438();
|
||||
break;
|
||||
case EScriptObjectMessage::Damage:
|
||||
x3ec_damageTimer = 0.33f;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CGrenadeLauncher::AddToRenderer(const zeus::CFrustum& frustum, const CStateManager& mgr) const {
|
||||
CActor::AddToRenderer(frustum, mgr);
|
||||
}
|
||||
|
||||
std::optional<zeus::CAABox> CGrenadeLauncher::GetTouchBounds() const {
|
||||
return x328_cSphere.CalculateAABox(GetTransform());
|
||||
}
|
||||
|
||||
void CGrenadeLauncher::PreRender(CStateManager& mgr, const zeus::CFrustum& frustum) {
|
||||
if (x3f4_color3.a() == 1.f) {
|
||||
xb4_drawFlags = CModelFlags{2, 0, 3, zeus::skWhite};
|
||||
// Original code redundantly sets a() = 1.f
|
||||
xb4_drawFlags.addColor = x3f4_color3;
|
||||
} else {
|
||||
xb4_drawFlags = CModelFlags{5, 0, 3, zeus::skWhite};
|
||||
xb4_drawFlags.addColor = x3f4_color3;
|
||||
}
|
||||
CActor::PreRender(mgr, frustum);
|
||||
}
|
||||
|
||||
void CGrenadeLauncher::Render(const CStateManager& mgr) const {
|
||||
if (x3fd_visible) {
|
||||
CPhysicsActor::Render(mgr);
|
||||
}
|
||||
}
|
||||
|
||||
void CGrenadeLauncher::Think(float dt, CStateManager& mgr) {
|
||||
if (GetActive()) {
|
||||
if (x3fc_launchGrenade) {
|
||||
LaunchGrenade(mgr);
|
||||
x3fc_launchGrenade = false;
|
||||
}
|
||||
|
||||
UpdateCollision();
|
||||
UpdateColor(dt);
|
||||
sub_8022f9e0(mgr, dt);
|
||||
UpdateDamageTime(dt);
|
||||
|
||||
const SAdvancementDeltas& deltas = CActor::UpdateAnimation(dt, mgr, true);
|
||||
MoveToOR(deltas.x0_posDelta, dt);
|
||||
RotateToOR(deltas.xc_rotDelta, dt);
|
||||
|
||||
TCastToPtr<CPatterned> parent = mgr.ObjectById(x2cc_parentId);
|
||||
if (parent == nullptr || !parent->IsAlive() || parent->HealthInfo(mgr)->GetHP() <= 0.f) {
|
||||
mgr.SendScriptMsg(parent, GetUniqueId(), EScriptObjectMessage::Damage);
|
||||
CreateExplosion(mgr);
|
||||
mgr.FreeScriptObject(GetUniqueId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CGrenadeLauncher::Touch(CActor& act, CStateManager& mgr) {
|
||||
if (TCastToPtr<CGameProjectile> projectile = act) {
|
||||
if (projectile->GetOwnerId() == mgr.GetPlayer().GetUniqueId() &&
|
||||
GetDamageVulnerability()->WeaponHurts(CWeaponMode{projectile->GetType()}, false)) {
|
||||
x348_shotTimer = 0.5f;
|
||||
CEntity* parent = mgr.ObjectById(x2cc_parentId);
|
||||
if (parent != nullptr) {
|
||||
mgr.SendScriptMsg(parent, GetUniqueId(), EScriptObjectMessage::Touched);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CGrenadeLauncher::UpdateCollision() {
|
||||
x328_cSphere.SetSphereCenter(GetLocatorTransform("lockon_target_LCTR"sv).origin);
|
||||
}
|
||||
|
||||
void CGrenadeLauncher::UpdateColor(float arg) {
|
||||
if (x348_shotTimer > 0.f) {
|
||||
x348_shotTimer = std::max(0.f, x348_shotTimer - arg);
|
||||
x34c_color1 = zeus::CColor::lerp(zeus::skWhite, zeus::skRed, x348_shotTimer);
|
||||
}
|
||||
}
|
||||
|
||||
void CGrenadeLauncher::UpdateDamageTime(float arg) {
|
||||
if (x3ec_damageTimer <= 0.f) {
|
||||
xd0_damageMag = x3e8_thermalMag;
|
||||
} else {
|
||||
x3ec_damageTimer = std::max(0.f, x3ec_damageTimer - arg);
|
||||
x3f4_color3 = zeus::CColor::lerp(zeus::skBlack, x3f0_color2, std::clamp(x3ec_damageTimer / 0.33f, 0.f, 1.f));
|
||||
xd0_damageMag = 5.f * x3ec_damageTimer + x3e8_thermalMag;
|
||||
}
|
||||
}
|
||||
|
||||
void CGrenadeLauncher::CreateExplosion(CStateManager& mgr) {
|
||||
if (!x3b8_particleGenDesc) {
|
||||
return;
|
||||
}
|
||||
mgr.AddObject(new CExplosion(*x3b8_particleGenDesc, mgr.AllocateUniqueId(), true,
|
||||
{GetAreaIdAlways(), CEntity::NullConnectionList}, "Grenade Launcher Explode Fx"sv,
|
||||
GetTransform(), 0, GetModelData()->GetScale(), zeus::skWhite));
|
||||
CSfxManager::SfxStart(x2d0_data.GetExplosionSfx(), 1.f, 1.f, false, 0x7f, false, kInvalidAreaId);
|
||||
}
|
||||
|
||||
void CGrenadeLauncher::sub_8022f9e0(CStateManager& mgr, float dt) {
|
||||
CModelData* modelData = GetModelData();
|
||||
CAnimData* animData = nullptr;
|
||||
|
||||
if (modelData != nullptr && (animData = modelData->GetAnimationData()) != nullptr && x258_started == 1 && x3fe_) {
|
||||
const zeus::CVector3f& target = mgr.GetPlayer().GetAimPosition(mgr, 0.f) - GetTranslation();
|
||||
const zeus::CVector3f& rot = GetTransform().rotate({target.x(), target.y(), 0.f}); // TODO double check
|
||||
|
||||
if (rot.canBeNormalized()) {
|
||||
constexpr float p36d = zeus::degToRad(36.476f);
|
||||
constexpr float n45d = zeus::degToRad(-45.f);
|
||||
constexpr float p45d = zeus::degToRad(45.f);
|
||||
|
||||
float l84 = p36d * std::clamp(std::atan2(rot.x(), rot.y()), n45d, p45d);
|
||||
float l88 = std::clamp((0.25f * (l84 - x3d8_)) / dt, -3.f, 3.f);
|
||||
float l8c = std::clamp((l88 - x3dc_) / dt, -10.f, 10.f);
|
||||
x3dc_ += dt * l8c;
|
||||
|
||||
float l90 = p36d * std::clamp(std::atan2(rot.z(), rot.toVec2f().magnitude()), n45d, p45d);
|
||||
l88 = std::clamp((0.25f * (l90 - x3e0_)) / dt, -3.f, 3.f);
|
||||
l8c = std::clamp((l88 - x3e4_) / dt, -10.f, 10.f);
|
||||
x3e4_ += dt * l8c;
|
||||
|
||||
float dVar7 = std::clamp(dt * x3dc_ + x3d8_, -0.5f, 0.5f);
|
||||
float dVar8 = std::clamp(dt * x3e4_ + x3e0_, -0.5f, 0.5f);
|
||||
|
||||
if (dVar7 != x3d8_) {
|
||||
if (std::abs(x3d8_) > 0.f && x3d8_ * dVar7 <= 0.f) {
|
||||
animData->DelAdditiveAnimation(x3c8_animIds[x3d8_ >= 0.f ? 1 : 0]);
|
||||
}
|
||||
float weight = std::abs(dVar7);
|
||||
if (weight > 0.f) {
|
||||
animData->AddAdditiveAnimation(x3c8_animIds[dVar7 >= 0.f ? 1 : 0], weight, false, false);
|
||||
}
|
||||
}
|
||||
if (dVar8 != x3e0_) {
|
||||
if (std::abs(x3e0_) > 0.f && x3e0_ * dVar8 <= 0.f) {
|
||||
animData->DelAdditiveAnimation(x3c8_animIds[x3e0_ <= 0.f ? 3 : 2]);
|
||||
}
|
||||
float weight = std::abs(dVar8);
|
||||
if (weight > 0.f) {
|
||||
animData->AddAdditiveAnimation(x3c8_animIds[dVar8 <= 0.f ? 3 : 2], weight, false, false);
|
||||
}
|
||||
}
|
||||
x3d8_ = dVar7;
|
||||
x3e0_ = dVar8;
|
||||
}
|
||||
} else {
|
||||
if (x3d8_ != 0.f) {
|
||||
if (animData != nullptr) { // Original code does not check
|
||||
animData->DelAdditiveAnimation(x3c8_animIds[x3d8_ >= 0.f ? 1 : 0]);
|
||||
}
|
||||
x3d8_ = 0.f;
|
||||
}
|
||||
if (x3e0_ != 0.f) {
|
||||
if (animData != nullptr) { // Original code does not check
|
||||
animData->DelAdditiveAnimation(x3c8_animIds[x3e0_ <= 0.f ? 3 : 2]);
|
||||
}
|
||||
x3e0_ = 0.f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CGrenadeLauncher::sub_80230438() {
|
||||
CModelData* modelData = GetModelData();
|
||||
CAnimData* animData;
|
||||
if (modelData == nullptr || (animData = modelData->GetAnimationData()) == nullptr || x258_started <= -1 ||
|
||||
x258_started >= 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
constexpr std::array arr = {0, 3};
|
||||
const auto& anim = animData->GetCharacterInfo().GetPASDatabase().FindBestAnimation(
|
||||
CPASAnimParmData{5, CPASAnimParm::FromEnum(0), CPASAnimParm::FromEnum(arr[x258_started])}, -1);
|
||||
if (anim.first > 0.f) {
|
||||
animData->SetAnimation({anim.second, -1, 1.f, true}, false);
|
||||
modelData->EnableLooping(true);
|
||||
}
|
||||
}
|
||||
|
||||
void CGrenadeLauncher::LaunchGrenade(CStateManager& mgr) {
|
||||
CModelData* modelData = GetModelData();
|
||||
CAnimData* animData;
|
||||
if (modelData == nullptr || (animData = modelData->GetAnimationData()) == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& anim = animData->GetCharacterInfo().GetPASDatabase().FindBestAnimation(CPASAnimParmData{23}, -1);
|
||||
if (anim.first > 0.f) {
|
||||
animData->AddAdditiveAnimation(anim.second, 1.f, false, true);
|
||||
const zeus::CVector3f& origin =
|
||||
GetTranslation() + GetTransform().rotate(GetLocatorTransform("grenade_LCTR"sv).origin);
|
||||
const zeus::CVector3f& target = GrenadeTarget(mgr);
|
||||
float angleOut = x2d0_data.GetGrenadeTrajectoryInfo().GetAngleMin();
|
||||
float velocityOut = x2d0_data.GetGrenadeTrajectoryInfo().GetVelocityMin();
|
||||
CalculateGrenadeTrajectory(target, origin, x2d0_data.GetGrenadeTrajectoryInfo(), angleOut, velocityOut);
|
||||
|
||||
zeus::CVector3f dist = target - origin;
|
||||
dist.z() = 0.f;
|
||||
const zeus::CVector3f& front = GetTransform().frontVector();
|
||||
if (dist.canBeNormalized()) {
|
||||
dist.normalize();
|
||||
} else {
|
||||
dist = front;
|
||||
}
|
||||
|
||||
constexpr float maxAngle = zeus::degToRad(45.f);
|
||||
if (zeus::CVector3f::getAngleDiff(front, dist) > maxAngle) {
|
||||
dist = zeus::CVector3f::slerp(front, dist, maxAngle);
|
||||
}
|
||||
|
||||
const zeus::CVector3f& look = zeus::CVector3f::slerp(dist, zeus::skUp, angleOut);
|
||||
const zeus::CTransform& xf = zeus::lookAt(origin, origin + look, zeus::skUp);
|
||||
CModelData mData{CStaticRes{x2d0_data.GetGrenadeModelId(), GetModelData()->GetScale()}};
|
||||
mgr.AddObject(new CBouncyGrenade(mgr.AllocateUniqueId(), "Bouncy Grenade"sv,
|
||||
{GetAreaIdAlways(), CEntity::NullConnectionList}, xf, std::move(mData),
|
||||
x350_grenadeActorParams, x2cc_parentId, x2d0_data.GetGrenadeData(), velocityOut,
|
||||
x3f8_explodePlayerDistance));
|
||||
}
|
||||
}
|
||||
} // namespace urde::MP1
|
|
@ -0,0 +1,124 @@
|
|||
#pragma once
|
||||
|
||||
#include "Runtime/Character/CModelData.hpp"
|
||||
#include "Runtime/Collision/CCollidableSphere.hpp"
|
||||
#include "Runtime/MP1/World/CBouncyGrenade.hpp"
|
||||
#include "Runtime/Particle/CGenDescription.hpp"
|
||||
#include "Runtime/World/CActorParameters.hpp"
|
||||
#include "Runtime/World/CDamageInfo.hpp"
|
||||
#include "Runtime/World/CDamageVulnerability.hpp"
|
||||
#include "Runtime/World/CEntityInfo.hpp"
|
||||
#include "Runtime/World/CHealthInfo.hpp"
|
||||
#include "Runtime/World/CPhysicsActor.hpp"
|
||||
|
||||
#include "TCastTo.hpp" // Generated file, do not modify include path
|
||||
|
||||
#include <array>
|
||||
#include <string_view>
|
||||
#include <zeus/CColor.hpp>
|
||||
#include <zeus/CTransform.hpp>
|
||||
#include <zeus/CQuaternion.hpp>
|
||||
|
||||
namespace urde::MP1 {
|
||||
struct SGrenadeTrajectoryInfo {
|
||||
private:
|
||||
float x0_velocityMin;
|
||||
float x4_velocityMax;
|
||||
float x8_angleMin;
|
||||
float xc_angleMax;
|
||||
|
||||
public:
|
||||
explicit SGrenadeTrajectoryInfo(CInputStream& in)
|
||||
: x0_velocityMin(in.readFloatBig())
|
||||
, x4_velocityMax(in.readFloatBig())
|
||||
, x8_angleMin(zeus::degToRad(in.readFloatBig()))
|
||||
, xc_angleMax(zeus::degToRad(in.readFloatBig())) {}
|
||||
|
||||
[[nodiscard]] float GetVelocityMin() const { return x0_velocityMin; }
|
||||
[[nodiscard]] float GetVelocityMax() const { return x4_velocityMax; }
|
||||
[[nodiscard]] float GetAngleMin() const { return x8_angleMin; }
|
||||
[[nodiscard]] float GetAngleMax() const { return xc_angleMax; }
|
||||
};
|
||||
|
||||
struct SGrenadeLauncherData {
|
||||
private:
|
||||
SBouncyGrenadeData x0_grenadeData;
|
||||
CAssetId x3c_grenadeCmdl;
|
||||
CAssetId x40_launcherExplodeGenDesc;
|
||||
u16 x44_launcherExplodeSfx;
|
||||
SGrenadeTrajectoryInfo x48_trajectoryInfo;
|
||||
|
||||
public:
|
||||
SGrenadeLauncherData(const SBouncyGrenadeData& data, CAssetId w1, CAssetId w2, u16 sfx,
|
||||
const SGrenadeTrajectoryInfo& trajectoryInfo)
|
||||
: x0_grenadeData(data)
|
||||
, x3c_grenadeCmdl(w1)
|
||||
, x40_launcherExplodeGenDesc(w2)
|
||||
, x44_launcherExplodeSfx(sfx)
|
||||
, x48_trajectoryInfo(trajectoryInfo){};
|
||||
|
||||
[[nodiscard]] const SBouncyGrenadeData& GetGrenadeData() const { return x0_grenadeData; }
|
||||
[[nodiscard]] CAssetId GetGrenadeModelId() const { return x3c_grenadeCmdl; }
|
||||
[[nodiscard]] CAssetId GetExplosionGenDescId() const { return x40_launcherExplodeGenDesc; }
|
||||
[[nodiscard]] u16 GetExplosionSfx() const { return x44_launcherExplodeSfx; }
|
||||
[[nodiscard]] const SGrenadeTrajectoryInfo& GetGrenadeTrajectoryInfo() const { return x48_trajectoryInfo; }
|
||||
};
|
||||
|
||||
class CGrenadeLauncher : public CPhysicsActor {
|
||||
private:
|
||||
int x258_started = 0;
|
||||
CHealthInfo x25c_healthInfo;
|
||||
CDamageVulnerability x264_vulnerability;
|
||||
TUniqueId x2cc_parentId;
|
||||
SGrenadeLauncherData x2d0_data;
|
||||
CCollidableSphere x328_cSphere;
|
||||
float x348_shotTimer = -1.f;
|
||||
zeus::CColor x34c_color1{1.f};
|
||||
CActorParameters x350_grenadeActorParams;
|
||||
std::optional<TLockedToken<CGenDescription>> x3b8_particleGenDesc;
|
||||
std::array<s32, 4> x3c8_animIds{};
|
||||
float x3d8_ = 0.f;
|
||||
float x3dc_ = 0.f;
|
||||
float x3e0_ = 0.f;
|
||||
float x3e4_ = 0.f;
|
||||
float x3e8_thermalMag;
|
||||
float x3ec_damageTimer = 0.f;
|
||||
zeus::CColor x3f0_color2{0.5f, 0.f, 0.f};
|
||||
zeus::CColor x3f4_color3{0.f};
|
||||
float x3f8_explodePlayerDistance;
|
||||
bool x3fc_launchGrenade = false;
|
||||
bool x3fd_visible = true;
|
||||
bool x3fe_ = true;
|
||||
|
||||
public:
|
||||
CGrenadeLauncher(TUniqueId uid, std::string_view name, const CEntityInfo& info, const zeus::CTransform& xf,
|
||||
CModelData&& mData, const zeus::CAABox& bounds, const CHealthInfo& healthInfo,
|
||||
const CDamageVulnerability& vulnerability, const CActorParameters& actParams, TUniqueId parentId,
|
||||
const SGrenadeLauncherData& data, float f1);
|
||||
|
||||
void Accept(IVisitor& visitor) override { visitor.Visit(this); }
|
||||
void AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) override;
|
||||
void AddToRenderer(const zeus::CFrustum& frustum, const CStateManager& mgr) const override;
|
||||
[[nodiscard]] const CCollisionPrimitive* GetCollisionPrimitive() const override { return &x328_cSphere; }
|
||||
[[nodiscard]] const CDamageVulnerability* GetDamageVulnerability() const override { return &x264_vulnerability; }
|
||||
[[nodiscard]] std::optional<zeus::CAABox> GetTouchBounds() const override;
|
||||
CHealthInfo* HealthInfo(CStateManager& mgr) override { return &x25c_healthInfo; }
|
||||
void PreRender(CStateManager& mgr, const zeus::CFrustum& frustum) override;
|
||||
void Render(const CStateManager& mgr) const override;
|
||||
void Think(float dt, CStateManager& mgr) override;
|
||||
void Touch(CActor& act, CStateManager& mgr) override;
|
||||
|
||||
static zeus::CVector3f GrenadeTarget(const CStateManager& mgr);
|
||||
static void CalculateGrenadeTrajectory(const zeus::CVector3f& target, const zeus::CVector3f& origin,
|
||||
const SGrenadeTrajectoryInfo& info, float& angleOut, float& velocityOut);
|
||||
|
||||
private:
|
||||
void UpdateCollision();
|
||||
void UpdateColor(float arg);
|
||||
void UpdateDamageTime(float arg);
|
||||
void CreateExplosion(CStateManager& mgr);
|
||||
void sub_8022f9e0(CStateManager& mgr, float dt);
|
||||
void sub_80230438();
|
||||
void LaunchGrenade(CStateManager& mgr);
|
||||
};
|
||||
} // namespace urde::MP1
|
|
@ -1,42 +1,47 @@
|
|||
set(MP1_WORLD_SOURCES
|
||||
CNewIntroBoss.hpp CNewIntroBoss.cpp
|
||||
CBeetle.hpp CBeetle.cpp
|
||||
CWarWasp.hpp CWarWasp.cpp
|
||||
CElitePirate.hpp CElitePirate.cpp
|
||||
CBloodFlower.hpp CBloodFlower.cpp
|
||||
CChozoGhost.hpp CChozoGhost.cpp
|
||||
CSpacePirate.hpp CSpacePirate.cpp
|
||||
CParasite.hpp CParasite.cpp
|
||||
CBabygoth.hpp CBabygoth.cpp
|
||||
CTryclops.hpp CTryclops.cpp
|
||||
CFireFlea.hpp CFireFlea.cpp
|
||||
CEnergyBall.hpp CEnergyBall.cpp
|
||||
CEyeball.hpp CEyeball.cpp
|
||||
CActorContraption.hpp CActorContraption.cpp
|
||||
CAtomicAlpha.hpp CAtomicAlpha.cpp
|
||||
CAtomicBeta.hpp CAtomicBeta.cpp
|
||||
CBabygoth.hpp CBabygoth.cpp
|
||||
CBeetle.hpp CBeetle.cpp
|
||||
CBloodFlower.hpp CBloodFlower.cpp
|
||||
CBouncyGrenade.hpp CBouncyGrenade.cpp
|
||||
CBurrower.hpp CBurrower.cpp
|
||||
CChozoGhost.hpp CChozoGhost.cpp
|
||||
CElitePirate.hpp CElitePirate.cpp
|
||||
CEnergyBall.hpp CEnergyBall.cpp
|
||||
CEyeball.hpp CEyeball.cpp
|
||||
CFireFlea.hpp CFireFlea.cpp
|
||||
CFlaahgra.hpp CFlaahgra.cpp
|
||||
CFlaahgraProjectile.hpp CFlaahgraProjectile.cpp
|
||||
CFlaahgraTentacle.hpp CFlaahgraTentacle.cpp
|
||||
CFlickerBat.hpp CFlickerBat.cpp
|
||||
CJellyZap.hpp CJellyZap.cpp
|
||||
CFlyingPirate.hpp CFlyingPirate.cpp
|
||||
CMetroidPrimeRelay.hpp CMetroidPrimeRelay.cpp
|
||||
CGrenadeLauncher.hpp CGrenadeLauncher.cpp
|
||||
CJellyZap.hpp CJellyZap.cpp
|
||||
CMagdolite.hpp CMagdolite.cpp
|
||||
CMetaree.hpp CMetaree.cpp
|
||||
CMetroid.hpp CMetroid.cpp
|
||||
CMetroidBeta.hpp CMetroidBeta.cpp
|
||||
CMetroidPrimeExo.hpp CMetroidPrimeExo.cpp
|
||||
CMetroidPrimeProjectile.hpp CMetroidPrimeProjectile.cpp
|
||||
CActorContraption.hpp CActorContraption.cpp
|
||||
CThardusRockProjectile.hpp CThardusRockProjectile.cpp
|
||||
CMetroidBeta.hpp CMetroidBeta.cpp
|
||||
CMetroid.hpp CMetroid.cpp
|
||||
CMetaree.hpp CMetaree.cpp
|
||||
CBurrower.hpp CBurrower.cpp
|
||||
CPuffer.hpp CPuffer.cpp
|
||||
CMagdolite.hpp CMagdolite.cpp
|
||||
CSeedling.hpp CSeedling.cpp
|
||||
CRidley.hpp CRidley.cpp
|
||||
CPuddleToadGamma.hpp CPuddleToadGamma.cpp
|
||||
CFlaahgra.hpp CFlaahgra.cpp
|
||||
CFlaahgraTentacle.hpp CFlaahgraTentacle.cpp
|
||||
CFlaahgraProjectile.hpp CFlaahgraProjectile.cpp
|
||||
CSpankWeed.hpp CSpankWeed.cpp
|
||||
CMetroidPrimeRelay.hpp CMetroidPrimeRelay.cpp
|
||||
CNewIntroBoss.hpp CNewIntroBoss.cpp
|
||||
COmegaPirate.hpp COmegaPirate.cpp
|
||||
CParasite.hpp CParasite.cpp
|
||||
CPuddleSpore.hpp CPuddleSpore.cpp
|
||||
CPuddleToadGamma.hpp CPuddleToadGamma.cpp
|
||||
CPuffer.hpp CPuffer.cpp
|
||||
CRidley.hpp CRidley.cpp
|
||||
CRipper.hpp CRipper.cpp
|
||||
CThardus.hpp CThardus.cpp)
|
||||
CSeedling.hpp CSeedling.cpp
|
||||
CShockWave.hpp CShockWave.cpp
|
||||
CSpacePirate.hpp CSpacePirate.cpp
|
||||
CSpankWeed.hpp CSpankWeed.cpp
|
||||
CThardus.hpp CThardus.cpp
|
||||
CThardusRockProjectile.hpp CThardusRockProjectile.cpp
|
||||
CTryclops.hpp CTryclops.cpp
|
||||
CWarWasp.hpp CWarWasp.cpp
|
||||
)
|
||||
|
||||
runtime_add_list(World MP1_WORLD_SOURCES)
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
#include "Runtime/MP1/World/COmegaPirate.hpp"
|
||||
|
||||
namespace urde::MP1 {
|
||||
COmegaPirate::CFlash::CFlash(TUniqueId uid, const CEntityInfo& info, const zeus::CVector3f& pos, CToken& p4, float p5)
|
||||
: CActor(uid, true, "Omega Pirate Flash", info, zeus::CTransform::Translate(pos), CModelData::CModelDataNull(), {},
|
||||
CActorParameters::None(), kInvalidUniqueId) {}
|
||||
|
||||
COmegaPirate::COmegaPirate(TUniqueId uid, std::string_view name, const CEntityInfo& info, const zeus::CTransform& xf,
|
||||
CModelData&& mData, const CPatternedInfo& pInfo, const CActorParameters& actParms,
|
||||
CElitePirateData data, CAssetId w1, CAssetId w2, CAssetId w3)
|
||||
: CElitePirate(uid, name, info, xf, std::move(mData), pInfo, actParms, data) {}
|
||||
} // namespace urde::MP1
|
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
|
||||
#include "Runtime/MP1/World/CElitePirate.hpp"
|
||||
|
||||
namespace urde::MP1 {
|
||||
class COmegaPirate : public CElitePirate {
|
||||
private:
|
||||
class CFlash : public CActor {
|
||||
private:
|
||||
CToken xe8_;
|
||||
int xf0_;
|
||||
float xf4_;
|
||||
float xf8_;
|
||||
float xfc_;
|
||||
|
||||
CFlash(TUniqueId uid, const CEntityInfo& info, const zeus::CVector3f& pos, CToken& p4, float p5);
|
||||
};
|
||||
|
||||
public:
|
||||
COmegaPirate(TUniqueId uid, std::string_view name, const CEntityInfo& info, const zeus::CTransform& xf,
|
||||
CModelData&& mData, const CPatternedInfo& pInfo, const CActorParameters& actParms, CElitePirateData data,
|
||||
CAssetId w1, CAssetId w2, CAssetId w3);
|
||||
};
|
||||
} // namespace urde::MP1
|
|
@ -0,0 +1,177 @@
|
|||
#include "Runtime/MP1/World/CShockWave.hpp"
|
||||
|
||||
#include "Runtime/Collision/CCollisionActor.hpp"
|
||||
#include "Runtime/CSimplePool.hpp"
|
||||
#include "Runtime/CStateManager.hpp"
|
||||
#include "Runtime/GameGlobalObjects.hpp"
|
||||
#include "Runtime/Graphics/CBooRenderer.hpp"
|
||||
#include "Runtime/World/CActorParameters.hpp"
|
||||
#include "Runtime/World/CGameLight.hpp"
|
||||
#include "Runtime/World/CHUDBillboardEffect.hpp"
|
||||
#include "Runtime/World/CPlayer.hpp"
|
||||
|
||||
#include "TCastTo.hpp" // Generated file, do not modify include path
|
||||
|
||||
namespace urde::MP1 {
|
||||
CShockWave::CShockWave(TUniqueId uid, std::string_view name, const CEntityInfo& info, const zeus::CTransform& xf,
|
||||
TUniqueId parent, const SShockWaveData& data, float minActiveTime, float knockback)
|
||||
: CActor(uid, true, name, info, xf, CModelData::CModelDataNull(), {EMaterialTypes::Projectile},
|
||||
CActorParameters::None(), kInvalidUniqueId)
|
||||
, xe8_id1(parent)
|
||||
, xec_damageInfo(data.GetDamageInfo())
|
||||
, x108_elementGenDesc(g_SimplePool->GetObj({SBIG('PART'), data.GetParticleDescId()}))
|
||||
, x110_elementGen(std::make_unique<CElementGen>(x108_elementGenDesc))
|
||||
, x114_data(data)
|
||||
, x150_(data.GetX24())
|
||||
, x154_(data.GetX2C())
|
||||
, x15c_minActiveTime(minActiveTime)
|
||||
, x160_knockback(knockback) {
|
||||
if (data.GetWeaponDescId().IsValid()) {
|
||||
x974_electricDesc = g_SimplePool->GetObj({SBIG('ELSC'), data.GetWeaponDescId()});
|
||||
}
|
||||
x110_elementGen->SetParticleEmission(true);
|
||||
x110_elementGen->SetOrientation(GetTransform().getRotation());
|
||||
x110_elementGen->SetGlobalTranslation(GetTranslation());
|
||||
xe6_27_thermalVisorFlags = 2;
|
||||
}
|
||||
|
||||
void CShockWave::Accept(IVisitor& visitor) { visitor.Visit(this); }
|
||||
|
||||
void CShockWave::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) {
|
||||
if (msg == EScriptObjectMessage::Registered) {
|
||||
if (x110_elementGen->SystemHasLight()) {
|
||||
x980_id2 = mgr.AllocateUniqueId();
|
||||
mgr.AddObject(new CGameLight(x980_id2, GetAreaIdAlways(), GetActive(), "ShockWaveLight_" + x10_name,
|
||||
GetTransform(), GetUniqueId(), x110_elementGen->GetLight(),
|
||||
x114_data.GetParticleDescId().Value(), 1, 0.f));
|
||||
}
|
||||
} else if (msg == EScriptObjectMessage::Deleted) {
|
||||
mgr.FreeScriptObject(x980_id2);
|
||||
x980_id2 = kInvalidUniqueId;
|
||||
}
|
||||
CActor::AcceptScriptMsg(msg, uid, mgr);
|
||||
mgr.SendScriptMsgAlways(x980_id2, uid, msg);
|
||||
}
|
||||
|
||||
void CShockWave::AddToRenderer(const zeus::CFrustum& frustum, const CStateManager& mgr) const {
|
||||
CActor::AddToRenderer(frustum, mgr);
|
||||
g_Renderer->AddParticleGen(*x110_elementGen);
|
||||
}
|
||||
|
||||
std::optional<zeus::CAABox> CShockWave::GetTouchBounds() const {
|
||||
if (x150_ <= 0.f) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return zeus::CAABox({-x150_, -x150_, 0.f}, {x150_, x150_, 1.f}).getTransformedAABox(GetTransform());
|
||||
}
|
||||
|
||||
void CShockWave::Render(const CStateManager& mgr) const {
|
||||
CActor::Render(mgr);
|
||||
x110_elementGen->Render();
|
||||
}
|
||||
|
||||
void CShockWave::Think(float dt, CStateManager& mgr) {
|
||||
if (GetActive()) {
|
||||
x110_elementGen->Update(dt);
|
||||
x158_activeTime += dt;
|
||||
x150_ += x154_ * dt;
|
||||
x154_ += dt * x114_data.GetX30();
|
||||
x110_elementGen->SetExternalVar(0, x150_);
|
||||
for (int i = 0; i < x110_elementGen->GetNumActiveChildParticles(); ++i) {
|
||||
auto& particle = static_cast<CElementGen&>(x110_elementGen->GetActiveChildParticle(i));
|
||||
if (particle.Get4CharId() == SBIG('PART')) {
|
||||
particle.SetExternalVar(0, x150_);
|
||||
}
|
||||
}
|
||||
if (x16c_hitPlayerInAir) {
|
||||
x164_timeSinceHitPlayerInAir += dt;
|
||||
x16c_hitPlayerInAir = false;
|
||||
}
|
||||
if (x16d_hitPlayer) {
|
||||
x168_timeSinceHitPlayer += dt;
|
||||
x16d_hitPlayer = false;
|
||||
}
|
||||
}
|
||||
if (x110_elementGen->IsSystemDeletable() && x15c_minActiveTime > 0.f && x158_activeTime >= x15c_minActiveTime) {
|
||||
mgr.FreeScriptObject(GetUniqueId());
|
||||
} else if (x980_id2 != kInvalidUniqueId) {
|
||||
if (TCastToPtr<CGameLight> light = mgr.ObjectById(x980_id2)) {
|
||||
if (light->GetActive()) {
|
||||
light->SetLight(x110_elementGen->GetLight());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CShockWave::Touch(CActor& actor, CStateManager& mgr) {
|
||||
if (x158_activeTime >= x15c_minActiveTime) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool isParent = xe8_id1 == actor.GetUniqueId();
|
||||
if (TCastToConstPtr<CCollisionActor> cactor = mgr.GetObjectById(actor.GetUniqueId())) {
|
||||
isParent = xe8_id1 == cactor->GetOwnerId();
|
||||
}
|
||||
if (isParent) {
|
||||
return;
|
||||
}
|
||||
|
||||
float mmax = x150_ * x150_;
|
||||
float mmin = mmax * x114_data.GetX28() * x114_data.GetX28();
|
||||
zeus::CVector3f dist = actor.GetTranslation() - GetTranslation();
|
||||
CDamageInfo damageInfo = xec_damageInfo;
|
||||
float knockBackScale = std::max(0.f, 1.f - x160_knockback * x158_activeTime);
|
||||
bool isPlayer = mgr.GetPlayer().GetUniqueId() == actor.GetUniqueId();
|
||||
bool isPlayerInAir = isPlayer && mgr.GetPlayer().GetPlayerMovementState() != CPlayer::EPlayerMovementState::OnGround;
|
||||
float distXYMag = dist.toVec2f().magSquared();
|
||||
if (distXYMag < mmin || distXYMag > mmax) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isPlayer) {
|
||||
if (mgr.GetPlayer().GetPlayerMovementState() == CPlayer::EPlayerMovementState::OnGround) {
|
||||
const zeus::CTransform& playerTransform = mgr.GetPlayer().GetTransform();
|
||||
zeus::CVector3f playerDir = GetTranslation() - playerTransform.origin;
|
||||
if (playerDir.canBeNormalized()) {
|
||||
playerDir.normalize();
|
||||
float dot = std::abs(playerDir.dot(playerTransform.frontVector()));
|
||||
knockBackScale = std::max(0.12f, 0.88f * dot * dot);
|
||||
}
|
||||
}
|
||||
if (mgr.GetPlayer().GetVelocity().magnitude() > 40.f) {
|
||||
x168_timeSinceHitPlayer = 0.2666f;
|
||||
}
|
||||
}
|
||||
damageInfo.SetKnockBackPower(knockBackScale * damageInfo.GetKnockBackPower());
|
||||
|
||||
if (isPlayer && (x164_timeSinceHitPlayerInAir >= 0.1333f || x168_timeSinceHitPlayer >= 0.2666f)) {
|
||||
return;
|
||||
}
|
||||
if (!IsHit(actor.GetUniqueId())) {
|
||||
mgr.ApplyDamage(GetUniqueId(), actor.GetUniqueId(), GetUniqueId(), damageInfo,
|
||||
CMaterialFilter::MakeInclude({EMaterialTypes::Solid}), zeus::skZero3f);
|
||||
if (isPlayer && x974_electricDesc) {
|
||||
mgr.AddObject(new CHUDBillboardEffect(std::nullopt, x974_electricDesc, mgr.AllocateUniqueId(), true,
|
||||
"VisorElectricFx", CHUDBillboardEffect::GetNearClipDistance(mgr),
|
||||
CHUDBillboardEffect::GetScaleForPOV(mgr), zeus::skWhite, zeus::skOne3f,
|
||||
zeus::skZero3f));
|
||||
CSfxManager::SfxStart(x114_data.GetElectrocuteSfx(), 1.f, 1.f, false, 0x7f, false, kInvalidAreaId);
|
||||
}
|
||||
x170_hitIds.push_back(actor.GetUniqueId());
|
||||
} else {
|
||||
damageInfo.SetDamage(0.f);
|
||||
mgr.ApplyDamage(GetUniqueId(), actor.GetUniqueId(), GetUniqueId(), damageInfo,
|
||||
CMaterialFilter::MakeInclude({EMaterialTypes::Solid}), zeus::skZero3f);
|
||||
}
|
||||
if (isPlayerInAir) {
|
||||
x16c_hitPlayerInAir = true;
|
||||
}
|
||||
if (isPlayer) {
|
||||
x16d_hitPlayer = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool CShockWave::IsHit(TUniqueId id) const {
|
||||
return std::find(x170_hitIds.begin(), x170_hitIds.end(), id) != x170_hitIds.end();
|
||||
}
|
||||
} // namespace urde::MP1
|
|
@ -0,0 +1,69 @@
|
|||
#pragma once
|
||||
|
||||
#include "Runtime/World/CActor.hpp"
|
||||
#include "Runtime/World/CDamageInfo.hpp"
|
||||
#include "Runtime/Particle/CElementGen.hpp"
|
||||
|
||||
namespace urde::MP1 {
|
||||
struct SShockWaveData {
|
||||
private:
|
||||
u32 x0_ = 8;
|
||||
CAssetId x4_particleDesc;
|
||||
CDamageInfo x8_damageInfo;
|
||||
float x24_ = 0.f;
|
||||
float x28_ = 0.5f;
|
||||
float x2c_ = 16.5217f;
|
||||
float x30_ = 0.f;
|
||||
CAssetId x34_weaponDesc;
|
||||
u16 x38_electrocuteSfx;
|
||||
|
||||
public:
|
||||
SShockWaveData(CAssetId part, const CDamageInfo& dInfo, CAssetId weapon, u16 sfx)
|
||||
: x4_particleDesc(part), x8_damageInfo(dInfo), x34_weaponDesc(weapon), x38_electrocuteSfx(sfx) {}
|
||||
|
||||
[[nodiscard]] CAssetId GetParticleDescId() const { return x4_particleDesc; }
|
||||
[[nodiscard]] const CDamageInfo& GetDamageInfo() const { return x8_damageInfo; }
|
||||
[[nodiscard]] float GetX24() const { return x24_; }
|
||||
[[nodiscard]] float GetX28() const { return x28_; }
|
||||
[[nodiscard]] float GetX2C() const { return x2c_; }
|
||||
[[nodiscard]] float GetX30() const { return x30_; }
|
||||
[[nodiscard]] CAssetId GetWeaponDescId() const { return x34_weaponDesc; }
|
||||
[[nodiscard]] u16 GetElectrocuteSfx() const { return x38_electrocuteSfx; }
|
||||
};
|
||||
|
||||
class CShockWave : public CActor {
|
||||
private:
|
||||
TUniqueId xe8_id1;
|
||||
CDamageInfo xec_damageInfo;
|
||||
TToken<CGenDescription> x108_elementGenDesc;
|
||||
std::unique_ptr<CElementGen> x110_elementGen;
|
||||
SShockWaveData x114_data;
|
||||
float x150_;
|
||||
float x154_;
|
||||
float x158_activeTime = 0.f;
|
||||
float x15c_minActiveTime;
|
||||
float x160_knockback;
|
||||
float x164_timeSinceHitPlayerInAir = 0.f;
|
||||
float x168_timeSinceHitPlayer = 0.f;
|
||||
bool x16c_hitPlayerInAir = false;
|
||||
bool x16d_hitPlayer = false;
|
||||
rstl::reserved_vector<TUniqueId, 1024> x170_hitIds;
|
||||
std::optional<TToken<CElectricDescription>> x974_electricDesc;
|
||||
TUniqueId x980_id2 = kInvalidUniqueId;
|
||||
|
||||
public:
|
||||
CShockWave(TUniqueId uid, std::string_view name, const CEntityInfo& info, const zeus::CTransform& xf,
|
||||
TUniqueId parent, const SShockWaveData& data, float minActiveTime, float knockback);
|
||||
|
||||
void Accept(IVisitor& visitor) override;
|
||||
void AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) override;
|
||||
void AddToRenderer(const zeus::CFrustum& frustum, const CStateManager& mgr) const override;
|
||||
[[nodiscard]] std::optional<zeus::CAABox> GetTouchBounds() const override;
|
||||
void Render(const CStateManager& mgr) const override;
|
||||
void Think(float dt, CStateManager& mgr) override;
|
||||
void Touch(CActor& actor, CStateManager& mgr) override;
|
||||
|
||||
private:
|
||||
[[nodiscard]] bool IsHit(TUniqueId id) const;
|
||||
};
|
||||
} // namespace urde::MP1
|
|
@ -25,7 +25,8 @@ CGameProjectile::CGameProjectile(bool active, const TToken<CWeaponDescription>&
|
|||
CMaterialFilter::MakeIncludeExclude(
|
||||
{EMaterialTypes::Solid, EMaterialTypes::NonSolidDamageable},
|
||||
{EMaterialTypes::Projectile, EMaterialTypes::ProjectilePassthrough, excludeMat}),
|
||||
CMaterialList(), dInfo, attribs | GetBeamAttribType(wType), CModelData::CModelDataNull())
|
||||
CMaterialList(EMaterialTypes::Projectile), dInfo, attribs | GetBeamAttribType(wType),
|
||||
CModelData::CModelDataNull())
|
||||
, x158_visorParticle(visorParticle)
|
||||
, x168_visorSfx(visorSfx)
|
||||
, x170_projectile(wDesc, xf.origin, xf.basis, scale,
|
||||
|
|
|
@ -17,14 +17,14 @@ const CDamageVulnerability CDamageVulnerability::sImmuneVulnerability(
|
|||
EVulnerability::Deflect, EVulnerability::Deflect, EVulnerability::Deflect, EVulnerability::Deflect,
|
||||
EVulnerability::Deflect, EVulnerability::Deflect, EVulnerability::Deflect, EVulnerability::Deflect,
|
||||
EVulnerability::Deflect, EVulnerability::Deflect, EVulnerability::Deflect, EDeflectType::None);
|
||||
/* LOL, thanks retro */
|
||||
|
||||
const CDamageVulnerability CDamageVulnerability::sReflectVulnerability(
|
||||
EVulnerability::Deflect, EVulnerability::Deflect, EVulnerability::Deflect, EVulnerability::Deflect,
|
||||
EVulnerability::Deflect, EVulnerability::Deflect, EVulnerability::Deflect, EVulnerability::Deflect,
|
||||
EVulnerability::Deflect, EVulnerability::Deflect, EVulnerability::Deflect, EVulnerability::Deflect,
|
||||
EVulnerability::Deflect, EVulnerability::Deflect, EVulnerability::Deflect, EVulnerability::Deflect,
|
||||
EVulnerability::Deflect, EVulnerability::Deflect, EVulnerability::Deflect, EVulnerability::Deflect,
|
||||
EVulnerability::Deflect, EVulnerability::Deflect, EVulnerability::Deflect, EDeflectType::None);
|
||||
EVulnerability::Deflect, EVulnerability::Deflect, EVulnerability::Deflect, EDeflectType::One);
|
||||
|
||||
const CDamageVulnerability CDamageVulnerability::sPassThroughVulnerability(
|
||||
EVulnerability::PassThrough, EVulnerability::PassThrough, EVulnerability::PassThrough, EVulnerability::PassThrough,
|
||||
|
|
|
@ -14,6 +14,7 @@ class CPathFindSearch;
|
|||
|
||||
class CPathFindVisualizer {
|
||||
CLineRenderer m_spline = {CLineRenderer::EPrimitiveMode::LineStrip, 16, {}, true};
|
||||
|
||||
public:
|
||||
void Draw(const CPathFindSearch& path);
|
||||
};
|
||||
|
@ -56,6 +57,8 @@ public:
|
|||
void SetArea(CPFArea* area) { x0_area = area; }
|
||||
float GetCharacterHeight() const { return xd0_chHeight; }
|
||||
void SetCharacterHeight(float h) { xd0_chHeight = h; }
|
||||
float GetCharacterRadius() const { return xd4_chRadius; }
|
||||
void SetCharacterRadius(float r) { xd4_chRadius = r; }
|
||||
void SetPadding(float padding) { xd8_padding = padding; }
|
||||
float RemainingPathDistance(const zeus::CVector3f& pos) const;
|
||||
void DebugDraw() const;
|
||||
|
|
|
@ -134,7 +134,7 @@ protected:
|
|||
bool x328_28_prevOnGround : 1;
|
||||
bool x328_29_noPatternShagging : 1;
|
||||
bool x328_30_lookAtDeathDir : 1;
|
||||
bool x328_31_ : 1;
|
||||
bool x328_31_energyAttractor : 1;
|
||||
bool x329_24_ : 1;
|
||||
};
|
||||
u32 _dummy = 0;
|
||||
|
@ -367,6 +367,7 @@ public:
|
|||
}
|
||||
float GetDamageDuration() const { return x504_damageDur; }
|
||||
zeus::CVector3f GetGunEyePos() const;
|
||||
bool IsEnergyAttractor() const { return x328_31_energyAttractor; }
|
||||
bool IsAlive() const { return x400_25_alive; }
|
||||
|
||||
void BuildBodyController(EBodyType);
|
||||
|
|
|
@ -161,6 +161,7 @@ public:
|
|||
void SetMomentumWR(const zeus::CVector3f& momentum) { x150_momentum = momentum; }
|
||||
const zeus::CVector3f& GetConstantForce() const { return xfc_constantForce; }
|
||||
void SetConstantForce(const zeus::CVector3f& force) { xfc_constantForce = force; }
|
||||
const zeus::CVector3f& GetAngularMomentum() const { return x108_angularMomentum; }
|
||||
void SetAngularMomentum(const zeus::CAxisAngle& momentum) { x108_angularMomentum = momentum; }
|
||||
const zeus::CVector3f& GetMomentum() const { return x150_momentum; }
|
||||
const zeus::CVector3f& GetVelocity() const { return x138_velocity; }
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "Runtime/MP1/World/CMetroidBeta.hpp"
|
||||
#include "Runtime/MP1/World/CMetroidPrimeRelay.hpp"
|
||||
#include "Runtime/MP1/World/CNewIntroBoss.hpp"
|
||||
#include "Runtime/MP1/World/COmegaPirate.hpp"
|
||||
#include "Runtime/MP1/World/CParasite.hpp"
|
||||
#include "Runtime/MP1/World/CPuddleSpore.hpp"
|
||||
#include "Runtime/MP1/World/CPuddleToadGamma.hpp"
|
||||
|
@ -127,6 +128,8 @@ static logvisor::Module Log("urde::ScriptLoader");
|
|||
|
||||
constexpr SObjectTag MorphballDoorANCS = {FOURCC('ANCS'), 0x1F9DA858};
|
||||
|
||||
constexpr int skElitePiratePropCount = 41;
|
||||
|
||||
static bool EnsurePropertyCount(int count, int expected, const char* structName) {
|
||||
if (count < expected) {
|
||||
Log.report(logvisor::Warning, fmt("Insufficient number of props ({}/{}) for {} entity"), count, expected,
|
||||
|
@ -1394,7 +1397,7 @@ CEntity* ScriptLoader::LoadFlyingPirate(CStateManager& mgr, CInputStream& in, in
|
|||
}
|
||||
|
||||
CEntity* ScriptLoader::LoadElitePirate(CStateManager& mgr, CInputStream& in, int propCount, const CEntityInfo& info) {
|
||||
if (!EnsurePropertyCount(propCount, 41, "ElitePirate"))
|
||||
if (!EnsurePropertyCount(propCount, skElitePiratePropCount, "ElitePirate"))
|
||||
return nullptr;
|
||||
|
||||
SScaledActorHead actHead = LoadScaledActorHead(in, mgr);
|
||||
|
@ -3638,7 +3641,33 @@ CEntity* ScriptLoader::LoadMazeNode(CStateManager& mgr, CInputStream& in, int pr
|
|||
}
|
||||
|
||||
CEntity* ScriptLoader::LoadOmegaPirate(CStateManager& mgr, CInputStream& in, int propCount, const CEntityInfo& info) {
|
||||
if (!EnsurePropertyCount(propCount, skElitePiratePropCount + 1, "OmegaPirate")) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#if 0
|
||||
SScaledActorHead actHead = LoadScaledActorHead(in, mgr);
|
||||
auto pair = CPatternedInfo::HasCorrectParameterCount(in);
|
||||
if (!pair.first) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CPatternedInfo pInfo(in, pair.second);
|
||||
CActorParameters actParms = LoadActorParameters(in);
|
||||
MP1::CElitePirateData elitePirateData(in, propCount);
|
||||
|
||||
if (!pInfo.GetAnimationParameters().GetACSFile().IsValid()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CModelData mData(CAnimRes(pInfo.GetAnimationParameters().GetACSFile(), pInfo.GetAnimationParameters().GetCharacter(),
|
||||
actHead.x40_scale, pInfo.GetAnimationParameters().GetInitialAnimation(), true));
|
||||
|
||||
return new MP1::COmegaPirate(mgr.AllocateUniqueId(), actHead.x0_name, info, actHead.x10_transform, std::move(mData),
|
||||
pInfo, actParms, elitePirateData, CAssetId(in), CAssetId(in), CAssetId(in));
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
CEntity* ScriptLoader::LoadPhazonPool(CStateManager& mgr, CInputStream& in, int propCount, const CEntityInfo& info) {
|
||||
|
|
Loading…
Reference in New Issue