#include "Runtime/World/CScriptPlatform.hpp" #include #include "Runtime/CStateManager.hpp" #include "Runtime/Collision/CCollidableOBBTreeGroup.hpp" #include "Runtime/Collision/CGameCollision.hpp" #include "Runtime/Collision/CMaterialList.hpp" #include "Runtime/Graphics/CCubeRenderer.hpp" #include "Runtime/World/CActorParameters.hpp" #include "Runtime/World/CPlayer.hpp" #include "Runtime/World/CScriptColorModulate.hpp" #include "Runtime/World/CScriptTrigger.hpp" #include "Runtime/World/CScriptWaypoint.hpp" #include "Runtime/World/CWorld.hpp" #include "TCastTo.hpp" // Generated file, do not modify include path namespace metaforce { constexpr auto skPlatformMaterialList = CMaterialList{EMaterialTypes::Solid, EMaterialTypes::Immovable, EMaterialTypes::Platform, EMaterialTypes::Occluder}; CScriptPlatform::CScriptPlatform(TUniqueId uid, std::string_view name, const CEntityInfo& info, const zeus::CTransform& xf, CModelData&& mData, const CActorParameters& actParms, const zeus::CAABox& aabb, float speed, bool detectCollision, float xrayAlpha, bool active, const CHealthInfo& hInfo, const CDamageVulnerability& dVuln, std::optional> dcln, bool rainSplashes, u32 maxRainSplashes, u32 rainGenRate) : CPhysicsActor(uid, active, name, info, xf, std::move(mData), skPlatformMaterialList, aabb, SMoverData(15000.f), actParms, 0.3f, 0.1f) , x25c_currentSpeed(speed) , x268_fadeInTime(actParms.GetFadeInTime()) , x26c_fadeOutTime(actParms.GetFadeOutTime()) , x28c_initialHealth(hInfo) , x294_health(hInfo) , x29c_damageVuln(dVuln) , x304_treeGroupContainer(std::move(dcln)) , x348_xrayAlpha(xrayAlpha) , x34c_maxRainSplashes(maxRainSplashes) , x350_rainGenRate(rainGenRate) , x356_26_detectCollision(detectCollision) , x356_28_rainSplashes(rainSplashes) { CActor::SetMaterialFilter(CMaterialFilter::MakeIncludeExclude( CMaterialList(EMaterialTypes::Solid), CMaterialList(EMaterialTypes::NoStaticCollision, EMaterialTypes::NoPlatformCollision, EMaterialTypes::Platform))); xf8_24_movable = false; if (HasModelData() && GetModelData()->HasAnimData()) { GetModelData()->GetAnimationData()->EnableLooping(true); } if (x304_treeGroupContainer) { x314_treeGroup = std::make_unique(x304_treeGroupContainer->GetObj(), x68_material); } } void CScriptPlatform::Accept(IVisitor& visitor) { visitor.Visit(this); } void CScriptPlatform::DragSlave(CStateManager& mgr, rstl::reserved_vector& draggedSet, CActor* actor, const zeus::CVector3f& delta) { if (std::find(draggedSet.begin(), draggedSet.end(), actor->GetUniqueId().Value()) != draggedSet.end()) { return; } draggedSet.push_back(actor->GetUniqueId().Value()); zeus::CTransform newXf = actor->GetTransform(); newXf.origin += delta; actor->SetTransform(newXf); if (const TCastToPtr plat = actor) { plat->DragSlaves(mgr, draggedSet, delta); } } void CScriptPlatform::DragSlaves(CStateManager& mgr, rstl::reserved_vector& draggedSet, const zeus::CVector3f& delta) { for (SRiders& rider : x328_slavesStatic) { if (const TCastToPtr act = mgr.ObjectById(rider.x0_uid)) { DragSlave(mgr, draggedSet, act.GetPtr(), delta); } } for (auto it = x338_slavesDynamic.begin(); it != x338_slavesDynamic.end();) { if (const TCastToPtr act = mgr.ObjectById(it->x0_uid)) { DragSlave(mgr, draggedSet, act.GetPtr(), delta); ++it; } else { it = x338_slavesDynamic.erase(it); } } } void CScriptPlatform::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) { switch (msg) { case EScriptObjectMessage::InitializedInArea: BuildSlaveList(mgr); break; case EScriptObjectMessage::AddPlatformRider: AddRider(x318_riders, uid, this, mgr); break; case EScriptObjectMessage::Stop: { x25c_currentSpeed = 0.f; Stop(); break; } case EScriptObjectMessage::Next: { x25a_targetWaypoint = GetNext(x258_currentWaypoint, mgr); if (x25a_targetWaypoint == kInvalidUniqueId) { mgr.SendScriptMsg(this, GetUniqueId(), EScriptObjectMessage::Stop); } else if (const TCastToPtr wp = mgr.ObjectById(x25a_targetWaypoint)) { x25c_currentSpeed = 0.f; Stop(); x270_dragDelta = wp->GetTranslation() - GetTranslation(); SetTranslation(wp->GetTranslation()); x258_currentWaypoint = x25a_targetWaypoint; x25a_targetWaypoint = GetNext(x258_currentWaypoint, mgr); mgr.SendScriptMsg(wp, GetUniqueId(), EScriptObjectMessage::Arrived); if (!x328_slavesStatic.empty() || !x338_slavesDynamic.empty()) { rstl::reserved_vector draggedSet; DragSlaves(mgr, draggedSet, x270_dragDelta); } x270_dragDelta = zeus::skZero3f; } break; } case EScriptObjectMessage::Start: { x25a_targetWaypoint = GetNext(x258_currentWaypoint, mgr); if (x25a_targetWaypoint == kInvalidUniqueId) { mgr.SendScriptMsg(this, GetUniqueId(), EScriptObjectMessage::Stop); } else if (const TCastToConstPtr wp = mgr.ObjectById(x25a_targetWaypoint)) { x25c_currentSpeed = wp->GetSpeed(); } break; } case EScriptObjectMessage::Reset: { x356_24_dead = false; x294_health = x28c_initialHealth; break; } case EScriptObjectMessage::Increment: { if (!GetActive()) { mgr.SendScriptMsg(this, GetUniqueId(), EScriptObjectMessage::Activate); } CScriptColorModulate::FadeInHelper(mgr, GetUniqueId(), x268_fadeInTime); break; } case EScriptObjectMessage::Decrement: CScriptColorModulate::FadeOutHelper(mgr, GetUniqueId(), x26c_fadeOutTime); break; case EScriptObjectMessage::Deleted: DecayRiders(x318_riders, 1.66666675f, mgr); break; default: break; } CPhysicsActor::AcceptScriptMsg(msg, uid, mgr); } void CScriptPlatform::DecayRiders(std::vector& riders, float dt, CStateManager& mgr) { for (auto it = riders.begin(); it != riders.end();) { it->x4_decayTimer -= dt; if (it->x4_decayTimer <= 0.f) { mgr.SendScriptMsgAlways(it->x0_uid, kInvalidUniqueId, EScriptObjectMessage::AddPlatformRider); it = riders.erase(it); continue; } ++it; } } void CScriptPlatform::MoveRiders(CStateManager& mgr, float dt, bool active, std::vector& riders, std::vector& collidedRiders, const zeus::CTransform& oldXf, const zeus::CTransform& newXf, const zeus::CVector3f& dragDelta, const zeus::CQuaternion& rotDelta) { for (auto it = riders.begin(); it != riders.end();) { if (active) { if (TCastToPtr act = mgr.ObjectById(it->x0_uid)) { if (act->GetActive()) { zeus::CVector3f delta = newXf.rotate(it->x8_transform.origin) - oldXf.rotate(it->x8_transform.origin) + dragDelta; zeus::CVector3f newPos = act->GetTranslation() + delta; act->MoveCollisionPrimitive(delta); bool collision = CGameCollision::DetectStaticCollisionBoolean( mgr, *act->GetCollisionPrimitive(), act->GetPrimitiveTransform(), act->GetMaterialFilter()); act->MoveCollisionPrimitive(zeus::skZero3f); if (collision) { AddRider(collidedRiders, act->GetUniqueId(), act.GetPtr(), mgr); it = riders.erase(it); continue; } act->SetTranslation(newPos); if (const TCastToConstPtr player = act.GetPtr()) { if (player->GetOrbitState() != CPlayer::EPlayerOrbitState::NoOrbit) { ++it; continue; } } zeus::CTransform xf = (rotDelta * zeus::CQuaternion(act->GetTransform().basis)).toTransform(); xf.origin = act->GetTranslation(); act->SetTransform(xf); } } } ++it; } } EntityList CScriptPlatform::BuildNearListFromRiders(CStateManager& mgr, const std::vector& movedRiders) { EntityList ret; for (const SRiders& rider : movedRiders) { if (const TCastToConstPtr act = mgr.ObjectById(rider.x0_uid)) { ret.push_back(act->GetUniqueId()); } } return ret; } void CScriptPlatform::PreThink(float dt, CStateManager& mgr) { DecayRiders(x318_riders, dt, mgr); x264_collisionRecoverDelay -= dt; x260_moveDelay -= dt; if (x260_moveDelay <= 0.f) { x270_dragDelta = zeus::skZero3f; zeus::CTransform oldXf = x34_transform; CMotionState mState = GetMotionState(); if (GetActive()) { for (SRiders& rider : x318_riders) { if (const TCastToConstPtr act = mgr.ObjectById(rider.x0_uid)) { rider.x8_transform.origin = x34_transform.transposeRotate(act->GetTranslation() - GetTranslation()); } } x27c_rotDelta = Move(dt, mgr); } x270_dragDelta = x34_transform.origin - oldXf.origin; std::vector collidedRiders; MoveRiders(mgr, dt, GetActive(), x318_riders, collidedRiders, oldXf, x34_transform, x270_dragDelta, x27c_rotDelta); x356_27_squishedRider = false; if (!collidedRiders.empty()) { EntityList nearList = BuildNearListFromRiders(mgr, collidedRiders); if (CGameCollision::DetectDynamicCollisionBoolean(*GetCollisionPrimitive(), GetPrimitiveTransform(), nearList, mgr)) { SetMotionState(mState); Stop(); x260_moveDelay = 0.035f; MoveRiders(mgr, dt, GetActive(), x318_riders, collidedRiders, x34_transform, oldXf, -x270_dragDelta, x27c_rotDelta.inverse()); x270_dragDelta = zeus::skZero3f; SendScriptMsgs(EScriptObjectState::Modify, mgr, EScriptObjectMessage::None); x356_27_squishedRider = true; } } } } void CScriptPlatform::Think(float dt, CStateManager& mgr) { if (!GetActive()) { return; } if (HasModelData() && GetModelData()->HasAnimData()) { if (!x356_25_controlledAnimation) { UpdateAnimation(dt, mgr, true); } if (x356_28_rainSplashes && mgr.GetWorld()->GetNeededEnvFx() == EEnvFxType::Rain) { if (HasModelData() && !GetModelData()->IsNull() && mgr.GetEnvFxManager()->IsSplashActive() && mgr.GetEnvFxManager()->GetRainMagnitude() != 0.f) { mgr.GetActorModelParticles()->AddRainSplashGenerator(*this, mgr, x34c_maxRainSplashes, x350_rainGenRate, 0.f); } } } if (!x328_slavesStatic.empty() || !x338_slavesDynamic.empty()) { rstl::reserved_vector draggedSet; DragSlaves(mgr, draggedSet, x270_dragDelta); } if (x356_24_dead) { return; } if (HealthInfo(mgr)->GetHP() <= 0.f) { x356_24_dead = true; SendScriptMsgs(EScriptObjectState::Dead, mgr, EScriptObjectMessage::None); } } void CScriptPlatform::PreRender(CStateManager& mgr, const zeus::CFrustum& frustum) { CActor::PreRender(mgr, frustum); if (!xe4_30_outOfFrustum && !zeus::close_enough(x348_xrayAlpha, 1.f)) { const CModelFlags flags(5, 0, 3, {1.f, x348_xrayAlpha}); if (mgr.GetPlayerState()->GetActiveVisor(mgr) == CPlayerState::EPlayerVisor::XRay && !x356_30_disableXrayAlpha) { xb4_drawFlags = flags; x356_29_setXrayDrawFlags = true; } else if (x356_29_setXrayDrawFlags) { x356_29_setXrayDrawFlags = false; if (xb4_drawFlags == flags && !x356_30_disableXrayAlpha) { xb4_drawFlags = CModelFlags(0, 0, 3, zeus::skWhite); } } } if (!mgr.GetObjectById(x354_boundsTrigger)) { x354_boundsTrigger = kInvalidUniqueId; } } void CScriptPlatform::Render(CStateManager& mgr) { const bool xray = mgr.GetPlayerState()->GetActiveVisor(mgr) == CPlayerState::EPlayerVisor::XRay; if (xray && !x356_31_xrayFog) { g_Renderer->SetWorldFog(ERglFogMode::None, 0.f, 1.f, zeus::skBlack); } CPhysicsActor::Render(mgr); if (xray && !x356_31_xrayFog) { mgr.SetupFogForArea(x4_areaId); } } std::optional CScriptPlatform::GetTouchBounds() const { if (x314_treeGroup) { return {x314_treeGroup->CalculateAABox(GetTransform())}; } return {CPhysicsActor::GetBoundingBox()}; } zeus::CTransform CScriptPlatform::GetPrimitiveTransform() const { zeus::CTransform ret = GetTransform(); ret.origin += GetPrimitiveOffset(); return ret; } const CCollisionPrimitive* CScriptPlatform::GetCollisionPrimitive() const { if (!x314_treeGroup) { return CPhysicsActor::GetCollisionPrimitive(); } return x314_treeGroup.get(); } zeus::CVector3f CScriptPlatform::GetOrbitPosition(const CStateManager& mgr) const { return GetAimPosition(mgr, 0.f); } zeus::CVector3f CScriptPlatform::GetAimPosition(const CStateManager& mgr, float dt) const { if (auto tb = GetTouchBounds()) { return {tb->center()}; } return CPhysicsActor::GetAimPosition(mgr, dt); } zeus::CAABox CScriptPlatform::GetSortingBounds(const CStateManager& mgr) const { if (x354_boundsTrigger != kInvalidUniqueId) { if (const TCastToConstPtr trig = mgr.GetObjectById(x354_boundsTrigger)) { return trig->GetTriggerBoundsWR(); } } return CActor::GetSortingBounds(mgr); } bool CScriptPlatform::IsRider(TUniqueId id) const { return std::any_of(x318_riders.cbegin(), x318_riders.cend(), [id](const auto& rider) { return rider.x0_uid == id; }); } bool CScriptPlatform::IsSlave(TUniqueId id) const { auto search = std::find_if(x328_slavesStatic.begin(), x328_slavesStatic.end(), [id](const SRiders& rider) { return rider.x0_uid == id; }); if (search != x328_slavesStatic.end()) { return true; } search = std::find_if(x338_slavesDynamic.begin(), x338_slavesDynamic.end(), [id](const SRiders& rider) { return rider.x0_uid == id; }); return search != x338_slavesDynamic.end(); } void CScriptPlatform::BuildSlaveList(CStateManager& mgr) { x328_slavesStatic.reserve(GetConnectionList().size()); for (const SConnection& conn : GetConnectionList()) { if (conn.x0_state == EScriptObjectState::Play && conn.x4_msg == EScriptObjectMessage::Activate) { if (const TCastToPtr act = mgr.ObjectById(mgr.GetIdForScript(conn.x8_objId))) { act->AddMaterial(EMaterialTypes::PlatformSlave, mgr); zeus::CTransform xf = act->GetTransform(); xf.origin = act->GetTranslation() - GetTranslation(); x328_slavesStatic.emplace_back(act->GetUniqueId(), 0.166667f, xf); } } else if (conn.x0_state == EScriptObjectState::InheritBounds && conn.x4_msg == EScriptObjectMessage::Activate) { auto list = mgr.GetIdListForScript(conn.x8_objId); for (auto it = list.first; it != list.second; ++it) { if (TCastToConstPtr(mgr.GetObjectById(it->second))) { x354_boundsTrigger = it->second; } } } } } void CScriptPlatform::AddRider(std::vector& riders, TUniqueId riderId, const CPhysicsActor* ridee, CStateManager& mgr) { const auto& search = std::find_if(riders.begin(), riders.end(), [riderId](const SRiders& r) { return r.x0_uid == riderId; }); if (search == riders.end()) { zeus::CTransform xf; if (const TCastToPtr act = mgr.ObjectById(riderId)) { xf.origin = ridee->GetTransform().transposeRotate(act->GetTranslation() - ridee->GetTranslation()); mgr.SendScriptMsg(act.GetPtr(), ridee->GetUniqueId(), EScriptObjectMessage::AddPlatformRider); } riders.emplace_back(riderId, 0.166667f, xf); } else { search->x4_decayTimer = 0.166667f; } } void CScriptPlatform::AddSlave(TUniqueId id, CStateManager& mgr) { const auto& search = std::find_if(x338_slavesDynamic.begin(), x338_slavesDynamic.end(), [id](const SRiders& r) { return r.x0_uid == id; }); if (search != x338_slavesDynamic.end()) { return; } if (const TCastToPtr act = mgr.ObjectById(id)) { act->AddMaterial(EMaterialTypes::PlatformSlave, mgr); const zeus::CTransform localXf = x34_transform.inverse() * act->GetTransform(); x338_slavesDynamic.emplace_back(id, 0.166667f, localXf); } } TUniqueId CScriptPlatform::GetNext(TUniqueId uid, CStateManager& mgr) { const TCastToConstPtr nextWp = mgr.GetObjectById(uid); if (!nextWp) { return GetWaypoint(mgr); } const TUniqueId next = nextWp->NextWaypoint(mgr); if (const TCastToConstPtr wp = mgr.GetObjectById(next)) { x25c_currentSpeed = wp->GetSpeed(); } return next; } TUniqueId CScriptPlatform::GetWaypoint(CStateManager& mgr) { for (const SConnection& conn : x20_conns) { if (conn.x4_msg == EScriptObjectMessage::Follow) { return mgr.GetIdForScript(conn.x8_objId); } } return kInvalidUniqueId; } void CScriptPlatform::SplashThink(const zeus::CAABox&, const CFluidPlane&, float, CStateManager&) const { // Empty } zeus::CQuaternion CScriptPlatform::Move(float dt, CStateManager& mgr) { TUniqueId nextWaypoint = x25a_targetWaypoint; if (x25a_targetWaypoint == kInvalidUniqueId) { nextWaypoint = GetNext(x258_currentWaypoint, mgr); } const TCastToConstPtr wp = mgr.ObjectById(nextWaypoint); if (x258_currentWaypoint != kInvalidUniqueId && wp && !wp->GetActive()) { nextWaypoint = GetNext(x258_currentWaypoint, mgr); if (nextWaypoint == kInvalidUniqueId) { if (const TCastToConstPtr wp2 = mgr.ObjectById(x258_currentWaypoint)) { if (wp2->GetActive()) { nextWaypoint = x258_currentWaypoint; } } } } if (nextWaypoint == kInvalidUniqueId) { return zeus::CQuaternion(); } while (nextWaypoint != kInvalidUniqueId) { if (const TCastToPtr wp2 = mgr.ObjectById(nextWaypoint)) { const zeus::CVector3f platToWp = wp2->GetTranslation() - GetTranslation(); if (zeus::close_enough(platToWp, zeus::skZero3f)) { x258_currentWaypoint = nextWaypoint; mgr.SendScriptMsg(wp2.GetPtr(), GetUniqueId(), EScriptObjectMessage::Arrived); if (zeus::close_enough(x25c_currentSpeed, 0.f, 0.02)) { nextWaypoint = GetNext(x258_currentWaypoint, mgr); x25c_currentSpeed = 0.f; Stop(); } else { nextWaypoint = GetNext(x258_currentWaypoint, mgr); } if (nextWaypoint != kInvalidUniqueId) { continue; } mgr.SendScriptMsg(this, GetUniqueId(), EScriptObjectMessage::Stop); } if (zeus::close_enough(platToWp, zeus::skZero3f)) { x270_dragDelta = wp2->GetTranslation() - GetTranslation(); MoveToWR(GetTranslation(), dt); } else if ((platToWp.normalized() * x25c_currentSpeed * dt).magSquared() > platToWp.magSquared()) { x270_dragDelta = wp2->GetTranslation() - GetTranslation(); MoveToWR(wp2->GetTranslation(), dt); } else { x270_dragDelta = platToWp.normalized() * x25c_currentSpeed * dt; MoveToWR(GetTranslation() + x270_dragDelta, dt); } EntityList nearList; mgr.BuildColliderList(nearList, *this, GetMotionVolume(dt)); EntityList nonRiders; for (TUniqueId id : nearList) { if (!IsRider(id) && !IsSlave(id)) { nonRiders.push_back(id); } } if (x356_26_detectCollision) { const CMotionState mState = PredictMotion(dt); MoveCollisionPrimitive(mState.x0_translation); const bool collision = CGameCollision::DetectDynamicCollisionBoolean(*GetCollisionPrimitive(), GetPrimitiveTransform(), nonRiders, mgr); MoveCollisionPrimitive(zeus::skZero3f); if (collision || x356_27_squishedRider) { if (x356_26_detectCollision) { if (x264_collisionRecoverDelay <= 0.f && !x356_27_squishedRider) { x264_collisionRecoverDelay = 0.035f; break; } else { x356_27_squishedRider = false; const TUniqueId prevWaypoint = nextWaypoint; nextWaypoint = GetNext(nextWaypoint, mgr); if (x25a_targetWaypoint == nextWaypoint || x25a_targetWaypoint == prevWaypoint) { x260_moveDelay = 0.035f; break; } } } else { break; } } else { AddMotionState(mState); break; } } else { xf8_24_movable = true; CGameCollision::Move(mgr, *this, dt, &nonRiders); xf8_24_movable = false; break; } } else { nextWaypoint = kInvalidUniqueId; break; } } x25a_targetWaypoint = nextWaypoint; return zeus::CQuaternion(); } void CScriptPlatform::DebugDraw() { if (!m_boxFilter) { m_boxFilter = {CAABoxShader()}; } m_boxFilter->setAABB(*GetTouchBounds()); m_boxFilter->draw({1.f, 0.f, 1.f, .5f}); } } // namespace metaforce