#include "World/CScriptPlayerActor.hpp" #include "World/CActorParameters.hpp" #include "World/CLightParameters.hpp" #include "GameGlobalObjects.hpp" #include "Graphics/CBooRenderer.hpp" #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 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) : CScriptActor(uid, name, info, xf, std::move(mData), aabox, mass, zMomentum, list, hInfo, dVuln, aParams, loop, active, 0, 1.f, false, false, false, false) , x2e8_suitRes(animRes) , x304_beam(beam) , x350_flags(flags) { x354_24_setBoundingBox = setBoundingBox; x354_29_loading = true; x354_30_enableLoading = true; CMaterialList exclude = GetMaterialFilter().GetExcludeList(); CMaterialList include = GetMaterialFilter().GetIncludeList(); include.Add(EMaterialTypes::Player); SetMaterialFilter(CMaterialFilter::MakeIncludeExclude(include, exclude)); SetActorLights(aParams.GetLightParameters().MakeActorLights()); xe7_29_drawEnabled = true; x2e3_24_isPlayerActor = true; } u32 CScriptPlayerActor::GetSuitCharIdx(const CStateManager& mgr, CPlayerState::EPlayerSuit suit) const { if (mgr.GetPlayerState()->IsFusionEnabled()) { switch (suit) { case CPlayerState::EPlayerSuit::Power: return 4; case CPlayerState::EPlayerSuit::Varia: return 7; case CPlayerState::EPlayerSuit::Gravity: return 6; case CPlayerState::EPlayerSuit::Phazon: return 8; default: break; } } 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); 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()->CycleLoadPauseState(); 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()->CycleLoadPauseState(); 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_deferOnlineLoad) { x354_25_deferOnlineModelData = true; x354_31_deferOnlineLoad = false; x308_suit = pState.GetCurrentSuitRaw(); LoadSuit(GetSuitCharIdx(mgr, x308_suit)); } if (x354_30_enableLoading) { if (!(x350_flags & 0x1)) { u32 tmpIdx = GetSuitCharIdx(mgr, pState.GetCurrentSuitRaw()); if (tmpIdx != x310_loadedCharIdx) { SetModelData(std::make_unique(CModelData::CModelDataNull())); LoadSuit(tmpIdx); 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(x34c_phazonOffsetAngle).asRel(); } 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; [[fallthrough]]; 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) { CActor::SetActive(active); xe7_29_drawEnabled = true; } 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& 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_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; } } } } // namespace urde