mirror of
https://github.com/AxioDL/metaforce.git
synced 2025-08-10 09:39:06 +00:00
This member function alters instance state in a few implementations, so it shouldn't be made const. The state manager parameter also shouldn't be const. Retrieved data from the post constructed instance is further modified in some implementations. This removes the constness on this parameter in order to fix more const_cast usages in a follow-up change.
708 lines
25 KiB
C++
708 lines
25 KiB
C++
#include "Runtime/World/CActor.hpp"
|
|
|
|
#include "Runtime/CSimplePool.hpp"
|
|
#include "Runtime/CStateManager.hpp"
|
|
#include "Runtime/CTimeProvider.hpp"
|
|
#include "Runtime/GameGlobalObjects.hpp"
|
|
#include "Runtime/Audio/CSfxManager.hpp"
|
|
#include "Runtime/Camera/CGameCamera.hpp"
|
|
#include "Runtime/Character/CActorLights.hpp"
|
|
#include "Runtime/Character/IAnimReader.hpp"
|
|
#include "Runtime/Collision/CMaterialList.hpp"
|
|
#include "Runtime/Graphics/CBooRenderer.hpp"
|
|
#include "Runtime/Graphics/CSkinnedModel.hpp"
|
|
#include "Runtime/World/CActorParameters.hpp"
|
|
#include "Runtime/World/CWorld.hpp"
|
|
|
|
#include "TCastTo.hpp" // Generated file, do not modify include path
|
|
|
|
#include <hecl/CVarManager.hpp>
|
|
|
|
namespace urde {
|
|
static CMaterialList MakeActorMaterialList(const CMaterialList& materialList, const CActorParameters& params) {
|
|
CMaterialList ret = materialList;
|
|
if (params.GetVisorParameters().x0_4_b1)
|
|
ret.Add(EMaterialTypes::Unknown46);
|
|
if (params.GetVisorParameters().x0_5_scanPassthrough)
|
|
ret.Add(EMaterialTypes::ScanPassthrough);
|
|
return ret;
|
|
}
|
|
|
|
CActor::CActor(TUniqueId uid, bool active, std::string_view name, const CEntityInfo& info, const zeus::CTransform& xf,
|
|
CModelData&& mData, const CMaterialList& list, const CActorParameters& params, TUniqueId otherUid)
|
|
: CEntity(uid, info, active, name)
|
|
, x34_transform(xf)
|
|
, x68_material(MakeActorMaterialList(list, params))
|
|
, x70_materialFilter(CMaterialFilter::MakeIncludeExclude({EMaterialTypes::Solid}, {0ull}))
|
|
, xc6_nextDrawNode(otherUid) {
|
|
x90_actorLights = mData.IsNull() ? nullptr : params.x0_lightParms.MakeActorLights();
|
|
if (mData.x10_animData || mData.x1c_normalModel)
|
|
x64_modelData = std::make_unique<CModelData>(std::move(mData));
|
|
xd0_damageMag = params.x64_thermalMag;
|
|
xd8_nonLoopingSfxHandles.resize(2);
|
|
xe4_27_notInSortedLists = true;
|
|
xe4_28_transformDirty = true;
|
|
xe4_29_actorLightsDirty = true;
|
|
xe4_31_calculateLighting = true;
|
|
xe5_27_useInSortedLists = true;
|
|
xe5_28_callTouch = true;
|
|
xe5_29_globalTimeProvider = params.x58_24_globalTimeProvider;
|
|
xe5_30_renderUnsorted = params.x58_26_renderUnsorted;
|
|
xe6_27_thermalVisorFlags = u8(params.x58_25_thermalHeat ? 2 : 1);
|
|
xe6_29_renderParticleDBInside = true;
|
|
xe6_31_targetableVisorFlags = params.GetVisorParameters().GetMask();
|
|
xe7_27_enableRender = true;
|
|
xe7_29_drawEnabled = active;
|
|
xe7_30_doTargetDistanceTest = true;
|
|
xe7_31_targetable = true;
|
|
if (x64_modelData) {
|
|
if (params.x44_xrayAssets.first.IsValid())
|
|
x64_modelData->SetXRayModel(params.x44_xrayAssets);
|
|
if (params.x4c_thermalAssets.first.IsValid())
|
|
x64_modelData->SetInfraModel(params.x4c_thermalAssets);
|
|
if (!params.x0_lightParms.x1c_makeLights || params.x0_lightParms.x3c_maxAreaLights == 0)
|
|
x64_modelData->x18_ambientColor = params.x0_lightParms.x18_noLightsAmbient;
|
|
x64_modelData->x14_25_sortThermal = !params.x58_27_noSortThermal;
|
|
}
|
|
|
|
if (params.x40_scanParms.GetScanId().IsValid())
|
|
x98_scanObjectInfo = g_SimplePool->GetObj(SObjectTag{FOURCC('SCAN'), params.x40_scanParms.GetScanId()});
|
|
}
|
|
|
|
void CActor::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) {
|
|
switch (msg) {
|
|
case EScriptObjectMessage::Activate: {
|
|
if (!x30_24_active)
|
|
xbc_time = CGraphics::GetSecondsMod900();
|
|
break;
|
|
}
|
|
case EScriptObjectMessage::Deactivate:
|
|
RemoveEmitter();
|
|
break;
|
|
case EScriptObjectMessage::Deleted: // 34
|
|
{
|
|
RemoveEmitter();
|
|
if (HasModelData() && !x64_modelData->IsNull())
|
|
if (CAnimData* aData = x64_modelData->GetAnimationData())
|
|
aData->GetParticleDB().DeleteAllLights(mgr);
|
|
break;
|
|
}
|
|
case EScriptObjectMessage::Registered: // 33
|
|
{
|
|
if (x98_scanObjectInfo)
|
|
AddMaterial(EMaterialTypes::Scannable, mgr);
|
|
else
|
|
RemoveMaterial(EMaterialTypes::Scannable, mgr);
|
|
|
|
if (HasModelData() && x64_modelData->GetAnimationData()) {
|
|
TAreaId aid = GetAreaId();
|
|
x64_modelData->GetAnimationData()->InitializeEffects(mgr, aid, x64_modelData->GetScale());
|
|
}
|
|
break;
|
|
}
|
|
case EScriptObjectMessage::UpdateSplashInhabitant: // 37
|
|
SetInFluid(true, uid);
|
|
break;
|
|
case EScriptObjectMessage::RemoveSplashInhabitant: // 39
|
|
SetInFluid(false, kInvalidUniqueId);
|
|
break;
|
|
case EScriptObjectMessage::InitializedInArea: // 35
|
|
{
|
|
for (const SConnection& conn : x20_conns) {
|
|
if (conn.x0_state != EScriptObjectState::Default)
|
|
continue;
|
|
|
|
const CActor* act = TCastToConstPtr<CActor>(mgr.GetObjectById(mgr.GetIdForScript(conn.x8_objId)));
|
|
if (act && xc6_nextDrawNode == kInvalidUniqueId)
|
|
xc6_nextDrawNode = act->GetUniqueId();
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
CEntity::AcceptScriptMsg(msg, uid, mgr);
|
|
}
|
|
|
|
void CActor::PreRender(CStateManager& mgr, const zeus::CFrustum& planes) {
|
|
if (!x64_modelData || x64_modelData->IsNull())
|
|
return;
|
|
|
|
xe4_30_outOfFrustum = !planes.aabbFrustumTest(x9c_renderBounds);
|
|
if (!xe4_30_outOfFrustum) {
|
|
xe7_28_worldLightingDirty = true;
|
|
|
|
bool lightsDirty = false;
|
|
if (xe4_29_actorLightsDirty) {
|
|
xe4_29_actorLightsDirty = false;
|
|
lightsDirty = true;
|
|
xe5_25_shadowDirty = true;
|
|
} else if (xe7_28_worldLightingDirty) {
|
|
lightsDirty = true;
|
|
} else if (x90_actorLights && x90_actorLights->GetIsDirty()) {
|
|
lightsDirty = true;
|
|
}
|
|
|
|
if (xe5_25_shadowDirty && xe5_24_shadowEnabled && x94_simpleShadow) {
|
|
x94_simpleShadow->Calculate(x64_modelData->GetBounds(), x34_transform, mgr);
|
|
xe5_25_shadowDirty = false;
|
|
}
|
|
|
|
if (xe4_31_calculateLighting && x90_actorLights) {
|
|
zeus::CAABox bounds = x64_modelData->GetBounds(x34_transform);
|
|
if (mgr.GetPlayerState()->GetActiveVisor(mgr) == CPlayerState::EPlayerVisor::Thermal) {
|
|
x90_actorLights->BuildConstantAmbientLighting();
|
|
} else {
|
|
if (lightsDirty && x4_areaId != kInvalidAreaId) {
|
|
const CGameArea* area = mgr.GetWorld()->GetAreaAlways(x4_areaId);
|
|
if (area->IsPostConstructed())
|
|
if (x90_actorLights->BuildAreaLightList(mgr, *area, bounds))
|
|
xe7_28_worldLightingDirty = false;
|
|
}
|
|
x90_actorLights->BuildDynamicLightList(mgr, bounds);
|
|
}
|
|
}
|
|
|
|
if (x64_modelData->HasAnimData())
|
|
x64_modelData->GetAnimationData()->PreRender();
|
|
} else {
|
|
if (xe4_29_actorLightsDirty) {
|
|
xe4_29_actorLightsDirty = false;
|
|
xe5_25_shadowDirty = true;
|
|
}
|
|
|
|
if (xe5_25_shadowDirty && xe5_24_shadowEnabled && x94_simpleShadow) {
|
|
zeus::CAABox bounds = x64_modelData->GetBounds(x34_transform);
|
|
if (planes.aabbFrustumTest(x94_simpleShadow->GetMaxShadowBox(bounds))) {
|
|
x94_simpleShadow->Calculate(x64_modelData->GetBounds(), x34_transform, mgr);
|
|
xe5_25_shadowDirty = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CActor::AddToRenderer(const zeus::CFrustum& planes, CStateManager& mgr) {
|
|
if (!x64_modelData || x64_modelData->IsNull()) {
|
|
return;
|
|
}
|
|
|
|
if (xe6_29_renderParticleDBInside) {
|
|
x64_modelData->RenderParticles(planes);
|
|
}
|
|
|
|
if (!xe4_30_outOfFrustum) {
|
|
if (CanRenderUnsorted(mgr)) {
|
|
Render(mgr);
|
|
} else {
|
|
EnsureRendered(mgr);
|
|
}
|
|
}
|
|
|
|
if (mgr.GetPlayerState()->GetActiveVisor(mgr) != CPlayerState::EPlayerVisor::XRay &&
|
|
mgr.GetPlayerState()->GetActiveVisor(mgr) != CPlayerState::EPlayerVisor::Thermal && xe5_24_shadowEnabled &&
|
|
x94_simpleShadow->Valid() && planes.aabbFrustumTest(x94_simpleShadow->GetBounds())) {
|
|
g_Renderer->AddDrawable(x94_simpleShadow.get(), x94_simpleShadow->GetTransform().origin,
|
|
x94_simpleShadow->GetBounds(), 1, CBooRenderer::EDrawableSorting::SortedCallback);
|
|
}
|
|
}
|
|
|
|
void CActor::DrawTouchBounds() const {
|
|
// Empty
|
|
}
|
|
|
|
void CActor::RenderInternal(const CStateManager& mgr) const {
|
|
SCOPED_GRAPHICS_DEBUG_GROUP(
|
|
fmt::format(fmt("CActor::RenderInternal {} {} {}"), x8_uid, xc_editorId, x10_name).c_str(), zeus::skOrange);
|
|
|
|
CModelData::EWhichModel which = CModelData::GetRenderingModel(mgr);
|
|
if (which == CModelData::EWhichModel::ThermalHot) {
|
|
if (x64_modelData->GetSortThermal()) {
|
|
float addMag;
|
|
float mulMag = 1.f;
|
|
if (xd0_damageMag <= 1.f) {
|
|
mulMag = xd0_damageMag;
|
|
addMag = 0.f;
|
|
} else if (xd0_damageMag < 2.f) {
|
|
addMag = xd0_damageMag - 1.f;
|
|
} else {
|
|
addMag = 1.f;
|
|
}
|
|
|
|
zeus::CColor mulColor(mulMag * xb4_drawFlags.x4_color.a(), xb4_drawFlags.x4_color.a());
|
|
zeus::CColor addColor(addMag, xb4_drawFlags.x4_color.a() / 4.f);
|
|
x64_modelData->RenderThermal(x34_transform, mulColor, addColor, xb4_drawFlags);
|
|
return;
|
|
} else if (mgr.GetThermalColdScale2() > 0.00001f && !xb4_drawFlags.x0_blendMode) {
|
|
zeus::CColor color(
|
|
zeus::clamp(0.f,
|
|
std::min((mgr.GetThermalColdScale2() + mgr.GetThermalColdScale1()) * mgr.GetThermalColdScale2(),
|
|
mgr.GetThermalColdScale2()),
|
|
1.f),
|
|
1.f);
|
|
CModelFlags flags(2, xb4_drawFlags.x1_matSetIdx, xb4_drawFlags.x2_flags, color);
|
|
x64_modelData->Render(mgr, x34_transform, x90_actorLights.get(), flags);
|
|
return;
|
|
}
|
|
}
|
|
x64_modelData->Render(which, x34_transform, x90_actorLights.get(), xb4_drawFlags);
|
|
}
|
|
|
|
bool CActor::IsModelOpaque(const CStateManager& mgr) const {
|
|
if (xe5_31_pointGeneratorParticles)
|
|
return false;
|
|
if (!x64_modelData || x64_modelData->IsNull())
|
|
return true;
|
|
if (xb4_drawFlags.x0_blendMode > 4)
|
|
return false;
|
|
return x64_modelData->IsDefinitelyOpaque(CModelData::GetRenderingModel(mgr));
|
|
}
|
|
|
|
void CActor::Render(const CStateManager& mgr) const {
|
|
if (x64_modelData && !x64_modelData->IsNull()) {
|
|
bool renderPrePostParticles = xe6_29_renderParticleDBInside && x64_modelData && x64_modelData->HasAnimData();
|
|
if (renderPrePostParticles)
|
|
x64_modelData->GetAnimationData()->GetParticleDB().RenderSystemsToBeDrawnFirst();
|
|
|
|
if (xe7_27_enableRender) {
|
|
if (xe5_31_pointGeneratorParticles)
|
|
mgr.SetupParticleHook(*this);
|
|
if (xe5_29_globalTimeProvider) {
|
|
RenderInternal(mgr);
|
|
} else {
|
|
const float timeSince = CGraphics::GetSecondsMod900() - xbc_time;
|
|
const float tpTime = timeSince - std::floor(timeSince / 900.f) * 900.f;
|
|
CTimeProvider tp(tpTime);
|
|
RenderInternal(mgr);
|
|
}
|
|
if (xe5_31_pointGeneratorParticles) {
|
|
CSkinnedModel::ClearPointGeneratorFunc();
|
|
mgr.GetActorModelParticles()->Render(mgr, *this);
|
|
}
|
|
}
|
|
|
|
if (renderPrePostParticles)
|
|
x64_modelData->GetAnimationData()->GetParticleDB().RenderSystemsToBeDrawnLast();
|
|
}
|
|
DrawTouchBounds();
|
|
}
|
|
|
|
bool CActor::CanRenderUnsorted(const CStateManager& mgr) const {
|
|
if (x64_modelData && x64_modelData->HasAnimData() &&
|
|
x64_modelData->GetAnimationData()->GetParticleDB().AreAnySystemsDrawnWithModel() && xe6_29_renderParticleDBInside)
|
|
return false;
|
|
else if (xe5_30_renderUnsorted || IsModelOpaque(mgr))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
void CActor::CalculateRenderBounds() {
|
|
if (x64_modelData && (x64_modelData->GetAnimationData() || x64_modelData->GetNormalModel()))
|
|
x9c_renderBounds = x64_modelData->GetBounds(x34_transform);
|
|
else
|
|
x9c_renderBounds = zeus::CAABox(x34_transform.origin, x34_transform.origin);
|
|
}
|
|
|
|
CHealthInfo* CActor::HealthInfo(CStateManager&) { return nullptr; }
|
|
|
|
const CDamageVulnerability* CActor::GetDamageVulnerability() const {
|
|
return &CDamageVulnerability::NormalVulnerabilty();
|
|
}
|
|
|
|
const CDamageVulnerability* CActor::GetDamageVulnerability(const zeus::CVector3f&, const zeus::CVector3f&,
|
|
const CDamageInfo&) const {
|
|
return GetDamageVulnerability();
|
|
}
|
|
|
|
std::optional<zeus::CAABox> CActor::GetTouchBounds() const { return {}; }
|
|
|
|
void CActor::Touch(CActor&, CStateManager&) {}
|
|
|
|
zeus::CVector3f CActor::GetOrbitPosition(const CStateManager&) const { return x34_transform.origin; }
|
|
|
|
zeus::CVector3f CActor::GetAimPosition(const CStateManager&, float) const { return x34_transform.origin; }
|
|
|
|
zeus::CVector3f CActor::GetHomingPosition(const CStateManager& mgr, float f) const { return GetAimPosition(mgr, f); }
|
|
|
|
zeus::CVector3f CActor::GetScanObjectIndicatorPosition(const CStateManager& mgr) const {
|
|
const CGameCamera* cam = mgr.GetCameraManager()->GetCurrentCamera(mgr);
|
|
zeus::CVector3f orbitPos = GetOrbitPosition(mgr);
|
|
float camToOrbitPos = (cam->GetTranslation() - orbitPos).magnitude();
|
|
const zeus::CVector3f boundsExtent = x9c_renderBounds.max - x9c_renderBounds.min;
|
|
float distFac = std::min(std::max(boundsExtent.x(), std::max(boundsExtent.y(), boundsExtent.z())) * 0.5f,
|
|
camToOrbitPos - cam->GetNearClipDistance() - 0.1f);
|
|
return orbitPos - (orbitPos - cam->GetTranslation()).normalized() * distFac;
|
|
}
|
|
|
|
void CActor::RemoveEmitter() {
|
|
if (x8c_loopingSfxHandle) {
|
|
CSfxManager::RemoveEmitter(x8c_loopingSfxHandle);
|
|
x88_sfxId = -1;
|
|
x8c_loopingSfxHandle.reset();
|
|
}
|
|
}
|
|
|
|
void CActor::SetVolume(float vol) {
|
|
if (x8c_loopingSfxHandle)
|
|
CSfxManager::UpdateEmitter(x8c_loopingSfxHandle, GetTranslation(), zeus::skZero3f, vol);
|
|
xd4_maxVol = vol;
|
|
}
|
|
|
|
zeus::CTransform CActor::GetScaledLocatorTransform(std::string_view segName) const {
|
|
return x64_modelData->GetScaledLocatorTransform(segName);
|
|
}
|
|
|
|
zeus::CTransform CActor::GetLocatorTransform(std::string_view segName) const {
|
|
return x64_modelData->GetLocatorTransform(segName);
|
|
}
|
|
|
|
EWeaponCollisionResponseTypes CActor::GetCollisionResponseType(const zeus::CVector3f&, const zeus::CVector3f&,
|
|
const CWeaponMode&, EProjectileAttrib) const {
|
|
return EWeaponCollisionResponseTypes::OtherProjectile;
|
|
}
|
|
|
|
void CActor::FluidFXThink(CActor::EFluidState, CScriptWater&, CStateManager&) {}
|
|
|
|
void CActor::OnScanStateChanged(EScanState state, CStateManager& mgr) {
|
|
if (state == EScanState::Start)
|
|
SendScriptMsgs(EScriptObjectState::ScanStart, mgr, EScriptObjectMessage::None);
|
|
else if (state == EScanState::Processing)
|
|
SendScriptMsgs(EScriptObjectState::ScanProcessing, mgr, EScriptObjectMessage::None);
|
|
else if (state == EScanState::Done)
|
|
SendScriptMsgs(EScriptObjectState::ScanDone, mgr, EScriptObjectMessage::None);
|
|
}
|
|
|
|
zeus::CAABox CActor::GetSortingBounds(const CStateManager&) const { return x9c_renderBounds; }
|
|
|
|
void CActor::DoUserAnimEvent(CStateManager& mgr, const CInt32POINode& node, EUserEventType event, float dt) {
|
|
if (event == EUserEventType::LoopedSoundStop)
|
|
RemoveEmitter();
|
|
}
|
|
|
|
void CActor::RemoveMaterial(EMaterialTypes t1, EMaterialTypes t2, EMaterialTypes t3, EMaterialTypes t4,
|
|
CStateManager& mgr) {
|
|
x68_material.Remove(t1);
|
|
RemoveMaterial(t2, t3, t4, mgr);
|
|
}
|
|
|
|
void CActor::RemoveMaterial(EMaterialTypes t1, EMaterialTypes t2, EMaterialTypes t3, CStateManager& mgr) {
|
|
x68_material.Remove(t1);
|
|
RemoveMaterial(t2, t3, mgr);
|
|
}
|
|
|
|
void CActor::RemoveMaterial(EMaterialTypes t1, EMaterialTypes t2, CStateManager& mgr) {
|
|
x68_material.Remove(t1);
|
|
RemoveMaterial(t2, mgr);
|
|
}
|
|
|
|
void CActor::RemoveMaterial(EMaterialTypes t, CStateManager& mgr) {
|
|
x68_material.Remove(t);
|
|
mgr.UpdateObjectInLists(*this);
|
|
}
|
|
|
|
void CActor::AddMaterial(EMaterialTypes t1, EMaterialTypes t2, EMaterialTypes t3, EMaterialTypes t4, EMaterialTypes t5,
|
|
CStateManager& mgr) {
|
|
x68_material.Add(t1);
|
|
AddMaterial(t2, t3, t4, t5, mgr);
|
|
}
|
|
|
|
void CActor::AddMaterial(EMaterialTypes t1, EMaterialTypes t2, EMaterialTypes t3, EMaterialTypes t4,
|
|
CStateManager& mgr) {
|
|
x68_material.Add(t1);
|
|
AddMaterial(t2, t3, t4, mgr);
|
|
}
|
|
|
|
void CActor::AddMaterial(EMaterialTypes t1, EMaterialTypes t2, EMaterialTypes t3, CStateManager& mgr) {
|
|
x68_material.Add(t1);
|
|
AddMaterial(t2, t3, mgr);
|
|
}
|
|
|
|
void CActor::AddMaterial(EMaterialTypes t1, EMaterialTypes t2, CStateManager& mgr) {
|
|
x68_material.Add(t1);
|
|
AddMaterial(t2, mgr);
|
|
}
|
|
|
|
void CActor::AddMaterial(EMaterialTypes type, CStateManager& mgr) {
|
|
x68_material.Add(type);
|
|
mgr.UpdateObjectInLists(*this);
|
|
}
|
|
|
|
void CActor::AddMaterial(const CMaterialList& l) { x68_material.Add(l); }
|
|
|
|
void CActor::CreateShadow(bool enabled) {
|
|
if (enabled) {
|
|
_CreateShadow();
|
|
if (!xe5_24_shadowEnabled && x94_simpleShadow)
|
|
xe5_25_shadowDirty = true;
|
|
}
|
|
xe5_24_shadowEnabled = enabled;
|
|
}
|
|
|
|
void CActor::_CreateShadow() {
|
|
if (!x94_simpleShadow && x64_modelData && (x64_modelData->HasAnimData() || x64_modelData->HasNormalModel())) {
|
|
x94_simpleShadow = std::make_unique<CSimpleShadow>(1.f, 1.f, 20.f, 0.05f);
|
|
}
|
|
}
|
|
|
|
void CActor::_CreateReflectionCube() {
|
|
if (hecl::com_cubemaps->toBoolean()) {
|
|
CGraphics::CommitResources([this](boo::IGraphicsDataFactory::Context& ctx) {
|
|
m_reflectionCube = ctx.newCubeRenderTexture(CUBEMAP_RES, CUBEMAP_MIPS);
|
|
return true;
|
|
} BooTrace);
|
|
}
|
|
}
|
|
|
|
void CActor::SetCallTouch(bool callTouch) { xe5_28_callTouch = callTouch; }
|
|
|
|
bool CActor::GetCallTouch() const { return xe5_28_callTouch; }
|
|
|
|
void CActor::SetUseInSortedLists(bool use) { xe5_27_useInSortedLists = use; }
|
|
|
|
bool CActor::GetUseInSortedLists() const { return xe5_27_useInSortedLists; }
|
|
|
|
void CActor::SetInFluid(bool in, TUniqueId uid) {
|
|
if (in) {
|
|
xe6_24_fluidCounter += 1;
|
|
xc4_fluidId = uid;
|
|
} else {
|
|
if (!xe6_24_fluidCounter)
|
|
return;
|
|
|
|
xe6_24_fluidCounter -= 1;
|
|
if (xe6_24_fluidCounter == 0)
|
|
xc4_fluidId = kInvalidUniqueId;
|
|
}
|
|
}
|
|
|
|
bool CActor::HasModelData() const { return bool(x64_modelData); }
|
|
|
|
void CActor::SetSoundEventPitchBend(s32 val) {
|
|
xe6_30_enablePitchBend = true;
|
|
xc0_pitchBend = val / 8192.f - 1.f;
|
|
if (!x8c_loopingSfxHandle)
|
|
return;
|
|
|
|
CSfxManager::PitchBend(x8c_loopingSfxHandle, xc0_pitchBend);
|
|
}
|
|
|
|
void CActor::SetRotation(const zeus::CQuaternion& q) {
|
|
x34_transform = q.toTransform(x34_transform.origin);
|
|
xe4_27_notInSortedLists = true;
|
|
xe4_28_transformDirty = true;
|
|
xe4_29_actorLightsDirty = true;
|
|
}
|
|
|
|
void CActor::SetTranslation(const zeus::CVector3f& tr) {
|
|
x34_transform.origin = tr;
|
|
xe4_27_notInSortedLists = true;
|
|
xe4_28_transformDirty = true;
|
|
xe4_29_actorLightsDirty = true;
|
|
}
|
|
|
|
void CActor::SetTransform(const zeus::CTransform& tr) {
|
|
x34_transform = tr;
|
|
xe4_27_notInSortedLists = true;
|
|
xe4_28_transformDirty = true;
|
|
xe4_29_actorLightsDirty = true;
|
|
}
|
|
|
|
void CActor::SetAddedToken(u32 tok) { xcc_addedToken = tok; }
|
|
|
|
float CActor::GetPitch() const { return zeus::CQuaternion(x34_transform.buildMatrix3f()).pitch(); }
|
|
|
|
float CActor::GetYaw() const { return zeus::CQuaternion(x34_transform.buildMatrix3f()).yaw(); }
|
|
|
|
void CActor::EnsureRendered(const CStateManager& mgr) const {
|
|
zeus::CAABox aabb = GetSortingBounds(mgr);
|
|
EnsureRendered(mgr, aabb.closestPointAlongVector(CGraphics::g_ViewMatrix.basis[1]), aabb);
|
|
}
|
|
|
|
void CActor::EnsureRendered(const CStateManager& stateMgr, const zeus::CVector3f& pos, const zeus::CAABox& aabb) const {
|
|
if (x64_modelData) {
|
|
x64_modelData->RenderUnsortedParts(x64_modelData->GetRenderingModel(stateMgr), x34_transform, x90_actorLights.get(),
|
|
xb4_drawFlags);
|
|
}
|
|
stateMgr.AddDrawableActor(*this, pos, aabb);
|
|
}
|
|
|
|
void CActor::UpdateSfxEmitters() {
|
|
for (CSfxHandle& sfx : xd8_nonLoopingSfxHandles)
|
|
CSfxManager::UpdateEmitter(sfx, x34_transform.origin, zeus::skZero3f, xd4_maxVol);
|
|
}
|
|
|
|
void CActor::ProcessSoundEvent(u32 sfxId, float weight, u32 flags, float falloff, float maxDist, float minVol,
|
|
float maxVol, const zeus::CVector3f& toListener, const zeus::CVector3f& position,
|
|
TAreaId aid, CStateManager& mgr, bool translateId) {
|
|
if (toListener.magSquared() >= maxDist * maxDist)
|
|
return;
|
|
u16 id = translateId ? CSfxManager::TranslateSFXID(sfxId) : sfxId;
|
|
|
|
u32 musyxFlags = 0x1; // Continuous parameter update
|
|
if (flags & 0x8)
|
|
musyxFlags |= 0x8; // Doppler FX
|
|
|
|
CAudioSys::C3DEmitterParmData parms;
|
|
parms.x0_pos = position;
|
|
parms.xc_dir = zeus::skZero3f;
|
|
parms.x18_maxDist = maxDist;
|
|
parms.x1c_distComp = falloff;
|
|
parms.x20_flags = musyxFlags;
|
|
parms.x24_sfxId = id;
|
|
parms.x26_maxVol = maxVol;
|
|
parms.x27_minVol = minVol;
|
|
parms.x28_important = false;
|
|
parms.x29_prio = 0x7f;
|
|
|
|
bool useAcoustics = (flags & 0x80) == 0;
|
|
bool looping = (sfxId & 0x80000000) != 0;
|
|
bool nonEmitter = (sfxId & 0x40000000) != 0;
|
|
bool continuousUpdate = (sfxId & 0x20000000) != 0;
|
|
|
|
if (mgr.GetActiveRandom()->Float() > weight)
|
|
return;
|
|
|
|
if (looping) {
|
|
u16 curId = x88_sfxId;
|
|
if (!x8c_loopingSfxHandle) {
|
|
CSfxHandle handle;
|
|
if (nonEmitter)
|
|
handle = CSfxManager::SfxStart(id, 1.f, 0.f, true, 0x7f, true, aid);
|
|
else
|
|
handle = CSfxManager::AddEmitter(parms, useAcoustics, 0x7f, true, aid);
|
|
if (handle) {
|
|
x88_sfxId = id;
|
|
x8c_loopingSfxHandle = handle;
|
|
if (xe6_30_enablePitchBend)
|
|
CSfxManager::PitchBend(handle, xc0_pitchBend);
|
|
}
|
|
} else if (curId == id) {
|
|
CSfxManager::UpdateEmitter(x8c_loopingSfxHandle, position, zeus::skZero3f, maxVol);
|
|
} else if (flags & 0x4) {
|
|
CSfxManager::RemoveEmitter(x8c_loopingSfxHandle);
|
|
CSfxHandle handle = CSfxManager::AddEmitter(parms, useAcoustics, 0x7f, true, aid);
|
|
if (handle) {
|
|
x88_sfxId = id;
|
|
x8c_loopingSfxHandle = handle;
|
|
if (xe6_30_enablePitchBend)
|
|
CSfxManager::PitchBend(handle, xc0_pitchBend);
|
|
}
|
|
}
|
|
} else {
|
|
CSfxHandle handle;
|
|
if (nonEmitter)
|
|
handle = CSfxManager::SfxStart(id, 1.f, 0.f, useAcoustics, 0x7f, false, aid);
|
|
else
|
|
handle = CSfxManager::AddEmitter(parms, useAcoustics, 0x7f, false, aid);
|
|
|
|
if (continuousUpdate) {
|
|
xd8_nonLoopingSfxHandles[xe4_24_nextNonLoopingSfxHandle] = handle;
|
|
xe4_24_nextNonLoopingSfxHandle = (xe4_24_nextNonLoopingSfxHandle + 1) % xd8_nonLoopingSfxHandles.size();
|
|
}
|
|
|
|
if (xe6_30_enablePitchBend)
|
|
CSfxManager::PitchBend(handle, xc0_pitchBend);
|
|
}
|
|
}
|
|
|
|
SAdvancementDeltas CActor::UpdateAnimation(float dt, CStateManager& mgr, bool advTree) {
|
|
SAdvancementDeltas deltas = x64_modelData->AdvanceAnimation(dt, mgr, GetAreaId(), advTree);
|
|
x64_modelData->AdvanceParticles(x34_transform, dt, mgr);
|
|
UpdateSfxEmitters();
|
|
if (x64_modelData && x64_modelData->HasAnimData()) {
|
|
zeus::CVector3f toCamera = mgr.GetCameraManager()->GetCurrentCamera(mgr)->GetTranslation() - x34_transform.origin;
|
|
|
|
for (int i = 0; i < x64_modelData->GetAnimationData()->GetPassedSoundPOICount(); ++i) {
|
|
CSoundPOINode& poi = CAnimData::g_SoundPOINodes[i];
|
|
if (poi.GetPoiType() != EPOIType::Sound)
|
|
continue;
|
|
if (xe5_26_muted)
|
|
continue;
|
|
if (poi.GetCharacterIndex() != -1 &&
|
|
x64_modelData->GetAnimationData()->GetCharacterIndex() != poi.GetCharacterIndex())
|
|
continue;
|
|
ProcessSoundEvent(poi.GetSfxId(), poi.GetWeight(), poi.GetFlags(), poi.GetFalloff(), poi.GetMaxDist(), 0.16f,
|
|
xd4_maxVol, toCamera, x34_transform.origin, x4_areaId, mgr, true);
|
|
}
|
|
|
|
for (int i = 0; i < x64_modelData->GetAnimationData()->GetPassedIntPOICount(); ++i) {
|
|
CInt32POINode& poi = CAnimData::g_Int32POINodes[i];
|
|
if (poi.GetPoiType() == EPOIType::SoundInt32) {
|
|
if (xe5_26_muted)
|
|
continue;
|
|
if (poi.GetCharacterIndex() != -1 &&
|
|
x64_modelData->GetAnimationData()->GetCharacterIndex() != poi.GetCharacterIndex())
|
|
continue;
|
|
ProcessSoundEvent(poi.GetValue(), poi.GetWeight(), poi.GetFlags(), 0.1f, 150.f, 0.16f, xd4_maxVol, toCamera,
|
|
x34_transform.origin, x4_areaId, mgr, true);
|
|
} else if (poi.GetPoiType() == EPOIType::UserEvent) {
|
|
DoUserAnimEvent(mgr, poi, EUserEventType(poi.GetValue()), dt);
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < x64_modelData->GetAnimationData()->GetPassedParticlePOICount(); ++i) {
|
|
CParticlePOINode& poi = CAnimData::g_ParticlePOINodes[i];
|
|
if (poi.GetCharacterIndex() != -1 &&
|
|
x64_modelData->GetAnimationData()->GetCharacterIndex() != poi.GetCharacterIndex())
|
|
continue;
|
|
x64_modelData->GetAnimationData()->GetParticleDB().SetParticleEffectState(poi.GetString(), true, mgr);
|
|
}
|
|
}
|
|
return deltas;
|
|
}
|
|
|
|
void CActor::SetActorLights(std::unique_ptr<CActorLights>&& lights) {
|
|
x90_actorLights = std::move(lights);
|
|
xe4_31_calculateLighting = true;
|
|
}
|
|
|
|
bool CActor::CanDrawStatic() const {
|
|
if (!x30_24_active)
|
|
return false;
|
|
|
|
if (x64_modelData && x64_modelData->HasNormalModel())
|
|
return xb4_drawFlags.x0_blendMode <= 4;
|
|
|
|
return false;
|
|
}
|
|
|
|
const CScannableObjectInfo* CActor::GetScannableObjectInfo() const {
|
|
if (!x98_scanObjectInfo || !x98_scanObjectInfo.IsLoaded())
|
|
return nullptr;
|
|
return x98_scanObjectInfo.GetObj();
|
|
}
|
|
|
|
void CActor::SetCalculateLighting(bool c) {
|
|
if (!x90_actorLights)
|
|
x90_actorLights = std::make_unique<CActorLights>(8, zeus::skZero3f, 4, 4, false, false, false, 0.1f);
|
|
xe4_31_calculateLighting = c;
|
|
}
|
|
|
|
float CActor::GetAverageAnimVelocity(int anim) const {
|
|
if (HasModelData() && GetModelData()->HasAnimData())
|
|
return GetModelData()->GetAnimationData()->GetAverageVelocity(anim);
|
|
return 0.f;
|
|
}
|
|
|
|
void CActor::SetModelData(std::unique_ptr<CModelData>&& mData) {
|
|
if (mData->IsNull())
|
|
x64_modelData.reset();
|
|
else
|
|
x64_modelData = std::move(mData);
|
|
}
|
|
|
|
void CActor::SetMuted(bool muted) {
|
|
xe5_26_muted = muted;
|
|
RemoveEmitter();
|
|
}
|
|
|
|
void CActor::MoveScannableObjectInfoToActor(CActor* act, CStateManager& mgr) {
|
|
if (!act)
|
|
return;
|
|
|
|
act->x98_scanObjectInfo = x98_scanObjectInfo;
|
|
x98_scanObjectInfo = TLockedToken<CScannableObjectInfo>();
|
|
act->AddMaterial(EMaterialTypes::Scannable, mgr);
|
|
RemoveMaterial(EMaterialTypes::Scannable, mgr);
|
|
}
|
|
} // namespace urde
|