mirror of
https://github.com/AxioDL/metaforce.git
synced 2025-05-14 15:11:21 +00:00
This member function alters instance state in a few implementations, so it shouldn't be made const. The state manager parameter also shouldn't be const. Retrieved data from the post constructed instance is further modified in some implementations. This removes the constness on this parameter in order to fix more const_cast usages in a follow-up change.
385 lines
13 KiB
C++
385 lines
13 KiB
C++
#include "Runtime/World/CScriptDoor.hpp"
|
|
|
|
#include "Runtime/CStateManager.hpp"
|
|
#include "Runtime/AutoMapper/CMapWorldInfo.hpp"
|
|
#include "Runtime/Camera/CBallCamera.hpp"
|
|
#include "Runtime/Camera/CCameraManager.hpp"
|
|
#include "Runtime/Character/CAnimData.hpp"
|
|
#include "Runtime/Character/CAnimPlaybackParms.hpp"
|
|
#include "Runtime/Collision/CMaterialList.hpp"
|
|
#include "Runtime/World/CScriptDock.hpp"
|
|
#include "Runtime/World/CWorld.hpp"
|
|
|
|
#include "TCastTo.hpp" // Generated file, do not modify include path
|
|
|
|
namespace urde {
|
|
|
|
static CMaterialList MakeDoorMaterialList(bool open) {
|
|
CMaterialList ret;
|
|
ret.Add(EMaterialTypes::Solid);
|
|
ret.Add(EMaterialTypes::Immovable);
|
|
ret.Add(EMaterialTypes::Orbit);
|
|
if (!open)
|
|
ret.Add(EMaterialTypes::Occluder);
|
|
|
|
return ret;
|
|
}
|
|
|
|
CScriptDoor::CScriptDoor(TUniqueId uid, std::string_view name, const CEntityInfo& info, const zeus::CTransform& xf,
|
|
CModelData&& mData, const CActorParameters& actParms, const zeus::CVector3f& orbitPos,
|
|
const zeus::CAABox& aabb, bool active, bool open, bool projectilesCollide, float animLen,
|
|
bool ballDoor)
|
|
: CPhysicsActor(uid, active, name, info, xf, std::move(mData), MakeDoorMaterialList(open), aabb, SMoverData(1.f),
|
|
actParms, 0.3f, 0.1f) {
|
|
x258_animLen = animLen;
|
|
x2a8_24_closing = false;
|
|
x2a8_25_wasOpen = open;
|
|
x2a8_26_isOpen = open;
|
|
x2a8_27_conditionsMet = false;
|
|
x2a8_28_projectilesCollide = projectilesCollide;
|
|
x2a8_29_ballDoor = ballDoor;
|
|
x2a8_30_doClose = false;
|
|
x264_ = GetBoundingBox();
|
|
x284_modelBounds = x64_modelData->GetBounds(xf.getRotation());
|
|
x29c_orbitPos = orbitPos;
|
|
|
|
xe6_27_thermalVisorFlags = 1;
|
|
if (open)
|
|
SetDoorAnimation(EDoorAnimType::Open);
|
|
|
|
SetMass(0.f);
|
|
}
|
|
|
|
void CScriptDoor::Accept(IVisitor& visitor) { visitor.Visit(this); }
|
|
|
|
/* ORIGINAL 0-00 OFFSET: 8007F054 */
|
|
zeus::CVector3f CScriptDoor::GetOrbitPosition(const CStateManager& /*mgr*/) const {
|
|
return x34_transform.origin + x29c_orbitPos;
|
|
}
|
|
|
|
/* ORIGINAL 0-00 OFFSET: 8007E550 */
|
|
void CScriptDoor::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) {
|
|
switch (msg) {
|
|
case EScriptObjectMessage::Close: {
|
|
if (!GetActive())
|
|
return;
|
|
|
|
if (x27c_partner1 != kInvalidUniqueId && x27c_partner1 != uid)
|
|
return;
|
|
|
|
if (x2a8_26_isOpen) {
|
|
if (x27e_partner2 != kInvalidUniqueId)
|
|
if (CEntity* ent = mgr.ObjectById(x27e_partner2))
|
|
mgr.SendScriptMsg(ent, GetUniqueId(), EScriptObjectMessage::Close);
|
|
x2a8_26_isOpen = false;
|
|
SetDoorAnimation(EDoorAnimType::Close);
|
|
mgr.GetCameraManager()->GetBallCamera()->DoorClosing(GetUniqueId());
|
|
} else if (x2a8_27_conditionsMet) {
|
|
x2a8_27_conditionsMet = false;
|
|
SendScriptMsgs(EScriptObjectState::Closed, mgr, EScriptObjectMessage::None);
|
|
}
|
|
break;
|
|
}
|
|
case EScriptObjectMessage::Action: {
|
|
if (x27c_partner1 != kInvalidUniqueId) {
|
|
if (TCastToPtr<CScriptDoor> door = mgr.ObjectById(x27c_partner1)) {
|
|
if (door->x2a8_26_isOpen) {
|
|
x2a8_30_doClose = true;
|
|
mgr.SendScriptMsg(door, GetUniqueId(), EScriptObjectMessage::Close);
|
|
door->x2a8_30_doClose = true;
|
|
}
|
|
}
|
|
} else if (x2a8_26_isOpen) {
|
|
x2a8_30_doClose = true;
|
|
if (TCastToPtr<CScriptDoor> door = mgr.ObjectById(x27e_partner2)) {
|
|
mgr.SendScriptMsg(door, GetUniqueId(), EScriptObjectMessage::Close);
|
|
door->x2a8_30_doClose = true;
|
|
}
|
|
x2a8_26_isOpen = false;
|
|
SetDoorAnimation(EDoorAnimType::Close);
|
|
mgr.GetCameraManager()->GetBallCamera()->DoorClosing(GetUniqueId());
|
|
}
|
|
break;
|
|
}
|
|
case EScriptObjectMessage::Open: {
|
|
if (!GetActive() || x2a8_26_isOpen)
|
|
return;
|
|
|
|
EDoorOpenCondition doorCond =
|
|
TCastToConstPtr<CScriptDoor>(mgr.GetObjectById(uid)) ? EDoorOpenCondition::Ready : GetDoorOpenCondition(mgr);
|
|
switch (doorCond) {
|
|
case EDoorOpenCondition::Loading:
|
|
x2a8_27_conditionsMet = true;
|
|
x280_prevDoor = uid;
|
|
break;
|
|
case EDoorOpenCondition::Ready:
|
|
OpenDoor(uid, mgr);
|
|
break;
|
|
default:
|
|
x2a8_25_wasOpen = false;
|
|
x2a8_24_closing = true;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case EScriptObjectMessage::InitializedInArea: {
|
|
for (const SConnection& conn : x20_conns) {
|
|
if (conn.x4_msg == EScriptObjectMessage::Increment) {
|
|
TUniqueId dock = mgr.GetIdForScript(conn.x8_objId);
|
|
if (TCastToConstPtr<CScriptDock> d = mgr.GetObjectById(dock)) {
|
|
x282_dockId = d->GetUniqueId();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case EScriptObjectMessage::SetToZero: {
|
|
x2a8_28_projectilesCollide = true;
|
|
mgr.MapWorldInfo()->SetDoorVisited(mgr.GetEditorIdForUniqueId(GetUniqueId()), true);
|
|
break;
|
|
}
|
|
case EScriptObjectMessage::SetToMax: {
|
|
x2a8_28_projectilesCollide = false;
|
|
break;
|
|
}
|
|
default:
|
|
CActor::AcceptScriptMsg(msg, uid, mgr);
|
|
}
|
|
}
|
|
|
|
void CScriptDoor::Think(float dt, CStateManager& mgr) {
|
|
if (!GetActive())
|
|
return;
|
|
|
|
if (!x2a8_26_isOpen && x25c_animTime < 0.5f)
|
|
x25c_animTime += dt;
|
|
|
|
if (x2a8_27_conditionsMet && GetDoorOpenCondition(mgr) == EDoorOpenCondition::Ready) {
|
|
x2a8_27_conditionsMet = false;
|
|
OpenDoor(x280_prevDoor, mgr);
|
|
}
|
|
|
|
if (x2a8_24_closing) {
|
|
x2a8_25_wasOpen = false;
|
|
mgr.GetCameraManager()->GetBallCamera()->DoorClosed(GetUniqueId());
|
|
x2a8_28_projectilesCollide = false;
|
|
x2a8_24_closing = false;
|
|
SendScriptMsgs(EScriptObjectState::Closed, mgr, EScriptObjectMessage::Decrement);
|
|
x25c_animTime = 0.f;
|
|
x2a8_30_doClose = false;
|
|
}
|
|
|
|
if (x2a8_26_isOpen && !x64_modelData->IsAnimating())
|
|
RemoveMaterial(EMaterialTypes::Solid, EMaterialTypes::Occluder, EMaterialTypes::Orbit, EMaterialTypes::Scannable,
|
|
mgr);
|
|
else {
|
|
if (x2a8_25_wasOpen && !x64_modelData->IsAnimating()) {
|
|
x2a8_25_wasOpen = false;
|
|
mgr.GetCameraManager()->GetBallCamera()->DoorClosed(GetUniqueId());
|
|
x2a8_28_projectilesCollide = false;
|
|
x2a8_27_conditionsMet = false;
|
|
SendScriptMsgs(EScriptObjectState::Closed, mgr, EScriptObjectMessage::None);
|
|
x25c_animTime = 0.f;
|
|
x2a8_30_doClose = false;
|
|
}
|
|
|
|
if (GetScannableObjectInfo())
|
|
AddMaterial(EMaterialTypes::Solid, EMaterialTypes::Metal, EMaterialTypes::Occluder, EMaterialTypes::Orbit,
|
|
EMaterialTypes::Scannable, mgr);
|
|
else
|
|
AddMaterial(EMaterialTypes::Solid, EMaterialTypes::Metal, EMaterialTypes::Occluder, EMaterialTypes::Orbit, mgr);
|
|
}
|
|
|
|
if (x64_modelData->IsAnimating())
|
|
UpdateAnimation((x64_modelData->GetAnimationDuration(s32(x260_doorAnimState)) / x258_animLen) * dt, mgr, true);
|
|
|
|
xe7_31_targetable = mgr.GetPlayerState()->GetCurrentVisor() == CPlayerState::EPlayerVisor::Scan;
|
|
}
|
|
|
|
void CScriptDoor::AddToRenderer(const zeus::CFrustum& /*frustum*/, CStateManager& mgr) {
|
|
if (xe4_30_outOfFrustum) {
|
|
return;
|
|
}
|
|
|
|
CPhysicsActor::Render(mgr);
|
|
}
|
|
|
|
/* ORIGINAL 0-00 OFFSET: 8007E0BC */
|
|
void CScriptDoor::ForceClosed(CStateManager& mgr) {
|
|
if (x2a8_26_isOpen) {
|
|
x2a8_26_isOpen = false;
|
|
x2a8_25_wasOpen = false;
|
|
|
|
mgr.GetCameraManager()->GetBallCamera()->DoorClosing(x8_uid);
|
|
mgr.GetCameraManager()->GetBallCamera()->DoorClosed(x8_uid);
|
|
|
|
SetDoorAnimation(EDoorAnimType::Close);
|
|
SendScriptMsgs(EScriptObjectState::Closed, mgr, EScriptObjectMessage::None);
|
|
|
|
x25c_animTime = 0.f;
|
|
x2a8_27_conditionsMet = false;
|
|
x2a8_30_doClose = false;
|
|
} else if (x2a8_27_conditionsMet) {
|
|
x2a8_27_conditionsMet = false;
|
|
x2a8_30_doClose = false;
|
|
SendScriptMsgs(EScriptObjectState::Closed, mgr, EScriptObjectMessage::None);
|
|
}
|
|
}
|
|
|
|
/* ORIGINAL 0-00 OFFSET: 8007E1C4 */
|
|
bool CScriptDoor::IsConnectedToArea(const CStateManager& mgr, TAreaId areaId) const {
|
|
const CScriptDock* dockEnt = TCastToConstPtr<CScriptDock>(mgr.GetObjectById(x282_dockId));
|
|
if (dockEnt) {
|
|
if (dockEnt->GetAreaId() == areaId)
|
|
return true;
|
|
|
|
const CWorld* world = mgr.GetWorld();
|
|
const CGameArea* area = world->GetAreaAlways(dockEnt->GetAreaId());
|
|
const CGameArea::Dock* dock = area->GetDock(dockEnt->GetDockId());
|
|
if (dock->GetConnectedAreaId(dockEnt->GetDockReference(mgr)) == areaId)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/* ORIGINAL 0-00 OFFSET: 8007EA64 */
|
|
void CScriptDoor::OpenDoor(TUniqueId uid, CStateManager& mgr) {
|
|
TEditorId eid = mgr.GetEditorIdForUniqueId(uid);
|
|
mgr.MapWorldInfo()->SetDoorVisited(eid, true);
|
|
x2a8_26_isOpen = true;
|
|
x2a8_25_wasOpen = true;
|
|
x2a8_27_conditionsMet = false;
|
|
x27c_partner1 = kInvalidUniqueId;
|
|
x27e_partner2 = kInvalidUniqueId;
|
|
|
|
if (const CScriptDoor* door = TCastToConstPtr<CScriptDoor>(mgr.GetObjectById(uid)))
|
|
x27c_partner1 = door->GetUniqueId();
|
|
|
|
SetDoorAnimation(EDoorAnimType::Open);
|
|
if (x27c_partner1 == kInvalidUniqueId)
|
|
SendScriptMsgs(EScriptObjectState::Open, mgr, EScriptObjectMessage::None);
|
|
else
|
|
SendScriptMsgs(EScriptObjectState::MaxReached, mgr, EScriptObjectMessage::None);
|
|
|
|
if (TCastToConstPtr<CScriptDock> dock1 = mgr.GetObjectById(x282_dockId)) {
|
|
for (CEntity* ent : mgr.GetPlatformAndDoorObjectList()) {
|
|
TCastToConstPtr<CScriptDoor> door = ent;
|
|
if (!door || door->GetUniqueId() == uid)
|
|
continue;
|
|
|
|
if (TCastToConstPtr<CScriptDock> dock2 = mgr.GetObjectById(door->x282_dockId)) {
|
|
if (dock1->GetCurrentConnectedAreaId(mgr) == dock2->GetAreaId() &&
|
|
dock2->GetCurrentConnectedAreaId(mgr) == dock1->GetAreaId()) {
|
|
x27e_partner2 = door->GetUniqueId();
|
|
mgr.SendScriptMsg(ent, GetUniqueId(), EScriptObjectMessage::Open);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (x27c_partner1 == kInvalidUniqueId && x27e_partner2 == kInvalidUniqueId) {
|
|
for (const SConnection& conn : x20_conns) {
|
|
if (conn.x4_msg != EScriptObjectMessage::Open)
|
|
continue;
|
|
if (TCastToConstPtr<CScriptDoor> door = mgr.GetObjectById(mgr.GetIdForScript(conn.x8_objId))) {
|
|
x27e_partner2 = door->GetUniqueId();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ORIGINAL 0-00 OFFSET: 8007ED4C */
|
|
CScriptDoor::EDoorOpenCondition CScriptDoor::GetDoorOpenCondition(CStateManager& mgr) const {
|
|
const TCastToPtr<CScriptDock> dock = mgr.ObjectById(x282_dockId);
|
|
if (!dock)
|
|
return EDoorOpenCondition::Ready;
|
|
|
|
if (x25c_animTime < 0.05f || x2a8_30_doClose)
|
|
return EDoorOpenCondition::Loading;
|
|
|
|
TAreaId destArea = dock->GetAreaId();
|
|
if (destArea < 0 || destArea >= mgr.GetWorld()->GetNumAreas())
|
|
return EDoorOpenCondition::NotReady;
|
|
|
|
if (!mgr.GetWorld()->GetAreaAlways(destArea)->IsPostConstructed())
|
|
return EDoorOpenCondition::Loading;
|
|
|
|
if (!mgr.GetWorld()->AreSkyNeedsMet())
|
|
return EDoorOpenCondition::Loading;
|
|
|
|
TAreaId connArea = mgr.GetWorld()
|
|
->GetAreaAlways(dock->GetAreaId())
|
|
->GetDock(dock->GetDockId())
|
|
->GetConnectedAreaId(dock->GetDockReference(mgr));
|
|
|
|
if (connArea == kInvalidAreaId)
|
|
return EDoorOpenCondition::NotReady;
|
|
|
|
CWorld* world = mgr.GetWorld();
|
|
const CGameArea* area = world->GetAreaAlways(connArea);
|
|
|
|
if (!area->IsPostConstructed()) {
|
|
mgr.SendScriptMsg(dock, GetUniqueId(), EScriptObjectMessage::SetToMax);
|
|
return EDoorOpenCondition::Loading;
|
|
}
|
|
|
|
if (area->GetPostConstructed()->x113c_playerActorsLoading != 0)
|
|
return EDoorOpenCondition::Loading;
|
|
|
|
for (CEntity* ent : mgr.GetPlatformAndDoorObjectList()) {
|
|
TCastToPtr<CScriptDoor> door(ent);
|
|
if (!door || door->GetUniqueId() == GetUniqueId())
|
|
continue;
|
|
|
|
if (door->GetAreaIdAlways() == GetAreaIdAlways() && door->x2a8_25_wasOpen) {
|
|
if (door->x282_dockId != kInvalidUniqueId)
|
|
return EDoorOpenCondition::Loading;
|
|
}
|
|
}
|
|
|
|
for (const CGameArea& aliveArea : *world) {
|
|
if (aliveArea.GetAreaId() == area->GetAreaId())
|
|
continue;
|
|
|
|
if (!aliveArea.IsFinishedOccluding())
|
|
return EDoorOpenCondition::Loading;
|
|
}
|
|
|
|
// if (area->TryTakingOutOfARAM())
|
|
{
|
|
if (world->GetMapWorld()->IsMapAreasStreaming())
|
|
return EDoorOpenCondition::Loading;
|
|
}
|
|
|
|
if (!CGraphics::g_BooFactory->areShadersReady())
|
|
return EDoorOpenCondition::Loading;
|
|
|
|
return EDoorOpenCondition::Ready;
|
|
}
|
|
|
|
/* ORIGINAL 0-00 OFFSET: 8007E9D0 */
|
|
void CScriptDoor::SetDoorAnimation(CScriptDoor::EDoorAnimType type) {
|
|
x260_doorAnimState = type;
|
|
CModelData* modelData = x64_modelData.get();
|
|
if (modelData && modelData->GetAnimationData())
|
|
modelData->GetAnimationData()->SetAnimation(CAnimPlaybackParms(s32(type), -1, 1.f, true), false);
|
|
}
|
|
|
|
std::optional<zeus::CAABox> CScriptDoor::GetTouchBounds() const {
|
|
if (GetActive() && GetMaterialList().HasMaterial(EMaterialTypes::Solid)) {
|
|
return CPhysicsActor::GetBoundingBox();
|
|
}
|
|
return std::nullopt;
|
|
}
|
|
|
|
std::optional<zeus::CAABox> CScriptDoor::GetProjectileBounds() const {
|
|
if (x2a8_28_projectilesCollide) {
|
|
return zeus::CAABox{x284_modelBounds.min + GetTranslation(), x284_modelBounds.max + GetTranslation()};
|
|
}
|
|
return std::nullopt;
|
|
}
|
|
|
|
} // namespace urde
|