diff --git a/include/Kyoto/Graphics/CModelFlags.hpp b/include/Kyoto/Graphics/CModelFlags.hpp index 724d15c0..a586459f 100644 --- a/include/Kyoto/Graphics/CModelFlags.hpp +++ b/include/Kyoto/Graphics/CModelFlags.hpp @@ -33,6 +33,10 @@ public: , x1_matSetIdx(0) , x2_flags(kF_DepthCompare | kF_DepthUpdate) , x4_color(color) {} + + CModelFlags(ETrans blendMode, u8 shadIdx, EFlags flags, const CColor& col) + : x0_blendMode(blendMode), x1_matSetIdx(shadIdx), x2_flags(flags), x4_color(col) {} + CModelFlags(const CModelFlags& flags, uint otherFlags) : x0_blendMode(flags.x0_blendMode) , x1_matSetIdx(flags.x1_matSetIdx) diff --git a/include/Kyoto/Math/CVector3f.hpp b/include/Kyoto/Math/CVector3f.hpp index 324702ab..e58197e9 100644 --- a/include/Kyoto/Math/CVector3f.hpp +++ b/include/Kyoto/Math/CVector3f.hpp @@ -42,7 +42,12 @@ public: static float GetAngleDiff(const CVector3f& a, const CVector3f& b); bool IsEqu(const CVector3f& other, f32 epsilon = FLT_EPSILON) const; // Lerp__9CVector3fFRC9CVector3fRC9CVector3ff - // MagSquared__9CVector3fCFv weak + inline float MagSquared() const { + float mag = mX * mX; + mag += mY * mY; + mag += mZ * mZ; + return mag; + } static CVector3f Cross(const CVector3f& lhs, const CVector3f& rhs) { const float x = (lhs.GetY() * rhs.GetZ()) - (rhs.GetY() * lhs.GetZ()); const float y = (lhs.GetZ() * rhs.GetX()) - (rhs.GetZ() * lhs.GetX()); diff --git a/include/MetroidPrime/CAnimData.hpp b/include/MetroidPrime/CAnimData.hpp index 0bb8aa2b..6e335275 100644 --- a/include/MetroidPrime/CAnimData.hpp +++ b/include/MetroidPrime/CAnimData.hpp @@ -82,7 +82,7 @@ public: // AdvanceIgnoreParticles__9CAnimDataFfR9CRandom16b // Advance__9CAnimDataFfRC9CVector3fR13CStateManagerb // DoAdvance__9CAnimDataFfRbR9CRandom16b - // SetAnimation__9CAnimDataFRC18CAnimPlaybackParmsb + void SetAnimation(const CAnimPlaybackParms& parms, bool noTrans); // GetAnimationPrimitives__9CAnimDataCFRC18CAnimPlaybackParmsRQ24rstl72set<10CPrimitive,Q24rstl18less<10CPrimitive>,Q24rstl17rmemory_allocator> // PrimitiveSetToTokenVector__9CAnimDataFRCQ24rstl72set<10CPrimitive,Q24rstl18less<10CPrimitive>,Q24rstl17rmemory_allocator>RQ24rstl42vector<6CToken,Q24rstl17rmemory_allocator>b // BuildPose__9CAnimDataFv diff --git a/include/MetroidPrime/CAnimPlaybackParms.hpp b/include/MetroidPrime/CAnimPlaybackParms.hpp index b397c5dd..b1334cde 100644 --- a/include/MetroidPrime/CAnimPlaybackParms.hpp +++ b/include/MetroidPrime/CAnimPlaybackParms.hpp @@ -19,6 +19,10 @@ private: CQuaternion* x1c_deltaOrient; CTransform4f* x20_objectXf; CVector3f* x24_objectScale; + +public: + CAnimPlaybackParms(int animA, int animB, float blendWeight, bool animating) + : x0_animA(animA), x4_animB(animB), x8_blendWeight(blendWeight), xc_animating(animating) {} }; CHECK_SIZEOF(CAnimPlaybackParms, 0x28) diff --git a/include/MetroidPrime/CArtifactDoll.hpp b/include/MetroidPrime/CArtifactDoll.hpp new file mode 100644 index 00000000..ce9eb31d --- /dev/null +++ b/include/MetroidPrime/CArtifactDoll.hpp @@ -0,0 +1,12 @@ +#ifndef _CARTIFACTDOLL_HPP +#define _CARTIFACTDOLL_HPP + +#include "MetroidPrime/TGameTypes.hpp" +#include "MetroidPrime/Player/CPlayerState.hpp" + +class CArtifactDoll { +public: + static CAssetId GetArtifactHeadScanFromItemType(CPlayerState::EItemType); +}; + +#endif // _CARTIFACTDOLL_HPP diff --git a/include/MetroidPrime/CPhysicsActor.hpp b/include/MetroidPrime/CPhysicsActor.hpp index 105b33cb..84740f63 100644 --- a/include/MetroidPrime/CPhysicsActor.hpp +++ b/include/MetroidPrime/CPhysicsActor.hpp @@ -111,6 +111,9 @@ public: bool GetMovable() const { return xf8_24_movable; } void SetMovable(bool v) { xf8_24_movable = v; } + void MoveToOR(const CVector3f&, float); + void RotateToOR(const CQuaternion&, float); + static float GetGravityConstant() { return skGravityConstant; } private: diff --git a/include/MetroidPrime/CStateManager.hpp b/include/MetroidPrime/CStateManager.hpp index 1a45902e..e981a641 100644 --- a/include/MetroidPrime/CStateManager.hpp +++ b/include/MetroidPrime/CStateManager.hpp @@ -163,6 +163,12 @@ public: const CDamageInfo& info, const CMaterialFilter& filter, const CVector3f& knockbackVec); + // + void QueueMessage(int frameCount, CAssetId msg, float f1); + int GetHUDMessageFrameCount() const { + return xf80_hudMessageFrameCount; + } + // State transitions void DeferStateTransition(EStateManagerTransition t); void EnterMapScreen() { DeferStateTransition(kSMT_MapScreen); } diff --git a/include/MetroidPrime/Cameras/CCameraManager.hpp b/include/MetroidPrime/Cameras/CCameraManager.hpp index 1e8827e4..b5d724f5 100644 --- a/include/MetroidPrime/Cameras/CCameraManager.hpp +++ b/include/MetroidPrime/Cameras/CCameraManager.hpp @@ -24,6 +24,7 @@ class CCameraManager { public: CGameCamera* CurrentCamera(CStateManager& mgr); const CGameCamera* GetCurrentCamera(const CStateManager& mgr) const; + const CFirstPersonCamera* GetFirstPersonCamera() const { return x7c_fpCamera; } void SetPlayerCamera(CStateManager& mgr, TUniqueId newCamId); void SetFogDensity(float fogDensityTarget, float fogDensitySpeed); diff --git a/include/MetroidPrime/Cameras/CFirstPersonCamera.hpp b/include/MetroidPrime/Cameras/CFirstPersonCamera.hpp new file mode 100644 index 00000000..cac5032b --- /dev/null +++ b/include/MetroidPrime/Cameras/CFirstPersonCamera.hpp @@ -0,0 +1,11 @@ +#ifndef _CFIRSTPERSONCAMERA_HPP +#define _CFIRSTPERSONCAMERA_HPP + +#include "MetroidPrime/Cameras/CGameCamera.hpp" + +class CFirstPersonCamera : public CGameCamera { +public: + +}; + +#endif // _CFIRSTPERSONCAMERA_HPP diff --git a/include/MetroidPrime/HUD/CHUDMemoParms.hpp b/include/MetroidPrime/HUD/CHUDMemoParms.hpp index e360fddf..9d173780 100644 --- a/include/MetroidPrime/HUD/CHUDMemoParms.hpp +++ b/include/MetroidPrime/HUD/CHUDMemoParms.hpp @@ -5,6 +5,8 @@ class CInputStream; class CHUDMemoParms { public: + CHUDMemoParms(float dispTime, bool clear, bool fadeOut, bool hint) + : mDispTime(dispTime), mClearMemoWindow(clear), mFadeOutOnly(fadeOut), mHintMemo(hint) {} CHUDMemoParms(CInputStream& in); float GetDisplayTime() const { return mDispTime; } diff --git a/include/MetroidPrime/HUD/CSamusHud.hpp b/include/MetroidPrime/HUD/CSamusHud.hpp new file mode 100644 index 00000000..21a0c831 --- /dev/null +++ b/include/MetroidPrime/HUD/CSamusHud.hpp @@ -0,0 +1,13 @@ +#ifndef __CSAMUSHUD_HPP__ +#define __CSAMUSHUD_HPP__ + +#include "MetroidPrime/HUD/CHUDMemoParms.hpp" + +#include "rstl/string.hpp" + +class CSamusHud { +public: + static void DisplayHudMemo(const rstl::wstring& text, const CHUDMemoParms& info); +}; + +#endif // __CSAMUSHUD_HPP__ diff --git a/include/MetroidPrime/Player/CPlayer.hpp b/include/MetroidPrime/Player/CPlayer.hpp index e1fbb3a6..294cf0ab 100644 --- a/include/MetroidPrime/Player/CPlayer.hpp +++ b/include/MetroidPrime/Player/CPlayer.hpp @@ -165,6 +165,9 @@ public: void AddOrbitDisableSource(CStateManager& mgr, TUniqueId addId); void RemoveOrbitDisableSource(TUniqueId uid); + CPlayerGun* PlayerGun() { return x490_gun.get(); } + const CPlayerGun* GetPlayerGun() const { return x490_gun.get(); } + private: struct CVisorSteam { f32 x0_curTargetAlpha; diff --git a/include/MetroidPrime/Player/CPlayerGun.hpp b/include/MetroidPrime/Player/CPlayerGun.hpp new file mode 100644 index 00000000..265ec8d3 --- /dev/null +++ b/include/MetroidPrime/Player/CPlayerGun.hpp @@ -0,0 +1,18 @@ +#ifndef _CPLAYERGUN_HPP +#define _CPLAYERGUN_HPP + +class CPlayerGun { + static float skTractorBeamFactor; + + public: + + bool IsCharging() const; + float GetChargeBeamFactor() const; + + static float GetTractorBeamFactor() { + return skTractorBeamFactor; + } + +}; + +#endif // _CPLAYERGUN_HPP diff --git a/include/MetroidPrime/Player/CSystemOptions.hpp b/include/MetroidPrime/Player/CSystemOptions.hpp index 2e22b9cc..3324f2aa 100644 --- a/include/MetroidPrime/Player/CSystemOptions.hpp +++ b/include/MetroidPrime/Player/CSystemOptions.hpp @@ -19,6 +19,12 @@ public: bool GetCinematicState(rstl::pair< CAssetId, TEditorId > cineId) const; void SetCinematicState(rstl::pair< CAssetId, TEditorId > cineId, bool state); + bool GetShowPowerBombAmmoMessage() const; + void IncrementPowerBombAmmoCount(); + + bool GetAllItemsCollected() const { return xd0_29_allItemsCollected; } + void SetAllItemsCollected(bool); + private: rstl::reserved_vector< u8, 98 > x0_nesState; rstl::reserved_vector< bool, 64 > x68_; diff --git a/include/MetroidPrime/ScriptObjects/CScriptPickup.hpp b/include/MetroidPrime/ScriptObjects/CScriptPickup.hpp new file mode 100644 index 00000000..6130bef0 --- /dev/null +++ b/include/MetroidPrime/ScriptObjects/CScriptPickup.hpp @@ -0,0 +1,45 @@ +#ifndef _CSCRIPTPICKUP_HPP +#define _CSCRIPTPICKUP_HPP + +#include "types.h" + +#include "MetroidPrime/CPhysicsActor.hpp" +#include "MetroidPrime/Player/CPlayerState.hpp" + +class CGenDescription; + +class CScriptPickup : public CPhysicsActor { + CPlayerState::EItemType x258_itemType; + int x25c_amount; + int x260_capacity; + float x264_possibility; + float x268_fadeInTime; + float x26c_lifeTime; + float x270_curTime; + float x274_tractorTime; + float x278_delayTimer; + TLockedToken x27c_pickupParticleDesc; + + bool x28c_24_generated : 1; + bool x28c_25_inTractor : 1; + bool x28c_26_enableTractorTest : 1; + +public: + CScriptPickup(TUniqueId uid, const rstl::string& name, const CEntityInfo& info, const CTransform4f& xf, + const CModelData& mData, const CActorParameters& aParams, const CAABox& aabb, + CPlayerState::EItemType itemType, int amount, int capacity, CAssetId pickupEffect, float possibility, + float lifeTime, float fadeInTime, float startDelay, bool active); + ~CScriptPickup(); + + void Think(float, CStateManager&) override; + void Touch(CActor&, CStateManager&) override; + rstl::optional_object GetTouchBounds() const override; + void AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) override; + void Render(const CStateManager&) const override; + void Accept(IVisitor& visitor) override; + float GetPossibility() const; + CPlayerState::EItemType GetItem() const; + void SetSpawned(); +}; + +#endif // _CSCRIPTPICKUP_HPP diff --git a/src/MetroidPrime/ScriptObjects/CScriptPickup.cpp b/src/MetroidPrime/ScriptObjects/CScriptPickup.cpp new file mode 100644 index 00000000..93e1793b --- /dev/null +++ b/src/MetroidPrime/ScriptObjects/CScriptPickup.cpp @@ -0,0 +1,208 @@ +#include "MetroidPrime/ScriptObjects/CScriptPickup.hpp" + +#include "MetroidPrime/CAnimData.hpp" +#include "MetroidPrime/CAnimPlaybackParms.hpp" +#include "MetroidPrime/CArtifactDoll.hpp" +#include "MetroidPrime/CModelData.hpp" +#include "MetroidPrime/CStateManager.hpp" +#include "MetroidPrime/Cameras/CCameraManager.hpp" +#include "MetroidPrime/Cameras/CFirstPersonCamera.hpp" +#include "MetroidPrime/Player/CGameState.hpp" +#include "MetroidPrime/Player/CPlayer.hpp" +#include "MetroidPrime/Player/CPlayerGun.hpp" +#include "MetroidPrime/Player/CPlayerState.hpp" +#include "MetroidPrime/Tweaks/CTweakGame.hpp" + +#include "MetroidPrime/HUD/CHUDMemoParms.hpp" +#include "MetroidPrime/HUD/CSamusHud.hpp" + +#include "Kyoto/CResFactory.hpp" +#include "Kyoto/Math/CMath.hpp" +#include "Kyoto/Math/CRelAngle.hpp" +#include "Kyoto/Text/CStringTable.hpp" + +#include "rstl/math.hpp" + +CScriptPickup::CScriptPickup(TUniqueId uid, const rstl::string& name, const CEntityInfo& info, + const CTransform4f& xf, const CModelData& mData, + const CActorParameters& aParams, const CAABox& aabb, + CPlayerState::EItemType itemType, int amount, int capacity, + CAssetId pickupEffect, float possibility, float lifeTime, + float fadeInTime, float startDelay, bool active) +: CPhysicsActor(uid, active, name, info, xf, mData, CMaterialList(), aabb, + SMoverData(1.f, CVector3f::Zero(), CAxisAngle::Identity(), CVector3f::Zero(), + CAxisAngle::Identity()), + aParams, 0.3f, 0.1f) +, x258_itemType(itemType) +, x25c_amount(amount) +, x260_capacity(capacity) +, x264_possibility(possibility) +, x268_fadeInTime(fadeInTime) +, x26c_lifeTime(lifeTime) +, x278_delayTimer(startDelay) { + if (pickupEffect != kInvalidAssetId) { + x27c_pickupParticleDesc = gpSimplePool->GetObj(SObjectTag('PART', pickupEffect)); + } + + if (!x64_modelData.null() && x64_modelData->GetAnimationData()) { + x64_modelData->AnimationData()->SetAnimation(CAnimPlaybackParms(0, -1, 1.f, true), false); + } + + if (x278_delayTimer != 0.f) { + xb4_drawFlags = CModelFlags(CModelFlags::kT_Blend, 0, CModelFlags::kF_DepthCompare, + CColor(1.f, 1.f, 1.f, 0.f)); + } +} + +CScriptPickup::~CScriptPickup() {} + +void CScriptPickup::Think(float dt, CStateManager& mgr) { + if (!GetActive()) { + return; + } + + if (x278_delayTimer >= 0.f) { + CPhysicsActor::Stop(); + x278_delayTimer -= dt; + return; + } + + x270_curTime += dt; + if (x28c_25_inTractor && (x26c_lifeTime - x270_curTime) < 2.f) { + x270_curTime = rstl::max_val(x270_curTime - 2.f * dt, x26c_lifeTime - 2.f - FLT_EPSILON); + } + + CModelFlags drawFlags(CModelFlags::kT_Opaque, CColor(1.f, 1.f, 1.f, 1.f)); + + if (x268_fadeInTime != 0.f) { + if (x270_curTime < x268_fadeInTime) { + drawFlags = CModelFlags(CModelFlags::kT_Blend, 0, CModelFlags::kF_DepthCompare, + CColor(1.f, 1.f, 1.f, x270_curTime / x268_fadeInTime)); + } else { + x268_fadeInTime = 0.f; + } + } else if (x26c_lifeTime != 0.f) { + float alpha = 1.f; + if (x26c_lifeTime < 2.f) { + alpha = 1.f - (x26c_lifeTime / x270_curTime); + } else if ((x26c_lifeTime - x270_curTime) < 2.f) { + alpha = (x26c_lifeTime - x270_curTime) * 0.5f; + } + + drawFlags = CModelFlags(CModelFlags::kT_Blend, 0, CModelFlags::kF_DepthCompare, + CColor(1.f, 1.f, 1.f, alpha)); + } + + xb4_drawFlags = drawFlags; + + if (!x64_modelData.null() && x64_modelData->HasAnimation()) { + SAdvancementDeltas deltas = UpdateAnimation(dt, mgr, true); + MoveToOR(deltas.GetOffsetDelta(), dt); + RotateToOR(deltas.GetOrientationDelta(), dt); + } + + if (x28c_25_inTractor) { + CVector3f posDelta = + mgr.GetPlayer()->GetTranslation() + (CVector3f::Up() * 2.0) - GetTranslation(); + x274_tractorTime += dt; + posDelta = posDelta.AsNormalized() * (20.f * (0.5f * rstl::min_val(2.f, x274_tractorTime))); + + if (x28c_26_enableTractorTest && (mgr.GetPlayer()->GetPlayerGun()->IsCharging() + ? mgr.GetPlayer()->GetPlayerGun()->GetChargeBeamFactor() + : 0.f) < CPlayerGun::GetTractorBeamFactor()) { + x28c_26_enableTractorTest = false; + x28c_25_inTractor = false; + posDelta = CVector3f::Zero(); + } + SetVelocityWR(posDelta); + } else if (x28c_24_generated) { + const float chargeFactor = mgr.GetPlayer()->GetPlayerGun()->IsCharging() + ? mgr.GetPlayer()->GetPlayerGun()->GetChargeBeamFactor() + : 0.f; + + if (chargeFactor > CPlayerGun::GetTractorBeamFactor()) { + const CVector3f posDelta = + GetTranslation() - mgr.GetCameraManager()->GetFirstPersonCamera()->GetTranslation(); + const float relFov = CRelAngle::FromDegrees(gpTweakGame->GetFirstPersonFOV()).AsRadians(); + if (CVector3f::Dot( + mgr.GetCameraManager()->GetFirstPersonCamera()->GetTransform().GetForward(), + posDelta.AsNormalized()) > cos(relFov) && + posDelta.MagSquared() < (30.f * 30.f)) { + x28c_25_inTractor = true; + x28c_26_enableTractorTest = true; + x274_tractorTime = 0.f; + } + } + } + + if (x26c_lifeTime != 0.f && x270_curTime > x26c_lifeTime) { + mgr.FreeScriptObject(GetUniqueId()); + } +} + +void CScriptPickup::Touch(CActor& act, CStateManager& mgr) { + if (GetActive() && x278_delayTimer < 0.f && TCastToPtr< CPlayer >(act)) { + if (x258_itemType >= CPlayerState::kIT_Truth && x258_itemType <= CPlayerState::kIT_Newborn) { + const CAssetId id = CArtifactDoll::GetArtifactHeadScanFromItemType(x258_itemType); + if (id != kInvalidAssetId) { + mgr.PlayerState()->SetScanTime(id, 0.5f); + } + } + + /*if (x27c_pickupParticleDesc) { + if (mgr.GetPlayerState()->GetActiveVisor(mgr) != CPlayerState::kPV_Thermal) { + mgr.AddObject(new CExplosion(x27c_pickupParticleDesc, mgr.AllocateUniqueId(), true, + CEntityInfo(GetAreaIdAlways(), CEntity::NullConnectionList, + kInvalidEditorId), "Explosion - Pickup Effect", x34_transform, 0, zeus::skOne3f, + zeus::skWhite)); + } + }*/ + + mgr.PlayerState()->InitializePowerUp(x258_itemType, x260_capacity); + mgr.PlayerState()->IncrPickUp(x258_itemType, x25c_amount); + mgr.FreeScriptObject(GetUniqueId()); + SendScriptMsgs(kSS_Arrived, mgr, kSM_None); + + if (x260_capacity > 0) { + const int total = mgr.GetPlayerState()->GetTotalPickupCount(); + const int colRate = mgr.GetPlayerState()->CalculateItemCollectionRate(); + if (total == colRate) { + CSystemOptions& opts = gpGameState->SystemOptions(); + mgr.QueueMessage(mgr.GetHUDMessageFrameCount() + 1, + gpResourceFactory + ->GetResourceIdByName(opts.GetAllItemsCollected() + ? "STRG_AllPickupsFound_2" + : "STRG_AllPickupsFound_1") + ->id, + 0.f); + opts.SetAllItemsCollected(true); + } + } + + if (x258_itemType == CPlayerState::kIT_PowerBombs && + gpGameState->SystemOptions().GetShowPowerBombAmmoMessage()) { + gpGameState->SystemOptions().IncrementPowerBombAmmoCount(); + CSamusHud::DisplayHudMemo(rstl::wstring_l(gpStringTable->GetString(109)), + CHUDMemoParms(0.5f, true, false, false)); + } + } +} + +rstl::optional_object< CAABox > CScriptPickup::GetTouchBounds() const override { + return CPhysicsActor::GetBoundingBox(); +} + +void CScriptPickup::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, + CStateManager& mgr) override { + CPhysicsActor::AcceptScriptMsg(msg, uid, mgr); +} + +void CScriptPickup::Render(const CStateManager& mgr) const override { CPhysicsActor::Render(mgr); } + +void CScriptPickup::Accept(IVisitor& visitor) { visitor.Visit(*this); } + +float CScriptPickup::GetPossibility() const { return x264_possibility; } + +CPlayerState::EItemType CScriptPickup::GetItem() const { return x258_itemType; } + +void CScriptPickup::SetSpawned() { x28c_24_generated = true; }