diff --git a/Runtime/AutoMapper/CMapWorldInfo.hpp b/Runtime/AutoMapper/CMapWorldInfo.hpp index 2b9ed3ecb..4a6afda2c 100644 --- a/Runtime/AutoMapper/CMapWorldInfo.hpp +++ b/Runtime/AutoMapper/CMapWorldInfo.hpp @@ -28,6 +28,7 @@ public: bool IsWorldVisible(TAreaId) const; bool IsAreaVisible(TAreaId) const; bool IsAnythingSet() const; + void SetMapStationUsed(bool val) { x38_mapStationUsed = val; } }; } diff --git a/Runtime/CStateManager.hpp b/Runtime/CStateManager.hpp index e9320ea49..d6bb479ba 100644 --- a/Runtime/CStateManager.hpp +++ b/Runtime/CStateManager.hpp @@ -447,6 +447,12 @@ public: TUniqueId GetBossId() const { return xf18_bossId; } float GetTotalBossEnergy() const { return xf1c_totalBossEnergy; } u32 GetBossStringIdx() const { return xf20_bossStringIdx; } + void SetPendingOnScreenTex(CAssetId texId, const zeus::CVector2i& origin, const zeus::CVector2i& extent) + { + xef4_pendingScreenTex.x0_id = texId; + xef4_pendingScreenTex.x4_origin = origin; + xef4_pendingScreenTex.xc_extent = extent; + } const SOnScreenTex& GetPendingScreenTex() const { return xef4_pendingScreenTex; } void SetViewportScale(const zeus::CVector2f& scale) { xf2c_viewportScale = scale; } float GetThermalColdScale1() const { return xf24_thermColdScale1; } diff --git a/Runtime/World/CScriptDoor.cpp b/Runtime/World/CScriptDoor.cpp index b29ea4b68..934c7147e 100644 --- a/Runtime/World/CScriptDoor.cpp +++ b/Runtime/World/CScriptDoor.cpp @@ -104,7 +104,7 @@ void CScriptDoor::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStat { if (TCastToPtr door = mgr.ObjectById(x27c_partner1)) { - if (x2a8_26_isOpen) + if (!x2a8_26_isOpen) return; x2a8_30_doClose = true; mgr.SendScriptMsg(door, GetUniqueId(), EScriptObjectMessage::Close); @@ -154,7 +154,10 @@ void CScriptDoor::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStat { TUniqueId dock = mgr.GetIdForScript(conn.x8_objId); if (TCastToConstPtr d = mgr.GetObjectById(dock)) + { x282_dockId = d->GetUniqueId(); + break; + } } } break; @@ -345,6 +348,9 @@ u32 CScriptDoor::GetDoorOpenCondition(CStateManager& mgr) if (destArea < 0 || destArea >= mgr.GetWorld()->GetNumAreas()) return 0; + if (!mgr.GetWorld()->GetAreaAlways(destArea)->IsPostConstructed()) + return 1; + if (!mgr.GetWorld()->AreSkyNeedsMet()) return 1; diff --git a/Runtime/World/CScriptSpecialFunction.cpp b/Runtime/World/CScriptSpecialFunction.cpp index 70a30da20..b22114cdd 100644 --- a/Runtime/World/CScriptSpecialFunction.cpp +++ b/Runtime/World/CScriptSpecialFunction.cpp @@ -6,6 +6,8 @@ #include "GameGlobalObjects.hpp" #include "CGameState.hpp" #include "CStateManager.hpp" +#include "IMain.hpp" +#include "CPlayer.hpp" namespace urde { @@ -41,10 +43,294 @@ CScriptSpecialFunction::CScriptSpecialFunction(TUniqueId uid, std::string_view n void CScriptSpecialFunction::Accept(IVisitor& visitor) { visitor.Visit(this); } -void CScriptSpecialFunction::Think(float, CStateManager&) {} +void CScriptSpecialFunction::Think(float dt, CStateManager& mgr) +{ + switch(xe8_function) + { + case ESpecialFunction::PlayerFollowLocator: ThinkPlayerFollowLocator(dt, mgr); break; + case ESpecialFunction::SpinnerController: ThinkSpinnerController(dt, mgr, ESpinnerControllerMode::Zero); break; + case ESpecialFunction::ShotSpinnerController: ThinkSpinnerController(dt, mgr, ESpinnerControllerMode::One); break; + case ESpecialFunction::ObjectFollowLocator: ThinkObjectFollowLocator(dt, mgr); break; + case ESpecialFunction::ObjectFollowObject: ThinkObjectFollowObject(dt, mgr); break; + case ESpecialFunction::ChaffTarget: ThinkChaffTarget(dt, mgr); break; + case ESpecialFunction::ViewFrustumTester: + { + if (x1e4_28_frustumEntered) + { + x1e4_28_frustumEntered = false; + SendScriptMsgs(EScriptObjectState::Entered, mgr, EScriptObjectMessage::None); + } + if (x1e4_29_frustumExited) + { + x1e4_29_frustumExited = false; + SendScriptMsgs(EScriptObjectState::Exited, mgr, EScriptObjectMessage::None); + } + break; + } + case ESpecialFunction::SaveStation: ThinkSaveStation(dt, mgr); break; + case ESpecialFunction::IntroBossRingController: ThinkIntroBossRingController(dt, mgr); break; + case ESpecialFunction::RainSimulator: ThinkRainSimulator(dt, mgr); break; + case ESpecialFunction::AreaDamage: ThinkAreaDamage(dt, mgr); break; + case ESpecialFunction::ScaleActor: ThinkActorScale(dt, mgr); break; + case ESpecialFunction::PlayerInAreaRelay: ThinkPlayerInArea(dt, mgr); break; + case ESpecialFunction::Billboard: + { +#if 0 + if (x1f0_ && x1e8_->x10_ && x1e5_26_) + { + SendScriptMsgs(EScriptObjectState::MaxReached, mgr, EScriptObjectMessage::None); + x1e5_26_ = false; + } +#endif + break; + } + default: break; + } +} void CScriptSpecialFunction::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) { + if (GetActive() && msg == EScriptObjectMessage::Deactivate && xe8_function == ESpecialFunction::Billboard) + { + mgr.SetPendingOnScreenTex(CAssetId(), zeus::CVector2i(), zeus::CVector2i()); + if (x1e8_) + x1e8_ = TLockedToken(); + x1e5_26_displayBillboard = false; + } + CActor::AcceptScriptMsg(msg, uid, mgr); + + if (xe8_function == ESpecialFunction::ChaffTarget && msg == EScriptObjectMessage::InitializedInArea) + AddMaterial(EMaterialTypes::Target, mgr); + + if (GetActive()) + { + switch(xe8_function) + { + case ESpecialFunction::HUDFadeIn: + { + if (msg == EScriptObjectMessage::Action) + mgr.Player()->SetHudDisable(xfc_, 0.f, 0.5f); + break; + } + case ESpecialFunction::EscapeSequence: + { + if (msg == EScriptObjectMessage::Action && xfc_ >= 0.f) + mgr.ResetEscapeSequenceTimer(xfc_); + break; + } + case ESpecialFunction::SpinnerController: + { + switch(msg) + { + case EScriptObjectMessage::Stop: + { + x1e4_25_spinnerCanMove = false; + break; + } + case EScriptObjectMessage::Play: + { + x1e4_25_spinnerCanMove = true; + mgr.Player()->SetAngularVelocityWR(zeus::CAxisAngle::sIdentity); + break; + } + case EScriptObjectMessage::Deactivate: + DeleteEmitter(x178_sfxHandle); + break; + default: + break; + } + break; + } + case ESpecialFunction::ShotSpinnerController: + { + switch(msg) + { + case EScriptObjectMessage::Increment: + { + x16c_ = zeus::clamp(0.f, x16c_ + 1.f, 1.f); + SendScriptMsgs(EScriptObjectState::Play, mgr, EScriptObjectMessage::None); + break; + } + case EScriptObjectMessage::SetToMax: + { + SendScriptMsgs(EScriptObjectState::Play, mgr, EScriptObjectMessage::None); + break; + } + case EScriptObjectMessage::SetToZero: + { + x16c_ = -0.5f * x104_; + break; + } + default: + break; + } + break; + } + case ESpecialFunction::MapStation: + { + if (msg == EScriptObjectMessage::Action) + { + mgr.MapWorldInfo()->SetMapStationUsed(true); + const_cast(*mgr.WorldNC()->GetMapWorld()).RecalculateWorldSphere(*mgr.MapWorldInfo(), *mgr.GetWorld()); + } + break; + } + case ESpecialFunction::MissileStation: + { + if (msg == EScriptObjectMessage::Action) + { + CPlayerState& pState = *mgr.GetPlayerState().get(); + pState.ResetAndIncrPickUp(CPlayerState::EItemType::Missiles, pState.GetItemCapacity(CPlayerState::EItemType::Missiles)); + } + break; + } + case ESpecialFunction::PowerBombStation: + { + if (msg == EScriptObjectMessage::Action) + { + CPlayerState& pState = *mgr.GetPlayerState().get(); + pState.ResetAndIncrPickUp(CPlayerState::EItemType::PowerBombs, pState.GetItemCapacity(CPlayerState::EItemType::PowerBombs)); + } + break; + } + case ESpecialFunction::SaveStation: + { + if (msg == EScriptObjectMessage::Action) + { + g_GameState->GetPlayerState()->IncrPickup(CPlayerState::EItemType::EnergyTanks, 1); + if (g_GameState->GetCardSerial() == 0) + SendScriptMsgs(EScriptObjectState::Closed, mgr, EScriptObjectMessage::None); + else + { + mgr.DeferStateTransition(EStateManagerTransition::SaveGame); + x1e5_24_doSave = true; + } + } + break; + } + case ESpecialFunction::IntroBossRingController: + { + if (x1a8_ != 3) + { + switch(msg) + { + case EScriptObjectMessage::Play: + { + if (x1a8_ != 0) + RingScramble(mgr); + + for (SRingController& cont : x198_ringControllers) + { + if (TCastToPtr act = mgr.ObjectById(cont.x0_id)) + cont.xc_ = act->GetTransform().frontVector(); + else + cont.xc_ = zeus::CVector3f::skForward; + } + + x1a8_ = 3; + break; + } + case EScriptObjectMessage::SetToZero: + { + x1a8_ = 1; + x1ac_ = GetTranslation() - mgr.GetPlayer().GetTranslation(); + x1ac_.z = 0.f; + x1ac_.normalize(); + break; + } + case EScriptObjectMessage::Action: + { + RingScramble(mgr); + break; + } + case EScriptObjectMessage::InitializedInArea: + { + x198_ringControllers.reserve(3); + for (const SConnection& conn : x20_conns) + { + if (conn.x0_state != EScriptObjectState::Play || conn.x4_msg != EScriptObjectMessage::Activate) + continue; + + auto search = mgr.GetIdListForScript(conn.x8_objId); + for (auto it = search.first; it != search.second; ++it) + { + if (TCastToPtr act = mgr.ObjectById(it->second)) + { + x198_ringControllers.push_back(SRingController(it->second, 0.f, false)); + act->RemoveMaterial(EMaterialTypes::Occluder, mgr); + } + } + + //std::sort(x198_ringControllers.begin(), x198_ringControllers.end()); + /* TODO: Finish */ + } + break; + } + default: + break; + } + } + break; + } + case ESpecialFunction::RadialDamage: + { + if (msg == EScriptObjectMessage::Action) + { + CDamageInfo dInfo = x11c_damageInfo; + dInfo.SetRadius(xfc_); + mgr.ApplyDamageToWorld(GetUniqueId(), *this, GetTranslation(), dInfo, CMaterialFilter::MakeIncludeExclude({EMaterialTypes::Solid}, {0ull})); + } + break; + } + case ESpecialFunction::BossEnergyBar: + { + if (msg == EScriptObjectMessage::Increment) + mgr.SetBossParams(uid, xfc_, u32(x100_) + 86); + else if (msg == EScriptObjectMessage::Decrement) + mgr.SetBossParams(kInvalidUniqueId, 0.f, 0); + break; + } + case ESpecialFunction::EndGame: + { + if (msg == EScriptObjectMessage::Action) + { + switch(GetSpecialEnding(mgr)) + { + case 0: + g_Main->SetFlowState(EFlowState::WinBad); + break; + case 1: + g_Main->SetFlowState(EFlowState::WinGood); + break; + case 2: + g_Main->SetFlowState(EFlowState::WinBest); + break; + } + mgr.SetShouldQuitGame(true); + } + break; + } + case ESpecialFunction::CinematicSkip: + { + if (msg == EScriptObjectMessage::Increment) + { + if (ShouldSkipCinematic(mgr)) + mgr.SetSkipCinematicSpecialFunction(GetUniqueId()); + } + else if (msg == EScriptObjectMessage::Decrement) + { + mgr.SetSkipCinematicSpecialFunction(kInvalidUniqueId); + g_GameState->SystemOptions().SetCinematicState(mgr.GetWorld()->GetWorldAssetId(), GetEditorId(), true); + + } + break; + } + case ESpecialFunction::ScriptLayerController: + { + break; + } + } + } } void CScriptSpecialFunction::PreRender(CStateManager&, const zeus::CFrustum&) {} @@ -59,6 +345,56 @@ void CScriptSpecialFunction::SkipCinematic(CStateManager& stateMgr) stateMgr.SetSkipCinematicSpecialFunction(kInvalidUniqueId); } +void CScriptSpecialFunction::RingMoveCloser(CStateManager &, float) +{ + +} + +void CScriptSpecialFunction::RingMoveAway(CStateManager &, float) +{ + +} + +void CScriptSpecialFunction::ThinkRingPuller(float, CStateManager &) +{ + +} + +void CScriptSpecialFunction::RingScramble(CStateManager &) +{ + +} + +void CScriptSpecialFunction::ThinkIntroBossRingController(float, CStateManager &) +{ + +} + +void CScriptSpecialFunction::ThinkPlayerFollowLocator(float, CStateManager &) +{ + +} + +void CScriptSpecialFunction::ThinkSpinnerController(float, CStateManager &, CScriptSpecialFunction::ESpinnerControllerMode) +{ + +} + +void CScriptSpecialFunction::ThinkObjectFollowLocator(float, CStateManager &) +{ + +} + +void CScriptSpecialFunction::ThinkObjectFollowObject(float, CStateManager &) +{ + +} + +void CScriptSpecialFunction::ThinkChaffTarget(float, CStateManager &) +{ + +} + void CScriptSpecialFunction::ThinkActorScale(float dt, CStateManager& mgr) { float deltaScale = dt * xfc_; @@ -97,8 +433,52 @@ void CScriptSpecialFunction::ThinkSaveStation(float, CStateManager& mgr) } } +void CScriptSpecialFunction::ThinkRainSimulator(float, CStateManager &) +{ + +} + +void CScriptSpecialFunction::ThinkAreaDamage(float, CStateManager &) +{ + +} + +void CScriptSpecialFunction::ThinkPlayerInArea(float, CStateManager &) +{ + +} + bool CScriptSpecialFunction::ShouldSkipCinematic(CStateManager& stateMgr) const { +#ifndef NDEBUG + return true; +#else return g_GameState->SystemOptions().GetCinematicState(stateMgr.GetWorld()->IGetWorldAssetId(), GetEditorId()); +#endif } + +void CScriptSpecialFunction::DeleteEmitter(const CSfxHandle& handle) +{ + if (handle) + CSfxManager::RemoveEmitter(handle); +} + +u32 CScriptSpecialFunction::GetSpecialEnding(const CStateManager& mgr) const +{ + const u32 rate = (mgr.GetPlayerState()->CalculateItemCollectionRate() * 100) / mgr.GetPlayerState()->GetPickupTotal(); + if (rate < 75) + return 0; + else if (rate < 100) + return 1; + return 2; +} + +CScriptSpecialFunction::SRingController::SRingController(TUniqueId uid, float f, bool b) + : x0_id(uid) + , x4_(f) + , x8_(b) +{ + +} + } diff --git a/Runtime/World/CScriptSpecialFunction.hpp b/Runtime/World/CScriptSpecialFunction.hpp index 47916ff67..d1362c1d1 100644 --- a/Runtime/World/CScriptSpecialFunction.hpp +++ b/Runtime/World/CScriptSpecialFunction.hpp @@ -54,11 +54,17 @@ public: enum class ESpinnerControllerMode { + Zero, + One, }; struct SRingController { - SRingController(TUniqueId, float, bool); + TUniqueId x0_id; + float x4_; + bool x8_; + zeus::CVector3f xc_; + SRingController(TUniqueId uid, float f, bool b); }; private: @@ -77,14 +83,12 @@ private: s16 x170_; s16 x172_; s16 x174_; - u32 x178_ = 0; + CSfxHandle x178_sfxHandle; u32 x17c_; float x180_ = 0.f; std::vector x184_; float x194_ = 0.f; - u32 x19c_ = 0; - u32 x1a0_ = 0; - u32 x1a4_ = 0; + std::vector x198_ringControllers; u32 x1a8_ = 2; zeus::CVector3f x1ac_ = zeus::CVector3f::skZero; bool x1b8_ = true; @@ -97,17 +101,20 @@ private: struct { bool x1e4_24_ : 1; - bool x1e4_25_ : 1; + bool x1e4_25_spinnerCanMove : 1; bool x1e4_26_ : 1; bool x1e4_27_ : 1; + bool x1e4_28_frustumEntered : 1; + bool x1e4_29_frustumExited : 1; + bool x1e4_30_ : 1; bool x1e4_31_ : 1; bool x1e5_24_doSave : 1; bool x1e5_25_ : 1; - bool x1e5_26_ : 1; + bool x1e5_26_displayBillboard : 1; }; u32 x1e4_dummy = 0; }; - bool x1f0_ = false; + TLockedToken x1e8_; // Used to be optional public: CScriptSpecialFunction(TUniqueId, std::string_view, const CEntityInfo&, const zeus::CTransform&, ESpecialFunction, std::string_view, float, float, float, float, const zeus::CVector3f&, const zeus::CColor&, @@ -129,11 +136,18 @@ public: void ThinkPlayerFollowLocator(float, CStateManager&); void ThinkSpinnerController(float, CStateManager&, ESpinnerControllerMode); void ThinkObjectFollowLocator(float, CStateManager&); + void ThinkObjectFollowObject(float, CStateManager&); void ThinkChaffTarget(float, CStateManager&); void ThinkActorScale(float, CStateManager&); void ThinkSaveStation(float, CStateManager&); + void ThinkRainSimulator(float, CStateManager&); + void ThinkAreaDamage(float, CStateManager&); + void ThinkPlayerInArea(float, CStateManager&); bool ShouldSkipCinematic(CStateManager& stateMgr) const; + + void DeleteEmitter(const CSfxHandle& handle); + u32 GetSpecialEnding(const CStateManager&) const; }; } diff --git a/Runtime/World/CWorld.cpp b/Runtime/World/CWorld.cpp index 50c07a482..a0c39a046 100644 --- a/Runtime/World/CWorld.cpp +++ b/Runtime/World/CWorld.cpp @@ -211,7 +211,7 @@ CWorld::~CWorld() CScriptRoomAcoustics::DisableAuxCallbacks(); } -CAssetId CWorld::IGetWorldAssetId() const { return x8_mlvlId; } +CAssetId CWorld::IGetWorldAssetId() const { return GetWorldAssetId(); } CAssetId CWorld::IGetStringTableAssetId() const { return xc_strgId; } diff --git a/Runtime/World/CWorld.hpp b/Runtime/World/CWorld.hpp index 5c65efbed..a535850e5 100644 --- a/Runtime/World/CWorld.hpp +++ b/Runtime/World/CWorld.hpp @@ -209,6 +209,7 @@ public: bool HasGlobalSound(u16 id) const; void AddGlobalSound(const CSfxHandle& hnd); EEnvFxType GetNeededEnvFx() const { return xc4_neededFx; } + CAssetId GetWorldAssetId() const { return x8_mlvlId; } bool AreSkyNeedsMet() const; }; diff --git a/amuse b/amuse index 1fefba66e..594fb346e 160000 --- a/amuse +++ b/amuse @@ -1 +1 @@ -Subproject commit 1fefba66e7fc96cb6fc1b1b014c365da2e0b7a43 +Subproject commit 594fb346e1ffd25f7d387f42716cd77202460c30