metaforce/Runtime/World/CScriptDoor.cpp

413 lines
12 KiB
C++
Raw Normal View History

2016-04-19 21:25:26 +00:00
#include "CScriptDoor.hpp"
2016-04-23 00:29:55 +00:00
#include "CScriptDock.hpp"
2016-04-19 21:25:26 +00:00
#include "Collision/CMaterialList.hpp"
2016-04-22 20:22:45 +00:00
#include "Character/CAnimData.hpp"
#include "Character/CAnimPlaybackParms.hpp"
#include "AutoMapper/CMapWorldInfo.hpp"
#include "CStateManager.hpp"
2016-04-23 00:29:55 +00:00
#include "CWorld.hpp"
2016-07-28 07:33:55 +00:00
#include "Camera/CCameraManager.hpp"
#include "Camera/CBallCamera.hpp"
2017-01-15 03:07:01 +00:00
#include "TCastTo.hpp"
2016-04-19 21:25:26 +00:00
namespace urde
{
2016-12-29 21:38:59 +00:00
static CMaterialList MakeDoorMaterialList(bool open)
2016-04-19 21:25:26 +00:00
{
CMaterialList ret;
//ret.Add(EMaterialTypes::Solid);
2016-12-29 21:38:59 +00:00
ret.Add(EMaterialTypes::Immovable);
ret.Add(EMaterialTypes::Orbit);
if (!open)
ret.Add(EMaterialTypes::Occluder);
2016-04-22 20:22:45 +00:00
2016-04-19 21:25:26 +00:00
return ret;
}
2017-11-13 06:19:18 +00:00
CScriptDoor::CScriptDoor(TUniqueId uid, std::string_view name, const CEntityInfo& info,
2016-04-22 20:22:45 +00:00
const zeus::CTransform& xf, CModelData&& mData, const CActorParameters& actParms,
const zeus::CVector3f& vec, const zeus::CAABox& aabb, bool active,
bool open, bool b2, float animLen, bool ballDoor)
2016-12-29 21:38:59 +00:00
: CPhysicsActor(uid, active, name, info, xf, std::move(mData), MakeDoorMaterialList(open),
2017-01-25 04:40:19 +00:00
aabb, SMoverData(1.f), actParms, 0.3f, 0.1f)
2016-04-19 21:25:26 +00:00
{
x258_animLen = animLen;
x2a8_24_ = false;
2017-01-25 04:40:19 +00:00
x2a8_25_ = open;
x2a8_26_isOpen = open;
x2a8_27_ = false;
2017-01-25 04:40:19 +00:00
x2a8_28_ = b2;
x2a8_29_ballDoor = ballDoor;
x2a8_30_ = false;
2016-04-22 20:22:45 +00:00
x264_ = GetBoundingBox();
2016-04-23 18:04:49 +00:00
x284_modelBounds = x64_modelData->GetBounds(xf.getRotation());
x29c_ = vec;
2016-04-23 18:04:49 +00:00
xe6_27_thermalVisorFlags = 1;
2016-12-29 21:38:59 +00:00
if (open)
2016-04-23 18:04:49 +00:00
SetDoorAnimation(EDoorAnimType::Open);
SetMass(0.f);
2016-04-22 20:22:45 +00:00
}
2017-01-15 03:07:01 +00:00
void CScriptDoor::Accept(IVisitor& visitor)
{
visitor.Visit(this);
}
2016-04-23 00:29:55 +00:00
/* ORIGINAL 0-00 OFFSET: 8007F054 */
2016-04-23 18:04:49 +00:00
zeus::CVector3f CScriptDoor::GetOrbitPosition(const CStateManager& /*mgr*/) const
2016-04-23 00:29:55 +00:00
{
2016-04-29 10:08:46 +00:00
return x34_transform.origin + x29c_;
2016-04-23 00:29:55 +00:00
}
/* 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_)
{
x2a8_27_ = false;
SendScriptMsgs(EScriptObjectState::Closed, mgr, EScriptObjectMessage::None);
}
break;
}
case EScriptObjectMessage::Action:
{
if (x27c_partner1 != kInvalidUniqueId)
{
if (TCastToPtr<CScriptDoor> door = mgr.ObjectById(x27c_partner1))
{
if (x2a8_26_isOpen)
return;
x2a8_30_ = true;
mgr.SendScriptMsg(door, GetUniqueId(), EScriptObjectMessage::Close);
}
}
else if (x2a8_26_isOpen)
{
x2a8_30_ = true;
if (TCastToPtr<CScriptDoor> door = mgr.ObjectById(x27e_partner2))
{
mgr.SendScriptMsg(door, GetUniqueId(), EScriptObjectMessage::Close);
x2a8_30_ = true;
}
x2a8_26_isOpen = false;
SetDoorAnimation(EDoorAnimType::Close);
mgr.GetCameraManager()->GetBallCamera()->DoorClosing(GetUniqueId());
}
break;
}
case EScriptObjectMessage::Open:
{
if (!GetActive() || x2a8_26_isOpen)
return;
u32 doorCond = TCastToConstPtr<CScriptDoor>(mgr.GetObjectById(uid)) ? 2 : GetDoorOpenCondition(mgr);
switch(doorCond)
{
case 1:
x2a8_27_ = true;
x280_ = uid;
break;
case 2:
OpenDoor(uid, mgr);
break;
default:
x2a8_25_= false;
x2a8_24_ = 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>(mgr.GetObjectById(dock)))
x282_dockId = dock;
}
}
break;
}
case EScriptObjectMessage::SetToZero:
{
x2a8_28_ = true;
mgr.MapWorldInfo()->SetDoorVisited(mgr.GetEditorIdForUniqueId(GetUniqueId()), true);
break;
}
case EScriptObjectMessage::SetToMax:
{
x2a8_28_ = false;
break;
}
default:
CActor::AcceptScriptMsg(msg, uid, mgr);
}
2016-04-23 00:29:55 +00:00
}
2016-04-24 02:46:13 +00:00
void CScriptDoor::Think(float dt, CStateManager& mgr)
{
if (!GetActive())
return;
if (!x2a8_26_isOpen && x25c_animTime < 0.5f)
x25c_animTime += dt;
if (x2a8_27_ && GetDoorOpenCondition(mgr) == 2)
{
x2a8_27_ = false;
OpenDoor(x280_, mgr);
}
if (x2a8_24_)
{
x2a8_25_ = false;
mgr.GetCameraManager()->GetBallCamera()->DoorClosed(GetUniqueId());
x2a8_28_ = false;
x2a8_24_ = false;
SendScriptMsgs(EScriptObjectState::Closed, mgr, EScriptObjectMessage::Decrement);
x25c_animTime = 0.f;
x2a8_30_ = false;
}
if (x2a8_26_isOpen && !x64_modelData->IsAnimating())
RemoveMaterial(EMaterialTypes::Solid, EMaterialTypes::Occluder, EMaterialTypes::Orbit, EMaterialTypes::Scannable, mgr);
else
{
if (x2a8_25_ && !x64_modelData->IsAnimating())
{
x2a8_25_ = false;
mgr.GetCameraManager()->GetBallCamera()->DoorClosed(GetUniqueId());
x2a8_28_ = false;
x2a8_27_ = false;
SendScriptMsgs(EScriptObjectState::Closed, mgr, EScriptObjectMessage::None);
}
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())
{
float f1 = x64_modelData->GetAnimationDuration(s32(x260_doorState));
float f0 = x258_animLen;
f0 = f1 / f0;
f1 = f0 * dt;
UpdateAnimation(f1, mgr, true);
}
xe7_31_targetable = mgr.GetPlayerState()->GetCurrentVisor() == CPlayerState::EPlayerVisor::Scan;
2016-04-24 02:46:13 +00:00
}
void CScriptDoor::AddToRenderer(const zeus::CFrustum& /*frustum*/, const CStateManager &mgr) const
2016-04-23 10:51:53 +00:00
{
2017-08-13 07:56:35 +00:00
if (!xe4_30_outOfFrustum)
2016-04-23 10:51:53 +00:00
CPhysicsActor::Render(mgr);
}
2016-04-23 00:29:55 +00:00
/* ORIGINAL 0-00 OFFSET: 8007E0BC */
2016-04-22 20:22:45 +00:00
void CScriptDoor::ForceClosed(CStateManager & mgr)
{
if (x2a8_26_isOpen)
2016-04-22 20:22:45 +00:00
{
x2a8_26_isOpen = false;
2016-04-22 20:22:45 +00:00
x2a8_25_ = false;
mgr.GetCameraManager()->GetBallCamera()->DoorClosing(x8_uid);
mgr.GetCameraManager()->GetBallCamera()->DoorClosed(x8_uid);
2016-04-22 20:22:45 +00:00
2016-04-23 18:04:49 +00:00
SetDoorAnimation(EDoorAnimType::Close);
2016-04-22 20:22:45 +00:00
SendScriptMsgs(EScriptObjectState::Closed, mgr, EScriptObjectMessage::None);
x25c_animTime = 0.f;
2016-04-22 20:22:45 +00:00
x2a8_27_ = false;
x2a8_30_ = false;
}
else if (x2a8_27_)
{
x2a8_27_ = false;
x2a8_30_ = false;
SendScriptMsgs(EScriptObjectState::Closed, mgr, EScriptObjectMessage::None);
}
}
2016-04-23 00:29:55 +00:00
/* ORIGINAL 0-00 OFFSET: 8007E1C4 */
bool CScriptDoor::IsConnectedToArea(const CStateManager& mgr, TAreaId areaId)
2016-04-23 00:29:55 +00:00
{
const CScriptDock* dockEnt = TCastToConstPtr<CScriptDock>(mgr.GetObjectById(x282_dockId));
if (dockEnt)
2016-04-23 00:29:55 +00:00
{
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)
2016-04-23 00:29:55 +00:00
return true;
}
return false;
}
/* ORIGINAL 0-00 OFFSET: 8007EA64 */
2016-04-22 20:22:45 +00:00
void CScriptDoor::OpenDoor(TUniqueId uid, CStateManager& mgr)
{
TEditorId eid = mgr.GetEditorIdForUniqueId(uid);
mgr.MapWorldInfo()->SetDoorVisited(eid, true);
x2a8_26_isOpen = true;
x2a8_25_ = true;
x2a8_27_ = false;
2016-04-22 20:22:45 +00:00
if (const CScriptDoor* door = TCastToConstPtr<CScriptDoor>(mgr.GetObjectById(uid)))
x27c_partner1 = door->GetUniqueId();
2016-04-22 20:22:45 +00:00
2016-04-23 18:04:49 +00:00
SetDoorAnimation(EDoorAnimType::Open);
if (x27c_partner1 == kInvalidUniqueId)
SendScriptMsgs(EScriptObjectState::Open, mgr, EScriptObjectMessage::None);
2016-04-22 20:22:45 +00:00
else
SendScriptMsgs(EScriptObjectState::MaxReached, mgr, EScriptObjectMessage::None);
if (TCastToConstPtr<CScriptDock> dock1 = mgr.GetObjectById(x282_dockId))
2016-04-22 20:22:45 +00:00
{
for (CEntity* ent : mgr.GetPlatformAndDoorObjectList())
{
TCastToConstPtr<CScriptDoor> door = ent;
if (!door || door->GetUniqueId() == GetUniqueId())
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);
}
}
}
}
2016-04-22 20:22:45 +00:00
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();
}
2016-04-22 20:22:45 +00:00
}
}
2016-04-23 00:29:55 +00:00
/* ORIGINAL 0-00 OFFSET: 8007ED4C */
u32 CScriptDoor::GetDoorOpenCondition(CStateManager& mgr)
{
const TCastToPtr<CScriptDock> dock = mgr.ObjectById(x282_dockId);
2016-04-23 00:29:55 +00:00
if (!dock)
return 2;
if (x25c_animTime < 0.05f || x2a8_30_)
return 1;
TAreaId destArea = dock->GetAreaId();
if (destArea < 0 || destArea >= mgr.GetWorld()->GetNumAreas())
return 0;
if (!mgr.GetWorld()->AreSkyNeedsMet())
return 1;
TAreaId connArea = mgr.GetWorld()->GetAreaAlways(
dock->GetAreaId())->GetDock(
dock->GetDockId())->GetConnectedAreaId(dock->GetDockReference(mgr));
if (connArea == kInvalidAreaId)
return 0;
const CWorld* world = mgr.GetWorld();
const CGameArea* area = world->GetAreaAlways(connArea);
if (!area->IsPostConstructed())
{
mgr.SendScriptMsg(dock, GetUniqueId(), EScriptObjectMessage::SetToMax);
2016-04-23 00:29:55 +00:00
return 1;
}
if (area->GetPostConstructed()->x113c_ != 0)
return 1;
for (CEntity* ent : mgr.GetPlatformAndDoorObjectList())
{
TCastToPtr<CScriptDoor> door(ent);
if (!door || door->GetUniqueId() == GetUniqueId())
continue;
if (door->GetAreaIdAlways() == GetAreaIdAlways() && door->x2a8_25_)
{
if (door->x282_dockId != kInvalidUniqueId)
return 1;
}
}
for (CGameArea::CConstChainIterator aliveArea = world->GetChainHead(EChain::Alive); aliveArea != CWorld::GetAliveAreasEnd(); ++aliveArea)
{
if (aliveArea->GetAreaId() == area->GetAreaId())
continue;
if (!aliveArea->IsFinishedOccluding())
return 1;
}
//if (area->TryTakingOutOfARAM())
{
if (world->GetMapWorld()->IsMapAreasStreaming())
return 1;
}
2016-04-23 00:29:55 +00:00
return 2;
2016-04-23 00:29:55 +00:00
}
/* ORIGINAL 0-00 OFFSET: 8007E9D0 */
2016-04-22 20:22:45 +00:00
void CScriptDoor::SetDoorAnimation(CScriptDoor::EDoorAnimType type)
{
2016-04-23 18:04:49 +00:00
x260_doorState = type;
2016-04-22 20:22:45 +00:00
CModelData* modelData = x64_modelData.get();
2016-04-23 18:04:49 +00:00
if (modelData && modelData->AnimationData())
modelData->AnimationData()->SetAnimation(CAnimPlaybackParms(s32(type), -1, 1.f, true), false);
2016-04-19 21:25:26 +00:00
}
std::experimental::optional<zeus::CAABox> CScriptDoor::GetProjectileBounds() const
2018-02-09 07:12:26 +00:00
{
if (x2a8_28_)
return {{x284_modelBounds.min + GetTranslation(), x284_modelBounds.max + GetTranslation()}};
return {};
}
2016-04-19 21:25:26 +00:00
}