diff --git a/configure.py b/configure.py index a4ca0e00..be45f554 100755 --- a/configure.py +++ b/configure.py @@ -264,7 +264,7 @@ LIBS = [ "MetroidPrime/Player/CPlayerEnergyDrain", "MetroidPrime/CFlameWarp", "MetroidPrime/Weapons/CIceImpact", - "MetroidPrime/GameObjectLists", + ["MetroidPrime/GameObjectLists", True], "MetroidPrime/Weapons/CAuxWeapon", "MetroidPrime/Weapons/CGunWeapon", "MetroidPrime/ScriptObjects/CScriptAreaAttributes", diff --git a/include/MetroidPrime/CObjectList.hpp b/include/MetroidPrime/CObjectList.hpp index f6d03166..f713d699 100644 --- a/include/MetroidPrime/CObjectList.hpp +++ b/include/MetroidPrime/CObjectList.hpp @@ -31,7 +31,7 @@ class CObjectList { public: CObjectList(EGameObjectList list); - virtual bool IsQualified(const CEntity& ent); + virtual uchar IsQualified(const CEntity& ent); void AddObject(CEntity& ent); void RemoveObject(TUniqueId uid); diff --git a/include/MetroidPrime/Enemies/CAi.hpp b/include/MetroidPrime/Enemies/CAi.hpp new file mode 100644 index 00000000..25260e6f --- /dev/null +++ b/include/MetroidPrime/Enemies/CAi.hpp @@ -0,0 +1,170 @@ +#ifndef _CAI +#define _CAI + +#include "MetroidPrime/CPhysicsActor.hpp" +#include "MetroidPrime/Enemies/CAiFuncMap.hpp" +#include "MetroidPrime/Enemies/CKnockBackController.hpp" + +enum EListenNoiseType { + kLNT_PlayerFire, + kLNT_BombExplode, + kLNT_ProjectileExplode, +}; + +class CTeamAiRole; +class CAiFuncMap; +class CAi : public CPhysicsActor { +public: + // static void CreateFuncLookup(CAiFuncMap* funcMap); + // static CAiStateFunc GetStateFunc(std::string_view func); + // static CAiTriggerFunc GetTriggerFunc(std::string_view func); + + // const CStateMachine* GetStateMachine() const; + ~CAi(); + void AcceptScriptMsg(EScriptObjectMessage, TUniqueId, CStateManager&) override; + CHealthInfo* HealthInfo(CStateManager&) override; + const CDamageVulnerability* GetDamageVulnerability() const override { return nullptr; } + EWeaponCollisionResponseTypes GetCollisionResponseType(const CVector3f&, const CVector3f&, + const CWeaponMode&, + EProjectileAttrib) const override; + void FluidFXThink(EFluidState, CScriptWater&, CStateManager&) override; + ; + + virtual void Death(CStateManager& mgr, const CVector3f& direction, EScriptObjectState state) = 0; + virtual void KnockBack(const CVector3f&, CStateManager&, const CDamageInfo& info, + EKnockBackType type, bool inDeferred, float magnitude) = 0; + virtual CDamageVulnerability* GetDamageVulnerability(); + virtual void TakeDamage(const CVector3f& direction, float magnitude); + virtual bool CanBeShot(const CStateManager&, int); + virtual bool IsListening() const; + virtual bool Listen(const CVector3f&, EListenNoiseType); + + virtual CVector3f GetOrigin(const CStateManager& mgr, const CTeamAiRole& role, + const CVector3f& aimPos) const; + virtual void Patrol(CStateManager&, EStateMsg, float); + virtual void FollowPattern(CStateManager&, EStateMsg, float); + virtual void Dead(CStateManager&, EStateMsg, float); + virtual void PathFind(CStateManager&, EStateMsg, float); + virtual void Start(CStateManager&, EStateMsg, float); + virtual void SelectTarget(CStateManager&, EStateMsg, float); + virtual void TargetPatrol(CStateManager&, EStateMsg, float); + virtual void TargetPlayer(CStateManager&, EStateMsg, float); + virtual void TargetCover(CStateManager&, EStateMsg, float); + virtual void Halt(CStateManager&, EStateMsg, float); + virtual void Walk(CStateManager&, EStateMsg, float); + virtual void Run(CStateManager&, EStateMsg, float); + virtual void Generate(CStateManager&, EStateMsg, float); + virtual void Deactivate(CStateManager&, EStateMsg, float); + virtual void Attack(CStateManager&, EStateMsg, float); + virtual void LoopedAttack(CStateManager&, EStateMsg, float); + virtual void JumpBack(CStateManager&, EStateMsg, float); + virtual void DoubleSnap(CStateManager&, EStateMsg, float); + virtual void Shuffle(CStateManager&, EStateMsg, float); + virtual void TurnAround(CStateManager&, EStateMsg, float); + virtual void Skid(CStateManager&, EStateMsg, float); + virtual void Active(CStateManager&, EStateMsg, float); + virtual void InActive(CStateManager&, EStateMsg, float); + virtual void CoverAttack(CStateManager&, EStateMsg, float); + virtual void Crouch(CStateManager&, EStateMsg, float); + virtual void FadeIn(CStateManager&, EStateMsg, float); + virtual void FadeOut(CStateManager&, EStateMsg, float); + virtual void GetUp(CStateManager&, EStateMsg, float); + virtual void Taunt(CStateManager&, EStateMsg, float); + virtual void Suck(CStateManager&, EStateMsg, float); + virtual void Flee(CStateManager&, EStateMsg, float); + virtual void Lurk(CStateManager&, EStateMsg, float); + virtual void ProjectileAttack(CStateManager&, EStateMsg, float); + virtual void Flinch(CStateManager&, EStateMsg, float); + virtual void Hurled(CStateManager&, EStateMsg, float); + virtual void TelegraphAttack(CStateManager&, EStateMsg, float); + virtual void Jump(CStateManager&, EStateMsg, float); + virtual void Explode(CStateManager&, EStateMsg, float); + virtual void Dodge(CStateManager&, EStateMsg, float); + virtual void Retreat(CStateManager&, EStateMsg, float); + virtual void Cover(CStateManager&, EStateMsg, float); + virtual void Approach(CStateManager&, EStateMsg, float); + virtual void WallHang(CStateManager&, EStateMsg, float); + virtual void WallDetach(CStateManager&, EStateMsg, float); + virtual void Enraged(CStateManager&, EStateMsg, float); + virtual void SpecialAttack(CStateManager&, EStateMsg, float); + virtual void Growth(CStateManager&, EStateMsg, float); + virtual void Faint(CStateManager&, EStateMsg, float); + virtual void Land(CStateManager&, EStateMsg, float); + virtual void Bounce(CStateManager&, EStateMsg, float); + virtual void PathFindEx(CStateManager&, EStateMsg, float); + virtual void Dizzy(CStateManager&, EStateMsg, float); + virtual void CallForBackup(CStateManager&, EStateMsg, float); + virtual void BulbAttack(CStateManager&, EStateMsg, float); + virtual void PodAttack(CStateManager&, EStateMsg, float); + + virtual bool InAttackPosition(CStateManager&, float); + virtual bool Leash(CStateManager&, float); + virtual bool OffLine(CStateManager&, float); + virtual bool Attacked(CStateManager&, float); + virtual bool PathShagged(CStateManager&, float); + virtual bool PathOver(CStateManager&, float); + virtual bool PathFound(CStateManager&, float); + virtual bool TooClose(CStateManager&, float); + virtual bool InRange(CStateManager&, float); + virtual bool InMaxRange(CStateManager&, float); + virtual bool InDetectionRange(CStateManager&, float); + virtual bool SpotPlayer(CStateManager&, float); + virtual bool PlayerSpot(CStateManager&, float); + virtual bool PatternOver(CStateManager&, float); + virtual bool PatternShagged(CStateManager&, float); + virtual bool HasAttackPattern(CStateManager&, float); + virtual bool HasPatrolPath(CStateManager&, float); + virtual bool HasRetreatPattern(CStateManager&, float); + virtual bool Delay(CStateManager&, float); + virtual bool RandomDelay(CStateManager&, float); + virtual bool FixedDelay(CStateManager&, float); + virtual bool Default(CStateManager&, float); + virtual bool AnimOver(CStateManager&, float); + virtual bool ShouldAttack(CStateManager&, float); + virtual bool ShouldDoubleSnap(CStateManager&, float); + virtual bool InPosition(CStateManager&, float); + virtual bool ShouldTurn(CStateManager&, float); + virtual bool HitSomething(CStateManager&, float); + virtual bool ShouldJumpBack(CStateManager&, float); + virtual bool Stuck(CStateManager&, float); + virtual bool NoPathNodes(CStateManager&, float); + virtual bool Landed(CStateManager&, float); + virtual bool HearShot(CStateManager&, float); + virtual bool HearPlayer(CStateManager&, float); + virtual bool CoverCheck(CStateManager&, float); + virtual bool CoverFind(CStateManager&, float); + virtual bool CoverBlown(CStateManager&, float); + virtual bool CoverNearlyBlown(CStateManager&, float); + virtual bool CoveringFire(CStateManager&, float); + virtual bool GotUp(CStateManager&, float); + virtual bool LineOfSight(CStateManager&, float); + virtual bool AggressionCheck(CStateManager&, float); + virtual bool AttackOver(CStateManager&, float); + virtual bool ShouldTaunt(CStateManager&, float); + virtual bool Inside(CStateManager&, float); + virtual bool ShouldFire(CStateManager&, float); + virtual bool ShouldFlinch(CStateManager&, float); + virtual bool PatrolPathOver(CStateManager&, float); + virtual bool ShouldDodge(CStateManager&, float); + virtual bool ShouldRetreat(CStateManager&, float); + virtual bool ShouldCrouch(CStateManager&, float); + virtual bool ShouldMove(CStateManager&, float); + virtual bool ShotAt(CStateManager&, float); + virtual bool HasTargetingPoint(CStateManager&, float); + virtual bool ShouldWallHang(CStateManager&, float); + virtual bool SetAIStage(CStateManager&, float); + virtual bool AIStage(CStateManager&, float); + virtual bool StartAttack(CStateManager&, float); + virtual bool BreakAttack(CStateManager&, float); + virtual bool ShouldStrafe(CStateManager&, float); + virtual bool ShouldSpecialAttack(CStateManager&, float); + virtual bool LostInterest(CStateManager&, float); + virtual bool CodeTrigger(CStateManager&, float); + virtual bool BounceFind(CStateManager&, float); + virtual bool Random(CStateManager&, float); + virtual bool FixedRandom(CStateManager&, float); + virtual bool IsDizzy(CStateManager&, float); + virtual bool ShouldCallForBackup(CStateManager&, float); +}; + +#endif // _CAI diff --git a/include/MetroidPrime/Enemies/CAiFuncMap.hpp b/include/MetroidPrime/Enemies/CAiFuncMap.hpp index cf4fb957..dfff8700 100644 --- a/include/MetroidPrime/Enemies/CAiFuncMap.hpp +++ b/include/MetroidPrime/Enemies/CAiFuncMap.hpp @@ -3,6 +3,12 @@ #include "types.h" +enum EStateMsg { + kStateMsg_Activate = 0, + kStateMsg_Update = 1, + kStateMsg_Deactivate = 2, +}; + class CAiFuncMap { public: CAiFuncMap(); diff --git a/include/MetroidPrime/Enemies/CKnockBackController.hpp b/include/MetroidPrime/Enemies/CKnockBackController.hpp new file mode 100644 index 00000000..7776d1a4 --- /dev/null +++ b/include/MetroidPrime/Enemies/CKnockBackController.hpp @@ -0,0 +1,148 @@ +#ifndef _CKNOCKBACKCONTROLLER +#define _CKNOCKBACKCONTROLLER + +class CDamageInfo; +class CPatterned; + +enum EKnockBackType { + kKBT_Radius, + kKBT_Direct, +}; +/* +enum class EKnockBackVariant { Small, Medium, Large }; + +enum class EKnockBackWeaponType { + Invalid = -1, + Power, + PowerCharged, + PowerComboed, + PowerComboedDirect, + Wave, + WaveCharged, + WaveComboed, + WaveComboedDirect, + Ice, + IceCharged, + IceComboed, + IceComboedDirect, + Plasma, + PlasmaCharged, + PlasmaComboed, + Missile, + Bomb, + PowerBomb, + Phazon +}; + +enum class EKnockBackCharacterState { Alive, Dead, FrozenAlive, FrozenDead }; + +enum class EKnockBackAnimationState { Invalid = -1, None, Flinch, KnockBack, Hurled, Fall }; + +enum class EKnockBackAnimationFollowUp { + Invalid = -1, + None, + Freeze, + Shock, + Burn, + PhazeOut, + Death, + ExplodeDeath, + IceDeath, + BurnDeath, + LaggedBurnDeath +}; + +class CKnockBackController { +public: + struct KnockBackParms { + EKnockBackAnimationState x0_animState = EKnockBackAnimationState::None; + EKnockBackAnimationFollowUp x4_animFollowup = EKnockBackAnimationFollowUp::None; + float x8_followupDuration = 0.f; + float xc_intoFreezeDur = 0.f; + }; + +private: + friend class CPatterned; + EKnockBackVariant x0_variant; + KnockBackParms x4_activeParms{}; + EWeaponType x14_deferWeaponType = EWeaponType::None; + EKnockBackAnimationState x18_minAnimState = EKnockBackAnimationState::None; + EKnockBackAnimationState x1c_maxAnimState = EKnockBackAnimationState::Fall; + u32 x20_impulseDurationIdx = 0; + rstl::reserved_vector< std::pair< float, float >, 5 > x24_; + zeus::CVector3f x50_impulseDir; + float x5c_impulseMag = 0.f; + float x60_impulseRemTime = 0.f; + float x64_flinchRemTime = 0.f; + float x68_deferRemTime = 0.f; + u32 x6c_ = 0; + u32 x70_ = 0; + u32 x74_ = 0; + pas::ESeverity x7c_severity = pas::ESeverity::One; + std::bitset< 5 > x80_availableStates{0b11111}; + bool x81_24_autoResetImpulse : 1 = true; + bool x81_25_enableFreeze : 1 = true; + bool x81_26_enableShock : 1 = false; + bool x81_27_enableBurn : 1 = true; + bool x81_28_enableBurnDeath : 1 = true; + bool x81_29_enableExplodeDeath : 1 = true; + bool x81_30_enableLaggedBurnDeath : 1 = true; + bool x81_31_ : 1 = true; + bool x82_24_ : 1 = true; + bool x82_25_inDeferredKnockBack : 1 = false; + bool x82_26_locomotionDuringElectrocution : 1 = false; + void ApplyImpulse(float dt, CPatterned& parent); + bool TickDeferredTimer(float dt); + EKnockBackCharacterState GetKnockBackCharacterState(const CPatterned& parent) const; + void ValidateState(const CPatterned& parent); + float CalculateExtraHurlVelocity(CStateManager& mgr, float magnitude, float kbResistance) const; + void DoKnockBackAnimation(const zeus::CVector3f& backVec, CStateManager& mgr, CPatterned& parent, + float magnitude); + void ResetKnockBackImpulse(const CPatterned& parent, const zeus::CVector3f& backVec, + float magnitude); + void DoDeferredKnockBack(CStateManager& mgr, CPatterned& parent); + EKnockBackWeaponType GetKnockBackWeaponType(const CDamageInfo& info, EWeaponType wType, + EKnockBackType type); + void SelectDamageState(const CPatterned& parent, const CDamageInfo& info, EWeaponType wType, + EKnockBackType type); + +public: + explicit CKnockBackController(EKnockBackVariant variant); + void SetKnockBackVariant(EKnockBackVariant v) { x0_variant = v; } + void DeferKnockBack(EWeaponType tp) { + x14_deferWeaponType = tp; + x68_deferRemTime = 0.05f; + } + void sub80233d40(int i, float f1, float f2); + void SetAutoResetImpulse(bool b); + void SetImpulseDurationIdx(u32 i) { x20_impulseDurationIdx = i; } + void SetAnimationStateRange(EKnockBackAnimationState a, EKnockBackAnimationState b) { + x18_minAnimState = a; + x1c_maxAnimState = b; + } + void Update(float dt, CStateManager& mgr, CPatterned& parent); + void KnockBack(const zeus::CVector3f& backVec, CStateManager& mgr, CPatterned& parent, + const CDamageInfo& info, EKnockBackType type, float magnitude); + void SetSeverity(pas::ESeverity v) { x7c_severity = v; } + void SetEnableFreeze(bool b) { x81_25_enableFreeze = b; } + bool GetEnableFreeze() const { return x81_25_enableFreeze; } + void SetEnableShock(bool b) { x81_26_enableShock = b; } + void SetEnableBurn(bool b) { x81_27_enableBurn = b; } + void SetEnableBurnDeath(bool b) { x81_28_enableBurnDeath = b; } + void SetEnableExplodeDeath(bool b) { x81_29_enableExplodeDeath = b; } + void SetEnableLaggedBurnDeath(bool b) { x81_30_enableLaggedBurnDeath = b; } + void SetX81_31(bool b) { x81_31_ = b; } + void SetX82_24(bool b) { x82_24_ = b; } + void SetLocomotionDuringElectrocution(bool b) { x82_26_locomotionDuringElectrocution = b; } + const KnockBackParms& GetActiveParms() const { return x4_activeParms; } + EKnockBackVariant GetVariant() const { return x0_variant; } + float GetFlinchRemTime() const { return x64_flinchRemTime; } + void SetAvailableState(EKnockBackAnimationState s, bool b) { + x80_availableStates.set(size_t(s), b); + } + bool TestAvailableState(EKnockBackAnimationState s) const { + return x80_availableStates.test(size_t(s)); + } +}; +*/ +#endif // _CKNOCKBACKCONTROLLER diff --git a/include/MetroidPrime/Enemies/CPatterned.hpp b/include/MetroidPrime/Enemies/CPatterned.hpp new file mode 100644 index 00000000..02845ad8 --- /dev/null +++ b/include/MetroidPrime/Enemies/CPatterned.hpp @@ -0,0 +1,15 @@ +#ifndef _CPATTERNED +#define _CPATTERNED + +#include "MetroidPrime/Enemies/CAi.hpp" + +class CPatterned : public CAi { +public: + ~CPatterned(); + void Accept(IVisitor& visitor); + void Death(CStateManager& mgr, const CVector3f& direction, EScriptObjectState state) {} + void KnockBack(const CVector3f&, CStateManager&, const CDamageInfo& info, EKnockBackType type, + bool inDeferred, float magnitude) {}; +}; + +#endif // _CPATTERNED diff --git a/include/MetroidPrime/GameObjectLists.hpp b/include/MetroidPrime/GameObjectLists.hpp new file mode 100644 index 00000000..c08b176c --- /dev/null +++ b/include/MetroidPrime/GameObjectLists.hpp @@ -0,0 +1,51 @@ +#ifndef _GAMEOBJECTLISTS +#define _GAMEOBJECTLISTS + +#include "MetroidPrime/CObjectList.hpp" + +class CActorList final : public CObjectList { +public: + CActorList(); + uchar IsQualified(const CEntity& ent) override; +}; + +class CPhysicsActorList final : public CObjectList { +public: + CPhysicsActorList(); + uchar IsQualified(const CEntity& ent) override; +}; + +class CGameCameraList final : public CObjectList { +public: + CGameCameraList(); + uchar IsQualified(const CEntity& ent) override; +}; + +class CListeningAiList final : public CObjectList { +public: + CListeningAiList(); + uchar IsQualified(const CEntity& ent) override; +}; + +class CAiWaypointList final : public CObjectList { +public: + CAiWaypointList(); + uchar IsQualified(const CEntity& ent) override; +}; + +class CPlatformAndDoorList final : public CObjectList { +public: + CPlatformAndDoorList(); + uchar IsQualified(const CEntity& ent) override; + static uchar IsPlatform(const CEntity* ent); + static uchar IsDoor(const CEntity*); +}; + +class CGameLightList : public CObjectList { +public: + CGameLightList(); + uchar IsQualified(const CEntity& ent) override; +}; + + +#endif // _GAMEOBJECTLISTS diff --git a/include/dolphin/types.h b/include/dolphin/types.h index 64bfe0ff..2a32bb54 100644 --- a/include/dolphin/types.h +++ b/include/dolphin/types.h @@ -68,6 +68,9 @@ typedef int BOOL; #ifndef nullptr #define nullptr NULL #endif +#ifndef final +#define final +#endif #ifndef override #define override #endif diff --git a/obj_files.mk b/obj_files.mk index 1573dcc0..0a88e587 100644 --- a/obj_files.mk +++ b/obj_files.mk @@ -231,7 +231,7 @@ METROIDPRIME :=\ $(BUILD_DIR)/asm/MetroidPrime/Player/CPlayerEnergyDrain.o\ $(BUILD_DIR)/asm/MetroidPrime/CFlameWarp.o\ $(BUILD_DIR)/asm/MetroidPrime/Weapons/CIceImpact.o\ - $(BUILD_DIR)/asm/MetroidPrime/GameObjectLists.o\ + $(BUILD_DIR)/src/MetroidPrime/GameObjectLists.o\ $(BUILD_DIR)/asm/MetroidPrime/Weapons/CAuxWeapon.o\ $(BUILD_DIR)/asm/MetroidPrime/Weapons/CGunWeapon.o\ $(BUILD_DIR)/asm/MetroidPrime/ScriptObjects/CScriptAreaAttributes.o\ diff --git a/src/MetroidPrime/CObjectList.cpp b/src/MetroidPrime/CObjectList.cpp index 297d5c90..cd1ce306 100644 --- a/src/MetroidPrime/CObjectList.cpp +++ b/src/MetroidPrime/CObjectList.cpp @@ -8,7 +8,7 @@ CObjectList::CObjectList(EGameObjectList list) : mListType(list), mFirstId(-1), } } -bool CObjectList::IsQualified(const CEntity& ent) { return true; } +uchar CObjectList::IsQualified(const CEntity& ent) { return true; } void CObjectList::AddObject(CEntity& ent) { if (IsQualified(ent)) { diff --git a/src/MetroidPrime/GameObjectLists.cpp b/src/MetroidPrime/GameObjectLists.cpp new file mode 100644 index 00000000..f38dc94d --- /dev/null +++ b/src/MetroidPrime/GameObjectLists.cpp @@ -0,0 +1,71 @@ +#include "MetroidPrime/GameObjectLists.hpp" +#include "MetroidPrime/Enemies/CPatterned.hpp" +#include "MetroidPrime/TCastTo.hpp" + +CActorList::CActorList() : CObjectList(kOL_Actor) {} + +uchar CActorList::IsQualified(const CEntity& ent) { + return TCastToConstPtr< CActor >(ent) != nullptr; +} + +CPhysicsActorList::CPhysicsActorList() : CObjectList(kOL_PhysicsActor) {} + +uchar CPhysicsActorList::IsQualified(const CEntity& ent) { + return TCastToConstPtr< CPhysicsActor >(ent) != nullptr; +} + +CGameCameraList::CGameCameraList() : CObjectList(kOL_GameCamera) {} + +uchar CGameCameraList::IsQualified(const CEntity& ent) { + return TCastToConstPtr< CGameCamera >(ent) != nullptr; +} + +CListeningAiList::CListeningAiList() : CObjectList(kOL_ListeningAi) {} + +uchar CListeningAiList::IsQualified(const CEntity& ent) { + bool ret = false; + const CPatterned* pat = TCastToConstPtr< CPatterned >(ent); + if (pat && pat->IsListening()) { + ret = true; + } + return ret; +} + +CAiWaypointList::CAiWaypointList() : CObjectList(kOL_AiWaypoint) {} + +uchar CAiWaypointList::IsQualified(const CEntity& ent) { + bool ret = false; + if (TCastToConstPtr< CScriptCoverPoint >(ent) != nullptr) { + ret = true; + } else if (TCastToConstPtr< CScriptAiJumpPoint >(ent) != nullptr) { + ret = true; + } + + return ret; +} + +CPlatformAndDoorList::CPlatformAndDoorList() : CObjectList(kOL_PlatformAndDoor) {} + +uchar CPlatformAndDoorList::IsPlatform(const CEntity* ent) { + return TCastToConstPtr< CScriptPlatform >(ent) != nullptr; +} + +uchar CPlatformAndDoorList::IsDoor(const CEntity* ent) { + return TCastToConstPtr< CScriptDoor >(ent) != nullptr; +} + +uchar CPlatformAndDoorList::IsQualified(const CEntity& ent) { + uchar ret = false; + + if (IsPlatform(&ent) || IsDoor(&ent)) { + ret = true; + } + + return ret; +} + + +CGameLightList::CGameLightList() : CObjectList(kOL_GameLight) {} +uchar CGameLightList::IsQualified(const CEntity& ent) { + return TCastToConstPtr< CGameLight >(ent) != nullptr; +}