mirror of
https://github.com/AxioDL/metaforce.git
synced 2025-05-14 13:11:21 +00:00
Same behavior, but makes it explicit to the reader that these are const. Prevents cases where the reader might assume that just because the variable isn't const qualified that it must be mutable, when it actually isn't.
346 lines
12 KiB
C++
346 lines
12 KiB
C++
#include "Runtime/Weapon/CAuxWeapon.hpp"
|
|
|
|
#include <array>
|
|
|
|
#include "Runtime/CSimplePool.hpp"
|
|
#include "Runtime/GameGlobalObjects.hpp"
|
|
#include "Runtime/Weapon/CEnergyProjectile.hpp"
|
|
#include "Runtime/Weapon/CNewFlameThrower.hpp"
|
|
#include "Runtime/Weapon/CWaveBuster.hpp"
|
|
|
|
namespace urde {
|
|
constexpr CCameraShakeData skHardShake{
|
|
0.3f,
|
|
100.f,
|
|
0,
|
|
zeus::skZero3f,
|
|
{},
|
|
{
|
|
true,
|
|
{false, 0.f, 0.f, 0.3f, -2.f},
|
|
{true, 0.f, 0.f, 0.05f, 0.5f},
|
|
},
|
|
{},
|
|
};
|
|
|
|
constexpr std::array skComboNames{
|
|
"SuperMissile"sv, "IceCombo"sv, "WaveBuster"sv, "FlameThrower"sv, "SuperMissile"sv,
|
|
};
|
|
|
|
constexpr std::array<u16, 5> skSoundId{
|
|
SFXsfx0712, SFXsfx072D, SFXwpn_combo_wavebuster, SFXwpn_combo_flamethrower, SFXsfx0712,
|
|
};
|
|
|
|
CAuxWeapon::CAuxWeapon(TUniqueId playerId)
|
|
: x0_missile(g_SimplePool->GetObj("Missile"))
|
|
, xc_flameMuzzle(g_SimplePool->GetObj("FlameMuzzle"))
|
|
, x18_busterMuzzle(g_SimplePool->GetObj("BusterMuzzle"))
|
|
, x6c_playerId(playerId) {
|
|
x0_missile.GetObj();
|
|
xc_flameMuzzle.GetObj();
|
|
x18_busterMuzzle.GetObj();
|
|
InitComboData();
|
|
}
|
|
|
|
void CAuxWeapon::InitComboData() {
|
|
for (const auto comboName : skComboNames) {
|
|
x28_combos.push_back(g_SimplePool->GetObj(comboName));
|
|
}
|
|
}
|
|
|
|
void CAuxWeapon::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId sender, CStateManager& mgr) {
|
|
if (msg == EScriptObjectMessage::Deleted) {
|
|
DeleteFlameThrower(mgr);
|
|
DeleteWaveBusterBeam(mgr);
|
|
}
|
|
}
|
|
|
|
bool CAuxWeapon::IsComboFxActive(const CStateManager& mgr) const {
|
|
switch (x74_firingBeamId) {
|
|
case CPlayerState::EBeamId::Wave:
|
|
if (const CEntity* ent = mgr.GetObjectById(x70_waveBusterId))
|
|
return static_cast<const CWaveBuster*>(ent)->IsFiring();
|
|
break;
|
|
case CPlayerState::EBeamId::Plasma:
|
|
if (const CEntity* ent = mgr.GetObjectById(x6e_flameThrowerId))
|
|
return static_cast<const CNewFlameThrower*>(ent)->IsFiring();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void CAuxWeapon::Load(CPlayerState::EBeamId curBeam, CStateManager& mgr) {
|
|
x80_24_isLoaded = false;
|
|
switch (x78_loadBeamId) {
|
|
case CPlayerState::EBeamId::Wave:
|
|
DeleteWaveBusterBeam(mgr);
|
|
break;
|
|
case CPlayerState::EBeamId::Plasma:
|
|
DeleteFlameThrower(mgr);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
x28_combos[int(x78_loadBeamId)].Unlock();
|
|
x28_combos[int(curBeam)].Lock();
|
|
x78_loadBeamId = curBeam;
|
|
LoadIdle();
|
|
}
|
|
|
|
void CAuxWeapon::StopComboFx(CStateManager& mgr, bool deactivate) {
|
|
switch (x74_firingBeamId) {
|
|
case CPlayerState::EBeamId::Wave: {
|
|
auto* wb = static_cast<CWaveBuster*>(mgr.ObjectById(x70_waveBusterId));
|
|
if (wb) {
|
|
wb->ResetBeam(deactivate);
|
|
DeleteWaveBusterBeam(mgr);
|
|
}
|
|
break;
|
|
}
|
|
case CPlayerState::EBeamId::Plasma: {
|
|
auto* ft = static_cast<CNewFlameThrower*>(mgr.ObjectById(x6e_flameThrowerId));
|
|
if (ft) {
|
|
mgr.GetPlayerState()->SetFiringComboBeam(false);
|
|
if (ft->IsFiring()) {
|
|
ft->Reset(mgr, deactivate);
|
|
FreeComboVoiceId();
|
|
} else if (ft->GetActive() && deactivate) {
|
|
ft->Reset(mgr, deactivate);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (deactivate) {
|
|
x74_firingBeamId = CPlayerState::EBeamId::Invalid;
|
|
x68_ammoConsumeTimer = 0.f;
|
|
}
|
|
}
|
|
|
|
bool CAuxWeapon::UpdateComboFx(float dt, const zeus::CVector3f& scale, const zeus::CVector3f& pos,
|
|
const zeus::CTransform& xf, CStateManager& mgr) {
|
|
if (!x80_24_isLoaded || x74_firingBeamId == CPlayerState::EBeamId::Invalid)
|
|
return false;
|
|
|
|
bool firing = false;
|
|
if (x7c_comboSfx && !CSfxManager::IsPlaying(x7c_comboSfx))
|
|
FreeComboVoiceId();
|
|
|
|
switch (x74_firingBeamId) {
|
|
case CPlayerState::EBeamId::Wave:
|
|
case CPlayerState::EBeamId::Plasma: {
|
|
bool firingFx = false;
|
|
if (x74_firingBeamId == CPlayerState::EBeamId::Wave) {
|
|
auto* wb = static_cast<CWaveBuster*>(mgr.ObjectById(x70_waveBusterId));
|
|
if (wb && wb->IsFiring()) {
|
|
wb->UpdateFx(xf, dt, mgr);
|
|
firing = true;
|
|
firingFx = true;
|
|
} else {
|
|
DeleteWaveBusterBeam(mgr);
|
|
mgr.GetPlayerState()->SetFiringComboBeam(false);
|
|
}
|
|
} else {
|
|
auto* ft = static_cast<CNewFlameThrower*>(mgr.ObjectById(x6e_flameThrowerId));
|
|
bool needsDelete = true;
|
|
if (ft) {
|
|
firingFx = ft->CanRenderAuxEffects();
|
|
if (ft->GetActive()) {
|
|
ft->UpdateFx(xf, dt, mgr);
|
|
firing = ft->IsFiring();
|
|
}
|
|
if (x6e_flameThrowerId != kInvalidUniqueId)
|
|
needsDelete = ft->AreEffectsFinished();
|
|
}
|
|
if (needsDelete) {
|
|
DeleteFlameThrower(mgr);
|
|
mgr.GetPlayerState()->SetFiringComboBeam(false);
|
|
}
|
|
}
|
|
|
|
if (firingFx) {
|
|
x68_ammoConsumeTimer += dt;
|
|
if (mgr.GetPlayerState()->GetItemAmount(CPlayerState::EItemType::Missiles) > 0) {
|
|
if (x68_ammoConsumeTimer >= mgr.GetPlayerState()->GetComboFireAmmoPeriod()) {
|
|
mgr.GetPlayerState()->DecrPickup(CPlayerState::EItemType::Missiles, 1);
|
|
x68_ammoConsumeTimer = 0.f;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (mgr.GetPlayerState()->GetItemAmount(CPlayerState::EItemType::Missiles) == 0)
|
|
StopComboFx(mgr, false);
|
|
|
|
x24_muzzleFxGen->SetGlobalTranslation(pos);
|
|
x24_muzzleFxGen->SetGlobalScale(scale);
|
|
x24_muzzleFxGen->SetParticleEmission(firingFx);
|
|
x24_muzzleFxGen->Update(dt);
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return firing;
|
|
}
|
|
|
|
void CAuxWeapon::FreeComboVoiceId() {
|
|
CSfxManager::SfxStop(x7c_comboSfx);
|
|
x7c_comboSfx.reset();
|
|
}
|
|
|
|
void CAuxWeapon::DeleteFlameThrower(CStateManager& mgr) {
|
|
FreeComboVoiceId();
|
|
if (x6e_flameThrowerId != kInvalidUniqueId) {
|
|
mgr.FreeScriptObject(x6e_flameThrowerId);
|
|
x6e_flameThrowerId = kInvalidUniqueId;
|
|
x74_firingBeamId = CPlayerState::EBeamId::Invalid;
|
|
mgr.GetPlayerState()->SetFiringComboBeam(false);
|
|
}
|
|
}
|
|
|
|
void CAuxWeapon::CreateFlameThrower(const zeus::CTransform& xf, CStateManager& mgr, float dt) {
|
|
DeleteFlameThrower(mgr);
|
|
if (x6e_flameThrowerId != kInvalidUniqueId)
|
|
return;
|
|
|
|
const std::array<CAssetId, 8> resInfo{
|
|
NWeaponTypes::get_asset_id_from_name("NFTMainFire"),
|
|
NWeaponTypes::get_asset_id_from_name("NFTMainSmoke"),
|
|
NWeaponTypes::get_asset_id_from_name("NFTSwooshCenter"),
|
|
NWeaponTypes::get_asset_id_from_name("NFTSwooshFire"),
|
|
NWeaponTypes::get_asset_id_from_name("NFTSecondarySmoke"),
|
|
NWeaponTypes::get_asset_id_from_name("NFTSecondaryFire"),
|
|
NWeaponTypes::get_asset_id_from_name("NFTSecondarySparks"),
|
|
{},
|
|
};
|
|
x6e_flameThrowerId = mgr.AllocateUniqueId();
|
|
auto* ft = new CNewFlameThrower(x28_combos[3], "Player_FlameThrower", EWeaponType::Plasma, resInfo, xf,
|
|
EMaterialTypes::Player,
|
|
CGunWeapon::GetShotDamageInfo(g_tweakPlayerGun->GetComboShotInfo(3), mgr),
|
|
x6e_flameThrowerId, kInvalidAreaId, x6c_playerId, EProjectileAttrib::None);
|
|
mgr.AddObject(ft);
|
|
ft->Think(dt, mgr);
|
|
ft->StartFiring(xf, mgr);
|
|
x24_muzzleFxGen = std::make_unique<CElementGen>(xc_flameMuzzle);
|
|
x7c_comboSfx = NWeaponTypes::play_sfx(SFXwpn_combo_flamethrower, false, true, 0.165f);
|
|
mgr.GetCameraManager()->AddCameraShaker(skHardShake, false);
|
|
mgr.GetPlayerState()->SetFiringComboBeam(true);
|
|
x74_firingBeamId = CPlayerState::EBeamId::Plasma;
|
|
}
|
|
|
|
void CAuxWeapon::DeleteWaveBusterBeam(CStateManager& mgr) {
|
|
FreeComboVoiceId();
|
|
if (x70_waveBusterId != kInvalidUniqueId) {
|
|
mgr.FreeScriptObject(x70_waveBusterId);
|
|
x70_waveBusterId = kInvalidUniqueId;
|
|
x74_firingBeamId = CPlayerState::EBeamId::Invalid;
|
|
mgr.GetPlayerState()->SetFiringComboBeam(false);
|
|
}
|
|
}
|
|
|
|
void CAuxWeapon::CreateWaveBusterBeam(EProjectileAttrib attribs, TUniqueId homingTarget, const zeus::CTransform& xf,
|
|
CStateManager& mgr) {
|
|
DeleteFlameThrower(mgr);
|
|
if (x70_waveBusterId != kInvalidUniqueId)
|
|
return;
|
|
|
|
x70_waveBusterId = mgr.AllocateUniqueId();
|
|
CWaveBuster* wb = new CWaveBuster(x28_combos[2], EWeaponType::Wave, xf, EMaterialTypes::Player,
|
|
CGunWeapon::GetShotDamageInfo(g_tweakPlayerGun->GetComboShotInfo(2), mgr),
|
|
x70_waveBusterId, kInvalidAreaId, x6c_playerId, homingTarget, attribs);
|
|
mgr.AddObject(wb);
|
|
x24_muzzleFxGen = std::make_unique<CElementGen>(x18_busterMuzzle);
|
|
x7c_comboSfx = NWeaponTypes::play_sfx(SFXwpn_combo_wavebuster, false, true, 0.165f);
|
|
mgr.GetCameraManager()->AddCameraShaker(CCameraShakeData::skChargedShotCameraShakeData, false);
|
|
mgr.GetPlayerState()->SetFiringComboBeam(true);
|
|
x74_firingBeamId = CPlayerState::EBeamId::Wave;
|
|
}
|
|
|
|
void CAuxWeapon::LaunchMissile(float dt, bool underwater, bool charged, CPlayerState::EBeamId currentBeam,
|
|
EProjectileAttrib attrib, const zeus::CTransform& xf, TUniqueId homingId,
|
|
CStateManager& mgr) {
|
|
const SShotParam& info =
|
|
charged ? g_tweakPlayerGun->GetComboShotInfo(int(currentBeam)) : g_tweakPlayerGun->GetMissileInfo();
|
|
u16 sfxId = charged ? skSoundId[int(currentBeam)] : u16(SFXwpn_fire_missile);
|
|
CEnergyProjectile* proj = new CEnergyProjectile(
|
|
true, charged ? x28_combos[int(currentBeam)] : x0_missile, charged ? EWeaponType::Power : EWeaponType::Missile,
|
|
xf, EMaterialTypes::Player, CGunWeapon::GetShotDamageInfo(info, mgr), mgr.AllocateUniqueId(), kInvalidAreaId,
|
|
x6c_playerId, homingId, attrib | EProjectileAttrib::ArmCannon, underwater, zeus::skOne3f, {}, -1, false);
|
|
mgr.AddObject(proj);
|
|
proj->Think(dt, mgr);
|
|
if (charged) {
|
|
proj->SetCameraShake(CCameraShakeData::BuildMissileCameraShake(0.25f, 0.75f, 50.f, proj->GetTranslation()));
|
|
mgr.GetCameraManager()->AddCameraShaker(skHardShake, false);
|
|
} else {
|
|
mgr.GetRumbleManager().Rumble(mgr, ERumbleFxId::PlayerMissileFire, 0.5f, ERumblePriority::One);
|
|
}
|
|
x7c_comboSfx = NWeaponTypes::play_sfx(sfxId, underwater, false, 0.165f);
|
|
}
|
|
|
|
void CAuxWeapon::Fire(float dt, bool underwater, CPlayerState::EBeamId currentBeam, EChargeState chargeState,
|
|
const zeus::CTransform& xf, CStateManager& mgr, EWeaponType type, TUniqueId homingId) {
|
|
if (!x80_24_isLoaded)
|
|
return;
|
|
|
|
EProjectileAttrib attrib = EProjectileAttrib::None;
|
|
if (chargeState == EChargeState::Charged)
|
|
attrib = CGameProjectile::GetBeamAttribType(type) | EProjectileAttrib::ComboShot;
|
|
|
|
if (chargeState == EChargeState::Normal) {
|
|
LaunchMissile(dt, underwater, false, currentBeam, attrib, xf, homingId, mgr);
|
|
} else {
|
|
switch (currentBeam) {
|
|
case CPlayerState::EBeamId::Power:
|
|
case CPlayerState::EBeamId::Ice:
|
|
LaunchMissile(dt, underwater, chargeState == EChargeState::Charged, currentBeam, attrib, xf, homingId, mgr);
|
|
break;
|
|
case CPlayerState::EBeamId::Wave:
|
|
CreateWaveBusterBeam(attrib, homingId, xf, mgr);
|
|
break;
|
|
case CPlayerState::EBeamId::Plasma:
|
|
CreateFlameThrower(xf, mgr, dt);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CAuxWeapon::LoadIdle() { x80_24_isLoaded = x28_combos[int(x78_loadBeamId)].IsLoaded(); }
|
|
|
|
void CAuxWeapon::RenderMuzzleFx() const {
|
|
switch (x74_firingBeamId) {
|
|
case CPlayerState::EBeamId::Wave:
|
|
case CPlayerState::EBeamId::Plasma:
|
|
x24_muzzleFxGen->Render();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
TUniqueId CAuxWeapon::HasTarget(const CStateManager& mgr) const {
|
|
if (x74_firingBeamId == CPlayerState::EBeamId::Wave) {
|
|
if (const auto* wb = static_cast<const CWaveBuster*>(mgr.GetObjectById(x70_waveBusterId))) {
|
|
return wb->GetHomingTargetId();
|
|
}
|
|
}
|
|
return kInvalidUniqueId;
|
|
}
|
|
|
|
void CAuxWeapon::SetNewTarget(TUniqueId targetId, CStateManager& mgr) {
|
|
if (x74_firingBeamId == CPlayerState::EBeamId::Wave) {
|
|
if (auto* wb = static_cast<CWaveBuster*>(mgr.ObjectById(x70_waveBusterId))) {
|
|
wb->SetNewTarget(targetId);
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace urde
|