diff --git a/asm/MetroidPrime/ScriptObjects/CScriptTrigger.s b/asm/MetroidPrime/ScriptObjects/CScriptTrigger.s index 65f78f1e..1a77df83 100644 --- a/asm/MetroidPrime/ScriptObjects/CScriptTrigger.s +++ b/asm/MetroidPrime/ScriptObjects/CScriptTrigger.s @@ -3,8 +3,8 @@ .section .data .balign 8 -.global lbl_803DA4D8 -lbl_803DA4D8: +.global __vt__14CScriptTrigger +__vt__14CScriptTrigger: # ROM: 0x3D74D8 .4byte 0 .4byte 0 @@ -59,8 +59,8 @@ lbl_805A6F94: .global lbl_805A8E00 lbl_805A8E00: .skip 0x4 -.global lbl_805A8E04 -lbl_805A8E04: +.global sktonOHurtWeaponMode$230 +sktonOHurtWeaponMode$230: .skip 0xC .section .sdata2, "a" @@ -160,8 +160,8 @@ GetInhabitants__14CScriptTriggerCFv: /* 80075D24 00072C84 38 63 00 E8 */ addi r3, r3, 0xe8 /* 80075D28 00072C88 4E 80 00 20 */ blr -.global UpdateInhabitants__14CScriptTriggerFR13CStateManager -UpdateInhabitants__14CScriptTriggerFR13CStateManager: +.global UpdateInhabitants__14CScriptTriggerFfR13CStateManager +UpdateInhabitants__14CScriptTriggerFfR13CStateManager: /* 80075D2C 00072C8C 94 21 FE 50 */ stwu r1, -0x1b0(r1) /* 80075D30 00072C90 7C 08 02 A6 */ mflr r0 /* 80075D34 00072C94 90 01 01 B4 */ stw r0, 0x1b4(r1) @@ -687,7 +687,7 @@ Think__14CScriptTriggerFfR13CStateManager: /* 800764D8 00073438 88 03 00 30 */ lbz r0, 0x30(r3) /* 800764DC 0007343C 54 00 CF FF */ rlwinm. r0, r0, 0x19, 0x1f, 0x1f /* 800764E0 00073440 41 82 00 08 */ beq lbl_800764E8 -/* 800764E4 00073444 4B FF F8 49 */ bl UpdateInhabitants__14CScriptTriggerFR13CStateManager +/* 800764E4 00073444 4B FF F8 49 */ bl UpdateInhabitants__14CScriptTriggerFfR13CStateManager lbl_800764E8: /* 800764E8 00073448 80 01 00 14 */ lwz r0, 0x14(r1) /* 800764EC 0007344C 7C 08 03 A6 */ mtlr r0 @@ -1136,12 +1136,12 @@ lbl_80076B24: /* 80076B50 00073AB0 88 0D A2 40 */ lbz r0, lbl_805A8E00@sda21(r13) /* 80076B54 00073AB4 7C 00 07 75 */ extsb. r0, r0 /* 80076B58 00073AB8 40 82 00 3C */ bne lbl_80076B94 -/* 80076B5C 00073ABC 38 ED A2 44 */ addi r7, r13, lbl_805A8E04@sda21 +/* 80076B5C 00073ABC 38 ED A2 44 */ addi r7, r13, sktonOHurtWeaponMode$230@sda21 /* 80076B60 00073AC0 38 C0 00 00 */ li r6, 0 /* 80076B64 00073AC4 88 07 00 04 */ lbz r0, 4(r7) /* 80076B68 00073AC8 50 C0 3E 30 */ rlwimi r0, r6, 7, 0x18, 0x18 /* 80076B6C 00073ACC 38 80 00 01 */ li r4, 1 -/* 80076B70 00073AD0 90 CD A2 44 */ stw r6, lbl_805A8E04@sda21(r13) +/* 80076B70 00073AD0 90 CD A2 44 */ stw r6, sktonOHurtWeaponMode$230@sda21(r13) /* 80076B74 00073AD4 54 05 06 3E */ clrlwi r5, r0, 0x18 /* 80076B78 00073AD8 50 C5 36 72 */ rlwimi r5, r6, 6, 0x19, 0x19 /* 80076B7C 00073ADC 98 07 00 04 */ stb r0, 4(r7) @@ -1152,14 +1152,14 @@ lbl_80076B24: /* 80076B90 00073AF0 98 8D A2 40 */ stb r4, lbl_805A8E00@sda21(r13) lbl_80076B94: /* 80076B94 00073AF4 C0 23 00 00 */ lfs f1, 0(r3) -/* 80076B98 00073AF8 38 8D A2 44 */ addi r4, r13, lbl_805A8E04@sda21 +/* 80076B98 00073AF8 38 8D A2 44 */ addi r4, r13, sktonOHurtWeaponMode$230@sda21 /* 80076B9C 00073AFC C0 42 88 D8 */ lfs f2, lbl_805AA5F8@sda21(r2) /* 80076BA0 00073B00 38 A0 00 00 */ li r5, 0 /* 80076BA4 00073B04 C0 02 88 D0 */ lfs f0, lbl_805AA5F0@sda21(r2) /* 80076BA8 00073B08 38 60 00 00 */ li r3, 0 /* 80076BAC 00073B0C EC 22 00 72 */ fmuls f1, f2, f1 /* 80076BB0 00073B10 88 C4 00 04 */ lbz r6, 4(r4) -/* 80076BB4 00073B14 80 ED A2 44 */ lwz r7, lbl_805A8E04@sda21(r13) +/* 80076BB4 00073B14 80 ED A2 44 */ lwz r7, sktonOHurtWeaponMode$230@sda21(r13) /* 80076BB8 00073B18 38 80 00 01 */ li r4, 1 /* 80076BBC 00073B1C 88 01 00 D0 */ lbz r0, 0xd0(r1) /* 80076BC0 00073B20 50 A0 3E 30 */ rlwimi r0, r5, 7, 0x18, 0x18 @@ -1225,8 +1225,8 @@ __dt__14CScriptTriggerFv: /* 80076C9C 00073BFC 93 81 00 10 */ stw r28, 0x10(r1) /* 80076CA0 00073C00 7C 7C 1B 79 */ or. r28, r3, r3 /* 80076CA4 00073C04 41 82 00 90 */ beq lbl_80076D34 -/* 80076CA8 00073C08 3C 60 80 3E */ lis r3, lbl_803DA4D8@ha -/* 80076CAC 00073C0C 38 03 A4 D8 */ addi r0, r3, lbl_803DA4D8@l +/* 80076CA8 00073C08 3C 60 80 3E */ lis r3, __vt__14CScriptTrigger@ha +/* 80076CAC 00073C0C 38 03 A4 D8 */ addi r0, r3, __vt__14CScriptTrigger@l /* 80076CB0 00073C10 90 1C 00 00 */ stw r0, 0(r28) /* 80076CB4 00073C14 83 FC 00 EC */ lwz r31, 0xec(r28) /* 80076CB8 00073C18 83 DC 00 F0 */ lwz r30, 0xf0(r28) @@ -1255,7 +1255,7 @@ lbl_80076CD4: lbl_80076D0C: /* 80076D0C 00073C6C 38 7C 00 E8 */ addi r3, r28, 0xe8 /* 80076D10 00073C70 38 80 FF FF */ li r4, -1 -/* 80076D14 00073C74 48 00 02 E1 */ bl sub_80076ff4 +/* 80076D14 00073C74 48 00 02 E1 */ bl "__dt__Q24rstl67listFv" /* 80076D18 00073C78 7F 83 E3 78 */ mr r3, r28 /* 80076D1C 00073C7C 38 80 00 00 */ li r4, 0 /* 80076D20 00073C80 4B FD E9 D1 */ bl __dt__6CActorFv @@ -1335,9 +1335,9 @@ lbl_80076D34: /* 80076E38 00073D98 38 61 00 B8 */ addi r3, r1, 0xb8 /* 80076E3C 00073D9C 38 80 FF FF */ li r4, -1 /* 80076E40 00073DA0 48 09 FC 0D */ bl __dt__10CModelDataFv -/* 80076E44 00073DA4 3C 60 80 3E */ lis r3, lbl_803DA4D8@ha +/* 80076E44 00073DA4 3C 60 80 3E */ lis r3, __vt__14CScriptTrigger@ha /* 80076E48 00073DA8 38 94 00 F4 */ addi r4, r20, 0xf4 -/* 80076E4C 00073DAC 38 63 A4 D8 */ addi r3, r3, lbl_803DA4D8@l +/* 80076E4C 00073DAC 38 63 A4 D8 */ addi r3, r3, __vt__14CScriptTrigger@l /* 80076E50 00073DB0 38 00 00 00 */ li r0, 0 /* 80076E54 00073DB4 90 74 00 00 */ stw r3, 0(r20) /* 80076E58 00073DB8 7F 63 DB 78 */ mr r3, r27 @@ -1452,8 +1452,8 @@ lbl_80076FCC: /* 80076FEC 00073F4C 38 21 00 10 */ addi r1, r1, 0x10 /* 80076FF0 00073F50 4E 80 00 20 */ blr -.global sub_80076ff4 -sub_80076ff4: +.global "__dt__Q24rstl67listFv" +"__dt__Q24rstl67listFv": /* 80076FF4 00073F54 94 21 FF E0 */ stwu r1, -0x20(r1) /* 80076FF8 00073F58 7C 08 02 A6 */ mflr r0 /* 80076FFC 00073F5C 90 01 00 24 */ stw r0, 0x24(r1) diff --git a/include/MetroidPrime/CDamageInfo.hpp b/include/MetroidPrime/CDamageInfo.hpp index 213e9a3c..97068d07 100644 --- a/include/MetroidPrime/CDamageInfo.hpp +++ b/include/MetroidPrime/CDamageInfo.hpp @@ -47,6 +47,7 @@ public: void SetKnockBackPower(float k) { x14_knockback = k; } float GetDamage() const { return x8_damage; } void SetDamage(float d) { x8_damage = d; } + bool HasNoDamage() const { return x8_damage <= 0.0f; } float GetDamage(const CDamageVulnerability& dVuln) const; float GetRadiusDamage() const { return xc_radiusDamage; } void SetRadiusDamage(float r) { xc_radiusDamage = r; } diff --git a/include/MetroidPrime/CStateManager.hpp b/include/MetroidPrime/CStateManager.hpp index f921d9eb..aa317b5d 100644 --- a/include/MetroidPrime/CStateManager.hpp +++ b/include/MetroidPrime/CStateManager.hpp @@ -120,6 +120,7 @@ public: CEntity* ObjectById(TUniqueId uid); const CEntity* GetObjectById(TUniqueId uid) const; + TEditorId GetEditorIdForUniqueId(TUniqueId) const; TUniqueId GetIdForScript(TEditorId eid) const; TIdListResult GetIdListForScript(TEditorId) const; @@ -198,6 +199,9 @@ public: return xf90_deferredTransition == kSMT_MessageScreen; } + void SetLastTriggerId(TUniqueId uid) { xf74_lastTrigger = uid; } + TUniqueId GetLastTriggerId() const { return xf74_lastTrigger; } + void SetLastRelayId(const TUniqueId& uid) { xf76_lastRelay = uid; } TUniqueId* GetLastRelayIdPtr() { return &xf76_lastRelay; } TUniqueId GetLastRelayId() const { return xf76_lastRelay; } diff --git a/include/MetroidPrime/ScriptObjects/CScriptSteam.hpp b/include/MetroidPrime/ScriptObjects/CScriptSteam.hpp new file mode 100644 index 00000000..90cf62b2 --- /dev/null +++ b/include/MetroidPrime/ScriptObjects/CScriptSteam.hpp @@ -0,0 +1,11 @@ +#ifndef _CSCRIPTSTEAM +#define _CSCRIPTSTEAM + +#include "MetroidPrime/ScriptObjects/CScriptTrigger.hpp" + +class CScriptSteam : public CScriptTrigger { + public: +}; + + +#endif // _CSCRIPTSTEAM diff --git a/include/MetroidPrime/ScriptObjects/CScriptTrigger.hpp b/include/MetroidPrime/ScriptObjects/CScriptTrigger.hpp new file mode 100644 index 00000000..496052d1 --- /dev/null +++ b/include/MetroidPrime/ScriptObjects/CScriptTrigger.hpp @@ -0,0 +1,78 @@ +#ifndef _CSCRIPTTRIGGER +#define _CSCRIPTTRIGGER + +#include "MetroidPrime/CActor.hpp" + +#include "MetroidPrime/CDamageInfo.hpp" + +#include "rstl/list.hpp" + +enum ETriggerFlags { + kTFL_None = 0, + kTFL_DetectPlayer = (1 << 0), + kTFL_DetectAI = (1 << 1), + kTFL_DetectProjectiles1 = (1 << 2), + kTFL_DetectProjectiles2 = (1 << 3), + kTFL_DetectProjectiles3 = (1 << 4), + kTFL_DetectProjectiles4 = (1 << 5), + kTFL_DetectBombs = (1 << 6), + kTFL_DetectPowerBombs = (1 << 7), + kTFL_DetectProjectiles5 = (1 << 8), + kTFL_DetectProjectiles6 = (1 << 9), + kTFL_DetectProjectiles7 = (1 << 10), + kTFL_KillOnEnter = (1 << 11), + kTFL_DetectMorphedPlayer = (1 << 12), + kTFL_UseCollisionImpulses = (1 << 13), + kTFL_DetectCamera = (1 << 14), + kTFL_UseBooleanIntersection = (1 << 15), + kTFL_DetectUnmorphedPlayer = (1 << 16), + kTFL_BlockEnvironmentalEffects = (1 << 17) +}; + +class CScriptTrigger : public CActor { +public: + class CObjectTracker { + TUniqueId x0_id; + + public: + explicit CObjectTracker(TUniqueId id) : x0_id(id) {} + + TUniqueId GetObjectId() const { return x0_id; } + bool operator==(const CObjectTracker& other) const { return x0_id == other.x0_id; } + }; + + rstl::list< CObjectTracker > xe8_inhabitants; + CDamageInfo x100_damageInfo; + CVector3f x11c_forceField; + float x128_forceMagnitude; + uint x12c_flags; + CAABox x130_bounds; + bool x148_24_detectCamera : 1; + bool x148_25_camSubmerged : 1; + bool x148_26_deactivateOnEntered : 1; + bool x148_27_deactivateOnExited : 1; + bool x148_28_playerTriggerProc : 1; + bool x148_29_didPhazonDamage : 1; + +public: + CScriptTrigger(TUniqueId, const rstl::string& name, const CEntityInfo& info, const CVector3f& pos, + const CAABox&, const CDamageInfo& dInfo, const CVector3f& orientedForce, + uint triggerFlags, bool active, bool deactivateOnEntered, bool deactivateOnExited); + ~CScriptTrigger(); + + void Touch(CActor&, CStateManager&); + CAABox GetTriggerBoundsWR() const; + rstl::optional_object GetTouchBounds() const override; + void AcceptScriptMsg(EScriptObjectMessage, TUniqueId, CStateManager&) override; + void Think(float, CStateManager&) override; + void UpdateInhabitants(float, CStateManager&); + const rstl::list& GetInhabitants() const; + const CScriptTrigger::CObjectTracker* FindObject(TUniqueId); + void Accept(IVisitor& visitor) override; + virtual void InhabitantAdded(CActor&, CStateManager&); + virtual void InhabitantIdle(CActor&, CStateManager&); + virtual void InhabitantExited(CActor&, CStateManager&); + virtual void InhabitantRejected(CActor&, CStateManager&); +}; + +#endif // _CSCRIPTTRIGGER diff --git a/include/MetroidPrime/Weapons/CWeapon.hpp b/include/MetroidPrime/Weapons/CWeapon.hpp index 5f078950..6d4bc911 100644 --- a/include/MetroidPrime/Weapons/CWeapon.hpp +++ b/include/MetroidPrime/Weapons/CWeapon.hpp @@ -22,6 +22,8 @@ public: int /*EProjectileAttrib?*/) const override; void FluidFXThink(EFluidState, CScriptWater&, CStateManager&) override; + EProjectileAttrib GetAttribField() const { return xe8_projectileAttribs; } + private: EProjectileAttrib xe8_projectileAttribs; TUniqueId xec_ownerId; diff --git a/include/rstl/list.hpp b/include/rstl/list.hpp index 4a48435f..d12c79dd 100644 --- a/include/rstl/list.hpp +++ b/include/rstl/list.hpp @@ -68,6 +68,7 @@ private: void set_prev(node* prev) { x0_prev = prev; } void set_next(node* next) { x4_next = next; } T* get_value() { return reinterpret_cast< T* >(&x8_item); } + const T* get_value() const { return reinterpret_cast< const T* >(&x8_item); } }; node* create_node(node* prev, node* next, const T& val) { @@ -103,9 +104,9 @@ public: return *this; } const_iterator operator--(int) const { return const_iterator(this->current->x0_prev); } - const T* get_pointer() const { return current->x8_item; } - const T& operator*() const { return *current->x8_item; } - const T* operator->() const { return current->x8_item; } + const T* get_pointer() const { return current->get_value(); } + const T& operator*() const { return *current->get_value(); } + const T* operator->() const { return current->get_value(); } bool operator==(const const_iterator& other) const { return current == other.current; } bool operator!=(const const_iterator& other) const { return current != other.current; } diff --git a/include/rstl/optional_object.hpp b/include/rstl/optional_object.hpp index 06abc8aa..429271e0 100644 --- a/include/rstl/optional_object.hpp +++ b/include/rstl/optional_object.hpp @@ -51,6 +51,9 @@ public: T& operator*() { return data(); } T* operator->() { return &data(); } + + const T& operator*() const { return data(); } + const T* operator->() const { return &data(); } private: uchar m_data[sizeof(T)]; diff --git a/src/MetroidPrime/ScriptObjects/CScriptSteam.cpp b/src/MetroidPrime/ScriptObjects/CScriptSteam.cpp new file mode 100644 index 00000000..8b177251 --- /dev/null +++ b/src/MetroidPrime/ScriptObjects/CScriptSteam.cpp @@ -0,0 +1 @@ +#include "MetroidPrime/ScriptObjects/CScriptSteam.hpp" diff --git a/src/MetroidPrime/ScriptObjects/CScriptTrigger.cpp b/src/MetroidPrime/ScriptObjects/CScriptTrigger.cpp new file mode 100644 index 00000000..da32a8d7 --- /dev/null +++ b/src/MetroidPrime/ScriptObjects/CScriptTrigger.cpp @@ -0,0 +1,352 @@ +#include "MetroidPrime/ScriptObjects/CScriptTrigger.hpp" + +#include "MetroidPrime/CActorParameters.hpp" +#include "MetroidPrime/CDamageVulnerability.hpp" +#include "MetroidPrime/CStateManager.hpp" +#include "MetroidPrime/Player/CPlayer.hpp" +#include "MetroidPrime/Weapons/CWeapon.hpp" +#include "MetroidPrime/Cameras/CCameraManager.hpp" +#include "MetroidPrime/Cameras/CGameCamera.hpp" + +CScriptTrigger::CScriptTrigger(TUniqueId uid, const rstl::string& name, const CEntityInfo& info, + const CVector3f& pos, const CAABox& bounds, const CDamageInfo& dInfo, + const CVector3f& forceField, uint triggerFlags, bool active, + bool deactivateOnEntered, bool deactivateOnExited) +: CActor(uid, active, name, info, CTransform4f::Translate(pos), CModelData::CModelDataNull(), + CMaterialList(kMT_Trigger), CActorParameters::None(), kInvalidUniqueId) +, x100_damageInfo(dInfo) +, x11c_forceField(forceField) +, x128_forceMagnitude(forceField.Magnitude()) +, x12c_flags(triggerFlags) +, x130_bounds(bounds) +, x148_24_detectCamera(false) +, x148_25_camSubmerged(false) +, x148_26_deactivateOnEntered(deactivateOnEntered) +, x148_27_deactivateOnExited(deactivateOnExited) +, x148_28_playerTriggerProc(false) +, x148_29_didPhazonDamage(false) { + SetCallTouch(false); +} + +CScriptTrigger::~CScriptTrigger() { + xe8_inhabitants.clear(); + if (x12c_flags & 0x11000) { + x12c_flags = x12c_flags & 0xfffeefff; + x12c_flags = x12c_flags | 1; + } +} + +void CScriptTrigger::Touch(CActor& act, CStateManager& mgr) { + if (act.GetActive() && !act.GetMaterialList().HasMaterial(kMT_Trigger)) { + if (FindObject(act.GetUniqueId()) == nullptr) { + uint testFlags = kTFL_None; + CPlayer* pl = TCastToPtr< CPlayer >(act); + if (pl) { + if (x128_forceMagnitude > 0.f && (x12c_flags & kTFL_DetectPlayer != 0)) { + if (mgr.GetLastTriggerId() != kInvalidUniqueId) { + return; + } + mgr.SetLastTriggerId(GetUniqueId()); + } + + testFlags |= kTFL_DetectPlayer; + if (pl->GetMorphballTransitionState() == CPlayer::kMS_Unmorphed) { + testFlags |= kTFL_DetectUnmorphedPlayer; + } + if (pl->GetMorphballTransitionState() == CPlayer::kMS_Morphed) { + testFlags |= kTFL_DetectMorphedPlayer; + } + } + if (TCastToPtr< CPatterned >(act)) { + testFlags |= kTFL_DetectAI; + } + if (TCastToPtr< CGameProjectile >(act)) { + testFlags |= kTFL_DetectProjectiles1 | kTFL_DetectProjectiles2 | kTFL_DetectProjectiles3 | + kTFL_DetectProjectiles4 | kTFL_DetectProjectiles5 | kTFL_DetectProjectiles6 | + kTFL_DetectProjectiles7; + } else if (const CWeapon* weap = TCastToConstPtr< CWeapon >(act)) { + if ((weap->GetAttribField() & kPA_Bombs) == kPA_Bombs) { + testFlags |= kTFL_DetectBombs; + } else if ((weap->GetAttribField() & kPA_PowerBombs) == kPA_PowerBombs) { + testFlags |= kTFL_DetectPowerBombs; + } + } + + if (testFlags & x12c_flags) { + xe8_inhabitants.push_back(CObjectTracker(act.GetUniqueId())); + InhabitantAdded(act, mgr); + + if ((testFlags & kTFL_DetectPlayer) && pl) { + if (x148_28_playerTriggerProc != true) { + x148_28_playerTriggerProc = true; + + pl = mgr.Player(); + if (x148_29_didPhazonDamage) { + pl->DecrementPhazon(); + x148_29_didPhazonDamage = false; + } + if (!x100_damageInfo.HasNoDamage()) { + const CDamageVulnerability* dVuln = pl->GetDamageVulnerability(); + bool phazonHurt = dVuln->WeaponHurts(x100_damageInfo.GetWeaponMode(), false); + if (x100_damageInfo.GetWeaponMode().GetType() == kWT_Phazon) { + if (mgr.GetPlayerState()->HasPowerUp(CPlayerState::kIT_PhazonSuit)) { + phazonHurt = false; + } + } + if (phazonHurt) { + pl->IncrementPhazon(); + x148_29_didPhazonDamage = true; + } + } + } + } + + SendScriptMsgs(kSS_Entered, mgr, kSM_None); + + if (x148_26_deactivateOnEntered) { + mgr.SendScriptMsg(GetUniqueId(), mgr.GetEditorIdForUniqueId(GetUniqueId()), + kSM_Deactivate, kSS_Entered); + if (act.HealthInfo(mgr) && x100_damageInfo.GetDamage() > 0.f) { + mgr.ApplyDamage(GetUniqueId(), act.GetUniqueId(), GetUniqueId(), x100_damageInfo, + CMaterialFilter::MakeIncludeExclude(SolidMaterial, CMaterialList(0)), + CVector3f::Zero()); + } + } + + if (x12c_flags & kTFL_KillOnEnter) { + CHealthInfo* hInfo = act.HealthInfo(mgr); + if (hInfo) { + static CWeaponMode sktonOHurtWeaponMode(kWT_Power, false, false, true); + CDamageInfo dmg(sktonOHurtWeaponMode, 10.f * hInfo->GetHP(), 0.f, 0.f); + + mgr.ApplyDamage(GetUniqueId(), act.GetUniqueId(), GetUniqueId(), dmg, + CMaterialFilter::MakeIncludeExclude(SolidMaterial, CMaterialList(0)), + CVector3f::Zero()); + } + } + } else { + InhabitantRejected(act, mgr); + } + } + } +} + +CAABox CScriptTrigger::GetTriggerBoundsWR() const { + return CAABox(x130_bounds.GetMinPoint() + x34_transform.GetTranslation(), + x130_bounds.GetMaxPoint() + x34_transform.GetTranslation()); +} + +rstl::optional_object< CAABox > CScriptTrigger::GetTouchBounds() const override { + if (x30_24_active) { + return GetTriggerBoundsWR(); + } + return rstl::optional_object_null(); +} + +void CScriptTrigger::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, + CStateManager& mgr) override { + if (GetActive()) { + if (msg == kSM_Deactivate) { + xe8_inhabitants.clear(); + x148_25_camSubmerged = false; + + if (x148_28_playerTriggerProc) { + x148_28_playerTriggerProc = false; + + CPlayer* player = mgr.Player(); + if (x148_29_didPhazonDamage) { + player->DecrementPhazon(); + x148_29_didPhazonDamage = false; + } + + if (x8_uid == mgr.GetLastTriggerId()) { + mgr.SetLastTriggerId(kInvalidUniqueId); + } + } + + } else if (msg == kSM_Deleted) { + if (x148_28_playerTriggerProc) { + x148_28_playerTriggerProc = false; + + CPlayer* player = mgr.Player(); + if (x148_29_didPhazonDamage) { + player->DecrementPhazon(); + x148_29_didPhazonDamage = false; + } + + if (x8_uid == mgr.GetLastTriggerId()) { + mgr.SetLastTriggerId(kInvalidUniqueId); + } + } + } + } + + CActor::AcceptScriptMsg(msg, uid, mgr); +} + +void CScriptTrigger::Think(float dt, CStateManager& mgr) override { + if (GetActive()) { + UpdateInhabitants(dt, mgr); + } +} + +void CScriptTrigger::UpdateInhabitants(float dt, CStateManager& mgr) { + bool sendInside = false; + bool sendExited = false; + rstl::list::iterator nextIt; + for (rstl::list::iterator it = xe8_inhabitants.begin(); it != xe8_inhabitants.end(); it = nextIt) { + nextIt = it; + ++nextIt; + if (CActor* act = TCastToPtr(mgr.ObjectById(it->GetObjectId()))) { + bool playerValid = true; + if (it->GetObjectId() == mgr.GetPlayer()->GetUniqueId()) { + if ((x12c_flags & kTFL_DetectPlayer == 0) && + ((mgr.GetPlayer()->GetMorphballTransitionState() == CPlayer::kMS_Morphed && + (x12c_flags & kTFL_DetectUnmorphedPlayer)) || + (mgr.GetPlayer()->GetMorphballTransitionState() == CPlayer::kMS_Unmorphed && + (x12c_flags & kTFL_DetectMorphedPlayer)))) { + playerValid = false; + } + if (!playerValid) { + xe8_inhabitants.erase(it); + sendExited = true; + if (x148_28_playerTriggerProc) { + x148_28_playerTriggerProc = false; + if (x148_29_didPhazonDamage) { + mgr.Player()->DecrementPhazon(); + x148_29_didPhazonDamage = false; + } + + if (mgr.GetLastTriggerId() == GetUniqueId()) { + mgr.SetLastTriggerId(kInvalidUniqueId); + } + } + + InhabitantExited(*act, mgr); + continue; + } + } + + rstl::optional_object< CAABox > touchBounds = GetTouchBounds(); + rstl::optional_object< CAABox > actTouchBounds = act->GetTouchBounds(); + if (touchBounds.valid() && actTouchBounds.valid() && touchBounds->DoBoundsOverlap(*actTouchBounds)) { + sendInside = true; + InhabitantIdle(*act, mgr); + if (act->HealthInfo(mgr) && x100_damageInfo.GetDamage() > 0.f) { + // mgr.ApplyDamage(GetUniqueId(), act->GetUniqueId(), GetUniqueId(), {x100_damageInfo, dt}, + // CMaterialFilter::MakeIncludeExclude({EMaterialTypes::Solid}, {}), zeus::skZero3f); + } + + if (x128_forceMagnitude > 0.f) { + if (CPhysicsActor* pact = TCastToPtr(act)) { + float forceMult = 1.f; + if ((x12c_flags & kTFL_UseBooleanIntersection)) { + forceMult = touchBounds->GetBooleanIntersection(*actTouchBounds).GetVolume() / actTouchBounds->GetVolume(); + } + + const CVector3f force = forceMult * x11c_forceField; + if ((x12c_flags & kTFL_UseCollisionImpulses)) { + pact->ApplyImpulseWR(force, CAxisAngle()); + pact->UseCollisionImpulses(); + } else { + pact->ApplyForceWR(force, CAxisAngle()); + } + } + } + } else { + const TUniqueId tmpId = it->GetObjectId(); + xe8_inhabitants.erase(it); + sendExited = true; + if (mgr.GetPlayer()->GetUniqueId() == tmpId && x148_28_playerTriggerProc) { + x148_28_playerTriggerProc = false; + if (x148_29_didPhazonDamage) { + mgr.Player()->DecrementPhazon(); + x148_29_didPhazonDamage = false; + } + + if (mgr.GetLastTriggerId() == GetUniqueId()) + mgr.SetLastTriggerId(kInvalidUniqueId); + } + + InhabitantExited(*act, mgr); + } + } else { + const TUniqueId tmpId = it->GetObjectId(); + xe8_inhabitants.erase(it); + if (mgr.GetPlayer()->GetUniqueId() == tmpId && x148_28_playerTriggerProc) { + x148_28_playerTriggerProc = false; + if (x148_29_didPhazonDamage) { + mgr.Player()->DecrementPhazon(); + x148_29_didPhazonDamage = false; + } + + if (mgr.GetLastTriggerId() == GetUniqueId()) { + mgr.SetLastTriggerId(kInvalidUniqueId); + } + } + } + } + + if ((x12c_flags & kTFL_DetectCamera) || x148_24_detectCamera) { + CGameCamera* cam = mgr.GetCameraManager()->GetCurrentCamera(mgr); + const bool camInTrigger = GetTriggerBoundsWR().PointInside(cam->GetTranslation()); + if (x148_25_camSubmerged) { + if (!camInTrigger) { + x148_25_camSubmerged = false; + if ((x12c_flags & kTFL_DetectCamera)) { + sendExited = true; + InhabitantExited(*cam, mgr); + } + } else { + if ((x12c_flags & kTFL_DetectCamera)) { + InhabitantIdle(*cam, mgr); + sendInside = true; + } + } + } else { + if (camInTrigger) { + x148_25_camSubmerged = true; + if ((x12c_flags & kTFL_DetectCamera)) { + InhabitantAdded(*cam, mgr); + SendScriptMsgs(kSS_Entered, mgr, kSM_None); + } + } + } + } + + if (sendInside) { + SendScriptMsgs(kSS_Inside, mgr, kSM_None); + } + + if (sendExited) { + SendScriptMsgs(kSS_Exited, mgr, kSM_None); + if (x148_27_deactivateOnExited) { + mgr.SendScriptMsg(GetUniqueId(), mgr.GetEditorIdForUniqueId(GetUniqueId()), kSM_Deactivate, + kSS_Exited); + } + } +} + +const rstl::list< CScriptTrigger::CObjectTracker >& CScriptTrigger::GetInhabitants() const { + return xe8_inhabitants; +} + +const CScriptTrigger::CObjectTracker* CScriptTrigger::FindObject(TUniqueId id) { + for (rstl::list< CScriptTrigger::CObjectTracker >::const_iterator it = GetInhabitants().begin(); + it != GetInhabitants().end(); ++it) { + if (it->GetObjectId() == id) { + return &*it; + } + } + return nullptr; +} + +void CScriptTrigger::Accept(IVisitor& visitor) override { visitor.Visit(*this); } + +void CScriptTrigger::InhabitantAdded(CActor&, CStateManager&) {} + +void CScriptTrigger::InhabitantIdle(CActor&, CStateManager&) {} + +void CScriptTrigger::InhabitantExited(CActor&, CStateManager&) {} + +void CScriptTrigger::InhabitantRejected(CActor&, CStateManager&) {}