#include "Runtime/World/CScriptDock.hpp" #include "Runtime/CStateManager.hpp" #include "Runtime/Character/CModelData.hpp" #include "Runtime/Collision/CMaterialList.hpp" #include "Runtime/Particle/CGenDescription.hpp" #include "Runtime/World/CActorParameters.hpp" #include "Runtime/World/CPlayer.hpp" #include "Runtime/World/CScriptDoor.hpp" #include "Runtime/World/CWorld.hpp" #include "TCastTo.hpp" // Generated file, do not modify include path namespace metaforce { constexpr auto skDockMaterialList = CMaterialList{EMaterialTypes::Trigger, EMaterialTypes::Immovable, EMaterialTypes::AIBlock}; CScriptDock::CScriptDock(TUniqueId uid, std::string_view name, const CEntityInfo& info, const zeus::CVector3f& position, const zeus::CVector3f& extents, s32 dock, TAreaId area, bool active, s32 dockReferenceCount, bool loadConnected) : CPhysicsActor(uid, active, name, info, zeus::CTransform(zeus::CMatrix3f(), position), CModelData::CModelDataNull(), skDockMaterialList, zeus::CAABox(-extents * 0.5f, extents * 0.5f), SMoverData(1.f), CActorParameters::None(), 0.3f, 0.1f) , x258_dockReferenceCount(dockReferenceCount) , x25c_dock(dock) , x260_area(area) , x268_25_loadConnected(loadConnected) {} void CScriptDock::Accept(IVisitor& visitor) { visitor.Visit(this); } void CScriptDock::Think(float dt, CStateManager& mgr) { if (!GetActive()) { UpdateAreaActivateFlags(mgr); x268_24_dockReferenced = false; } const IGameArea::Dock* gameDock = mgr.GetWorld()->GetArea(x260_area)->GetDock(x25c_dock); const TAreaId connArea = gameDock->GetConnectedAreaId(gameDock->GetReferenceCount()); if (connArea != kInvalidAreaId) { const bool connPostConstructed = mgr.GetWorld()->GetArea(connArea)->IsPostConstructed(); if (x268_26_areaPostConstructed != connPostConstructed) { x268_26_areaPostConstructed = connPostConstructed; if (connPostConstructed) { CEntity::SendScriptMsgs(EScriptObjectState::MaxReached, mgr, EScriptObjectMessage::None); } else { CEntity::SendScriptMsgs(EScriptObjectState::Zero, mgr, EScriptObjectMessage::None); } } } if (mgr.GetNextAreaId() != x260_area) { x264_dockState = EDockState::InNextRoom; } else if (x264_dockState == EDockState::InNextRoom) { x264_dockState = EDockState::InSourceRoom; } else if (x264_dockState == EDockState::PlayerTouched) { x264_dockState = EDockState::EnterNextArea; } else if (x264_dockState == EDockState::EnterNextArea) { CPlayer& player = mgr.GetPlayer(); if (HasPointCrossedDock(mgr, player.GetTranslation())) { const IGameArea::Dock* dock = mgr.GetWorld()->GetArea(mgr.GetNextAreaId())->GetDock(x25c_dock); const TAreaId aid = dock->GetConnectedAreaId(dock->GetReferenceCount()); if (aid != kInvalidAreaId && mgr.GetWorld()->GetArea(aid)->GetActive()) { mgr.SetCurrentAreaId(aid); const s32 otherDock = dock->GetOtherDockNumber(dock->GetReferenceCount()); if (CObjectList* objs = mgr.GetWorld()->GetArea(aid)->GetAreaObjects()) { for (CEntity* ent : *objs) { const TCastToPtr dock2(ent); if (dock2 && dock2->GetDockId() == otherDock) { dock2->SetLoadConnected(mgr, true); } } } } } x264_dockState = EDockState::InSourceRoom; } } void CScriptDock::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) { switch (msg) { case EScriptObjectMessage::Registered: { CGameArea* area = mgr.GetWorld()->GetArea(x260_area); if (area->GetDockCount() < x25c_dock) { return; } IGameArea::Dock* dock = area->GetDock(x25c_dock); if (!dock->IsReferenced()) { dock->SetReferenceCount(x258_dockReferenceCount); } } break; case EScriptObjectMessage::Deleted: CleanUp(); break; case EScriptObjectMessage::InitializedInArea: AreaLoaded(mgr); break; case EScriptObjectMessage::WorldInitialized: { UpdateAreaActivateFlags(mgr); const CMaterialList exclude = GetMaterialFilter().GetExcludeList(); CMaterialList include = GetMaterialFilter().GetIncludeList(); include.Add(EMaterialTypes::AIBlock); SetMaterialFilter(CMaterialFilter::MakeIncludeExclude(include, exclude)); } break; case EScriptObjectMessage::SetToZero: { if (mgr.GetNextAreaId() != x260_area) { return; } SetLoadConnected(mgr, false); const CGameArea* area = mgr.GetWorld()->GetArea(x260_area); const IGameArea::Dock* dock = area->GetDock(x25c_dock); const TAreaId aid = dock->GetConnectedAreaId(dock->GetReferenceCount()); CPlatformAndDoorList& lst = mgr.GetPlatformAndDoorObjectList(); for (CEntity* ent : lst) { const TCastToPtr door(ent); if (door && door->IsConnectedToArea(mgr, aid)) { door->ForceClosed(mgr); } } } break; case EScriptObjectMessage::SetToMax: if (mgr.GetNextAreaId() != x260_area) { return; } SetLoadConnected(mgr, true); break; case EScriptObjectMessage::Increment: SetLoadConnected(mgr, true); [[fallthrough]]; case EScriptObjectMessage::Decrement: { TAreaId aid = x260_area; if (mgr.GetNextAreaId() == x260_area) { const IGameArea::Dock* dock = mgr.GetWorld()->GetArea(x260_area)->GetDock(x25c_dock); aid = dock->GetConnectedAreaId(dock->GetReferenceCount()); } if (aid >= 0 && aid < mgr.GetWorld()->GetNumAreas() && mgr.GetWorld()->GetArea(aid)->GetActive()) { CWorld::PropogateAreaChain(CGameArea::EOcclusionState(msg == EScriptObjectMessage::Increment), mgr.GetWorld()->GetArea(aid), mgr.GetWorld()); } } break; default: CPhysicsActor::AcceptScriptMsg(msg, uid, mgr); break; } } std::optional CScriptDock::GetTouchBounds() const { if (x264_dockState == EDockState::InNextRoom) { return std::nullopt; } return GetBoundingBox(); } void CScriptDock::Touch(CActor& act, CStateManager&) { if (x264_dockState == EDockState::InNextRoom) { return; } if (TCastToConstPtr(act)) { x264_dockState = EDockState::PlayerTouched; } } zeus::CPlane CScriptDock::GetPlane(const CStateManager& mgr) const { const IGameArea::Dock* dock = mgr.GetWorld()->GetAreaAlways(x260_area)->GetDock(x25c_dock); return zeus::CPlane(dock->GetPoint(0), dock->GetPoint(1), dock->GetPoint(2)); } void CScriptDock::SetDockReference(CStateManager& mgr, s32 ref) { mgr.GetWorld()->GetArea(x260_area)->GetDock(x25c_dock)->SetReferenceCount(ref); x268_24_dockReferenced = true; } s32 CScriptDock::GetDockReference(const CStateManager& mgr) const { return mgr.GetWorld()->GetAreaAlways(x260_area)->GetDock(x25c_dock)->GetReferenceCount(); } TAreaId CScriptDock::GetCurrentConnectedAreaId(const CStateManager& mgr) const { if (x260_area >= mgr.GetWorld()->GetNumAreas()) { return kInvalidAreaId; } const CGameArea* area = mgr.GetWorld()->GetAreaAlways(x260_area); if (x25c_dock >= area->GetDockCount()) { return kInvalidAreaId; } const IGameArea::Dock* dock = area->GetDock(x25c_dock); return dock->GetConnectedAreaId(dock->GetReferenceCount()); } void CScriptDock::UpdateAreaActivateFlags(CStateManager& mgr) { CWorld* world = mgr.GetWorld(); if (x260_area >= world->GetNumAreas()) { return; } CGameArea* area = world->GetArea(x260_area); if (x25c_dock >= area->GetDockCount()) return; const IGameArea::Dock* dock = area->GetDock(x25c_dock); for (s32 i = 0; i < dock->GetDockRefs().size(); ++i) { const s32 dockRefCount = dock->GetReferenceCount(); const TAreaId aid = dock->GetConnectedAreaId(i); if (aid != kInvalidAreaId) { world->GetArea(aid)->SetActive(i == dockRefCount); } } mgr.SetCurrentAreaId(mgr.GetNextAreaId()); } bool CScriptDock::HasPointCrossedDock(const CStateManager& mgr, const zeus::CVector3f& point) const { const zeus::CPlane plane = GetPlane(mgr); return plane.pointToPlaneDist(point) >= 0.f; } void CScriptDock::AreaLoaded(CStateManager& mgr) { SetLoadConnected(mgr, x268_25_loadConnected); } void CScriptDock::SetLoadConnected(CStateManager& mgr, bool loadOther) { IGameArea::Dock* dock = mgr.GetWorld()->GetArea(x260_area)->GetDock(x25c_dock); const bool cur = dock->GetShouldLoadOther(dock->GetReferenceCount()); if (cur == loadOther) { return; } dock->SetShouldLoadOther(dock->GetReferenceCount(), loadOther); } } // namespace metaforce