mirror of https://github.com/AxioDL/metaforce.git
730 lines
22 KiB
C++
730 lines
22 KiB
C++
#include "CGunWeapon.hpp"
|
|
#include "GameGlobalObjects.hpp"
|
|
#include "CSimplePool.hpp"
|
|
#include "CDependencyGroup.hpp"
|
|
#include "CGameState.hpp"
|
|
#include "CWeapon.hpp"
|
|
#include "CEnergyProjectile.hpp"
|
|
#include "Graphics/CSkinnedModel.hpp"
|
|
#include "Graphics/CVertexMorphEffect.hpp"
|
|
|
|
namespace urde
|
|
{
|
|
static const char* skBeamXferNames[] =
|
|
{
|
|
"PowerXfer",
|
|
"IceXfer",
|
|
"WaveXfer",
|
|
"PlasmaXfer",
|
|
"PhazonXfer"
|
|
};
|
|
|
|
static const char* skSuitArmNames[] =
|
|
{
|
|
"PowerArm",
|
|
"GravityArm",
|
|
"VariaArm",
|
|
"PhazonArm",
|
|
"FusionArm",
|
|
"FusionArmG",
|
|
"FusionArmV",
|
|
"FusionArmP",
|
|
};
|
|
|
|
static const char* skMuzzleNames[] =
|
|
{
|
|
"PowerMuzzle",
|
|
"PowerCharge",
|
|
"IceMuzzle",
|
|
"IceCharge",
|
|
"PowerMuzzle",
|
|
"WaveCharge",
|
|
"PlasmaMuzzle",
|
|
"PlasmaCharge",
|
|
"PhazonMuzzle",
|
|
"EmptyMuzzle"
|
|
};
|
|
|
|
static const char* skFrozenNames[] =
|
|
{
|
|
"powerFrozen",
|
|
"Ice2nd_2",
|
|
"iceFrozen",
|
|
"Ice2nd_2",
|
|
"waveFrozen",
|
|
"Ice2nd_2",
|
|
"plasmaFrozen",
|
|
"Ice2nd_2",
|
|
"iceFrozen",
|
|
"Ice2nd_2"
|
|
};
|
|
|
|
static const char* skDependencyNames[] =
|
|
{
|
|
"Power_DGRP",
|
|
"Ice_DGRP",
|
|
"Wave_DGRP",
|
|
"Plasma_DGRP",
|
|
"Phazon_DGRP"
|
|
};
|
|
|
|
static const char* skAnimDependencyNames[] =
|
|
{
|
|
"Power_Anim_DGRP",
|
|
"Ice_Anim_DGRP",
|
|
"Wave_Anim_DGRP",
|
|
"Plasma_Anim_DGRP",
|
|
"Phazon_Anim_DGRP"
|
|
};
|
|
|
|
CPlayerState::EBeamId GetWeaponIndex(EWeaponType type)
|
|
{
|
|
if (type == EWeaponType::Power)
|
|
return CPlayerState::EBeamId::Power;
|
|
else if (type == EWeaponType::Ice)
|
|
return CPlayerState::EBeamId::Ice;
|
|
else if (type == EWeaponType::Wave)
|
|
return CPlayerState::EBeamId::Wave;
|
|
else if (type == EWeaponType::Plasma)
|
|
return CPlayerState::EBeamId::Plasma;
|
|
else if (type == EWeaponType::Phazon)
|
|
return CPlayerState::EBeamId::Phazon;
|
|
return CPlayerState::EBeamId::Power;
|
|
}
|
|
|
|
CGunWeapon::CGunWeapon(CAssetId ancsId, EWeaponType type, TUniqueId playerId,
|
|
EMaterialTypes playerMaterial, const zeus::CVector3f& scale)
|
|
: x4_scale(scale),
|
|
x104_gunCharacter(g_SimplePool->GetObj(SObjectTag{FOURCC('ANCS'), ancsId})),
|
|
x13c_armCharacter(g_SimplePool->GetObj(skSuitArmNames[0])),
|
|
x160_xferEffect(g_SimplePool->GetObj(skBeamXferNames[int(GetWeaponIndex(type))])),
|
|
x1c0_weaponType(type),
|
|
x1c4_playerId(playerId),
|
|
x1c8_playerMaterial(playerMaterial),
|
|
x200_beamId(GetWeaponIndex(type)),
|
|
x20c_shaderIdx(u32(x200_beamId)),
|
|
x214_ancsId(ancsId)
|
|
{
|
|
AllocResPools(x200_beamId);
|
|
BuildDependencyList(x200_beamId);
|
|
}
|
|
|
|
void CGunWeapon::AllocResPools(CPlayerState::EBeamId beam)
|
|
{
|
|
const CAssetId* wPair = g_tweakGunRes->GetWeaponPair(beam);
|
|
const char** muzzleNames = &skMuzzleNames[int(beam) * 2];
|
|
const char** frozenNames = &skFrozenNames[int(beam) * 2];
|
|
for (int i=0 ; i<2 ; ++i)
|
|
{
|
|
x16c_muzzleEffects.push_back(g_SimplePool->GetObj(muzzleNames[i]));
|
|
x144_weapons.push_back(g_SimplePool->GetObj(SObjectTag{FOURCC('WPSC'), wPair[1]}));
|
|
x188_frozenEffects.push_back(g_SimplePool->GetObj(frozenNames[i]));
|
|
}
|
|
}
|
|
|
|
void CGunWeapon::FreeResPools()
|
|
{
|
|
x160_xferEffect.Unlock();
|
|
for (int i=0 ; i<2 ; ++i)
|
|
{
|
|
x16c_muzzleEffects[i].Unlock();
|
|
x144_weapons[i].Unlock();
|
|
x188_frozenEffects[i].Unlock();
|
|
}
|
|
x10c_anims.clear();
|
|
x1a4_muzzleGenerators.clear();
|
|
x1d0_velInfo.Clear();
|
|
}
|
|
|
|
void CGunWeapon::FillTokenVector(const std::vector<SObjectTag>& tags, std::vector<CToken>& objects)
|
|
{
|
|
for (const SObjectTag& tag : tags)
|
|
objects.push_back(g_SimplePool->GetObj(tag));
|
|
}
|
|
|
|
void CGunWeapon::BuildDependencyList(CPlayerState::EBeamId beam)
|
|
{
|
|
TLockedToken<CDependencyGroup> deps = g_SimplePool->GetObj(skDependencyNames[int(beam)]);
|
|
TLockedToken<CDependencyGroup> animDeps = g_SimplePool->GetObj(skAnimDependencyNames[int(beam)]);
|
|
x12c_deps.reserve(deps->GetObjectTagVector().size() + animDeps->GetObjectTagVector().size());
|
|
FillTokenVector(deps->GetObjectTagVector(), x12c_deps);
|
|
FillTokenVector(animDeps->GetObjectTagVector(), x12c_deps);
|
|
}
|
|
|
|
void CGunWeapon::AsyncLoadSuitArm(CStateManager& mgr)
|
|
{
|
|
|
|
xb0_suitArmModelData = std::experimental::nullopt;
|
|
x13c_armCharacter = g_SimplePool->GetObj(skSuitArmNames[int(NWeaponTypes::get_current_suit(mgr))]);
|
|
x13c_armCharacter.Lock();
|
|
x218_28_suitArmLocked = true;
|
|
}
|
|
|
|
void CGunWeapon::Reset(CStateManager& mgr)
|
|
{
|
|
if (!x218_26_loaded)
|
|
return;
|
|
|
|
x10_solidModelData->AnimationData()->EnableLooping(false);
|
|
if (x218_25_enableCharge)
|
|
x218_25_enableCharge = false;
|
|
else
|
|
x100_gunController->Reset();
|
|
}
|
|
|
|
static const s32 skAnimTypeList[] = { 0, 4, 1, 2, 3, 5, 6, 7, 8, 9, 10 };
|
|
|
|
void CGunWeapon::PlayAnim(NWeaponTypes::EGunAnimType type, bool loop)
|
|
{
|
|
if (x218_26_loaded && type >= NWeaponTypes::EGunAnimType::BasePosition &&
|
|
type <= NWeaponTypes::EGunAnimType::ToBeam)
|
|
{
|
|
x10_solidModelData->AnimationData()->EnableLooping(loop);
|
|
CAnimPlaybackParms parms(skAnimTypeList[int(type)], -1, 1.f, true);
|
|
x10_solidModelData->AnimationData()->SetAnimation(parms, false);
|
|
}
|
|
}
|
|
|
|
void CGunWeapon::PreRenderGunFx(const CStateManager& mgr, const zeus::CTransform& xf)
|
|
{
|
|
// Empty
|
|
}
|
|
|
|
void CGunWeapon::PostRenderGunFx(const CStateManager& mgr, const zeus::CTransform& xf)
|
|
{
|
|
if (x218_26_loaded && x1b8_frozenGenerator && x204_frozenEffect != EFrozenFxType::None)
|
|
x1b8_frozenGenerator->Render();
|
|
}
|
|
|
|
void CGunWeapon::UpdateGunFx(bool shotSmoke, float dt, const CStateManager& mgr, const zeus::CTransform& xf)
|
|
{
|
|
if (x218_26_loaded && x204_frozenEffect != EFrozenFxType::None)
|
|
{
|
|
if (x204_frozenEffect == EFrozenFxType::Thawed)
|
|
{
|
|
if (x1b8_frozenGenerator->IsSystemDeletable())
|
|
{
|
|
x1b8_frozenGenerator.reset();
|
|
}
|
|
else
|
|
{
|
|
x1b8_frozenGenerator->SetTranslation(xf.origin);
|
|
x1b8_frozenGenerator->SetOrientation(xf.getRotation());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
x1b8_frozenGenerator->SetGlobalOrientAndTrans(xf);
|
|
}
|
|
if (x1b8_frozenGenerator)
|
|
x1b8_frozenGenerator->Update(dt);
|
|
}
|
|
}
|
|
|
|
const s32 CGunWeapon::skShootAnim[2] = { 4, 3 };
|
|
|
|
void CGunWeapon::Fire(bool underwater, float dt, EChargeState chargeState, const zeus::CTransform& xf,
|
|
CStateManager& mgr, TUniqueId homingTarget, float chargeFactor1, float chargeFactor2)
|
|
{
|
|
CDamageInfo dInfo = GetDamageInfo(mgr, chargeState, chargeFactor1);
|
|
zeus::CVector3f scale(chargeState == EChargeState::Normal ? 1.f : chargeFactor2);
|
|
bool partialCharge = chargeState == EChargeState::Normal ? false : !zeus::close_enough(chargeFactor1, 1.f);
|
|
CWeapon::EProjectileAttrib attribs = CWeapon::EProjectileAttrib::ArmCannon;
|
|
if (partialCharge)
|
|
attribs |= CWeapon::EProjectileAttrib::PartialCharge;
|
|
if (chargeState == EChargeState::Charged)
|
|
attribs |= CWeapon::EProjectileAttrib::Charged;
|
|
|
|
CEnergyProjectile* proj = new CEnergyProjectile(true, x144_weapons[int(chargeState)], x1c0_weaponType,
|
|
xf, x1c8_playerMaterial, dInfo, mgr.AllocateUniqueId(),
|
|
kInvalidAreaId, x1c4_playerId, homingTarget, attribs,
|
|
underwater, scale, {}, -1, false);
|
|
mgr.AddObject(proj);
|
|
proj->Think(dt, mgr);
|
|
|
|
if (chargeState == EChargeState::Charged)
|
|
{
|
|
x218_25_enableCharge = true;
|
|
mgr.GetCameraManager()->AddCameraShaker(CCameraShakeData::skChargedShotCameraShakeData, false);
|
|
}
|
|
|
|
x10_solidModelData->AnimationData()->EnableLooping(false);
|
|
CAnimPlaybackParms parms(skShootAnim[int(chargeState)], -1, 1.f, true);
|
|
x10_solidModelData->AnimationData()->SetAnimation(parms, false);
|
|
}
|
|
|
|
void CGunWeapon::EnableFx(bool enable)
|
|
{
|
|
// Empty
|
|
}
|
|
|
|
void CGunWeapon::EnableSecondaryFx(ESecondaryFxType type)
|
|
{
|
|
x1cc_enabledSecondaryEffect = type;
|
|
}
|
|
|
|
void CGunWeapon::EnableFrozenEffect(EFrozenFxType type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case EFrozenFxType::Thawed:
|
|
if (x204_frozenEffect == EFrozenFxType::Thawed)
|
|
break;
|
|
x1b8_frozenGenerator = std::make_unique<CElementGen>(x188_frozenEffects[1]);
|
|
x1b8_frozenGenerator->SetGlobalScale(x4_scale);
|
|
break;
|
|
case EFrozenFxType::Frozen:
|
|
if (x204_frozenEffect == EFrozenFxType::Frozen)
|
|
break;
|
|
x1b8_frozenGenerator = std::make_unique<CElementGen>(x188_frozenEffects[0]);
|
|
x1b8_frozenGenerator->SetGlobalScale(x4_scale);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
x204_frozenEffect = type;
|
|
}
|
|
|
|
void CGunWeapon::ActivateCharge(bool enable, bool resetEffect)
|
|
{
|
|
x1a4_muzzleGenerators[x208_muzzleEffectIdx]->SetParticleEmission(false);
|
|
x208_muzzleEffectIdx = u32(enable);
|
|
if (enable || resetEffect)
|
|
{
|
|
x1a4_muzzleGenerators[x208_muzzleEffectIdx] =
|
|
std::make_unique<CElementGen>(x16c_muzzleEffects[x208_muzzleEffectIdx]);
|
|
}
|
|
}
|
|
|
|
void CGunWeapon::Touch(const CStateManager& mgr)
|
|
{
|
|
if (x10_solidModelData)
|
|
{
|
|
x10_solidModelData->Touch(mgr, x20c_shaderIdx);
|
|
if (xb0_suitArmModelData)
|
|
xb0_suitArmModelData->Touch(mgr, 0);
|
|
}
|
|
}
|
|
|
|
void CGunWeapon::TouchHolo(const CStateManager& mgr)
|
|
{
|
|
if (x60_holoModelData)
|
|
x60_holoModelData->Touch(mgr, 0);
|
|
}
|
|
|
|
void CGunWeapon::PointGenerator(void* ctx, const std::vector<std::pair<zeus::CVector3f, zeus::CVector3f>>& vn)
|
|
{
|
|
reinterpret_cast<CRainSplashGenerator*>(ctx)->GeneratePoints(vn);
|
|
}
|
|
|
|
void CGunWeapon::Draw(bool drawSuitArm, const CStateManager& mgr, const zeus::CTransform& xf,
|
|
const CModelFlags& flags, const CActorLights* lights) const
|
|
{
|
|
if (!x218_26_loaded)
|
|
return;
|
|
|
|
zeus::CTransform armXf = xf * x10_solidModelData->GetScaledLocatorTransform("elbow");
|
|
|
|
if (x1bc_rainSplashGenerator && x1bc_rainSplashGenerator->IsRaining())
|
|
CSkinnedModel::SetPointGeneratorFunc(x1bc_rainSplashGenerator, PointGenerator);
|
|
|
|
if (mgr.GetThermalDrawFlag() == EThermalDrawFlag::Hot && x200_beamId != CPlayerState::EBeamId::Ice)
|
|
{
|
|
/* Hot Draw */
|
|
zeus::CColor mulColor(flags.x4_color.a, flags.x4_color.a);
|
|
zeus::CColor addColor(0.25f, 0.25f);
|
|
if (x218_29_drawHologram)
|
|
{
|
|
DrawHologram(mgr, xf, flags);
|
|
}
|
|
else
|
|
{
|
|
CModelFlags useFlags(0, 0, 3, zeus::CColor::skWhite);
|
|
x10_solidModelData->RenderThermal(xf, mulColor, addColor, useFlags);
|
|
}
|
|
|
|
if (drawSuitArm && xb0_suitArmModelData)
|
|
{
|
|
CModelFlags useFlags(0, 0, 3, zeus::CColor::skWhite);
|
|
xb0_suitArmModelData->RenderThermal(xf, mulColor, addColor, useFlags);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Cold Draw */
|
|
if (mgr.GetPlayerState()->GetCurrentVisor() != CPlayerState::EPlayerVisor::XRay && !x218_29_drawHologram)
|
|
{
|
|
CModelFlags useFlags = flags;
|
|
useFlags.x1_matSetIdx = u8(x20c_shaderIdx);
|
|
x10_solidModelData->Render(mgr, xf, lights, useFlags);
|
|
}
|
|
else
|
|
{
|
|
DrawHologram(mgr, xf, flags);
|
|
}
|
|
|
|
if (drawSuitArm && xb0_suitArmModelData)
|
|
{
|
|
xb0_suitArmModelData->Render(mgr, armXf, lights, flags);
|
|
}
|
|
}
|
|
|
|
if (x1bc_rainSplashGenerator && x1bc_rainSplashGenerator->IsRaining())
|
|
{
|
|
CSkinnedModel::ClearPointGeneratorFunc();
|
|
x1bc_rainSplashGenerator->Draw(xf);
|
|
}
|
|
}
|
|
|
|
void CGunWeapon::DrawMuzzleFx(const CStateManager& mgr) const
|
|
{
|
|
if (const CElementGen* effect = x1a4_muzzleGenerators[x208_muzzleEffectIdx].get())
|
|
{
|
|
if (x200_beamId != CPlayerState::EBeamId::Ice &&
|
|
mgr.GetPlayerState()->GetActiveVisor(mgr) == CPlayerState::EPlayerVisor::XRay)
|
|
{
|
|
CElementGen::SetSubtractBlend(true);
|
|
const_cast<CElementGen*>(effect)->Render();
|
|
CElementGen::SetSubtractBlend(false);
|
|
}
|
|
else
|
|
{
|
|
const_cast<CElementGen*>(effect)->Render();
|
|
}
|
|
}
|
|
}
|
|
|
|
void CGunWeapon::LoadSuitArm(CStateManager& mgr)
|
|
{
|
|
if (x13c_armCharacter.IsLoaded())
|
|
{
|
|
CAssetId armId = NWeaponTypes::get_asset_id_from_name(skSuitArmNames[int(NWeaponTypes::get_current_suit(mgr))]);
|
|
xb0_suitArmModelData.emplace(CStaticRes(armId, x4_scale));
|
|
xb0_suitArmModelData->SetSortThermal(true);
|
|
x218_28_suitArmLocked = false;
|
|
x13c_armCharacter.Unlock();
|
|
}
|
|
}
|
|
|
|
void CGunWeapon::LoadGunModels(CStateManager& mgr)
|
|
{
|
|
s32 defaultAnim = x218_27_subtypeBasePose ? 0 : 9;
|
|
x10_solidModelData.emplace(CAnimRes(x214_ancsId, 0, x4_scale, defaultAnim, false));
|
|
x60_holoModelData.emplace(CAnimRes(x214_ancsId, 1, x4_scale, defaultAnim, false));
|
|
CAnimPlaybackParms parms(defaultAnim, -1, 1.f, true);
|
|
x10_solidModelData->AnimationData()->SetAnimation(parms, true);
|
|
LoadSuitArm(mgr);
|
|
x10_solidModelData->SetSortThermal(true);
|
|
x60_holoModelData->SetSortThermal(true);
|
|
x100_gunController = std::make_unique<CGunController>(*x10_solidModelData);
|
|
}
|
|
|
|
void CGunWeapon::LoadAnimations()
|
|
{
|
|
NWeaponTypes::get_token_vector(*x10_solidModelData->GetAnimationData(), 0, 15, x10c_anims, true);
|
|
}
|
|
|
|
bool CGunWeapon::IsAnimsLoaded() const
|
|
{
|
|
for (const CToken& tok : x10c_anims)
|
|
if (!tok.IsLoaded())
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
void CGunWeapon::LoadMuzzleFx(float dt)
|
|
{
|
|
for (int i=0 ; i<2 ; ++i)
|
|
{
|
|
x1a4_muzzleGenerators.push_back(std::make_unique<CElementGen>(x16c_muzzleEffects[i]));
|
|
x1a4_muzzleGenerators.back()->SetParticleEmission(false);
|
|
x1a4_muzzleGenerators.back()->Update(dt);
|
|
}
|
|
}
|
|
|
|
void CGunWeapon::LoadProjectileData(CStateManager& mgr)
|
|
{
|
|
CRandom16 random(mgr.GetUpdateFrameIndex());
|
|
CGlobalRandom grand(random);
|
|
for (int i=0 ; i<2 ; ++i)
|
|
{
|
|
zeus::CVector3f weaponVel;
|
|
if (const CVectorElement* ivec = x144_weapons[i]->x4_IVEC.get())
|
|
ivec->GetValue(0, weaponVel);
|
|
x1d0_velInfo.x0_vel.push_back(weaponVel);
|
|
float tratVal = 0.f;
|
|
if (const CRealElement* trat = x144_weapons[i]->x30_TRAT.get())
|
|
trat->GetValue(0, tratVal);
|
|
x1d0_velInfo.x24_trat.push_back(tratVal);
|
|
x1d0_velInfo.x1c_targetHoming.push_back(x144_weapons[i]->x29_HOMG);
|
|
if (weaponVel.y > 0.f)
|
|
x1d0_velInfo.x0_vel.back() *= zeus::CVector3f(60.f);
|
|
else
|
|
x1d0_velInfo.x0_vel.back() = zeus::CVector3f::skForward;
|
|
}
|
|
}
|
|
|
|
void CGunWeapon::LoadFxIdle(float dt, CStateManager& mgr)
|
|
{
|
|
if (NWeaponTypes::are_tokens_ready(x12c_deps))
|
|
{
|
|
if ((x210_loadFlags & 0x2) != 0 && (x210_loadFlags & 0x4) != 0 && (x210_loadFlags & 0x10) != 0)
|
|
return;
|
|
bool loaded = true;
|
|
for (int i=0 ; i<2 ; ++i)
|
|
{
|
|
if (!x16c_muzzleEffects[i].IsLoaded())
|
|
{
|
|
loaded = false;
|
|
break;
|
|
}
|
|
if (!x144_weapons[i].IsLoaded())
|
|
{
|
|
loaded = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (int i=0 ; i<2 ; ++i)
|
|
{
|
|
if (!x188_frozenEffects[i].IsLoaded())
|
|
{
|
|
loaded = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!x160_xferEffect.IsLoaded())
|
|
loaded = false;
|
|
|
|
if (loaded)
|
|
{
|
|
if ((x210_loadFlags & 0x2) != 0x2)
|
|
{
|
|
LoadMuzzleFx(dt);
|
|
x210_loadFlags |= 0x2;
|
|
}
|
|
x210_loadFlags |= 0x10;
|
|
if ((x210_loadFlags & 0x4) != 0x4)
|
|
{
|
|
LoadProjectileData(mgr);
|
|
x210_loadFlags |= 0x4;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CGunWeapon::Update(float dt, CStateManager& mgr)
|
|
{
|
|
if (x218_26_loaded)
|
|
{
|
|
x10_solidModelData->AdvanceAnimation(dt, mgr, kInvalidAreaId, true);
|
|
x100_gunController->Update(dt, mgr);
|
|
if (x218_28_suitArmLocked)
|
|
LoadSuitArm(mgr);
|
|
}
|
|
else
|
|
{
|
|
if (x104_gunCharacter)
|
|
{
|
|
if (x104_gunCharacter.IsLoaded())
|
|
{
|
|
if ((x210_loadFlags & 0x1) != 0x1)
|
|
{
|
|
LoadGunModels(mgr);
|
|
LoadAnimations();
|
|
x210_loadFlags |= 0x1;
|
|
}
|
|
if ((x210_loadFlags & 0x8) != 0x8)
|
|
{
|
|
if (IsAnimsLoaded())
|
|
x210_loadFlags |= 0x8;
|
|
}
|
|
}
|
|
|
|
LoadFxIdle(dt, mgr);
|
|
if ((x210_loadFlags & 0x1f) == 0x1f)
|
|
{
|
|
if (x10_solidModelData->PickAnimatedModel(CModelData::EWhichModel::Normal).GetModel()->
|
|
IsLoaded(x20c_shaderIdx) && xb0_suitArmModelData->IsLoaded(0))
|
|
x218_26_loaded = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CGunWeapon::LockTokens(CStateManager& mgr)
|
|
{
|
|
AsyncLoadSuitArm(mgr);
|
|
NWeaponTypes::lock_tokens(x12c_deps);
|
|
}
|
|
|
|
void CGunWeapon::UnlockTokens()
|
|
{
|
|
x13c_armCharacter.Unlock();
|
|
NWeaponTypes::unlock_tokens(x12c_deps);
|
|
}
|
|
|
|
void CGunWeapon::Load(CStateManager& mgr, bool subtypeBasePose)
|
|
{
|
|
LockTokens(mgr);
|
|
x218_27_subtypeBasePose = subtypeBasePose;
|
|
x204_frozenEffect = EFrozenFxType::None;
|
|
x1b8_frozenGenerator.reset();
|
|
x104_gunCharacter.Lock();
|
|
x160_xferEffect.Lock();
|
|
for (int i=0 ; i<2 ; ++i)
|
|
{
|
|
x16c_muzzleEffects[i].Lock();
|
|
x144_weapons[i].Lock();
|
|
}
|
|
for (int i=0 ; i<2 ; ++i)
|
|
x188_frozenEffects[i].Lock();
|
|
}
|
|
|
|
void CGunWeapon::Unload(CStateManager& mgr)
|
|
{
|
|
UnlockTokens();
|
|
x210_loadFlags = 0;
|
|
x204_frozenEffect = EFrozenFxType::None;
|
|
x10_solidModelData = std::experimental::nullopt;
|
|
x60_holoModelData = std::experimental::nullopt;
|
|
xb0_suitArmModelData = std::experimental::nullopt;
|
|
x100_gunController.reset();
|
|
x1bc_rainSplashGenerator = nullptr;
|
|
x1b8_frozenGenerator.reset();
|
|
FreeResPools();
|
|
x104_gunCharacter.Unlock();
|
|
x218_26_loaded = false;
|
|
}
|
|
|
|
bool CGunWeapon::IsLoaded() const
|
|
{
|
|
return x218_26_loaded;
|
|
}
|
|
|
|
void CGunWeapon::DrawHologram(const CStateManager& mgr, const zeus::CTransform& xf, const CModelFlags& flags) const
|
|
{
|
|
if (!x218_26_loaded)
|
|
return;
|
|
|
|
if (x218_29_drawHologram)
|
|
{
|
|
CModelFlags useFlags = flags;
|
|
useFlags.m_extendedShader = EExtendedShader::Flat;
|
|
x60_holoModelData->Render(CModelData::EWhichModel::Normal, xf, nullptr, useFlags);
|
|
}
|
|
else
|
|
{
|
|
CGraphics::SetModelMatrix(xf * zeus::CTransform::Scale(x10_solidModelData->GetScale()));
|
|
//CGraphics::DisableAllLights();
|
|
//g_Renderer->SetAmbientColor(zeus::CColor::skWhite);
|
|
CSkinnedModel& model =
|
|
const_cast<CSkinnedModel&>(*x60_holoModelData->GetAnimationData()->GetModelData());
|
|
model.GetModelInst()->ActivateLights({CLight::BuildLocalAmbient({}, zeus::CColor::skWhite)});
|
|
const_cast<CGunWeapon*>(this)->x10_solidModelData->AnimationData()->Render(model, flags, {}, nullptr);
|
|
//g_Renderer->SetAmbientColor(zeus::CColor::skWhite);
|
|
//CGraphics::DisableAllLights();
|
|
}
|
|
}
|
|
|
|
void CGunWeapon::UpdateMuzzleFx(float dt, const zeus::CVector3f& scale, const zeus::CVector3f& pos, bool emitting)
|
|
{
|
|
x1a4_muzzleGenerators[x208_muzzleEffectIdx]->SetGlobalTranslation(pos);
|
|
x1a4_muzzleGenerators[x208_muzzleEffectIdx]->SetGlobalScale(scale);
|
|
x1a4_muzzleGenerators[x208_muzzleEffectIdx]->SetParticleEmission(emitting);
|
|
x1a4_muzzleGenerators[x208_muzzleEffectIdx]->Update(dt);
|
|
}
|
|
|
|
void CGunWeapon::ReturnToDefault(CStateManager& mgr)
|
|
{
|
|
x100_gunController->ReturnToDefault(mgr, 0.f, false);
|
|
}
|
|
|
|
bool CGunWeapon::PlayPasAnim(SamusGun::EAnimationState state, CStateManager& mgr, float angle)
|
|
{
|
|
switch (state)
|
|
{
|
|
case SamusGun::EAnimationState::ComboFire:
|
|
x100_gunController->EnterComboFire(mgr, s32(x200_beamId));
|
|
return true;
|
|
default:
|
|
return false;
|
|
case SamusGun::EAnimationState::Wander:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
void CGunWeapon::UnLoadFidget()
|
|
{
|
|
x100_gunController->UnLoadFidget();
|
|
}
|
|
|
|
bool CGunWeapon::IsFidgetLoaded() const
|
|
{
|
|
return x100_gunController->IsFidgetLoaded();
|
|
}
|
|
|
|
void CGunWeapon::AsyncLoadFidget(CStateManager& mgr, SamusGun::EFidgetType type, s32 animSet)
|
|
{
|
|
x100_gunController->LoadFidgetAnimAsync(mgr, s32(type), s32(x200_beamId), animSet);
|
|
}
|
|
|
|
void CGunWeapon::EnterFidget(CStateManager& mgr, SamusGun::EFidgetType type, s32 parm2)
|
|
{
|
|
x100_gunController->EnterFidget(mgr, s32(type), s32(x200_beamId), parm2);
|
|
}
|
|
|
|
CDamageInfo CGunWeapon::GetShotDamageInfo(const SShotParam& shotParam, CStateManager& mgr)
|
|
{
|
|
CDamageInfo ret(shotParam);
|
|
if (g_GameState->GetHardMode())
|
|
ret.MultiplyDamage(g_GameState->GetHardModeWeaponMultiplier());
|
|
return ret;
|
|
}
|
|
|
|
CDamageInfo CGunWeapon::GetDamageInfo(CStateManager& mgr, EChargeState chargeState, float chargeFactor) const
|
|
{
|
|
const SWeaponInfo& wInfo = GetWeaponInfo();
|
|
if (chargeState == EChargeState::Normal)
|
|
{
|
|
return GetShotDamageInfo(wInfo.x4_normal, mgr);
|
|
}
|
|
else
|
|
{
|
|
SShotParam param = wInfo.x20_charged;
|
|
param.damage *= chargeFactor;
|
|
param.radiusDamage *= chargeFactor;
|
|
param.radius *= chargeFactor;
|
|
param.knockback *= chargeFactor;
|
|
param.noImmunity = false;
|
|
return GetShotDamageInfo(param, mgr);
|
|
}
|
|
}
|
|
|
|
const SWeaponInfo& CGunWeapon::GetWeaponInfo() const
|
|
{
|
|
return g_tweakPlayerGun->GetBeamInfo(s32(x200_beamId));
|
|
}
|
|
|
|
zeus::CAABox CGunWeapon::GetBounds() const
|
|
{
|
|
if (x10_solidModelData)
|
|
return x10_solidModelData->GetBounds();
|
|
return zeus::CAABox::skNullBox;
|
|
}
|
|
|
|
zeus::CAABox CGunWeapon::GetBounds(const zeus::CTransform& xf) const
|
|
{
|
|
if (x10_solidModelData)
|
|
return x10_solidModelData->GetBounds(xf);
|
|
return zeus::CAABox::skNullBox;
|
|
}
|
|
|
|
bool CGunWeapon::IsChargeAnimOver() const
|
|
{
|
|
return !(x218_25_enableCharge && x10_solidModelData->GetAnimationData()->IsAnimTimeRemaining(0.001f, "Whole Body"));
|
|
}
|
|
|
|
}
|