Merge pull request #287 from AxioDL/elitepirate

Elite Pirate implementation
This commit is contained in:
Luke Street 2020-04-01 21:13:33 -04:00 committed by GitHub
commit a4a7888338
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 2507 additions and 87 deletions

1
.clang-tidy Normal file
View File

@ -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'

View File

@ -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 };

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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{

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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,

View File

@ -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;

View File

@ -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);

View File

@ -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; }

View File

@ -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) {