mirror of
https://github.com/PrimeDecomp/prime.git
synced 2025-08-04 15:35:36 +00:00
233 lines
7.9 KiB
C++
233 lines
7.9 KiB
C++
#include "MetroidPrime/ScriptObjects/CScriptPlatform.hpp"
|
|
|
|
#include "MetroidPrime/CActorParameters.hpp"
|
|
#include "MetroidPrime/CAnimData.hpp"
|
|
#include "MetroidPrime/CGameCollision.hpp"
|
|
#include "MetroidPrime/Player/CPlayer.hpp"
|
|
#include "MetroidPrime/ScriptObjects/CScriptWaypoint.hpp"
|
|
|
|
#include "Kyoto/Graphics/CGX.hpp"
|
|
|
|
#include "WorldFormat/CCollidableOBBTreeGroup.hpp"
|
|
|
|
#include "rstl/algorithm.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_null();
|
|
}
|
|
}
|
|
|
|
TUniqueId CScriptPlatform::GetWaypoint(CStateManager& mgr) {
|
|
rstl::vector< SConnection >::const_iterator conn = GetConnectionList().begin();
|
|
for (; conn != GetConnectionList().end(); ++conn) {
|
|
if (conn->x4_msg == kSM_Follow) {
|
|
return mgr.GetIdForScript(conn->x8_objId);
|
|
}
|
|
}
|
|
return kInvalidUniqueId;
|
|
}
|
|
|
|
TUniqueId CScriptPlatform::GetNext(TUniqueId uid, CStateManager& mgr) {
|
|
const CScriptWaypoint* nextWp = TCastToConstPtr< CScriptWaypoint >(mgr.GetObjectById(uid));
|
|
if (!nextWp) {
|
|
return GetWaypoint(mgr);
|
|
}
|
|
TUniqueId next = nextWp->NextWaypoint(mgr);
|
|
if (const CScriptWaypoint* wp = TCastToConstPtr< CScriptWaypoint >(mgr.GetObjectById(next))) {
|
|
x25c_currentSpeed = wp->GetSpeed();
|
|
}
|
|
return next;
|
|
}
|
|
|
|
void CScriptPlatform::AddRider(rstl::vector< SRiders >& riders, TUniqueId riderId,
|
|
const CPhysicsActor* ridee, CStateManager& mgr) {
|
|
rstl::vector< SRiders >::iterator it = rstl::find(riders.begin(), riders.end(), SRiders(riderId));
|
|
if (it == riders.end()) {
|
|
SRiders rider(riderId);
|
|
if (CPhysicsActor* act = TCastToPtr< CPhysicsActor >(mgr.ObjectById(riderId))) {
|
|
CVector3f rideePos = ridee->GetTranslation();
|
|
rider.x8_transform.SetTranslation(
|
|
ridee->GetTransform().TransposeRotate(act->GetTranslation() - rideePos));
|
|
mgr.SendScriptMsg(act, ridee->GetUniqueId(), kSM_AddPlatformRider);
|
|
}
|
|
riders.reserve(riders.size() + 1);
|
|
riders.push_back(rider);
|
|
} else {
|
|
it->x4_decayTimer = 1.f / 6.f;
|
|
}
|
|
}
|
|
|
|
TEntityList CScriptPlatform::BuildNearListFromRiders(CStateManager& mgr,
|
|
const rstl::vector< SRiders >& riders) {
|
|
TEntityList result;
|
|
rstl::vector< SRiders >::const_iterator it = riders.begin();
|
|
for (; it != riders.end(); ++it) {
|
|
if (CActor* actor = TCastToPtr< CActor >(mgr.ObjectById(it->x0_uid))) {
|
|
result.push_back(actor->GetUniqueId());
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void CScriptPlatform::DecayRiders(rstl::vector< SRiders >& riders, f32 dt, CStateManager& mgr) {
|
|
rstl::vector< SRiders >::iterator it = riders.begin();
|
|
while (it != riders.end()) {
|
|
it->x4_decayTimer -= dt;
|
|
if (it->x4_decayTimer <= 0.f) {
|
|
mgr.SendScriptMsgAlways(it->x0_uid, kInvalidUniqueId, kSM_AddPlatformRider);
|
|
#ifdef NON_MATCHING
|
|
it = riders.erase(it);
|
|
#else
|
|
// Oops, forgot to reassign the iterator
|
|
riders.erase(it);
|
|
#endif
|
|
} else {
|
|
it = it + 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
// TODO: minor regswap
|
|
void CScriptPlatform::MoveRiders(CStateManager& mgr, f32 dt, bool active,
|
|
rstl::vector< SRiders >& riders,
|
|
rstl::vector< SRiders >& collidedRiders, const CTransform4f& oldXf,
|
|
const CTransform4f& newXf, const CVector3f& dragDelta,
|
|
CQuaternion rotDelta) {
|
|
rstl::vector< SRiders >::iterator it = riders.begin();
|
|
while (it != riders.end()) {
|
|
if (active) {
|
|
CPhysicsActor* act = TCastToPtr< CPhysicsActor >(mgr.ObjectById(it->x0_uid));
|
|
if (act == nullptr || !act->GetActive()) {
|
|
++it;
|
|
continue;
|
|
}
|
|
const CTransform4f& xf = it->x8_transform;
|
|
CVector3f diff = newXf.Rotate(xf.GetTranslation()) - oldXf.Rotate(xf.GetTranslation());
|
|
diff.SetZ(0.f);
|
|
CVector3f delta = dragDelta + diff;
|
|
CVector3f newPos = act->GetTranslation() + delta;
|
|
act->MoveCollisionPrimitive(delta);
|
|
bool collision = CGameCollision::DetectStaticCollisionBoolean(
|
|
mgr, *act->GetCollisionPrimitive(), act->GetPrimitiveTransform(),
|
|
act->GetMaterialFilter());
|
|
act->MoveCollisionPrimitive(CVector3f::Zero());
|
|
if (collision) {
|
|
AddRider(collidedRiders, act->GetUniqueId(), act, mgr);
|
|
#ifdef NON_MATCHING
|
|
it = riders.erase(it);
|
|
#else
|
|
// Oops, forgot to reassign the iterator (again)
|
|
riders.erase(it);
|
|
#endif
|
|
continue;
|
|
}
|
|
act->SetTranslation(newPos);
|
|
const CPlayer* player = TCastToConstPtr< CPlayer >(*act);
|
|
if (player == nullptr || player->GetOrbitState() == CPlayer::kOS_NoOrbit) {
|
|
const CQuaternion& rot = rotDelta * CQuaternion::FromMatrix(act->GetTransform());
|
|
act->SetTransform(rot.BuildTransform4f(act->GetTranslation()));
|
|
}
|
|
}
|
|
++it;
|
|
}
|
|
}
|