metaforce/Runtime/World/CScriptPlayerActor.cpp

458 lines
15 KiB
C++
Raw Permalink Normal View History

#include "Runtime/World/CScriptPlayerActor.hpp"
#include "Runtime/CStateManager.hpp"
#include "Runtime/GameGlobalObjects.hpp"
#include "Runtime/Camera/CGameCamera.hpp"
#include "Runtime/Character/CAssetFactory.hpp"
#include "Runtime/Character/CCharacterFactory.hpp"
#include "Runtime/Graphics/CCubeRenderer.hpp"
#include "Runtime/MP1/MP1.hpp"
#include "Runtime/World/CActorParameters.hpp"
#include "Runtime/World/CLightParameters.hpp"
#include "Runtime/World/CPlayer.hpp"
#include "Runtime/World/CWorld.hpp"
#include "TCastTo.hpp" // Generated file, do not modify include path
2021-04-10 08:42:06 +00:00
namespace metaforce {
2017-11-13 06:19:18 +00:00
CScriptPlayerActor::CScriptPlayerActor(TUniqueId uid, std::string_view name, const CEntityInfo& info,
const zeus::CTransform& xf, const CAnimRes& animRes, CModelData&& mData,
2018-12-08 05:30:43 +00:00
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)
2018-05-13 23:27:47 +00:00
, x2e8_suitRes(animRes)
, x304_beam(beam)
, x350_flags(flags)
, x354_24_setBoundingBox(setBoundingBox) {
2018-12-08 05:30:43 +00:00
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;
2019-06-01 03:41:01 +00:00
_CreateReflectionCube();
}
2018-12-08 05:30:43 +00:00
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;
2018-05-13 23:27:47 +00:00
}
2018-12-08 05:30:43 +00:00
}
return u32(suit);
2018-05-13 23:27:47 +00:00
}
2018-12-08 05:30:43 +00:00
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;
2018-05-14 04:38:58 +00:00
}
2018-12-08 05:30:43 +00:00
} 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;
2018-05-14 04:38:58 +00:00
}
2018-12-08 05:30:43 +00:00
}
2018-05-14 04:38:58 +00:00
2018-12-08 05:30:43 +00:00
return GetSuitCharIdx(mgr, nextSuit);
2018-05-14 04:38:58 +00:00
}
2018-12-08 05:30:43 +00:00
void CScriptPlayerActor::LoadSuit(u32 charIdx) {
if (charIdx == x310_loadedCharIdx) {
return;
2018-12-08 05:30:43 +00:00
}
const TToken<CCharacterFactory> 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;
2018-05-13 23:27:47 +00:00
}
2018-12-08 05:30:43 +00:00
void CScriptPlayerActor::LoadBeam(CPlayerState::EBeamId beam) {
if (beam == x30c_setBeamId) {
return;
2018-12-08 05:30:43 +00:00
}
x31c_beamModel = g_SimplePool->GetObj({FOURCC('CMDL'), g_tweakPlayerRes->GetBeamCineModel(beam)});
x354_27_beamModelLoading = true;
x30c_setBeamId = beam;
2018-05-14 04:38:58 +00:00
}
2018-05-13 23:27:47 +00:00
2018-12-08 05:30:43 +00:00
void CScriptPlayerActor::PumpBeamModel(CStateManager& mgr) {
if (!x31c_beamModel || !x31c_beamModel.IsLoaded()) {
2018-12-08 05:30:43 +00:00
return;
}
2018-12-08 05:30:43 +00:00
BuildBeamModelData();
x314_beamModelData->Touch(mgr, 0);
mgr.GetWorld()->CycleLoadPauseState();
2018-12-08 05:30:43 +00:00
x31c_beamModel = TLockedToken<CModel>();
x354_27_beamModelLoading = false;
2018-05-14 04:38:58 +00:00
}
2018-12-08 05:30:43 +00:00
void CScriptPlayerActor::BuildBeamModelData() {
x314_beamModelData = std::make_unique<CModelData>(
CStaticRes(g_tweakPlayerRes->GetBeamCineModel(x30c_setBeamId), x2e8_suitRes.GetScale()));
2018-05-14 04:38:58 +00:00
}
2018-12-08 05:30:43 +00:00
void CScriptPlayerActor::PumpSuitModel(CStateManager& mgr) {
if (!x320_suitModel || !x320_suitModel.IsLoaded() || !x324_suitSkin || !x324_suitSkin.IsLoaded()) {
2018-12-08 05:30:43 +00:00
return;
}
2018-12-08 05:30:43 +00:00
x320_suitModel->Touch(0);
mgr.GetWorld()->CycleLoadPauseState();
2018-12-08 05:30:43 +00:00
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<CModel>();
x324_suitSkin = TLockedToken<CSkinRules>();
}
2018-05-14 04:38:58 +00:00
}
2018-12-08 05:30:43 +00:00
void CScriptPlayerActor::SetupOfflineModelData() {
x2e8_suitRes.SetCharacterNodeId(x310_loadedCharIdx);
x318_suitModelData = std::make_unique<CModelData>(x2e8_suitRes);
if (!static_cast<MP1::CMain&>(*g_Main).GetScreenFading()) {
x328_backupModelData = x64_modelData->GetAnimationData()->GetModelData();
2018-12-08 05:30:43 +00:00
x348_deallocateBackupCountdown = 2;
}
x64_modelData->GetAnimationData()->SubstituteModelData(x318_suitModelData->GetAnimationData()->GetModelData());
2018-05-14 04:38:58 +00:00
}
2018-12-08 05:30:43 +00:00
void CScriptPlayerActor::SetupOnlineModelData() {
if (x310_loadedCharIdx == x2e8_suitRes.GetCharacterNodeId() && x64_modelData && x64_modelData->HasAnimData()) {
return;
}
x2e8_suitRes.SetCharacterNodeId(x310_loadedCharIdx);
SetModelData(std::make_unique<CModelData>(x2e8_suitRes));
const CAnimPlaybackParms parms(x2e8_suitRes.GetDefaultAnim(), -1, 1.f, true);
x64_modelData->GetAnimationData()->SetAnimation(parms, false);
if (x354_24_setBoundingBox) {
SetBoundingBox(x64_modelData->GetBounds(GetTransform().getRotation()));
2018-12-08 05:30:43 +00:00
}
2018-05-13 23:27:47 +00:00
}
2018-12-08 05:30:43 +00:00
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) == 0) {
const u32 tmpIdx = GetSuitCharIdx(mgr, pState.GetCurrentSuitRaw());
2018-12-08 05:30:43 +00:00
if (tmpIdx != x310_loadedCharIdx) {
SetModelData(std::make_unique<CModelData>(CModelData::CModelDataNull()));
LoadSuit(tmpIdx);
2018-05-14 04:38:58 +00:00
x354_25_deferOnlineModelData = true;
2018-12-08 05:30:43 +00:00
}
2018-05-13 23:27:47 +00:00
}
2018-12-08 05:30:43 +00:00
LoadBeam(x304_beam != CPlayerState::EBeamId::Invalid ? x304_beam : pState.GetCurrentBeam());
2018-05-14 04:38:58 +00:00
if (x354_27_beamModelLoading) {
2018-12-08 05:30:43 +00:00
PumpBeamModel(mgr);
}
2018-05-14 04:38:58 +00:00
if (x354_28_suitModelLoading) {
2018-12-08 05:30:43 +00:00
PumpSuitModel(mgr);
}
2018-05-14 04:38:58 +00:00
2018-12-08 05:30:43 +00:00
if (!x354_29_loading) {
if (x354_28_suitModelLoading || x354_27_beamModelLoading || !x64_modelData || x64_modelData->IsNull() ||
!x64_modelData->IsLoaded(0)) {
2018-12-08 05:30:43 +00:00
x354_29_loading = true;
}
2018-05-14 04:38:58 +00:00
}
2018-12-08 05:30:43 +00:00
if (x354_29_loading && !x354_28_suitModelLoading && !x354_27_beamModelLoading && x64_modelData &&
!x64_modelData->IsNull() && x64_modelData->IsLoaded(0)) {
if (x355_24_areaTrackingLoad) {
CGameArea* area = mgr.GetWorld()->GetArea(x4_areaId);
--area->GetPostConstructed()->x113c_playerActorsLoading;
2018-12-08 05:30:43 +00:00
x355_24_areaTrackingLoad = false;
}
x354_29_loading = false;
SendScriptMsgs(EScriptObjectState::Arrived, mgr, EScriptObjectMessage::None);
2018-05-14 04:38:58 +00:00
}
2018-12-08 05:30:43 +00:00
}
2018-05-14 04:38:58 +00:00
2018-12-08 05:30:43 +00:00
if (x2e8_suitRes.GetCharacterNodeId() == 3) {
if (!x338_phazonIndirectTexture) {
2018-12-08 05:30:43 +00:00
x338_phazonIndirectTexture = g_SimplePool->GetObj("PhazonIndirectTexture");
}
2018-12-08 05:30:43 +00:00
} else {
if (x338_phazonIndirectTexture) {
2018-12-08 05:30:43 +00:00
x338_phazonIndirectTexture = TLockedToken<CTexture>();
}
2018-12-08 05:30:43 +00:00
}
if (x338_phazonIndirectTexture) {
x34c_phazonOffsetAngle += 0.03f;
2018-12-17 03:52:51 +00:00
x34c_phazonOffsetAngle = zeus::CRelAngle(x34c_phazonOffsetAngle).asRel();
2018-12-08 05:30:43 +00:00
}
2018-05-14 04:38:58 +00:00
2018-12-08 05:30:43 +00:00
CScriptActor::Think(dt, mgr);
2018-05-14 04:38:58 +00:00
}
2018-12-08 05:30:43 +00:00
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) {
2018-12-08 05:30:43 +00:00
mgr.GetActorModelParticles()->AddRainSplashGenerator(*this, mgr, 250, 10, 1.2f);
}
}
}
2018-12-08 05:30:43 +00:00
} else {
mgr.GetActorModelParticles()->RemoveRainSplashGenerator(*this);
}
2018-05-14 04:38:58 +00:00
}
2018-12-08 05:30:43 +00:00
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;
}
const TCastToPtr<CScriptActor> act = mgr.ObjectById(paId);
2018-12-08 05:30:43 +00:00
if (act && act->IsPlayerActor()) {
other = static_cast<CScriptPlayerActor*>(act.GetPtr());
paId = other->x356_nextPlayerActor;
} else {
paId = kInvalidUniqueId;
2018-05-14 04:38:58 +00:00
x356_nextPlayerActor = kInvalidUniqueId;
2018-12-08 05:30:43 +00:00
}
2018-05-14 04:38:58 +00:00
}
2018-12-08 05:30:43 +00:00
if (set) {
x356_nextPlayerActor = mgr.GetPlayerActorHead();
mgr.SetPlayerActorHead(x8_uid);
2018-05-13 23:27:47 +00:00
}
2018-12-08 05:30:43 +00:00
}
}
2018-12-08 05:30:43 +00:00
void CScriptPlayerActor::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) {
switch (msg) {
case EScriptObjectMessage::InitializedInArea:
x354_31_deferOnlineLoad = true;
if (x350_flags & 0x8) {
CGameArea* area = mgr.GetWorld()->GetArea(x4_areaId);
++area->GetPostConstructed()->x113c_playerActorsLoading;
2018-12-08 05:30:43 +00:00
x355_24_areaTrackingLoad = true;
}
if (GetActive()) {
SetupEnvFx(mgr, true);
SetIntoStateManager(mgr, true);
}
break;
case EScriptObjectMessage::Activate:
if (!GetActive()) {
if ((x350_flags & 0x1) != 0) {
2018-12-08 05:30:43 +00:00
LoadSuit(GetNextSuitCharIdx(mgr));
}
2018-12-08 05:30:43 +00:00
SetIntoStateManager(mgr, true);
SetupEnvFx(mgr, true);
x354_30_enableLoading = true;
}
break;
case EScriptObjectMessage::Increment:
if ((x350_flags & 0x1) != 0) {
2018-12-08 05:30:43 +00:00
x354_25_deferOnlineModelData = false;
x354_26_deferOfflineModelData = true;
mgr.GetPlayer().AsyncLoadSuit(mgr);
}
break;
case EScriptObjectMessage::Deactivate:
if (GetActive()) {
if ((x350_flags & 0x10) == 0) {
2018-05-14 04:38:58 +00:00
SetIntoStateManager(mgr, false);
}
2018-12-08 05:30:43 +00:00
SetupEnvFx(mgr, false);
2018-05-14 04:38:58 +00:00
}
if ((x350_flags & 0x4) == 0) {
2018-12-08 05:30:43 +00:00
break;
}
2019-02-18 05:47:46 +00:00
[[fallthrough]];
2018-12-08 05:30:43 +00:00
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<CModel>();
x320_suitModel = TLockedToken<CModel>();
x324_suitSkin = TLockedToken<CSkinRules>();
x328_backupModelData = TLockedToken<CSkinnedModel>();
x338_phazonIndirectTexture = TLockedToken<CTexture>();
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>(CModelData::CModelDataNull()));
SetActive(false);
2018-12-08 05:30:43 +00:00
}
break;
case EScriptObjectMessage::Deleted:
SetIntoStateManager(mgr, false);
break;
default:
break;
}
CScriptActor::AcceptScriptMsg(msg, uid, mgr);
}
2018-12-08 05:30:43 +00:00
void CScriptPlayerActor::SetActive(bool active) {
CActor::SetActive(active);
xe7_29_drawEnabled = true;
}
2018-12-08 05:30:43 +00:00
void CScriptPlayerActor::PreRender(CStateManager& mgr, const zeus::CFrustum& frustum) {
if (x328_backupModelData) {
if (x348_deallocateBackupCountdown == 0) {
2018-12-08 05:30:43 +00:00
x328_backupModelData = TLockedToken<CSkinnedModel>();
} else {
2018-12-08 05:30:43 +00:00
--x348_deallocateBackupCountdown;
}
2018-12-08 05:30:43 +00:00
}
if (x2e8_suitRes.GetCharacterNodeId() == 3) {
2018-12-08 05:30:43 +00:00
g_Renderer->AllocatePhazonSuitMaskTexture();
}
// TODO xb4_drawFlags.m_extendedShader = EExtendedShader::LightingCubeReflection;
2018-12-08 05:30:43 +00:00
CScriptActor::PreRender(mgr, frustum);
}
void CScriptPlayerActor::AddToRenderer(const zeus::CFrustum& frustum, CStateManager& mgr) {
TouchModels_Internal(mgr);
if (GetActive()) {
2018-12-08 05:30:43 +00:00
CActor::AddToRenderer(frustum, mgr);
}
}
void CScriptPlayerActor::Render(CStateManager& mgr) {
const bool phazonSuit = x2e8_suitRes.GetCharacterNodeId() == 3;
2020-03-04 00:49:13 +00:00
if (phazonSuit) {
GXSetDstAlpha(true, 1.f);
2018-12-08 05:30:43 +00:00
}
CPhysicsActor::Render(mgr);
if (x314_beamModelData && !x314_beamModelData->IsNull() && x64_modelData && !x64_modelData->IsNull()) {
const auto modelXf = GetTransform() * x64_modelData->GetScaledLocatorTransform("GUN_LCTR");
const CModelFlags flags{5, 0, 3, zeus::CColor{1.f, xb4_drawFlags.x4_color.a()}};
2018-12-08 05:30:43 +00:00
x314_beamModelData->Render(mgr, modelXf, x90_actorLights.get(), flags);
}
2020-03-04 00:49:13 +00:00
if (phazonSuit) {
// TODO
// CCubeRenderer::CopyTex
2018-12-08 05:30:43 +00:00
zeus::CVector3f vecFromCam =
GetBoundingBox().center() - mgr.GetCameraManager()->GetCurrentCamera(mgr)->GetTranslation();
const float radius = zeus::clamp(0.25f, (6.f - vecFromCam.magnitude()) / 6.f, 2.f);
const float offsetX = std::sin(x34c_phazonOffsetAngle);
const float offsetY = std::sin(x34c_phazonOffsetAngle) * 0.5f;
g_Renderer->DrawPhazonSuitIndirectEffect(zeus::CColor(0.1f, 1.f), x338_phazonIndirectTexture, zeus::skWhite, radius,
0.05f, offsetX, offsetY);
2018-12-08 05:30:43 +00:00
}
2017-03-26 05:53:04 +00:00
}
2018-12-08 05:30:43 +00:00
void CScriptPlayerActor::TouchModels_Internal(const CStateManager& mgr) const {
if (x64_modelData && !x64_modelData->IsNull()) {
2018-12-08 05:30:43 +00:00
x64_modelData->Touch(mgr, 0);
}
2017-03-26 05:53:04 +00:00
if (x318_suitModelData && !x318_suitModelData->IsNull()) {
2018-12-08 05:30:43 +00:00
x318_suitModelData->Touch(mgr, 0);
}
2018-05-14 04:38:58 +00:00
if (!x354_27_beamModelLoading) {
if (x314_beamModelData && !x314_beamModelData->IsNull()) {
2018-12-08 05:30:43 +00:00
x314_beamModelData->Touch(mgr, 0);
}
}
2018-05-14 04:38:58 +00:00
}
2018-12-08 05:30:43 +00:00
void CScriptPlayerActor::TouchModels(const CStateManager& mgr) const {
TouchModels_Internal(mgr);
TUniqueId paId = x356_nextPlayerActor;
while (paId != kInvalidUniqueId) {
const TCastToConstPtr<CScriptActor> act = mgr.GetObjectById(paId);
2018-12-08 05:30:43 +00:00
if (act && act->IsPlayerActor()) {
const auto* pa = static_cast<const CScriptPlayerActor*>(act.GetPtr());
pa->TouchModels_Internal(mgr);
paId = pa->x356_nextPlayerActor;
} else {
paId = kInvalidUniqueId;
2018-05-14 04:38:58 +00:00
}
2018-12-08 05:30:43 +00:00
}
}
2021-04-10 08:42:06 +00:00
} // namespace metaforce