diff --git a/.clang-format b/.clang-format index 496dd130..3035b7ce 100644 --- a/.clang-format +++ b/.clang-format @@ -1,7 +1,7 @@ --- BasedOnStyle: LLVM IndentWidth: 2 -ColumnLimit: 140 +ColumnLimit: 100 --- Language: Cpp DerivePointerAlignment: false diff --git a/.gitignore b/.gitignore index 17add3f1..268fa3c2 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,6 @@ tools/mwcc_compiler/* !tools/mwcc_compiler/.gitkeep *.bat include/lmgr326b.dll +.idea/ +.vscode/ +versions/ \ No newline at end of file diff --git a/include/Collision/CCollidableAABox.hpp b/include/Collision/CCollidableAABox.hpp new file mode 100644 index 00000000..de27974f --- /dev/null +++ b/include/Collision/CCollidableAABox.hpp @@ -0,0 +1,24 @@ +#ifndef _CCOLLIDABLEAABOX_HPP +#define _CCOLLIDABLEAABOX_HPP + +#include "types.h" + +#include "Collision/CCollisionPrimitive.hpp" + +class CCollidableAABox : public CCollisionPrimitive { +public: + // TODO + + u32 GetTableIndex() const override; + CAABox CalculateAABox(const CTransform4f&) const override; + CAABox CalculateLocalAABox() const override; + FourCC GetPrimType() const override; + ~CCollidableAABox() override; + CRayCastResult CastRayInternal(const CInternalRayCastStructure&) const; + +private: + CAABox x10_aabb; +}; +CHECK_SIZEOF(CCollidableAABox, 0x28) + +#endif \ No newline at end of file diff --git a/include/Collision/CCollisionPrimitive.hpp b/include/Collision/CCollisionPrimitive.hpp new file mode 100644 index 00000000..6cf40329 --- /dev/null +++ b/include/Collision/CCollisionPrimitive.hpp @@ -0,0 +1,36 @@ +#ifndef _CCOLLISIONPRIMITIVE_HPP +#define _CCOLLISIONPRIMITIVE_HPP + +#include "types.h" + +#include "Collision/CMaterialList.hpp" + +#include "Kyoto/IObjectStore.hpp" +#include "Kyoto/Math/CAABox.hpp" +#include "Kyoto/Math/CTransform4f.hpp" + +class CRayCastResult; +class CInternalRayCastStructure; + +class CCollisionPrimitive { +public: + CCollisionPrimitive(const CMaterialList& list); + + virtual u32 GetTableIndex() const = 0; + virtual void SetMaterial(const CMaterialList&); + virtual const CMaterialList& GetMaterial() const; + virtual CAABox CalculateAABox(const CTransform4f&) const = 0; + virtual CAABox CalculateLocalAABox() const = 0; + virtual FourCC GetPrimType() const = 0; + virtual ~CCollisionPrimitive(); + virtual CRayCastResult CastRayInternal(const CInternalRayCastStructure&) const = 0; + +private: + uint x4_; + CMaterialList x8_material; +}; +CHECK_SIZEOF(CCollisionPrimitive, 0x10) + +inline CCollisionPrimitive::~CCollisionPrimitive() {} + +#endif \ No newline at end of file diff --git a/include/Collision/CMaterialList.hpp b/include/Collision/CMaterialList.hpp index 2f92d652..9194f8c4 100644 --- a/include/Collision/CMaterialList.hpp +++ b/include/Collision/CMaterialList.hpp @@ -73,12 +73,33 @@ class CMaterialList { public: CMaterialList() : value(0) {} CMaterialList(const EMaterialTypes& material) : value(0) { value |= u64(1) << material; } - // TODO - CMaterialList(const EMaterialTypes& m1, const EMaterialTypes& m2); - CMaterialList(const EMaterialTypes& m1, const EMaterialTypes& m2, const EMaterialTypes& m3); - CMaterialList(const EMaterialTypes& m1, const EMaterialTypes& m2, const EMaterialTypes& m3, const EMaterialTypes& m4); - CMaterialList(const EMaterialTypes& m1, const EMaterialTypes& m2, const EMaterialTypes& m3, const EMaterialTypes& m4, - const EMaterialTypes& m5); + CMaterialList(const EMaterialTypes& m1, const EMaterialTypes& m2) : value(0) { + value |= u64(1) << m1; + value |= u64(1) << m2; + } + CMaterialList(const EMaterialTypes& m1, const EMaterialTypes& m2, const EMaterialTypes& m3) + : value(0) { + value |= u64(1) << m1; + value |= u64(1) << m2; + value |= u64(1) << m3; + } + CMaterialList(const EMaterialTypes& m1, const EMaterialTypes& m2, const EMaterialTypes& m3, + const EMaterialTypes& m4) + : value(0) { + value |= u64(1) << m1; + value |= u64(1) << m2; + value |= u64(1) << m3; + value |= u64(1) << m4; + } + CMaterialList(const EMaterialTypes& m1, const EMaterialTypes& m2, const EMaterialTypes& m3, + const EMaterialTypes& m4, const EMaterialTypes& m5) + : value(0) { + value |= u64(1) << m1; + value |= u64(1) << m2; + value |= u64(1) << m3; + value |= u64(1) << m4; + value |= u64(1) << m5; + } CMaterialList(u64 value) : value(value) {} void Add(EMaterialTypes material) { value |= u64(1) << material; } diff --git a/include/Collision/CRayCastResult.hpp b/include/Collision/CRayCastResult.hpp new file mode 100644 index 00000000..30a92a45 --- /dev/null +++ b/include/Collision/CRayCastResult.hpp @@ -0,0 +1,27 @@ +#ifndef _CRAYCASTRESULT_HPP +#define _CRAYCASTRESULT_HPP + +#include "types.h" + +#include "Kyoto/Math/CPlane.hpp" +#include "Kyoto/Math/CVector3f.hpp" + +#include "Collision/CMaterialList.hpp" + +class CRayCastResult { +public: + enum EInvalid { + kI_Invalid, + kI_Valid, + }; + +private: + f32 x0_t; + CVector3f x4_point; + CPlane x10_plane; + EInvalid x20_invalid; + CMaterialList x28_material; +}; +CHECK_SIZEOF(CRayCastResult, 0x30) + +#endif \ No newline at end of file diff --git a/include/Kyoto/Math/CMatrix3f.hpp b/include/Kyoto/Math/CMatrix3f.hpp new file mode 100644 index 00000000..fbb3d22d --- /dev/null +++ b/include/Kyoto/Math/CMatrix3f.hpp @@ -0,0 +1,20 @@ +#ifndef _CMATRIX3F_HPP +#define _CMATRIX3F_HPP + +#include "types.h" + +#include "Kyoto/Math/CVector3f.hpp" + +class CMatrix3f { +public: + // TODO + +private: + // TODO maybe individual f32s + CVector3f m0; + CVector3f m1; + CVector3f m2; +}; +CHECK_SIZEOF(CMatrix3f, 0x24); + +#endif \ No newline at end of file diff --git a/include/Kyoto/Math/CNUQuaternion.hpp b/include/Kyoto/Math/CNUQuaternion.hpp new file mode 100644 index 00000000..aa052bcf --- /dev/null +++ b/include/Kyoto/Math/CNUQuaternion.hpp @@ -0,0 +1,17 @@ +#ifndef _CNUQUATERNION_HPP +#define _CNUQUATERNION_HPP + +#include "types.h" + +class CNUQuaternion { +public: + CNUQuaternion(f32 w, f32 x, f32 y, f32 z) : w(w), x(x), y(y), z(z) {} + +private: + f32 w; + f32 x; + f32 y; + f32 z; +}; + +#endif \ No newline at end of file diff --git a/include/Kyoto/Math/CPlane.hpp b/include/Kyoto/Math/CPlane.hpp new file mode 100644 index 00000000..8daeff51 --- /dev/null +++ b/include/Kyoto/Math/CPlane.hpp @@ -0,0 +1,18 @@ +#ifndef _CPLANE_HPP +#define _CPLANE_HPP + +#include "types.h" + +class CPlane { +public: + // TODO + +private: + f32 x; + f32 y; + f32 z; + f32 w; +}; +CHECK_SIZEOF(CPlane, 0x10) + +#endif \ No newline at end of file diff --git a/include/Kyoto/Math/CQuaternion.hpp b/include/Kyoto/Math/CQuaternion.hpp index 3fb7f4c4..3e15eeb3 100644 --- a/include/Kyoto/Math/CQuaternion.hpp +++ b/include/Kyoto/Math/CQuaternion.hpp @@ -6,12 +6,21 @@ class CQuaternion { public: CQuaternion(f32 w, f32 x, f32 y, f32 z) : w(w), x(x), y(y), z(z) {} + // CQuaternion(const CQuaternion& other) + // : w(other.w) + // , x(other.x) + // , y(other.y) + // , z(other.z) {} + + static const CQuaternion& NoRotation() { return sNoRotation; } private: f32 w; f32 x; f32 y; f32 z; + + static const CQuaternion sNoRotation; }; #endif \ No newline at end of file diff --git a/include/MetroidPrime/CActor.hpp b/include/MetroidPrime/CActor.hpp index 20748af8..a7836723 100644 --- a/include/MetroidPrime/CActor.hpp +++ b/include/MetroidPrime/CActor.hpp @@ -209,7 +209,7 @@ public: CActor(TUniqueId uid, bool active, const rstl::string& name, const CEntityInfo& info, const CTransform4f& xf, const CModelData& mData, const CMaterialList& list, const CActorParameters& params, TUniqueId nextDrawNode); - ~CActor(); + ~CActor() override; void AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) override; void SetActive(bool active) override; @@ -249,8 +249,15 @@ public: void DrawTouchBounds() const; bool IsModelOpaque(const CStateManager& mgr) const; void RenderInternal(const CStateManager& mgr) const; + void SetMaterialFilter(const CMaterialFilter& filter); const CTransform4f& GetTransform() const { return x34_transform; } + void SetTransform(const CTransform4f& xf) { + x34_transform = xf; + xe4_27_notInSortedLists = true; + xe4_28_transformDirty = true; + xe4_29_actorLightsDirty = true; + } CVector3f GetTranslation() const { return x34_transform.GetTranslation(); } void SetTranslation(const CVector3f& vec); @@ -276,6 +283,9 @@ public: const CModelFlags& GetModelFlags() const { return xb4_drawFlags; } void SetModelFlags(const CModelFlags& flags) { xb4_drawFlags = flags; } + const CMaterialList& GetMaterialList() const { return x68_material; } + CMaterialList& MaterialList() { return x68_material; } + bool GetTransformDirty() const { return xe4_27_notInSortedLists; } bool GetTransformDirtySpare() const { return xe4_28_transformDirty; } bool GetPreRenderHasMoved() const { return xe4_29_actorLightsDirty; } diff --git a/include/MetroidPrime/CActorParameters.hpp b/include/MetroidPrime/CActorParameters.hpp index bc667f43..8a2e7b31 100644 --- a/include/MetroidPrime/CActorParameters.hpp +++ b/include/MetroidPrime/CActorParameters.hpp @@ -3,8 +3,8 @@ #include "types.h" -#include "Kyoto/IObjectStore.hpp" #include "Kyoto/Graphics/CColor.hpp" +#include "Kyoto/IObjectStore.hpp" #include "Kyoto/Math/CVector3f.hpp" #include "rstl/auto_ptr.hpp" @@ -112,6 +112,8 @@ public: bool IsHotInThermal() const { return x58_25_thermalHeat; } bool ForceRenderUnsorted() const { return x58_26_renderUnsorted; } bool NoSortThermal() const { return x58_27_noSortThermal; } + f32 GetFadeInTime() const { return x5c_fadeInTime; } + f32 GetFadeOutTime() const { return x60_fadeOutTime; } static CActorParameters None(); diff --git a/include/MetroidPrime/CAnimData.hpp b/include/MetroidPrime/CAnimData.hpp index b046fcae..0abb7078 100644 --- a/include/MetroidPrime/CAnimData.hpp +++ b/include/MetroidPrime/CAnimData.hpp @@ -33,6 +33,13 @@ public: }; void PreRender(); + void EnableLooping(bool v) { + x220_25_loop = v; + x220_24_animating = true; + } + void SetIsAnimating(bool v) { + x220_24_animating = v; + } void SetParticleEffectState(const rstl::string& name, bool active, CStateManager& mgr) { x120_particleDB.SetParticleEffectState(name, active, mgr); } diff --git a/include/MetroidPrime/CAxisAngle.hpp b/include/MetroidPrime/CAxisAngle.hpp new file mode 100644 index 00000000..b5df150e --- /dev/null +++ b/include/MetroidPrime/CAxisAngle.hpp @@ -0,0 +1,21 @@ +#ifndef _CAXISANGLE_HPP +#define _CAXISANGLE_HPP + +#include "types.h" + +#include "Kyoto/Math/CVector3f.hpp" + +class CAxisAngle { +public: + CAxisAngle(f32 x, f32 y, f32 z) : x(x), y(y), z(z) {} + CAxisAngle(const CAxisAngle& other) : x(other.x), y(other.y), z(other.z) {} + + static const CAxisAngle& Identity(); + +private: + // maybe CUnitVector3f? + f32 x, y, z; +}; +CHECK_SIZEOF(CAxisAngle, 0xc) + +#endif \ No newline at end of file diff --git a/include/MetroidPrime/CDamageVulnerability.hpp b/include/MetroidPrime/CDamageVulnerability.hpp new file mode 100644 index 00000000..07fa7619 --- /dev/null +++ b/include/MetroidPrime/CDamageVulnerability.hpp @@ -0,0 +1,46 @@ +#ifndef _CDAMAGEVULNERABILITY_HPP +#define _CDAMAGEVULNERABILITY_HPP + +#include "types.h" + +enum EVulnerability { + kVN_Weak, + kVN_Normal, + kVN_Deflect, + kVN_Immune, + kVN_PassThrough, + kVN_DirectWeak, + kVN_DirectNormal, + kVN_DirectImmune, +}; + +enum EDeflectionType { + kDT_None, + kDT_One, + kDT_Two, + kDT_Three, + kDT_Four, +}; + +class CInputStream; + +class CDamageVulnerability { +public: + CDamageVulnerability(CInputStream& in); + CDamageVulnerability(EVulnerability, EVulnerability, EVulnerability, EVulnerability, + EVulnerability, EVulnerability, EVulnerability, EVulnerability, + EVulnerability, EVulnerability, EDeflectionType); + + // TODO + +private: + EVulnerability x0_normal[15]; + EVulnerability x3c_charged[4]; + EVulnerability x4c_combo[4]; + EDeflectionType x5c_deflect; + EDeflectionType x60_chargedDeflect; + EDeflectionType x64_comboDeflect; +}; +CHECK_SIZEOF(CDamageVulnerability, 0x68) + +#endif \ No newline at end of file diff --git a/include/MetroidPrime/CEntity.hpp b/include/MetroidPrime/CEntity.hpp index 620c4933..2832d64e 100644 --- a/include/MetroidPrime/CEntity.hpp +++ b/include/MetroidPrime/CEntity.hpp @@ -15,27 +15,30 @@ class CEntity { public: virtual ~CEntity(); virtual void Accept(IVisitor& visitor) = 0; - virtual void PreThink(float dt, CStateManager& mgr); - virtual void Think(float dt, CStateManager& mgr); + virtual void PreThink(f32 dt, CStateManager& mgr); + virtual void Think(f32 dt, CStateManager& mgr); virtual void AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr); virtual void SetActive(bool active); CEntity(TUniqueId id, const CEntityInfo& info, bool active, const rstl::string& name); void SendScriptMsgs(EScriptObjectState state, CStateManager& mgr, EScriptObjectMessage msg); + static inline void SendScriptMsg(CStateManager& mgr, CEntity* to, TUniqueId sender, EScriptObjectMessage msg) { + mgr.SendScriptMsg(to, sender, msg); + } TUniqueId GetUniqueId() const { return x8_uid; } TAreaId GetAreaId() const; bool GetActive() const { return x30_24_active; } - const rstl::vector& GetConnectionList() const { return x20_conns; } + const rstl::vector< SConnection >& GetConnectionList() const { return x20_conns; } - static rstl::vector NullConnectionList; + static rstl::vector< SConnection > NullConnectionList; protected: TAreaId x4_areaId; TUniqueId x8_uid; TEditorId xc_editorId; rstl::string x10_name; - rstl::vector x20_conns; + rstl::vector< SConnection > x20_conns; bool x30_24_active : 1; bool x30_25_inGraveyard : 1; bool x30_26_scriptingBlocked : 1; diff --git a/include/MetroidPrime/CHealthInfo.hpp b/include/MetroidPrime/CHealthInfo.hpp new file mode 100644 index 00000000..60a6ec25 --- /dev/null +++ b/include/MetroidPrime/CHealthInfo.hpp @@ -0,0 +1,17 @@ +#ifndef _CHEALTHINFO_HPP +#define _CHEALTHINFO_HPP + +#include "types.h" + +class CHealthInfo { +public: + CHealthInfo(f32 hp, f32 resist); + // TODO + +private: + f32 x0_health; + f32 x4_knockbackResistance; +}; +CHECK_SIZEOF(CHealthInfo, 0x8) + +#endif \ No newline at end of file diff --git a/include/MetroidPrime/CObjectList.hpp b/include/MetroidPrime/CObjectList.hpp index 15cb16da..b99c122b 100644 --- a/include/MetroidPrime/CObjectList.hpp +++ b/include/MetroidPrime/CObjectList.hpp @@ -8,15 +8,15 @@ #define kMaxObjects 1024 enum EGameObjectList { - kGOL_Invalid = -1, - kGOL_All, - kGOL_Actor, - kGOL_PhysicsActor, - kGOL_GameCamera, - kGOL_GameLight, - kGOL_ListeningAi, - kGOL_AiWaypoint, - kGOL_PlatformAndDoor, + kOL_Invalid = -1, + kOL_All, + kOL_Actor, + kOL_PhysicsActor, + kOL_GameCamera, + kOL_GameLight, + kOL_ListeningAi, + kOL_AiWaypoint, + kOL_PlatformAndDoor, }; class CEntity; @@ -30,7 +30,9 @@ class CObjectList { public: CObjectList(EGameObjectList list); - bool IsQualified(CEntity& ent); + + virtual bool IsQualified(CEntity& ent); + void AddObject(CEntity& ent); void RemoveObject(TUniqueId uid); CEntity* GetObjectById(); @@ -42,11 +44,21 @@ public: const CEntity* GetValidObjectByIndex(int idx) const; int size() const { return mCount; } + int GetFirstObjectIndex() const { return mFirstId; } + int GetNextObjectIndex(int idx) const { + if (idx != -1) { + return mObjects[idx].mNext; + } else { + return -1; + } + } + private: SObjectListEntry mObjects[1024]; EGameObjectList mListType; - s16 mFirstId = -1; - s16 mCount = 0; + s16 mFirstId; + s16 mCount; }; +CHECK_SIZEOF(CObjectList, 0x200c) #endif // __COBJECTLIST_HPP__ diff --git a/include/MetroidPrime/CPhysicsActor.hpp b/include/MetroidPrime/CPhysicsActor.hpp new file mode 100644 index 00000000..082772cc --- /dev/null +++ b/include/MetroidPrime/CPhysicsActor.hpp @@ -0,0 +1,108 @@ +#ifndef _CPHYSICSACTOR_HPP +#define _CPHYSICSACTOR_HPP + +#include "types.h" + +#include "MetroidPrime/CActor.hpp" +#include "MetroidPrime/CAxisAngle.hpp" + +#include "Kyoto/Math/CAABox.hpp" +#include "Kyoto/Math/CMatrix3f.hpp" +#include "Kyoto/Math/CNUQuaternion.hpp" +#include "Kyoto/Math/CVector3f.hpp" + +#include "Collision/CCollidableAABox.hpp" + +#include "rstl/optional_object.hpp" + +struct SMoverData { + CVector3f x0_velocity; + CAxisAngle xc_angularVelocity; + CVector3f x18_momentum; + CAxisAngle x24_; + f32 x30_mass; + + SMoverData(f32 mass, const CVector3f& velocity, const CAxisAngle& angularVelocity, + const CVector3f& momentum, const CAxisAngle& unk) + : x0_velocity(velocity) + , xc_angularVelocity(angularVelocity) + , x18_momentum(momentum) + , x24_(unk) + , x30_mass(mass) {} +}; + +class CMotionState { +public: + // TODO + +private: + CVector3f x0_translation; + CNUQuaternion xc_orientation; + CVector3f x1c_velocity; + CAxisAngle x28_angularMomentum; +}; +CHECK_SIZEOF(CMotionState, 0x34) + +class CCollisionInfoList; + +class CPhysicsActor : public CActor { +public: + CPhysicsActor(TUniqueId uid, bool active, const rstl::string& name, const CEntityInfo& info, + const CTransform4f& xf, const CModelData& mData, const CMaterialList& matList, + const CAABox& aabb, const SMoverData& moverData, const CActorParameters& actParams, + f32 stepUp, f32 stepDown); + ~CPhysicsActor() override; + + // CActor + CVector3f GetOrbitPosition(const CStateManager& mgr) const override; + CVector3f GetAimPosition(const CStateManager& mgr, f32 val) const override; + + // CPhysicsActor + virtual const CCollisionPrimitive* GetCollisionPrimitive() const; + virtual CTransform4f GetPrimitiveTransform() const; + virtual void CollidedWith(TUniqueId id, const CCollisionInfoList& list, CStateManager& mgr); + virtual f32 GetStepUpHeight() const; + virtual f32 GetStepDownHeight() const; + virtual f32 GetWeight() const; + + CAABox GetBoundingBox() const; + + bool GetMovable() const { return xf8_24_movable; } + void SetMovable(bool v) { xf8_24_movable = v; } + +private: + f32 xe8_mass; + f32 xec_massRecip; + f32 xf0_inertiaTensor; + f32 xf4_inertiaTensorRecip; + bool xf8_24_movable : 1; + bool xf8_25_angularEnabled : 1; + bool xf9_standardCollider; + CVector3f xfc_constantForce; + CAxisAngle x108_angularMomentum; + CMatrix3f x114_; + CVector3f x138_velocity; + CAxisAngle x144_angularVelocity; + CVector3f x150_momentum; + CVector3f x15c_force; + CVector3f x168_impulse; + CAxisAngle x174_torque; + CAxisAngle x180_angularImpulse; + CVector3f x18c_moveImpulse; + CAxisAngle x198_moveAngularImpulse; + CAABox x1a4_baseBoundingBox; + CCollidableAABox x1c0_collisionPrimitive; + CVector3f x1e8_primitiveOffset; + CMotionState x1f4_lastNonCollidingState; + rstl::optional_object< CVector3f > x228_lastFloorPlaneNormal; + f32 x238_maximumCollisionVelocity; + f32 x23c_stepUpHeight; + f32 x240_stepDownHeight; + f32 x244_restitutionCoefModifier; + f32 x248_collisionAccuracyModifier; + uint x24c_numTicksStuck; + uint x250_numTicksPartialUpdate; +}; +CHECK_SIZEOF(CPhysicsActor, 0x258) + +#endif \ No newline at end of file diff --git a/include/MetroidPrime/CStateManager.hpp b/include/MetroidPrime/CStateManager.hpp index 9729033f..130c0180 100644 --- a/include/MetroidPrime/CStateManager.hpp +++ b/include/MetroidPrime/CStateManager.hpp @@ -3,7 +3,9 @@ #include "types.h" +#include "Kyoto/CRandom16.hpp" #include "MetroidPrime/CEntityInfo.hpp" +#include "MetroidPrime/CObjectList.hpp" #include "MetroidPrime/TGameTypes.hpp" #include "rstl/auto_ptr.hpp" @@ -31,6 +33,7 @@ class CWeaponMgr; class CWorld; class CWorldTransManager; class CEntity; +class CMazeState; namespace SL { class CSortedListManager; @@ -49,6 +52,10 @@ public: const CEntity* GetObjectById(TUniqueId uid) const; TUniqueId GetIdForScript(TEditorId eid) const; + CMazeState* CurrentMaze(); + const CMazeState* GetCurrentMaze() const; + void SetCurrentMaze(const rstl::single_ptr& maze); + CCameraManager* CameraManager() { return x870_cameraManager; } const CCameraManager* GetCameraManager() const { return x870_cameraManager; } CPlayerState* PlayerState() { return x8b8_playerState.GetPtr(); } @@ -57,6 +64,9 @@ public: const CWorld* GetWorld() const { return x850_world.get(); } CActorModelParticles* ActorModelParticles() { return x884_actorModelParticles.get(); } const CActorModelParticles* GetActorModelParticles() const { return x884_actorModelParticles.get(); } + CRandom16* GetActiveRandom() const { return x900_random; } + + CObjectList& GetObjectListById(EGameObjectList id) { return *x808_objectLists[id]; } f32 GetThermalColdScale1() const { return xf24_thermColdScale1; } f32 GetThermalColdScale2() const { return xf28_thermColdScale2; } @@ -64,6 +74,14 @@ public: bool IsGeneratingObject() const { return xf94_26_generatingObject; } void SetIsGeneratingObject(bool gen) { xf94_26_generatingObject = gen; } + inline TUniqueId GenerateObjectInline(TEditorId eid) { + bool wasGeneratingObject = IsGeneratingObject(); + SetIsGeneratingObject(true); + TUniqueId objUid = GenerateObject(eid).second; + SetIsGeneratingObject(wasGeneratingObject); + return objUid; + } + private: u16 x0_nextFreeIndex; rstl::reserved_vector< u16, 1024 > x8_objectIndexArray; @@ -87,7 +105,9 @@ private: rstl::rc_ptr< CScriptMailbox > x8bc_mailbox; rstl::rc_ptr< CMapWorldInfo > x8c0_mapWorldInfo; rstl::rc_ptr< CWorldTransManager > x8c4_worldTransManager; - u8 pad2[0x658]; + u8 pad2[0x38]; + CRandom16* x900_random; + u8 pad4[0x61c]; f32 xf24_thermColdScale1; f32 xf28_thermColdScale2; u8 pad3[0x6c]; diff --git a/include/MetroidPrime/ScriptObjects/CScriptMazeNode.hpp b/include/MetroidPrime/ScriptObjects/CScriptMazeNode.hpp index 32bfaea9..9e5f4e33 100644 --- a/include/MetroidPrime/ScriptObjects/CScriptMazeNode.hpp +++ b/include/MetroidPrime/ScriptObjects/CScriptMazeNode.hpp @@ -64,7 +64,7 @@ public: void GenerateObstacles(); SMazeCell& GetCell(uint col, uint row); - SMazeCell& GetCell2(uint col, uint row); // ???? + const SMazeCell& GetCell(uint col, uint row) const; SMazeCell& GetCellInline(uint col, uint row) { return x4_cells[col + row * skMazeCols]; } // ???? inline SMazeCell& GetCell(uint idx) { return x4_cells[idx]; } }; @@ -77,14 +77,10 @@ public: void Accept(IVisitor& visitor) override; void AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) override; - void Think(float dt, CStateManager& mgr) override; + void Think(f32 dt, CStateManager& mgr) override; static void LoadMazeSeeds(); - static inline void SendScriptMsg(CStateManager& mgr, CEntity* to, TUniqueId sender, EScriptObjectMessage msg) { - mgr.SendScriptMsg(to, sender, msg); - } - private: enum ESide { Invalid = -1, @@ -98,7 +94,7 @@ private: int xec_row; ESide xf0_side; TUniqueId xf4_gateEffectId; - float xf8_msgTimer; + f32 xf8_msgTimer; TUniqueId xfc_actorId; CVector3f x100_actorPos; TUniqueId x10c_triggerId; diff --git a/include/MetroidPrime/ScriptObjects/CScriptPlatform.hpp b/include/MetroidPrime/ScriptObjects/CScriptPlatform.hpp new file mode 100644 index 00000000..59e87024 --- /dev/null +++ b/include/MetroidPrime/ScriptObjects/CScriptPlatform.hpp @@ -0,0 +1,96 @@ +#ifndef _CSCRIPTPLATFORM_HPP +#define _CSCRIPTPLATFORM_HPP + +#include "types.h" + +#include "MetroidPrime/CDamageVulnerability.hpp" +#include "MetroidPrime/CHealthInfo.hpp" +#include "MetroidPrime/CPhysicsActor.hpp" + +#include "Kyoto/CRandom16.hpp" +#include "Kyoto/Math/CQuaternion.hpp" +#include "Kyoto/Math/CVector3f.hpp" + +#include "rstl/auto_ptr.hpp" +#include "rstl/optional_object.hpp" +#include "rstl/vector.hpp" + +class CCollidableOBBTreeGroup; +class CCollidableOBBTreeGroupContainer; +class CFluidPlane; + +struct SRiders { + TUniqueId x0_uid; + f32 x4_decayTimer; + CTransform4f x8_transform; +}; + +class CScriptPlatform : public CPhysicsActor { +public: + CScriptPlatform( + TUniqueId uid, const rstl::string& name, const CEntityInfo& info, const CTransform4f& xf, + const CModelData& mData, const CActorParameters& actParams, const CAABox& aabb, f32 speed, + bool detectCollision, f32 xrayAlpha, bool active, const CHealthInfo& hInfo, + const CDamageVulnerability& dVuln, + const rstl::optional_object< TLockedToken< CCollidableOBBTreeGroupContainer > >& dcln, + bool rainSplashes, uint maxRainSplashes, uint rainGenRate); + + // CEntity + ~CScriptPlatform() override; + void Accept(IVisitor& visitor) override; + void PreThink(f32 dt, CStateManager& mgr) override; + void Think(f32 dt, CStateManager& mgr) override; + void AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) override; + + // CActor + void PreRender(CStateManager&, const CFrustumPlanes&) override; + void Render(const CStateManager&) const override; + CHealthInfo* HealthInfo(CStateManager&) override; + const CDamageVulnerability* GetDamageVulnerability() const override; + rstl::optional_object< CAABox > GetTouchBounds() const override; + CVector3f GetOrbitPosition(const CStateManager&) const override; + CVector3f GetAimPosition(const CStateManager&, float) const override; + CAABox GetSortingBounds(const CTransform4f&) const override; + + // CPhysicsActor + const CCollisionPrimitive* GetCollisionPrimitive() const override; + CTransform4f GetPrimitiveTransform() const override; + + // CScriptPlatform + virtual void SplashThink(const CAABox&, const CFluidPlane&, float, CStateManager&) const; + virtual CQuaternion Move(float, CStateManager&); + +private: + TUniqueId x258_currentWaypoint; + TUniqueId x25a_targetWaypoint; + f32 x25c_currentSpeed; + f32 x260_moveDelay; + f32 x264_collisionRecoverDelay; + f32 x268_fadeInTime; + f32 x26c_fadeOutTime; + CVector3f x270_dragDelta; + CQuaternion x27c_rotDelta; + CHealthInfo x28c_initialHealth; + CHealthInfo x294_health; + CDamageVulnerability x29c_damageVuln; + rstl::optional_object< TLockedToken< CCollidableOBBTreeGroupContainer > > x304_treeGroupContainer; + rstl::single_ptr< CCollidableOBBTreeGroup > x314_treeGroup; + rstl::vector< SRiders > x318_riders; + rstl::vector< SRiders > x328_slavesStatic; + rstl::vector< SRiders > x338_slavesDynamic; + f32 x348_xrayAlpha; + uint x34c_maxRainSplashes; + uint x350_rainGenRate; + TUniqueId x354_boundsTrigger; + bool x356_24_dead : 1; + bool x356_25_controlledAnimation : 1; + bool x356_26_detectCollision : 1; + bool x356_27_squishedRider : 1; + bool x356_28_rainSplashes : 1; + bool x356_29_setXrayDrawFlags : 1; + bool x356_30_disableXrayAlpha : 1; + bool x356_31_xrayFog : 1; +}; +CHECK_SIZEOF(CScriptPlatform, 0x358) + +#endif diff --git a/include/MetroidPrime/TGameTypes.hpp b/include/MetroidPrime/TGameTypes.hpp index 480a85bb..42494353 100644 --- a/include/MetroidPrime/TGameTypes.hpp +++ b/include/MetroidPrime/TGameTypes.hpp @@ -3,6 +3,9 @@ #include "types.h" +class CInputStream; +class COutputStream; + struct TAreaId; struct TEditorId; struct TUniqueId; @@ -26,9 +29,14 @@ CHECK_SIZEOF(TAreaId, 0x4) struct TEditorId { uint value; - TEditorId() : value(-1) {} TEditorId(uint value) : value(value) {} + TEditorId(CInputStream& in); + // TODO uint Value() const { return value; } + uint Id() const { return value; } + uint AreaNum() const { return value; } + + void PutTo(COutputStream&) const; bool operator==(const TEditorId& other) const { return value == other.value; } bool operator!=(const TEditorId& other) const { return value != other.value; } @@ -36,22 +44,19 @@ struct TEditorId { CHECK_SIZEOF(TEditorId, 0x4) struct TUniqueId { - union { - struct { - u16 version : 6; - u16 id : 10; - }; - u16 value; - }; + u16 value; - TUniqueId() : value(-1) {} - TUniqueId(u16 value) : value(value) {} - u16 Value() const { return value; } + TUniqueId(u16 version, u16 id) : value(((version & 0x3F) << 10) | (id & 0x3FF)) {} + u16 Value() const { return value & 0x3FF; } + u16 Version() const { return (value >> 10) & 0x3F; } bool operator==(const TUniqueId& other) const { return value == other.value; } bool operator!=(const TUniqueId& other) const { return value != other.value; } + bool operator<(const TUniqueId& other) const; // TODO + +private: }; -CHECK_SIZEOF(TUniqueId, 0x2) +// CHECK_SIZEOF(TUniqueId, 0x2) typedef u16 TSfxId; static TSfxId InvalidSfxId = 0xFFFFu; diff --git a/include/WorldFormat/CCollidableOBBTreeGroup.hpp b/include/WorldFormat/CCollidableOBBTreeGroup.hpp new file mode 100644 index 00000000..3d190df0 --- /dev/null +++ b/include/WorldFormat/CCollidableOBBTreeGroup.hpp @@ -0,0 +1,40 @@ +#ifndef _CCOLLIDABLEOBBTREEGROUP_HPP +#define _CCOLLIDABLEOBBTREEGROUP_HPP + +#include "types.h" + +#include "Collision/CCollisionPrimitive.hpp" + +#include "rstl/auto_ptr.hpp" +#include "rstl/vector.hpp" + +class COBBTree; + +class CCollidableOBBTreeGroupContainer { + friend class CCollidableOBBTreeGroup; + rstl::vector< rstl::auto_ptr< COBBTree > > x0_trees; + rstl::vector< CAABox > x10_aabbs; + CAABox x20_aabox; + +public: + CCollidableOBBTreeGroupContainer(CInputStream& in); + CCollidableOBBTreeGroupContainer(const CVector3f&, const CVector3f&); +}; + +class CCollidableOBBTreeGroup : public CCollisionPrimitive { +public: + CCollidableOBBTreeGroup(CCollidableOBBTreeGroupContainer* container, + const CMaterialList& matList); + + u32 GetTableIndex() const override; + CAABox CalculateAABox(const CTransform4f&) const override; + CAABox CalculateLocalAABox() const override; + FourCC GetPrimType() const override; + ~CCollidableOBBTreeGroup() override {} + CRayCastResult CastRayInternal(const CInternalRayCastStructure&) const override; + +private: + CCollidableOBBTreeGroupContainer* x10_container; +}; + +#endif \ No newline at end of file diff --git a/include/rstl/algorithm.hpp b/include/rstl/algorithm.hpp index 67bcfd70..aede661c 100644 --- a/include/rstl/algorithm.hpp +++ b/include/rstl/algorithm.hpp @@ -1,15 +1,29 @@ #ifndef _RSTL_MATH_HPP #define _RSTL_MATH_HPP +#include "rstl/pointer_iterator.hpp" + namespace rstl { -template +template < typename T > inline const T& min_val(const T& a, const T& b) { - return (b < a) ? b : a; + return (b < a) ? b : a; } -template +template < typename T > inline const T& max_val(const T& a, const T& b) { - return (a < b) ? b : a; + return (a < b) ? b : a; } + +template < class Iter, class T > +inline Iter find(Iter first, Iter last, const T& val) { + return find(first, last, val, typename Iter::iterator_category()); } + +template < class Iter, class T > +inline Iter find(Iter first, Iter last, const T& val, input_iterator_tag) { + while (first != last && !(*first == val)) + ++first; + return first; +} +} // namespace rstl #endif // _RSTL_MATH_HPP diff --git a/include/rstl/optional_object.hpp b/include/rstl/optional_object.hpp index d0c537dc..7ed5330e 100644 --- a/include/rstl/optional_object.hpp +++ b/include/rstl/optional_object.hpp @@ -9,8 +9,13 @@ namespace rstl { template < typename T > class optional_object { public: - optional_object() : x4_valid(false) {} - optional_object(const T& item) : x0_item(item), x4_valid(true) {} + optional_object() : m_valid(false) {} + optional_object(const T& item) : m_valid(true) { rstl::construct< T >(m_data, item); } + optional_object(const optional_object& other) : m_valid(other.m_valid) { + if (other.m_valid) { + rstl::construct< T >(m_data, other.data()); + } + } ~optional_object() { clear(); } optional_object& operator=(const T& item) { @@ -18,24 +23,30 @@ public: return *this; } - T& data() { return x0_item; } - T* get_ptr() { return &x0_item; } - operator bool() const { return x4_valid; } + T& data() { return *get_ptr(); } + const T& data() const { return *get_ptr(); } + T* get_ptr() { return reinterpret_cast< T* >(m_data); } + const T* get_ptr() const { return reinterpret_cast< const T* >(m_data); } + bool valid() const { return m_valid; } + operator bool() const { return m_valid; } // replace with valid()? void clear() { - rstl::destroy(&x0_item); - x4_valid = false; + if (m_valid) { + rstl::destroy(get_ptr()); + } + m_valid = false; } T& operator*() { return data(); } + T* operator->() { return data(); } private: - T x0_item; - bool x4_valid; + u8 m_data[sizeof(T)]; + bool m_valid; void assign(const T& item) { - if (!x4_valid) { + if (!m_valid) { rstl::construct(get_ptr(), item); - x4_valid = true; + m_valid = true; } else { data() = item; } diff --git a/include/rstl/pointer_iterator.hpp b/include/rstl/pointer_iterator.hpp index 51e62899..269a558e 100644 --- a/include/rstl/pointer_iterator.hpp +++ b/include/rstl/pointer_iterator.hpp @@ -6,16 +6,24 @@ #include "rstl/construct.hpp" namespace rstl { +struct input_iterator_tag {}; +struct output_iterator_tag {}; +struct forward_iterator_tag : public input_iterator_tag {}; +struct bidirectional_iterator_tag : public forward_iterator_tag {}; +struct random_access_iterator_tag : public bidirectional_iterator_tag {}; + template < typename T, typename Vec, typename Alloc > class const_pointer_iterator { protected: const T* current; public: + typedef random_access_iterator_tag iterator_category; + const_pointer_iterator() : current(nullptr) {} const_pointer_iterator(const T* begin) : current(begin) {} - void operator++() { ++current; } - void operator--() { --current; } + const_pointer_iterator& operator++() { ++current; return *this; } + const_pointer_iterator& operator--() { --current; return *this; } T* get_pointer() const { return const_cast< T* >(current); } const T& operator*() const { return *get_pointer(); } const T* operator->() const { return get_pointer(); } @@ -46,6 +54,8 @@ public: rstl::destroy(get_pointer()); } } + pointer_iterator& operator++() { ++current; return *this; } + pointer_iterator& operator--() { --current; return *this; } friend pointer_iterator operator+(const pointer_iterator& x, int v) { return pointer_iterator(x.get_pointer() + v); } friend pointer_iterator operator-(const pointer_iterator& x, int v) { return pointer_iterator(x.get_pointer() - v); } diff --git a/include/rstl/single_ptr.hpp b/include/rstl/single_ptr.hpp index a3c97ab2..b6d391dc 100644 --- a/include/rstl/single_ptr.hpp +++ b/include/rstl/single_ptr.hpp @@ -24,9 +24,14 @@ public: bool null() const { return x0_ptr == nullptr; } T& operator*() { return *x0_ptr; } const T& operator*() const { return *x0_ptr; } + T* release() { + T* ptr = x0_ptr; + x0_ptr = nullptr; + return ptr; + } }; -typedef single_ptr unk_singleptr; +typedef single_ptr< void > unk_singleptr; CHECK_SIZEOF(unk_singleptr, 0x4); } // namespace rstl diff --git a/src/MetroidPrime/ScriptObjects/CScriptMazeNode.cpp b/src/MetroidPrime/ScriptObjects/CScriptMazeNode.cpp index 430b252f..0c50b70b 100644 --- a/src/MetroidPrime/ScriptObjects/CScriptMazeNode.cpp +++ b/src/MetroidPrime/ScriptObjects/CScriptMazeNode.cpp @@ -2,6 +2,9 @@ #include "Kyoto/CResFactory.hpp" #include "MetroidPrime/CActorParameters.hpp" +#include "MetroidPrime/CObjectList.hpp" + +#include "rstl/algorithm.hpp" uint CScriptMazeNode::sMazeSeeds[300]; @@ -79,8 +82,7 @@ void CMazeState::Reset(int seed) { SMazeCell& CMazeState::GetCell(uint col, uint row) { return x4_cells[col + row * skMazeCols]; } -// ???? -SMazeCell& CMazeState::GetCell2(uint col, uint row) { return x4_cells[col + row * skMazeCols]; } +const SMazeCell& CMazeState::GetCell(uint col, uint row) const { return x4_cells[col + row * skMazeCols]; } static inline int GetRandom(CRandom16& rand, int offset) { int tmp = rand.Next(); @@ -156,7 +158,6 @@ void CMazeState::GenerateObstacles() { puddle2Idx++; } } else { - // SMazeCell& cell = GetCellInline(curCol, curRow); GetCellInline(curCol, curRow).x1_24_puddle = true; switch (side) { case kS_Top: @@ -178,6 +179,7 @@ void CMazeState::GenerateObstacles() { } } } +#undef GetCellInline idx++; prevCol = curCol; @@ -247,10 +249,10 @@ CScriptMazeNode::CScriptMazeNode(TUniqueId uid, const rstl::string& name, const void CScriptMazeNode::Accept(IVisitor& visitor) { visitor.Visit(*this); } -static inline TUniqueId GenerateObject(CStateManager& mgr, const SConnection& conn) { +static inline TUniqueId GenerateObject(CStateManager& mgr, const TEditorId& eid) { bool wasGeneratingObject = mgr.IsGeneratingObject(); mgr.SetIsGeneratingObject(true); - TUniqueId objUid = mgr.GenerateObject(conn.x8_objId).second; + TUniqueId objUid = mgr.GenerateObject(eid).second; mgr.SetIsGeneratingObject(wasGeneratingObject); return objUid; } @@ -267,26 +269,31 @@ void CScriptMazeNode::GenerateObjects(CStateManager& mgr) { CScriptEffect* scriptEffect = TCastToPtr< CScriptEffect >(ent); CScriptActor* scriptActor = TCastToPtr< CScriptActor >(ent); CScriptTrigger* scriptTrigger = TCastToPtr< CScriptTrigger >(ent); - if ((scriptEffect || scriptActor || scriptTrigger) && (!scriptEffect || !x13c_25_hasGate)) { - // TUniqueId objUid = GenerateObject(mgr, *conn); - bool wasGeneratingObject = mgr.IsGeneratingObject(); - mgr.SetIsGeneratingObject(true); - TUniqueId objUid = mgr.GenerateObject(conn->x8_objId).second; - mgr.SetIsGeneratingObject(wasGeneratingObject); - if (CActor* actor = static_cast< CActor* >(mgr.ObjectById(objUid))) { - mgr.SendScriptMsg(actor, GetUniqueId(), kSM_Activate); - if (scriptEffect) { - actor->SetTranslation(GetTranslation() + x120_effectPos); - x11c_effectId = objUid; - } - if (scriptActor) { - actor->SetTranslation(GetTranslation() + x100_actorPos); - xfc_actorId = objUid; - } - if (scriptTrigger) { - actor->SetTranslation(GetTranslation() + x110_triggerPos); - x10c_triggerId = objUid; - } + if (!scriptEffect && !scriptActor && !scriptTrigger) { + continue; + } + if (scriptEffect && x13c_25_hasGate) { + continue; + } + // TUniqueId objUid = GenerateObject(mgr, conn->x8_objId); + TUniqueId objUid = GenerateObject(mgr, conn->x8_objId); + // bool wasGeneratingObject = mgr.IsGeneratingObject(); + // mgr.SetIsGeneratingObject(true); + // TUniqueId objUid = mgr.GenerateObject(conn->x8_objId).second; + // mgr.SetIsGeneratingObject(wasGeneratingObject); + if (CActor* actor = static_cast< CActor* >(mgr.ObjectById(objUid))) { + mgr.SendScriptMsg(actor, GetUniqueId(), kSM_Activate); + if (scriptEffect) { + actor->SetTranslation(GetTranslation() + x120_effectPos); + x11c_effectId = objUid; + } + if (scriptActor) { + actor->SetTranslation(GetTranslation() + x100_actorPos); + xfc_actorId = objUid; + } + if (scriptTrigger) { + actor->SetTranslation(GetTranslation() + x110_triggerPos); + x10c_triggerId = objUid; } } } @@ -307,8 +314,185 @@ void CScriptMazeNode::SendScriptMsgs(CStateManager& mgr, EScriptObjectMessage ms SendScriptMsg(mgr, mgr.ObjectById(xf4_gateEffectId), GetUniqueId(), msg); } +template < typename Iter, typename T > +static inline Iter contains(Iter it, Iter end, const T& value) { + for (; it != end && *it != value; ++it) { + } + return it; +} + +template < typename T > +static inline bool contains(const rstl::vector< T >& vec, typename rstl::vector< T >::const_iterator end, const T& value) { + return rstl::find< rstl::vector< T >::const_iterator, T >(vec.begin(), end, value) != end; +} + void CScriptMazeNode::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) { - // TODO + if (GetActive()) { + switch (msg) { + case kSM_InitializedInArea: { + if (mgr.CurrentMaze() == nullptr) { + rstl::single_ptr< CMazeState > maze = new CMazeState(skEnterCol, skEnterRow, skTargetCol, skTargetRow); + maze->Reset(sMazeSeeds[mgr.GetActiveRandom()->Next() % 300]); + maze->Initialize(); + maze->GenerateObstacles(); + mgr.SetCurrentMaze(maze.release()); + } + break; + } + case kSM_Action: { + bool shouldGenObjs = false; + if (const CMazeState* maze = mgr.CurrentMaze()) { + const SMazeCell& cell = maze->GetCell(xe8_col, xec_row); + if (xf0_side == CMazeState::kS_Top && cell.x0_24_openTop) { + if (cell.x0_28_gateTop) { + shouldGenObjs = true; + x13c_25_hasGate = true; + } + } else if (xf0_side == CMazeState::kS_Right && cell.x0_25_openRight) { + if (cell.x0_29_gateRight) { + shouldGenObjs = true; + x13c_25_hasGate = true; + } + } else { + shouldGenObjs = true; + } + if (shouldGenObjs) { + GenerateObjects(mgr); + } + if (xf0_side == CMazeState::kS_Right && cell.x1_24_puddle) { + x13c_24_hasPuddle = true; + } + if (x13c_25_hasGate) { +#ifndef NON_MATCHING + // Unused + CTransform4f xf = GetTransform(); +#endif + rstl::vector< SConnection >::const_iterator conn = GetConnectionList().begin(); + for (; conn != GetConnectionList().end(); ++conn) { + if (conn->x0_state != kSS_Modify || conn->x4_msg != kSM_Activate) { + continue; + } + + // TUniqueId genObj = GenerateObject(mgr, conn->x8_objId); + bool wasGeneratingObject = mgr.IsGeneratingObject(); + mgr.SetIsGeneratingObject(true); + TUniqueId genObj = mgr.GenerateObject(conn->x8_objId).second; + mgr.SetIsGeneratingObject(wasGeneratingObject); + + xf4_gateEffectId = genObj; + if (CActor* actor = TCastToPtr< CActor >(mgr.ObjectById(genObj))) { + actor->SetTranslation(GetTranslation() + x120_effectPos); + mgr.SendScriptMsg(actor, GetUniqueId(), kSM_Activate); + } + break; + } + } + if (x13c_24_hasPuddle) { + int count = 0; + rstl::vector< SConnection >::const_iterator conn = GetConnectionList().begin(); + for (; conn != GetConnectionList().end(); ++conn) { + if ((conn->x0_state == kSS_Closed || conn->x0_state == kSS_DeactivateState) && conn->x4_msg == kSM_Activate) { + count++; + } + } + x12c_puddleObjectIds.reserve(count); + conn = GetConnectionList().begin(); + for (; conn != GetConnectionList().end(); ++conn) { + if ((conn->x0_state == kSS_Closed || conn->x0_state == kSS_DeactivateState) && conn->x4_msg == kSM_Activate) { + // TUniqueId genObj = GenerateObject(mgr, conn->x8_objId); + bool wasGeneratingObject = mgr.IsGeneratingObject(); + mgr.SetIsGeneratingObject(true); + TUniqueId genObj = mgr.GenerateObject(conn->x8_objId).second; + mgr.SetIsGeneratingObject(wasGeneratingObject); + + x12c_puddleObjectIds.push_back(genObj); + if (CActor* actor = TCastToPtr< CActor >(mgr.ObjectById(genObj))) { + actor->SetTransform(GetTransform()); + if (conn->x0_state == kSS_Closed) { + mgr.SendScriptMsg(actor, GetUniqueId(), kSM_Activate); + } + } + } + } + } + } + break; + } + case kSM_SetToZero: { + CMazeState* maze = mgr.CurrentMaze(); + if (x13c_24_hasPuddle && maze != nullptr) { + rstl::vector< TUniqueId >::const_iterator pend = x12c_puddleObjectIds.end(); + rstl::vector< TUniqueId >::const_iterator pit = + rstl::find< rstl::vector< TUniqueId >::const_iterator, TUniqueId >(x12c_puddleObjectIds.begin(), pend, uid); + if (pit != pend) { + // if (contains(x12c_puddleObjectIds, x12c_puddleObjectIds.end(), uid)) { + rstl::vector< TUniqueId >::const_iterator it = x12c_puddleObjectIds.begin(); + for (; it != x12c_puddleObjectIds.end(); ++it) { + if (CEntity* ent = mgr.ObjectById(*it)) { + if (!ent->GetActive()) { + mgr.SendScriptMsg(ent, GetUniqueId(), kSM_Activate); + } else { + mgr.FreeScriptObject(ent->GetUniqueId()); + } + } + } + CObjectList& list = mgr.GetObjectListById(kOL_All); + int objIdx = list.GetFirstObjectIndex(); + while (objIdx != -1) { + if (CScriptMazeNode* node = TCastToPtr< CScriptMazeNode >(list[objIdx])) { + if (node->xe8_col == xe8_col - 1 && node->xec_row == xec_row && node->xf0_side == CMazeState::kS_Right) { + SMazeCell& cell = maze->GetCell(xe8_col - 1, xec_row); + if (!cell.x0_25_openRight) { + cell.x0_25_openRight = true; + node->Reset(mgr); + node->x13c_25_hasGate = false; + } + } + if (node->xe8_col == xe8_col && node->xec_row == xec_row && node->xf0_side == CMazeState::kS_Right) { + SMazeCell& cell = maze->GetCell(xe8_col, xec_row); + if (!cell.x0_25_openRight) { + cell.x0_25_openRight = true; + node->Reset(mgr); + node->x13c_25_hasGate = false; + } + } + if (node->xe8_col == xe8_col && node->xec_row == xec_row && node->xf0_side == CMazeState::kS_Top) { + SMazeCell& cell = maze->GetCell(xe8_col, xec_row); + if (!cell.x0_24_openTop) { + cell.x0_24_openTop = true; + node->Reset(mgr); + node->x13c_25_hasGate = false; + } + } + if (node->xe8_col == xe8_col && node->xec_row == xec_row + 1 && node->xf0_side == CMazeState::kS_Top) { + SMazeCell& cell = maze->GetCell(xe8_col, xec_row + 1); + if (!cell.x0_24_openTop) { + cell.x0_24_openTop = true; + node->Reset(mgr); + node->x13c_25_hasGate = false; + } + } + } + objIdx = list.GetNextObjectIndex(objIdx); + } + } + } + break; + } + case kSM_Deleted: { + if (mgr.GetCurrentMaze()) { + mgr.SetCurrentMaze(nullptr); + } + Reset(mgr); + break; + } + case kSM_Deactivate: { + Reset(mgr); + break; + } + } + } + CEntity::AcceptScriptMsg(msg, uid, mgr); } void CScriptMazeNode::Think(float dt, CStateManager& mgr) { diff --git a/src/MetroidPrime/ScriptObjects/CScriptPlatform.cpp b/src/MetroidPrime/ScriptObjects/CScriptPlatform.cpp new file mode 100644 index 00000000..df622dd1 --- /dev/null +++ b/src/MetroidPrime/ScriptObjects/CScriptPlatform.cpp @@ -0,0 +1,112 @@ +#include "MetroidPrime/ScriptObjects/CScriptPlatform.hpp" + +#include "MetroidPrime/CActorParameters.hpp" +#include "MetroidPrime/CAnimData.hpp" + +#include "Kyoto/Graphics/CGX.hpp" + +#include "WorldFormat/CCollidableOBBTreeGroup.hpp" + +#ifndef TARGET_PC +struct GXData { + u16 cpSRreg; + u16 cpCRreg; +}; +extern GXData* __GXData; + +static inline void write_bp_cmd(u32 cmd) { + GXWGFifo.u8 = GX_LOAD_BP_REG; + GXWGFifo.u32 = cmd; + __GXData->cpCRreg = 0; +} +#endif + +void CGX::update_fog(uint flags) { + if (sGXState.x53_fogType == 0) { + return; + } + if ((sGXState.x56_blendMode & 0xE0) == (flags & 0xE0)) { + return; + } + if ((flags & 0xE0) == 0x20) { +#ifdef TARGET_PC + static const GXColor sGXClear = {0, 0, 0, 0}; + GXSetFogColor(sGXClear); +#else + write_bp_cmd(0xf2000000); +#endif + } else { +#ifdef TARGET_PC + GXSetFogColor(sGXState.x24c_fogParams.x10_fogColor); +#else + write_bp_cmd((sGXState.x24c_fogParams.x10_fogColor.b) | + (sGXState.x24c_fogParams.x10_fogColor.g << 8) | + (sGXState.x24c_fogParams.x10_fogColor.r << 16) | 0xf2000000); +#endif + } +} + +CScriptPlatform::CScriptPlatform( + TUniqueId uid, const rstl::string& name, const CEntityInfo& info, const CTransform4f& xf, + const CModelData& mData, const CActorParameters& actParams, const CAABox& aabb, f32 speed, + bool detectCollision, f32 xrayAlpha, bool active, const CHealthInfo& hInfo, + const CDamageVulnerability& dVuln, + const rstl::optional_object< TLockedToken< CCollidableOBBTreeGroupContainer > >& dcln, + bool rainSplashes, uint maxRainSplashes, uint rainGenRate) +: CPhysicsActor(uid, active, name, info, xf, mData, + CMaterialList(kMT_Solid, kMT_Immovable, kMT_Platform, kMT_Occluder), aabb, + SMoverData(15000.f, CVector3f::Zero(), CAxisAngle::Identity(), CVector3f::Zero(), + CAxisAngle::Identity()), + actParams, 0.3f, 0.1f) +, x258_currentWaypoint(kInvalidUniqueId) +, x25a_targetWaypoint(kInvalidUniqueId) +, x25c_currentSpeed(speed) +, x260_moveDelay(0.f) +, x264_collisionRecoverDelay(0.f) +, x268_fadeInTime(actParams.GetFadeInTime()) +, x26c_fadeOutTime(actParams.GetFadeOutTime()) +, x270_dragDelta(CVector3f::Zero()) +, x27c_rotDelta(CQuaternion::NoRotation()) +, x28c_initialHealth(hInfo) +, x294_health(hInfo) +, x29c_damageVuln(dVuln) +, x304_treeGroupContainer(dcln) +, x314_treeGroup(nullptr) +, x348_xrayAlpha(xrayAlpha) +, x34c_maxRainSplashes(maxRainSplashes) +, x350_rainGenRate(rainGenRate) +, x354_boundsTrigger(kInvalidUniqueId) +, x356_24_dead(false) +, x356_25_controlledAnimation(false) +, x356_26_detectCollision(detectCollision) +, x356_27_squishedRider(false) +, x356_28_rainSplashes(rainSplashes) +, x356_29_setXrayDrawFlags(false) +, x356_30_disableXrayAlpha(false) +, x356_31_xrayFog(true) { + SetMaterialFilter(CMaterialFilter::MakeIncludeExclude( + CMaterialList(kMT_Solid), + CMaterialList(kMT_NoStaticCollision, kMT_NoPlatformCollision, kMT_Platform))); + SetMovable(false); + if (HasAnimation()) { + AnimationData()->EnableLooping(true); + AnimationData()->SetIsAnimating(true); + } + if (x304_treeGroupContainer) { + x314_treeGroup = new CCollidableOBBTreeGroup(**x304_treeGroupContainer, GetMaterialList()); + } +} + +CScriptPlatform::~CScriptPlatform() {} + +rstl::optional_object< CAABox > CScriptPlatform::GetTouchBounds() const { + if (GetActive()) { + if (!x314_treeGroup.null()) { + return x314_treeGroup->CalculateAABox(GetTransform()); + } else { + return GetBoundingBox(); + } + } else { + return rstl::optional_object< CAABox >(); + } +}