diff --git a/DataSpec/DNAMP1/ScriptObjects/PlayerActor.hpp b/DataSpec/DNAMP1/ScriptObjects/PlayerActor.hpp index 561a6391a..4d73c68cd 100644 --- a/DataSpec/DNAMP1/ScriptObjects/PlayerActor.hpp +++ b/DataSpec/DNAMP1/ScriptObjects/PlayerActor.hpp @@ -15,21 +15,21 @@ struct PlayerActor : IScriptObject Value location; Value orientation; Value scale; - Value unknown1; - Value scanOffset; - Value unknown2; - Value unknown3; + Value boxExtents; + Value boxOffset; + Value mass; + Value zMomentum; HealthInfo healthInfo; DamageVulnerability damageVulnerability; UniqueID32 model; AnimationParameters animationParameters; ActorParameters actorParameters; - Value unknown4; - Value unknown5; - Value unknown6; - Value unknown7; + Value loop; + Value snow; + Value solid; + Value active; PlayerParameters playerParameters; - Value unknown8; + Value beamId; void addCMDLRigPairs(PAKRouter& pakRouter, std::unordered_map>& addTo) const diff --git a/Runtime/CStateManager.cpp b/Runtime/CStateManager.cpp index 32aa28f27..09bbff53a 100644 --- a/Runtime/CStateManager.cpp +++ b/Runtime/CStateManager.cpp @@ -465,10 +465,10 @@ void CStateManager::TouchSky() const void CStateManager::TouchPlayerActor() { - if (xf6c_playerActor == kInvalidUniqueId) + if (xf6c_playerActorHead == kInvalidUniqueId) return; - if (CEntity* ent = ObjectById(xf6c_playerActor)) - static_cast(ent)->TouchModels(); + if (CEntity* ent = ObjectById(xf6c_playerActorHead)) + static_cast(ent)->TouchModels(*this); } void CStateManager::DrawSpaceWarp(const zeus::CVector3f& v, float strength) const diff --git a/Runtime/CStateManager.hpp b/Runtime/CStateManager.hpp index aade03aaa..352a566db 100644 --- a/Runtime/CStateManager.hpp +++ b/Runtime/CStateManager.hpp @@ -204,7 +204,7 @@ private: TUniqueId xf38_skipCineSpecialFunc = kInvalidUniqueId; std::list xf3c_; std::list xf54_; - TUniqueId xf6c_playerActor = kInvalidUniqueId; + TUniqueId xf6c_playerActorHead = kInvalidUniqueId; u32 xf70_ = 0; TUniqueId xf74_lastTrigger = kInvalidUniqueId; @@ -461,6 +461,8 @@ public: xf88_ = msg; xf8c_ = f1; } + TUniqueId GetPlayerActorHead() const { return xf6c_playerActorHead; } + void SetPlayerActorHead(TUniqueId id) { xf6c_playerActorHead = id; } static float g_EscapeShakeCountdown; static bool g_EscapeShakeCountdownInit; diff --git a/Runtime/Camera/CCinematicCamera.cpp b/Runtime/Camera/CCinematicCamera.cpp index 07eac2f52..3b8e3dcd2 100644 --- a/Runtime/Camera/CCinematicCamera.cpp +++ b/Runtime/Camera/CCinematicCamera.cpp @@ -215,7 +215,7 @@ void CCinematicCamera::Think(float dt, CStateManager& mgr) if (x20c_lookAtId != kInvalidUniqueId) if (TCastToPtr act = mgr.ObjectById(x20c_lookAtId)) - if (act->IsCameraMoveIntoAlpha()) + if (act->IsPlayerActor()) act->SetDrawFlags({5, 0, 3, zeus::CColor(1.f, GetMoveOutofIntoAlpha())}); x1ec_t += dt; @@ -243,7 +243,7 @@ void CCinematicCamera::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, TUniqueId id = mgr.GetIdForScript(conn.x8_objId); if (TCastToPtr act = mgr.ObjectById(id)) { - if (act->IsCameraMoveIntoAlpha()) + if (act->IsPlayerActor()) { x20c_lookAtId = id; if (conn.x4_msg != EScriptObjectMessage::Deactivate && @@ -286,7 +286,7 @@ void CCinematicCamera::CalculateMoveOutofIntoEyePosition(bool outOfEye, CStateMa { if (TCastToConstPtr act = mgr.GetObjectById(x20c_lookAtId)) { - if (act->IsCameraMoveIntoAlpha()) + if (act->IsPlayerActor()) { if (const CModelData* mData = act->GetModelData()) { diff --git a/Runtime/MP1/MP1.hpp b/Runtime/MP1/MP1.hpp index 1053a739f..715c064c0 100644 --- a/Runtime/MP1/MP1.hpp +++ b/Runtime/MP1/MP1.hpp @@ -283,6 +283,7 @@ public: void CheckTweakManagerDebugOptions() {} void SetMFGameBuilt(bool b) { x160_25_mfGameBuilt = b; } void SetScreenFading(bool b) { x160_26_screenFading = b; } + bool GetScreenFading() const { return x160_26_screenFading; } static void UpdateDiscordPresence(CAssetId worldSTRG = {}); diff --git a/Runtime/World/CActor.hpp b/Runtime/World/CActor.hpp index 29eebe166..ccc5dd4bc 100644 --- a/Runtime/World/CActor.hpp +++ b/Runtime/World/CActor.hpp @@ -198,6 +198,8 @@ public: void SetModelData(std::unique_ptr&& mData); u8 GetFluidCounter() const { return xe6_24_fluidCounter; } TUniqueId GetFluidId() const { return xc4_fluidId; } + bool GetPointGeneratorParticles() const { return xe5_31_pointGeneratorParticles; } + void SetPointGeneratorParticles(bool s) { xe5_31_pointGeneratorParticles = s; } }; } diff --git a/Runtime/World/CActorModelParticles.cpp b/Runtime/World/CActorModelParticles.cpp index 0a91f0698..c66bc429f 100644 --- a/Runtime/World/CActorModelParticles.cpp +++ b/Runtime/World/CActorModelParticles.cpp @@ -9,6 +9,7 @@ #include "World/CWorld.hpp" #include "Graphics/CBooRenderer.hpp" #include "Graphics/CSkinnedModel.hpp" +#include "World/CScriptPlayerActor.hpp" namespace urde { @@ -275,11 +276,42 @@ std::list::const_iterator CActorModelParticles::Fin return x0_items.cend(); } +std::list::iterator CActorModelParticles::FindOrCreateSystem(CActor& act) +{ + if (act.GetPointGeneratorParticles()) + { + for (auto it = x0_items.begin() ; it != x0_items.end() ; ++it) + if (it->x0_id == act.GetUniqueId()) + return it; + } + + act.SetPointGeneratorParticles(true); + return x0_items.emplace(x0_items.end(), act, *this); +} + void CActorModelParticles::StartIce(CActor& actor, CStateManager& mgr) { } +void CActorModelParticles::AddRainSplashGenerator(CScriptPlayerActor& act, CStateManager& mgr, u32 maxSplashes, + u32 genRate, float minZ) +{ + auto it = FindOrCreateSystem(act); + if (it->xd4_rainSplashGenerator) + return; + + if (act.GetModelData() && !act.GetModelData()->IsNull()) + it->xd4_rainSplashGenerator = std::make_unique(act.GetModelData()->GetScale(), + maxSplashes, genRate, minZ, 0.1875f); +} + +void CActorModelParticles::RemoveRainSplashGenerator(CScriptPlayerActor& act) +{ + auto it = FindOrCreateSystem(act); + it->xd4_rainSplashGenerator.reset(); +} + void CActorModelParticles::Render(const CActor& actor) const { diff --git a/Runtime/World/CActorModelParticles.hpp b/Runtime/World/CActorModelParticles.hpp index 737ba5a11..e3bc321fd 100644 --- a/Runtime/World/CActorModelParticles.hpp +++ b/Runtime/World/CActorModelParticles.hpp @@ -17,6 +17,7 @@ class CElementGen; class CTexture; class CGenDescription; class CActor; +class CScriptPlayerActor; class CActorModelParticles { @@ -93,7 +94,11 @@ public: void Update(float dt, CStateManager& mgr); void SetupHook(TUniqueId uid); std::list::const_iterator FindSystem(TUniqueId uid) const; + std::list::iterator FindOrCreateSystem(CActor& act); void StartIce(CActor& actor, CStateManager& mgr); + void AddRainSplashGenerator(CScriptPlayerActor& act, CStateManager& mgr, u32 maxSplashes, + u32 genRate, float minZ); + void RemoveRainSplashGenerator(CScriptPlayerActor& act); void Render(const CActor& actor) const; }; } diff --git a/Runtime/World/CGameArea.hpp b/Runtime/World/CGameArea.hpp index 79b5f72e4..0888e3995 100644 --- a/Runtime/World/CGameArea.hpp +++ b/Runtime/World/CGameArea.hpp @@ -260,7 +260,7 @@ public: float x1130_xrayTarget = 1.f; float x1134_weaponWorldLightingSpeed = 0.f; float x1138_weaponWorldLightingTarget = 1.f; - u32 x113c_ = 0; + u32 x113c_playerActorsLoading = 0; }; private: std::vector, int>> x110_mreaSecBufs; diff --git a/Runtime/World/CScriptActor.cpp b/Runtime/World/CScriptActor.cpp index 86774dd9d..f0079f61d 100644 --- a/Runtime/World/CScriptActor.cpp +++ b/Runtime/World/CScriptActor.cpp @@ -31,7 +31,7 @@ CScriptActor::CScriptActor(TUniqueId uid, std::string_view name, const CEntityIn x2e2_29_processModelFlags = (x2e2_27_xrayAlphaEnabled || x2e2_24_noThermalHotZ || x2d8_shaderIdx != 0); x2e2_30_scaleAdvancementDelta = scaleAdvancementDelta; x2e2_31_materialFlag54 = materialFlag54; - x2e3_24_cameraMoveIntoAlpha = false; + x2e3_24_isPlayerActor = false; if (x64_modelData && (x64_modelData->HasAnimData() || x64_modelData->HasNormalModel()) && castsShadow) CreateShadow(true); diff --git a/Runtime/World/CScriptActor.hpp b/Runtime/World/CScriptActor.hpp index fa11d8a84..c89e8805a 100644 --- a/Runtime/World/CScriptActor.hpp +++ b/Runtime/World/CScriptActor.hpp @@ -27,7 +27,7 @@ protected: bool x2e2_29_processModelFlags : 1; bool x2e2_30_scaleAdvancementDelta : 1; bool x2e2_31_materialFlag54 : 1; - bool x2e3_24_cameraMoveIntoAlpha : 1; + bool x2e3_24_isPlayerActor : 1; public: CScriptActor(TUniqueId uid, std::string_view name, const CEntityInfo& info, const zeus::CTransform& xf, @@ -46,7 +46,7 @@ public: void Touch(CActor&, CStateManager&); const CDamageVulnerability* GetDamageVulnerability() const { return &x268_damageVulnerability; } CHealthInfo* HealthInfo(CStateManager&) { return &x260_currentHealth; } - bool IsCameraMoveIntoAlpha() const { return x2e3_24_cameraMoveIntoAlpha; } + bool IsPlayerActor() const { return x2e3_24_isPlayerActor; } }; }; diff --git a/Runtime/World/CScriptDoor.cpp b/Runtime/World/CScriptDoor.cpp index 4476592f9..937f7c2d4 100644 --- a/Runtime/World/CScriptDoor.cpp +++ b/Runtime/World/CScriptDoor.cpp @@ -356,7 +356,7 @@ u32 CScriptDoor::GetDoorOpenCondition(CStateManager& mgr) return 1; } - if (area->GetPostConstructed()->x113c_ != 0) + if (area->GetPostConstructed()->x113c_playerActorsLoading != 0) return 1; for (CEntity* ent : mgr.GetPlatformAndDoorObjectList()) diff --git a/Runtime/World/CScriptPlayerActor.cpp b/Runtime/World/CScriptPlayerActor.cpp index 27691a842..bc5ed4a1b 100644 --- a/Runtime/World/CScriptPlayerActor.cpp +++ b/Runtime/World/CScriptPlayerActor.cpp @@ -6,12 +6,17 @@ #include "CStateManager.hpp" #include "Character/CAssetFactory.hpp" #include "Character/CCharacterFactory.hpp" +#include "World/CWorld.hpp" +#include "MP1/MP1.hpp" +#include "World/CPlayer.hpp" +#include "TCastTo.hpp" +#include "Camera/CGameCamera.hpp" namespace urde { CScriptPlayerActor::CScriptPlayerActor(TUniqueId uid, std::string_view name, const CEntityInfo& info, const zeus::CTransform& xf, const CAnimRes& animRes, CModelData&& mData, - const zeus::CAABox& aabox, bool b1, const CMaterialList& list, float mass, + const zeus::CAABox& aabox, bool setBoundingBox, const CMaterialList& list, float mass, float zMomentum, const CHealthInfo& hInfo, const CDamageVulnerability& dVuln, const CActorParameters& aParams, bool loop, bool active, u32 flags, CPlayerState::EBeamId beam) @@ -21,9 +26,9 @@ CScriptPlayerActor::CScriptPlayerActor(TUniqueId uid, std::string_view name, con , x304_beam(beam) , x350_flags(flags) { - x354_24_ = b1; - x354_29_ = true; - x354_30_ = true; + x354_24_setBoundingBox = setBoundingBox; + x354_29_loading = true; + x354_30_enableLoading = true; CMaterialList exclude = GetMaterialFilter().GetExcludeList(); CMaterialList include = GetMaterialFilter().GetIncludeList(); include.Add(EMaterialTypes::Player); @@ -31,7 +36,7 @@ CScriptPlayerActor::CScriptPlayerActor(TUniqueId uid, std::string_view name, con SetActorLights(aParams.GetLightParameters().MakeActorLights()); xe7_29_actorActive = true; - x2e3_24_cameraMoveIntoAlpha = true; + x2e3_24_isPlayerActor = true; } u32 CScriptPlayerActor::GetSuitCharIdx(const CStateManager& mgr, CPlayerState::EPlayerSuit suit) const @@ -55,36 +60,157 @@ u32 CScriptPlayerActor::GetSuitCharIdx(const CStateManager& mgr, CPlayerState::E return u32(suit); } +u32 CScriptPlayerActor::GetNextSuitCharIdx(const CStateManager& mgr) const +{ + CPlayerState::EPlayerSuit nextSuit = CPlayerState::EPlayerSuit::Phazon; + + if (x350_flags & 0x2) + { + switch (x308_suit) + { + case CPlayerState::EPlayerSuit::Gravity: + nextSuit = CPlayerState::EPlayerSuit::Varia; + break; + case CPlayerState::EPlayerSuit::Phazon: + nextSuit = CPlayerState::EPlayerSuit::Gravity; + break; + case CPlayerState::EPlayerSuit::Varia: + default: + nextSuit = CPlayerState::EPlayerSuit::Power; + break; + } + } + else + { + switch (x308_suit) + { + case CPlayerState::EPlayerSuit::Power: + nextSuit = CPlayerState::EPlayerSuit::Varia; + break; + case CPlayerState::EPlayerSuit::Varia: + nextSuit = CPlayerState::EPlayerSuit::Gravity; + break; + case CPlayerState::EPlayerSuit::Gravity: + nextSuit = CPlayerState::EPlayerSuit::Phazon; + break; + default: + break; + } + } + + return GetSuitCharIdx(mgr, nextSuit); +} + void CScriptPlayerActor::LoadSuit(u32 charIdx) { if (charIdx != x310_loadedCharIdx) { TToken fac = g_CharFactoryBuilder->GetFactory(x2e8_suitRes); const CCharacterInfo& chInfo = fac->GetCharInfo(charIdx); - x324_suitModel = g_SimplePool->GetObj({FOURCC('CMDL'), chInfo.GetModelId()}); - x354_28_ = true; + x320_suitModel = g_SimplePool->GetObj({FOURCC('CMDL'), chInfo.GetModelId()}); + x324_suitSkin = g_SimplePool->GetObj({FOURCC('CSKR'), chInfo.GetSkinRulesId()}); + x354_28_suitModelLoading = true; x310_loadedCharIdx = charIdx; } } void CScriptPlayerActor::LoadBeam(CPlayerState::EBeamId beam) { + if (beam != x30c_setBeamId) + { + x31c_beamModel = g_SimplePool->GetObj({FOURCC('CMDL'), g_tweakPlayerRes->GetBeamCineModel(beam)}); + x354_27_beamModelLoading = true; + x30c_setBeamId = beam; + } +} +void CScriptPlayerActor::PumpBeamModel(CStateManager& mgr) +{ + if (!x31c_beamModel || !x31c_beamModel.IsLoaded()) + return; + BuildBeamModelData(); + x314_beamModelData->Touch(mgr, 0); + mgr.WorldNC()->CyclePauseState(); + x31c_beamModel = TLockedToken(); + x354_27_beamModelLoading = false; +} + +void CScriptPlayerActor::BuildBeamModelData() +{ + x314_beamModelData = std::make_unique( + CStaticRes(g_tweakPlayerRes->GetBeamCineModel(x30c_setBeamId), x2e8_suitRes.GetScale())); +} + +void CScriptPlayerActor::PumpSuitModel(CStateManager& mgr) +{ + if (!x320_suitModel || !x320_suitModel.IsLoaded() || + !x324_suitSkin || !x324_suitSkin.IsLoaded()) + return; + + x320_suitModel->Touch(0); + mgr.WorldNC()->CyclePauseState(); + + bool didSetup = false; + if (x354_26_deferOfflineModelData) + { + didSetup = true; + x354_26_deferOfflineModelData = false; + SetupOfflineModelData(); + } + else if (x354_25_deferOnlineModelData) + { + didSetup = true; + x354_25_deferOnlineModelData = false; + SetupOnlineModelData(); + } + + if (didSetup) + { + x354_28_suitModelLoading = false; + x320_suitModel = TLockedToken(); + x324_suitSkin = TLockedToken(); + } +} + +void CScriptPlayerActor::SetupOfflineModelData() +{ + x2e8_suitRes.SetCharacterNodeId(x310_loadedCharIdx); + x318_suitModelData = std::make_unique(x2e8_suitRes); + if (!static_cast(*g_Main).GetScreenFading()) + { + x328_backupModelData = x64_modelData->AnimationData()->GetModelData(); + x348_deallocateBackupCountdown = 2; + } + x64_modelData->AnimationData()->SubstituteModelData(x318_suitModelData->AnimationData()->GetModelData()); +} + +void CScriptPlayerActor::SetupOnlineModelData() +{ + if (x310_loadedCharIdx != x2e8_suitRes.GetCharacterNodeId() || + !x64_modelData || !x64_modelData->HasAnimData()) + { + x2e8_suitRes.SetCharacterNodeId(x310_loadedCharIdx); + SetModelData(std::make_unique(x2e8_suitRes)); + CAnimPlaybackParms parms(x2e8_suitRes.GetDefaultAnim(), -1, 1.f, true); + x64_modelData->AnimationData()->SetAnimation(parms, false); + if (x354_24_setBoundingBox) + SetBoundingBox(x64_modelData->GetBounds(GetTransform().getRotation())); + } } void CScriptPlayerActor::Think(float dt, CStateManager& mgr) { auto& pState = *mgr.GetPlayerState(); - if (x354_31_) + if (x354_31_deferOnlineLoad) { - x354_25_ = true; - x354_31_ = false; + x354_25_deferOnlineModelData = true; + x354_31_deferOnlineLoad = false; x308_suit = pState.GetCurrentSuitRaw(); LoadSuit(GetSuitCharIdx(mgr, x308_suit)); } - if (x354_30_) + if (x354_30_enableLoading) { if (!(x350_flags & 0x1)) { @@ -93,16 +219,193 @@ void CScriptPlayerActor::Think(float dt, CStateManager& mgr) { SetModelData(std::make_unique(CModelData::CModelDataNull())); LoadSuit(tmpIdx); - x354_25_ = true; + x354_25_deferOnlineModelData = true; } } LoadBeam(x304_beam != CPlayerState::EBeamId::Invalid ? x304_beam : pState.GetCurrentBeam()); + + if (x354_27_beamModelLoading) + PumpBeamModel(mgr); + + if (x354_28_suitModelLoading) + PumpSuitModel(mgr); + + if (!x354_29_loading) + { + if (x354_28_suitModelLoading || x354_27_beamModelLoading || !x64_modelData || + x64_modelData->IsNull() || !x64_modelData->IsLoaded(0)) + x354_29_loading = true; + } + + if (x354_29_loading && !x354_28_suitModelLoading && !x354_27_beamModelLoading && + x64_modelData && !x64_modelData->IsNull() && x64_modelData->IsLoaded(0)) + { + if (x355_24_areaTrackingLoad) + { + const CGameArea* area = mgr.GetWorld()->GetAreaAlways(x4_areaId); + --const_cast(area->GetPostConstructed())->x113c_playerActorsLoading; + x355_24_areaTrackingLoad = false; + } + x354_29_loading = false; + SendScriptMsgs(EScriptObjectState::Arrived, mgr, EScriptObjectMessage::None); + } + } + + if (x2e8_suitRes.GetCharacterNodeId() == 3) + { + if (!x338_phazonIndirectTexture) + x338_phazonIndirectTexture = g_SimplePool->GetObj("PhazonIndirectTexture"); + } + else + { + if (x338_phazonIndirectTexture) + x338_phazonIndirectTexture = TLockedToken(); + } + + if (x338_phazonIndirectTexture) + { + x34c_phazonOffsetAngle += 0.03f; + x34c_phazonOffsetAngle = zeus::CRelAngle::FromRadians(x34c_phazonOffsetAngle); + } + + CScriptActor::Think(dt, mgr); +} + +void CScriptPlayerActor::SetupEnvFx(CStateManager& mgr, bool set) +{ + if (set) + { + if (mgr.GetWorld()->GetNeededEnvFx() == EEnvFxType::Rain) + if (x64_modelData && !x64_modelData->IsNull()) + if (mgr.GetEnvFxManager()->GetRainMagnitude() != 0.f) + mgr.GetActorModelParticles()->AddRainSplashGenerator(*this, mgr, 250, 10, 1.2f); + } + else + { + mgr.GetActorModelParticles()->RemoveRainSplashGenerator(*this); + } +} + +void CScriptPlayerActor::SetIntoStateManager(CStateManager& mgr, bool set) +{ + if (!set && mgr.GetPlayerActorHead() == x8_uid) + { + mgr.SetPlayerActorHead(x356_nextPlayerActor); + x356_nextPlayerActor = kInvalidUniqueId; + } + else + { + TUniqueId paId = mgr.GetPlayerActorHead(); + CScriptPlayerActor* other = nullptr; + while (paId != kInvalidUniqueId) + { + if (paId == x8_uid) + { + if (!set && other) + { + other->x356_nextPlayerActor = x356_nextPlayerActor; + x356_nextPlayerActor = kInvalidUniqueId; + } + return; + } + + TCastToPtr act = mgr.ObjectById(paId); + if (act && act->IsPlayerActor()) + { + other = static_cast(act.GetPtr()); + paId = other->x356_nextPlayerActor; + } + else + { + paId = kInvalidUniqueId; + x356_nextPlayerActor = kInvalidUniqueId; + } + } + + if (set) + { + x356_nextPlayerActor = mgr.GetPlayerActorHead(); + mgr.SetPlayerActorHead(x8_uid); + } } } void CScriptPlayerActor::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) { + switch (msg) + { + case EScriptObjectMessage::InitializedInArea: + x354_31_deferOnlineLoad = true; + if (x350_flags & 0x8) + { + const CGameArea* area = mgr.GetWorld()->GetAreaAlways(x4_areaId); + ++const_cast(area->GetPostConstructed())->x113c_playerActorsLoading; + x355_24_areaTrackingLoad = true; + } + if (GetActive()) + { + SetupEnvFx(mgr, true); + SetIntoStateManager(mgr, true); + } + break; + case EScriptObjectMessage::Activate: + if (!GetActive()) + { + if (x350_flags & 0x1) + LoadSuit(GetNextSuitCharIdx(mgr)); + SetIntoStateManager(mgr, true); + SetupEnvFx(mgr, true); + x354_30_enableLoading = true; + } + break; + case EScriptObjectMessage::Increment: + if (x350_flags & 0x1) + { + x354_25_deferOnlineModelData = false; + x354_26_deferOfflineModelData = true; + mgr.GetPlayer().AsyncLoadSuit(mgr); + } + break; + case EScriptObjectMessage::Deactivate: + if (GetActive()) + { + if (!(x350_flags & 0x10)) + SetIntoStateManager(mgr, false); + SetupEnvFx(mgr, false); + } + if (!(x350_flags & 0x4)) + break; + case EScriptObjectMessage::Reset: + if (GetActive() || msg == EScriptObjectMessage::Reset) + { + x30c_setBeamId = CPlayerState::EBeamId::Invalid; + x310_loadedCharIdx = -1; + x314_beamModelData.reset(); + x318_suitModelData.reset(); + x31c_beamModel = TLockedToken(); + x320_suitModel = TLockedToken(); + x324_suitSkin = TLockedToken(); + x328_backupModelData = TLockedToken(); + x338_phazonIndirectTexture = TLockedToken(); + x348_deallocateBackupCountdown = 0; + x350_flags &= ~0x1; + x354_25_deferOnlineModelData = false; + x354_26_deferOfflineModelData = false; + x354_27_beamModelLoading = false; + x354_28_suitModelLoading = false; + x354_30_enableLoading = false; + SetModelData(std::make_unique(CModelData::CModelDataNull())); + } + break; + case EScriptObjectMessage::Deleted: + SetIntoStateManager(mgr, false); + break; + default: + break; + } + + CScriptActor::AcceptScriptMsg(msg, uid, mgr); } void CScriptPlayerActor::SetActive(bool active) @@ -113,22 +416,94 @@ void CScriptPlayerActor::SetActive(bool active) void CScriptPlayerActor::PreRender(CStateManager& mgr, const zeus::CFrustum& frustum) { + if (x328_backupModelData) + { + if (x348_deallocateBackupCountdown == 0) + x328_backupModelData = TLockedToken(); + else + --x348_deallocateBackupCountdown; + } if (x2e8_suitRes.GetCharacterNodeId() == 3) g_Renderer->AllocatePhazonSuitMaskTexture(); CScriptActor::PreRender(mgr, frustum); } -void CScriptPlayerActor::AddToRenderer(const zeus::CFrustum&, const CStateManager&) const +void CScriptPlayerActor::AddToRenderer(const zeus::CFrustum& frustum, const CStateManager& mgr) const { - + const_cast(this)->TouchModels_Internal(mgr); + if (GetActive()) + CActor::AddToRenderer(frustum, mgr); } void CScriptPlayerActor::Render(const CStateManager& mgr) const { + bool phazonSuit = x2e8_suitRes.GetCharacterNodeId() == 3; + if (phazonSuit) + { + // Draw into alpha buffer + CModelFlags flags = xb4_drawFlags; + flags.x4_color = zeus::CColor::skWhite; + flags.m_extendedShader = EExtendedShader::SolidColorBackfaceCullLEqualAlphaOnly; + CModelData::EWhichModel which = CModelData::GetRenderingModel(mgr); + x64_modelData->Render(which, x34_transform, x90_actorLights.get(), flags); + } + + CPhysicsActor::Render(mgr); + + if (x314_beamModelData && !x314_beamModelData->IsNull() && + x64_modelData && !x64_modelData->IsNull()) + { + zeus::CTransform modelXf = GetTransform() * x64_modelData->GetScaledLocatorTransform("GUN_LCTR"); + CModelFlags flags(5, 0, 3, zeus::CColor::skWhite); + flags.m_extendedShader = EExtendedShader::SolidColorBackfaceCullLEqualAlphaOnly; + x314_beamModelData->Render(mgr, modelXf, x90_actorLights.get(), flags); + flags.m_extendedShader = EExtendedShader::Lighting; + flags.x4_color = zeus::CColor{1.f, xb4_drawFlags.x4_color.a}; + x314_beamModelData->Render(mgr, modelXf, x90_actorLights.get(), flags); + } + + if (phazonSuit) + { + zeus::CVector3f vecFromCam = + GetBoundingBox().center() - mgr.GetCameraManager()->GetCurrentCamera(mgr)->GetTranslation(); + float radius = zeus::clamp(0.25f, (6.f - vecFromCam.magnitude()) / 6.f, 2.f); + float offsetX = std::sin(x34c_phazonOffsetAngle); + float offsetY = std::sin(x34c_phazonOffsetAngle) * 0.5f; + g_Renderer->DrawPhazonSuitIndirectEffect(zeus::CColor(0.1f, 1.f), x338_phazonIndirectTexture, + zeus::CColor::skWhite, radius, 0.05f, offsetX, offsetY); + } } -void CScriptPlayerActor::TouchModels() +void CScriptPlayerActor::TouchModels_Internal(const CStateManager& mgr) const { + if (x64_modelData && !x64_modelData->IsNull()) + x64_modelData->Touch(mgr, 0); + if (x318_suitModelData && !x318_suitModelData->IsNull()) + x318_suitModelData->Touch(mgr, 0); + + if (!x354_27_beamModelLoading) + if (x314_beamModelData && !x314_beamModelData->IsNull()) + x314_beamModelData->Touch(mgr, 0); +} + +void CScriptPlayerActor::TouchModels(const CStateManager& mgr) const +{ + TouchModels_Internal(mgr); + TUniqueId paId = x356_nextPlayerActor; + while (paId != kInvalidUniqueId) + { + TCastToConstPtr act = mgr.GetObjectById(paId); + if (act && act->IsPlayerActor()) + { + const auto* pa = static_cast(act.GetPtr()); + pa->TouchModels_Internal(mgr); + paId = pa->x356_nextPlayerActor; + } + else + { + paId = kInvalidUniqueId; + } + } } } diff --git a/Runtime/World/CScriptPlayerActor.hpp b/Runtime/World/CScriptPlayerActor.hpp index fd0970a93..efd869d42 100644 --- a/Runtime/World/CScriptPlayerActor.hpp +++ b/Runtime/World/CScriptPlayerActor.hpp @@ -11,43 +11,56 @@ class CScriptPlayerActor : public CScriptActor CAnimRes x2e8_suitRes; CPlayerState::EBeamId x304_beam; CPlayerState::EPlayerSuit x308_suit = CPlayerState::EPlayerSuit::Invalid; - s32 x30c_ = -1; + CPlayerState::EBeamId x30c_setBeamId = CPlayerState::EBeamId::Invalid; s32 x310_loadedCharIdx = -1; - u32 x314_ = 0; - u32 x318_ = 0; - u32 x31c_ = 0; - u32 x320_ = 0; - TLockedToken x324_suitModel; - u8 x334_ = 0; - u8 x344_ = 0; - u32 x348_ = 0; - float x34c_ = 0.f; - u32 x350_flags; + std::unique_ptr x314_beamModelData; + std::unique_ptr x318_suitModelData; + TLockedToken x31c_beamModel; // Used to be single_ptr + TLockedToken x320_suitModel; // Used to be single_ptr + TLockedToken x324_suitSkin; // Used to be single_ptr + TLockedToken x328_backupModelData; // Used to be optional + TLockedToken x338_phazonIndirectTexture; // Used to be optional + u32 x348_deallocateBackupCountdown = 0; + float x34c_phazonOffsetAngle = 0.f; + u32 x350_flags; /* 0x1: suit transition, 0x2: previous suit, 0x4: force reset + * 0x8: track in area data, 0x10: keep in state manager */ union { struct { - bool x354_24_ : 1; - bool x354_25_ : 1; - bool x354_26_ : 1; - bool x354_27_ : 1; - bool x354_28_ : 1; - bool x354_29_ : 1; - bool x354_30_ : 1; - bool x354_31_ : 1; - bool x355_24_ : 1; + bool x354_24_setBoundingBox : 1; + bool x354_25_deferOnlineModelData : 1; + bool x354_26_deferOfflineModelData : 1; + bool x354_27_beamModelLoading : 1; + bool x354_28_suitModelLoading : 1; + bool x354_29_loading : 1; + bool x354_30_enableLoading : 1; + bool x354_31_deferOnlineLoad : 1; + bool x355_24_areaTrackingLoad : 1; }; u32 _dummy = 0; }; + TUniqueId x356_nextPlayerActor = kInvalidUniqueId; u32 GetSuitCharIdx(const CStateManager& mgr, CPlayerState::EPlayerSuit suit) const; + u32 GetNextSuitCharIdx(const CStateManager& mgr) const; void LoadSuit(u32 charIdx); void LoadBeam(CPlayerState::EBeamId beam); + void PumpBeamModel(CStateManager& mgr); + void BuildBeamModelData(); + void PumpSuitModel(CStateManager& mgr); + void SetupOfflineModelData(); + void SetupOnlineModelData(); + + void SetupEnvFx(CStateManager& mgr, bool set); + void SetIntoStateManager(CStateManager& mgr, bool set); + + void TouchModels_Internal(const CStateManager& mgr) const; public: CScriptPlayerActor(TUniqueId uid, std::string_view name, const CEntityInfo& info, const zeus::CTransform& xf, const CAnimRes& animRes, CModelData&& mData, - const zeus::CAABox& aabox, bool b1, const CMaterialList& list, float mass, + const zeus::CAABox& aabox, bool setBoundingBox, const CMaterialList& list, float mass, float zMomentum, const CHealthInfo& hInfo, const CDamageVulnerability& dVuln, const CActorParameters& aParams, bool loop, bool active, u32 flags, CPlayerState::EBeamId beam); @@ -57,8 +70,7 @@ public: void PreRender(CStateManager &, const zeus::CFrustum &); void AddToRenderer(const zeus::CFrustum &, const CStateManager &) const; void Render(const CStateManager &mgr) const; - void TouchModels(); - + void TouchModels(const CStateManager& mgr) const; }; } diff --git a/Runtime/World/CWorld.cpp b/Runtime/World/CWorld.cpp index 3d828cab5..50c07a482 100644 --- a/Runtime/World/CWorld.cpp +++ b/Runtime/World/CWorld.cpp @@ -570,6 +570,15 @@ void CWorld::SetPauseState(bool paused) x70_25_paused = paused; } +void CWorld::CyclePauseState() +{ + if (!x70_25_paused) + { + SetPauseState(true); + SetPauseState(false); + } +} + bool CWorld::ICheckWorldComplete() { return CheckWorldComplete(nullptr, kInvalidAreaId, -1); } std::string CWorld::IGetDefaultAudioTrack() const { return x84_defAudioTrack; } diff --git a/Runtime/World/CWorld.hpp b/Runtime/World/CWorld.hpp index 91c731075..5c65efbed 100644 --- a/Runtime/World/CWorld.hpp +++ b/Runtime/World/CWorld.hpp @@ -170,6 +170,7 @@ public: bool ScheduleAreaToLoad(CGameArea* area, CStateManager& mgr); void TravelToArea(TAreaId aid, CStateManager& mgr, bool); void SetPauseState(bool paused); + void CyclePauseState(); CWorld(IObjectStore& objStore, IFactory& resFactory, CAssetId mlvlId); ~CWorld();