prime/src/MetroidPrime/Player/CPlayerGun.cpp

1103 lines
38 KiB
C++

#include "MetroidPrime/Player/CPlayerGun.hpp"
#include "MetroidPrime/CAnimData.hpp"
#include "MetroidPrime/CAnimRes.hpp"
#include "MetroidPrime/CRainSplashGenerator.hpp"
#include "MetroidPrime/CStateManager.hpp"
#include "MetroidPrime/CWorld.hpp"
#include "MetroidPrime/CWorldShadow.hpp"
#include "MetroidPrime/Cameras/CCameraManager.hpp"
#include "MetroidPrime/Player/CGrappleArm.hpp"
#include "MetroidPrime/Player/CPlayer.hpp"
#include "MetroidPrime/SFX/Weapons.h"
#include "MetroidPrime/Tweaks/CTweakGunRes.hpp"
#include "MetroidPrime/Tweaks/CTweakPlayerGun.hpp"
#include "MetroidPrime/Weapons/CAuxWeapon.hpp"
#include "MetroidPrime/Weapons/CIceBeam.hpp"
#include "MetroidPrime/Weapons/CPhazonBeam.hpp"
#include "MetroidPrime/Weapons/CPlasmaBeam.hpp"
#include "MetroidPrime/Weapons/CPowerBeam.hpp"
#include "MetroidPrime/Weapons/CPowerBomb.hpp"
#include "MetroidPrime/Weapons/CWaveBeam.hpp"
#include "MetroidPrime/Weapons/GunController/CGunMotion.hpp"
#include "MetroidPrime/Weapons/WeaponTypes.hpp"
#include "Kyoto/Audio/CSfxManager.hpp"
#include "Kyoto/Graphics/CModelFlags.hpp"
#include "Kyoto/Math/CAbsAngle.hpp"
#include "Kyoto/Math/CMath.hpp"
#include "Kyoto/Math/CRelAngle.hpp"
#include "Kyoto/Particles/CElementGen.hpp"
#include "Kyoto/Particles/CGenDescription.hpp"
#include "Kyoto/SObjectTag.hpp"
#include "Collision/CMaterialFilter.hpp"
#include "Collision/CMaterialList.hpp"
#include "MetaRender/CCubeRenderer.hpp"
#include "math.h"
static float kVerticalAngleTable[3] = {-30.f, 0.f, 30.f};
static float kHorizontalAngleTable[3] = {30.f, 30.f, 30.f};
static float kVerticalVarianceTable[3] = {30.f, 30.f, 30.f};
static const float chargeShakeTbl[3] = {
-0.001f,
0.f,
0.001f,
};
const uint CPlayerGun::mHandAnimId[4] = {
0,
1,
2,
1,
};
static const CPlayerState::EItemType mBeamArr[4] = {
CPlayerState::kIT_PowerBeam,
CPlayerState::kIT_IceBeam,
CPlayerState::kIT_WaveBeam,
CPlayerState::kIT_PlasmaBeam,
};
static const CPlayerState::EItemType mBeamComboArr[4] = {
CPlayerState::kIT_SuperMissile,
CPlayerState::kIT_IceSpreader,
CPlayerState::kIT_Wavebuster,
CPlayerState::kIT_Flamethrower,
};
// static ControlMapper::ECommands mBeamCtrlCmd[4] = {
// ControlMapper::kC_PowerBeam,
// ControlMapper::kC_IceBeam,
// ControlMapper::kC_WaveBeam,
// ControlMapper::kC_PlasmaBeam,
// };
// constexpr std::array<ushort, 4> skFromMissileSound{
// SFXwpn_from_missile_power,
// SFXwpn_from_missile_ice,
// SFXwpn_from_missile_wave,
// SFXwpn_from_missile_plasma,
// };
// constexpr std::array<ushort, 4> mFromBeamSound{
// SFXsfx0000,
// SFXwpn_from_beam_ice,
// SFXwpn_from_beam_wave,
// SFXwpn_from_beam_plasma,
// };
// constexpr std::array<ushort, 4> skToMissileSound{
// SFXwpn_to_missile_power,
// SFXwpn_to_missile_ice,
// SFXwpn_to_missile_wave,
// SFXwpn_to_missile_plasma,
// };
// constexpr std::array<ushort, 4> mIntoBeamSound{
// SFXsfx0000,
// SFXwpn_into_beam_ice,
// SFXwpn_into_beam_wave,
// SFXwpn_into_beam_plasma,
// };
float CPlayerGun::kTractorBeamFactor = 0.25f / CPlayerState::GetMissileComboChargeFactor();
CVector3f CPlayerGun::kScaleVector(2.f, 2.f, 2.f);
float CPlayerGun::CMotionState::gGunExtendDistance = 0.125f;
static CColor kArmColor = CColor(0.75f, 0.5f, 0.f, 1.f);
static CMaterialFilter sAimFilter = CMaterialFilter::MakeIncludeExclude(
CMaterialList(kMT_Solid), CMaterialList(kMT_ProjectilePassthrough));
static const float kChargeSpeed = 1.f / CPlayerState::GetMissileComboChargeFactor();
static const float kChargeStart = 0.025f / CPlayerState::GetMissileComboChargeFactor();
static const float kChargeFxStart = 1.f / CPlayerState::GetMissileComboChargeFactor();
// constexpr std::array<ushort, 4> skBeamChargeUpSound{
// SFXwpn_chargeup_power,
// SFXwpn_chargeup_ice,
// SFXwpn_chargeup_wave,
// SFXwpn_chargeup_plasma,
// };
static const CPlayerState::EItemType skItemArr[2] = {
CPlayerState::kIT_Invalid,
CPlayerState::kIT_Missiles,
};
static const CModelFlags kThermalFlags[4] = {
CModelFlags::Normal(),
CModelFlags::AlphaBlended(CColor(u8(255), u8(255), u8(255), u8(128))),
CModelFlags::Normal(),
CModelFlags::Normal(),
};
static const CModelFlags kHandThermalFlag(CModelFlags::kT_Additive, CColor::White());
static const CModelFlags kHandHoloFlag(CModelFlags::kT_One, kArmColor);
static ushort mItemEmptySound[2] = {
CSfxManager::kInternalInvalidSfxId,
SFXwpn_empty_action,
};
static ushort mIntoBeamSound[4] = {
CSfxManager::kInternalInvalidSfxId,
SFXwpn_into_beam_ice,
SFXwpn_into_beam_wave,
SFXwpn_into_beam_plasma,
};
static ushort mFromBeamSound[4] = {
CSfxManager::kInternalInvalidSfxId,
SFXwpn_from_beam_ice,
SFXwpn_from_beam_wave,
SFXwpn_from_beam_plasma,
};
CPlayerGun::CPlayerGun(TUniqueId playerId)
: x0_lights(8, CVector3f::Zero(), 4, 4, false, false, false, 0.1)
, x2ec_lastFireButtonStates(0)
, x2f0_pressedFireButtonStates(0)
, x2f4_fireButtonStates(0)
, x2f8_stateFlags(0x1)
, x2fc_fidgetAnimBits(0)
, x300_remainingMissiles(0)
, x304_(0)
, x308_bombCount(3)
, x30c_rapidFireShots(0)
, x310_currentBeam(CPlayerState::kBI_Power)
, x314_nextBeam(CPlayerState::kBI_Power)
, x318_comboAmmoIdx(0)
, x31c_missileMode(kMM_Inactive)
, x320_currentAuxBeam(CPlayerState::kBI_Power)
, x324_idleState(kIS_Four)
, x328_animSfxPitch(0.f)
, x32c_chargePhase(kCP_NotCharging)
, x330_chargeState(kCS_Normal)
, x334_(0)
, x338_nextState(kNS_StatusQuo)
, x33c_phazonBeamState(kPBS_Inactive)
, x340_chargeBeamFactor(0.f)
, x344_comboXferTimer(0.f)
, x348_chargeCooldownTimer(0.f)
, x34c_shakeX(0.f)
, x350_shakeZ(0.f)
, x354_bombFuseTime(gpTweakPlayerGun->GetBombFuseTime())
, x358_bombDropDelayTime(gpTweakPlayerGun->GetBombDropDelayTime())
, x35c_bombTime(0.f)
, x360_(0.f)
, x364_gunStrikeCoolTimer(0.f)
, x368_idleWanderDelayTimer(0.f)
, x36c_(1.f)
, x370_gunMotionSpeedMult(1.f)
, x374_(0.f)
, x378_shotSmokeStartTimer(0.f)
, x37c_rapidFireShotsDecayTimer(0.f)
, x380_shotSmokeTimer(0.f)
, x384_gunStrikeDelayTimer(0.f)
, x388_enterFreeLookDelayTimer(0.f)
, x38c_muzzleEffectVisTimer(0.f)
, x390_cooldown(0.f)
, x394_damageTimer(0.f)
, x398_damageAmt(0.f)
, x39c_phazonMorphT(0.f)
, x3a0_missileExitTimer(0.f)
, x3dc_damageLocation(CVector3f::Zero())
, x3e8_xf(CTransform4f::Identity())
, x418_beamLocalXf(CTransform4f::Identity())
, x448_elbowWorldXf(CTransform4f::Identity())
, x478_assistAimXf(CTransform4f::Identity())
, x4a8_gunWorldXf(CTransform4f::Identity())
, x4d8_gunLocalXf(CTransform4f::Identity())
, x508_elbowLocalXf(CTransform4f::Identity())
, x538_playerId(playerId)
, x53a_powerBomb(kInvalidUniqueId)
, x53c_lightId(kInvalidUniqueId)
, x550_camBob(CPlayerCameraBob::kCBT_One,
CVector2f(CPlayerCameraBob::kCameraBobExtentX, CPlayerCameraBob::kCameraBobExtentY),
CPlayerCameraBob::kCameraBobPeriod)
, x658_(1)
, x65c_(0.f)
, x660_(0.f)
, x664_(0.f)
, x668_aimVerticalSpeed(gpTweakPlayerGun->GetAimVerticalSpeed())
, x66c_aimHorizontalSpeed(gpTweakPlayerGun->GetAimHorizontalSpeed())
, x670_animSfx(InvalidSfxId, CSfxHandle())
, x678_morph(gpTweakPlayerGun->GetGunTransformTime(), gpTweakPlayerGun->GetHoloHoldTime())
, x6a0_motionState()
, x6c8_hologramClipCube(CVector3f(-0.29329199f, 0.f, -0.2481945f),
CVector3f(0.29329199f, 1.292392f, 0.2481945f))
, x6e0_rightHandModel(CAnimRes(gpTweakGunRes->xc_rightHand, CAnimRes::kDefaultCharIdx,
CVector3f(3.f, 3.f, 3.f), 0, true))
, x72c_currentBeam(nullptr)
, x730_outgoingBeam(nullptr)
, x734_loadingBeam(nullptr)
, x738_nextBeam(nullptr)
, x73c_gunMotion(new CGunMotion(gpTweakGunRes->x4_gunMotion, kScaleVector))
, x740_grappleArm(new CGrappleArm(kScaleVector))
, x744_auxWeapon(new CAuxWeapon(playerId))
, x748_rainSplashGenerator(new CRainSplashGenerator(kScaleVector, 20, 2, 0.f, 0.125f))
, x74c_powerBeam(
new CPowerBeam(gpTweakGunRes->x10_powerBeam, kWT_Power, playerId, kMT_Player, kScaleVector))
, x750_iceBeam(
new CIceBeam(gpTweakGunRes->x14_iceBeam, kWT_Ice, playerId, kMT_Player, kScaleVector))
, x754_waveBeam(
new CWaveBeam(gpTweakGunRes->x18_waveBeam, kWT_Wave, playerId, kMT_Player, kScaleVector))
, x758_plasmaBeam(new CPlasmaBeam(gpTweakGunRes->x1c_plasmaBeam, kWT_Plasma, playerId, kMT_Player,
kScaleVector))
, x75c_phazonBeam(new CPhazonBeam(gpTweakGunRes->x20_phazonBeam, kWT_Phazon, playerId, kMT_Player,
kScaleVector))
, x760_selectableBeams(nullptr)
, x774_holoTransitionGen(
new CElementGen(gpSimplePool->GetObj(SObjectTag('PART', gpTweakGunRes->x24_holoTransition))))
, x82c_shadow(new CWorldShadow(32, 32, true))
, x830_chargeRumbleHandle(-1)
, x832_24_coolingCharge(false)
, x832_25_chargeEffectVisible(false)
, x832_26_comboFiring(false)
, x832_27_chargeAnimStarted(false)
, x832_28_readyForShot(false)
, x832_29_lockedOn(false)
, x832_30_requestReturnToDefault(false)
, x832_31_inRestPose(true)
, x833_24_notFidgeting(true)
, x833_25_(false)
, x833_26_(false)
, x833_27_(false)
, x833_28_phazonBeamActive(false)
, x833_29_pointBlankWorldSurface(false)
, x833_30_canShowAuxMuzzleEffect(true)
, x833_31_inFreeLook(false)
, x834_24_charging(false)
, x834_25_gunMotionFidgeting(false)
, x834_26_animPlaying(false)
, x834_27_underwater(false)
, x834_28_requestImmediateRecharge(false)
, x834_29_frozen(false)
, x834_30_inBigStrike(false)
, x834_31_gunMotionInFidgetBasePosition(false)
, x835_24_canFirePhazon(false)
, x835_25_inPhazonBeam(false)
, x835_26_phazonBeamMorphing(false)
, x835_27_intoPhazonBeam(false)
, x835_28_bombReady(false)
, x835_29_powerBombReady(false)
, x835_30_inPhazonPool(false)
, x835_31_actorAttached(false) {
x6e0_rightHandModel.SetSortThermal(true);
kVerticalAngleTable[2] = gpTweakPlayerGun->GetUpLookAngle();
kVerticalAngleTable[0] = gpTweakPlayerGun->GetDownLookAngle();
kHorizontalAngleTable[1] = gpTweakPlayerGun->GetHorizontalSpread();
kHorizontalAngleTable[2] = gpTweakPlayerGun->GetHighHorizontalSpread();
kHorizontalAngleTable[0] = gpTweakPlayerGun->GetLowHorizontalSpread();
kVerticalVarianceTable[1] = gpTweakPlayerGun->GetVerticalSpread();
kVerticalVarianceTable[2] = gpTweakPlayerGun->GetHighVerticalSpread();
kVerticalVarianceTable[0] = gpTweakPlayerGun->GetLowVerticalSpread();
CMotionState::SetExtendDistance(gpTweakPlayerGun->GetGunExtendDistance());
InitBeamData();
InitBombData();
InitMuzzleData();
InitCTData();
LoadHandAnimTokens();
x550_camBob.SetPlayerVelocity(CVector3f::Zero());
x550_camBob.SetBobMagnitude(0.f);
x550_camBob.SetBobTimeScale(0.f);
}
CPlayerGun::~CPlayerGun() {}
void CPlayerGun::AddToRenderer(const CFrustumPlanes& frustum, const CStateManager&) const {
rstl::optional_object< CModelData >& model = x72c_currentBeam->SolidModelData();
if (model) {
model->RenderParticles(frustum);
}
}
void CPlayerGun::PreRender(CStateManager& mgr, const CFrustumPlanes& frustum,
const CVector3f& camPos) {
const CPlayerState& playerState = *mgr.GetPlayerState();
if (playerState.GetCurrentVisor() == CPlayerState::kPV_Scan) {
return;
}
CPlayerState::EPlayerVisor activeVisor = playerState.GetActiveVisor(mgr);
switch (activeVisor) {
case CPlayerState::kPV_Thermal: {
float rgb =
CMath::Clamp(0.6f, 0.5f * x380_shotSmokeTimer + 0.6f - x378_shotSmokeStartTimer, 1.f);
x0_lights.BuildConstantAmbientLighting(CColor(rgb, rgb, rgb, 1.f));
break;
}
case CPlayerState::kPV_Combat: {
CAABox aabb = x72c_currentBeam->GetBounds(CTransform4f::Translate(camPos) * x4a8_gunWorldXf);
if (mgr.GetNextAreaId() != kInvalidAreaId) {
x0_lights.SetFindShadowLight(true);
x0_lights.SetShadowDynamicRangeThreshold(0.25f);
x0_lights.BuildAreaLightList(mgr, mgr.GetWorld()->GetAreaAlways(mgr.GetNextAreaId()), aabb);
}
x0_lights.BuildDynamicLightList(mgr, aabb);
if (x0_lights.HasShadowLight()) {
if (x72c_currentBeam->IsLoaded()) {
x82c_shadow->BuildLightShadowTexture(mgr, mgr.GetNextAreaId(),
x0_lights.GetShadowLightIndex(), aabb, true, false);
}
} else {
x82c_shadow->ResetBlur();
}
break;
}
default:
break;
}
if (x740_grappleArm->GetActive()) {
x740_grappleArm->PreRender(mgr, frustum, camPos);
}
if (x678_morph.GetGunState() != CGunMorph::kGS_OutWipeDone ||
activeVisor == CPlayerState::kPV_XRay) {
x6e0_rightHandModel.AnimationData()->PreRender();
}
if (x833_28_phazonBeamActive) {
gpRender->AllocatePhazonSuitMaskTexture();
}
}
void CPlayerGun::TouchModel(const CStateManager&) const {}
CVector3f CPlayerGun::ConvertToScreenSpace(const CVector3f& pos, const CGameCamera&) const {
return pos;
}
void CPlayerGun::DrawArm(const CStateManager&, const CVector3f&, const CModelFlags&) const {}
void CPlayerGun::Render(const CStateManager&, const CVector3f&, const CModelFlags&) const {}
void CPlayerGun::GetLctrWithShake(CTransform4f& xfOut, const CModelData&, const rstl::string&, bool,
bool) {}
void CPlayerGun::PlayAnim(NWeaponTypes::EGunAnimType type, bool) {}
void CPlayerGun::Update(float, float, float, CStateManager&) {}
void CPlayerGun::ProcessInput(const CFinalInput&, CStateManager&) {}
void CPlayerGun::ProcessChargeState(int releasedStates, int pressedStates, CStateManager& mgr,
float dt) {
if ((releasedStates & 0x1) != 0) {
ResetCharged(dt, mgr);
return;
}
if ((pressedStates & 0x1) != 0) {
if (x32c_chargePhase == kCP_NotCharging && (pressedStates & 0x1) != 0 &&
x348_chargeCooldownTimer == 0.f && x832_28_readyForShot == 1) {
UpdateNormalShotCycle(dt, mgr);
x32c_chargePhase = kCP_ChargeRequested;
}
} else {
const CPlayerState* state = mgr.GetPlayerState();
if (state->HasPowerUp(CPlayerState::kIT_Missiles) && (pressedStates & 0x2) != 0) {
if (x32c_chargePhase >= kCP_FxGrown) {
if (state->HasPowerUp(mBeamComboArr[size_t(x310_currentBeam)]))
ActivateCombo(mgr);
} else if (x32c_chargePhase == kCP_NotCharging) {
FireSecondary(dt, mgr);
}
}
}
}
void CPlayerGun::ResetNormal(CStateManager& mgr) {
Reset(mgr, false);
x832_28_readyForShot = false;
}
void CPlayerGun::ResetCharged(float dt, CStateManager& mgr) {
if (x832_26_comboFiring == true) {
return;
}
if (x32c_chargePhase >= kCP_FxGrowing) {
x833_30_canShowAuxMuzzleEffect = false;
UpdateNormalShotCycle(dt, mgr);
x832_24_coolingCharge = true;
CancelCharge(mgr, true);
} else if (x32c_chargePhase != kCP_NotCharging) {
x320_currentAuxBeam = x310_currentBeam;
x833_30_canShowAuxMuzzleEffect = true;
x32c_chargePhase = kCP_ChargeDone;
}
StopChargeSound(mgr);
}
void CPlayerGun::ProcessNormalState(int releasedStates, int pressedStates, CStateManager& mgr,
float dt) {
if ((releasedStates & 0x1) != 0) {
ResetNormal(mgr);
return;
}
if ((pressedStates & 0x1) != 0 && x348_chargeCooldownTimer == 0.f &&
x832_28_readyForShot == true) {
UpdateNormalShotCycle(dt, mgr);
return;
}
if ((pressedStates & 0x2) != 0) {
FireSecondary(dt, mgr);
}
}
bool CPlayerGun::ExitMissile() {
if ((x2f8_stateFlags & 0x1) != 0x1) {
if ((x2f8_stateFlags & 0x10) != 0x10 && x338_nextState != kNS_ExitMissile) {
x338_nextState = kNS_ExitMissile;
PlayAnim(NWeaponTypes::kGAT_FromMissile, false);
}
return false;
}
return true;
}
void CPlayerGun::UpdateNormalShotCycle(float, CStateManager&) {}
void CPlayerGun::FireSecondary(float, CStateManager&) {}
void CPlayerGun::DropBomb(CPlayerGun::EBWeapon, CStateManager&) {}
void CPlayerGun::ActivateCombo(CStateManager&) {}
void CPlayerGun::EnableChargeFx(CPlayerState::EChargeStage, CStateManager&) {}
void CPlayerGun::UpdateChargeState(float, CStateManager&) {}
void CPlayerGun::Reset(CStateManager& mgr, bool b1) {
x72c_currentBeam->Reset(mgr);
x832_25_chargeEffectVisible = false;
x832_24_coolingCharge = false;
x833_26_ = false;
x348_chargeCooldownTimer = 0.f;
SetGunLightActive(false, mgr);
if ((x2f8_stateFlags & 0x10) != 0x10) {
if (!b1 && (x2f8_stateFlags & 0x2) != 0x2) {
if ((x2f8_stateFlags & 0x8) != 0x8) {
x2f8_stateFlags |= 0x1;
x2f8_stateFlags &= ~0x16;
}
x318_comboAmmoIdx = 0;
x31c_missileMode = kMM_Inactive;
}
} else {
x2f8_stateFlags &= ~0x7;
}
}
void CPlayerGun::ResetCharge(CStateManager& mgr, bool resetBeam) {
if (x32c_chargePhase != kCP_NotCharging)
StopChargeSound(mgr);
if ((x2f8_stateFlags & 0x8) != 0x8 && (x2f8_stateFlags & 0x10) != 0x10) {
bool doResetBeam =
mgr.GetPlayer()->GetMorphballTransitionState() == CPlayer::kMS_Morphed || resetBeam;
if (x832_27_chargeAnimStarted || doResetBeam)
PlayAnim(NWeaponTypes::kGAT_BasePosition, false);
if (doResetBeam)
x72c_currentBeam->EnableSecondaryFx(CGunWeapon::kSFT_None);
if ((x2f8_stateFlags & 0x2) != 0x2 || x330_chargeState != kCS_Normal) {
if ((x2f8_stateFlags & 0x8) != 0x8) {
x2f8_stateFlags |= 0x1;
x2f8_stateFlags &= ~0x16;
}
x318_comboAmmoIdx = 0;
x31c_missileMode = kMM_Inactive;
}
}
x32c_chargePhase = kCP_NotCharging;
x330_chargeState = kCS_Normal;
x320_currentAuxBeam = x310_currentBeam;
x833_30_canShowAuxMuzzleEffect = true;
x832_27_chargeAnimStarted = false;
x832_26_comboFiring = false;
x344_comboXferTimer = 0.f;
}
#define SFXwpn_morph_out_wipe 1774
void CPlayerGun::ResetBeamParams(CStateManager& mgr, const CPlayerState& playerState,
bool playSelectionSfx) {
StopContinuousBeam(mgr, true);
if (playerState.ItemEnabled(CPlayerState::kIT_ChargeBeam)) {
ResetCharge(mgr, false);
}
const CAnimPlaybackParms parms(mHandAnimId[size_t(x314_nextBeam)], -1, 1.f, true);
x6e0_rightHandModel.AnimationData()->SetAnimation(parms, false);
Reset(mgr, false);
if (playSelectionSfx) {
CSfxManager::SfxStart(SFXwpn_morph_out_wipe, 0x7f, 0x40, true, CSfxManager::kMaxPriority, false,
CSfxManager::kAllAreas);
}
x2ec_lastFireButtonStates &= ~0x1;
x320_currentAuxBeam = x310_currentBeam;
x833_30_canShowAuxMuzzleEffect = true;
}
void CPlayerGun::ChangeWeapon(const CPlayerState&, CStateManager&) {}
void CPlayerGun::StartPhazonBeamTransition(bool, CStateManager&, CPlayerState&) {}
void CPlayerGun::HandleWeaponChange(const CFinalInput&, CStateManager&) {}
void CPlayerGun::HandleBeamChange(const CFinalInput&, CStateManager&) {}
void CPlayerGun::SetPhazonBeamMorph(bool) {}
void CPlayerGun::HandlePhazonBeamChange(CStateManager&) {}
void CPlayerGun::InitBeamData() {
x760_selectableBeams[0] = x74c_powerBeam.get();
x760_selectableBeams[1] = x750_iceBeam.get();
x760_selectableBeams[2] = x754_waveBeam.get();
x760_selectableBeams[3] = x758_plasmaBeam.get();
x72c_currentBeam = x760_selectableBeams[0];
x738_nextBeam = x72c_currentBeam;
x774_holoTransitionGen->SetParticleEmission(true);
}
void CPlayerGun::InitBombData() {
for (int i = 0; i < 2; ++i)
x784_bombEffects.push_back(rstl::reserved_vector< TLockedToken< CGenDescription >, 2 >());
CToken obj1 = gpSimplePool->GetObj(SObjectTag('PART', gpTweakGunRes->x28_bombSet));
CToken obj2 = gpSimplePool->GetObj(SObjectTag('PART', gpTweakGunRes->x2c_bombExplode));
CToken obj3 = gpSimplePool->GetObj(SObjectTag('PART', gpTweakGunRes->x30_powerBombExplode));
x784_bombEffects[0].push_back(obj1);
x784_bombEffects[0].push_back(obj2);
x784_bombEffects[1].push_back(obj3);
x784_bombEffects[1].push_back(obj3);
}
void CPlayerGun::InitMuzzleData() {
for (int i = 0; i < 5; ++i) {
SObjectTag tag('PART', (i < 0 || 4 < i) ? kInvalidAssetId : gpTweakGunRes->xa4_auxMuzzle[i]);
x7c0_auxMuzzleEffects.push_back(gpSimplePool->GetObj(tag));
// TODO: not likely correct, maybe need improvements to auto_ptr
x800_auxMuzzleGenerators.push_back(new CElementGen(x7c0_auxMuzzleEffects.back()));
x800_auxMuzzleGenerators.back()->SetParticleEmission(false);
}
}
void CPlayerGun::InitCTData() { x77c_comboXferGen = rstl::auto_ptr< CElementGen >(); }
float CPlayerGun::GetBeamVelocity() const {
if (x72c_currentBeam->IsLoaded())
return x72c_currentBeam->GetVelocityInfo().GetVelocity(int(x330_chargeState)).GetY();
return 10.f;
}
TUniqueId CPlayerGun::GetTargetId(CStateManager& mgr) {
TUniqueId ret = mgr.GetPlayer()->GetOrbitTargetId();
if (x832_26_comboFiring && ret == kInvalidUniqueId && x310_currentBeam == CPlayerState::kBI_Wave)
ret = mgr.GetPlayer()->GetOrbitNextTargetId();
if (ret != kInvalidUniqueId) {
const CActor* act = TCastToConstPtr< CActor >(mgr.GetObjectById(ret));
if (act != nullptr) {
if (!act->GetMaterialList().HasMaterial(kMT_Target)) {
ret = kInvalidUniqueId;
}
}
}
return ret;
}
CPlayerGun::CGunMorph::CGunMorph(float gunTransformTime, float holoHoldTime)
: x0_yLerp(0.f)
, x4_gunTransformTime(CMath::Sign(gunTransformTime))
, x8_remTime(0.f)
, xc_speed(0.1f)
, x10_holoHoldTime(fabs(holoHoldTime))
, x14_remHoldTime(2.f)
, x18_transitionFactor(1.f)
, x1c_dir(kD_Done)
, x20_gunState(kGS_OutWipeDone)
, x24_24_morphing(false)
, x24_25_weaponChanged(false) {}
void CPlayerGun::CGunMorph::StartWipe(CPlayerGun::CGunMorph::EDir dir) {
x14_remHoldTime = x10_holoHoldTime;
if (dir == kD_In && x20_gunState == kGS_InWipeDone)
return;
if (x1c_dir != dir && x20_gunState != kGS_OutWipe) {
x8_remTime = x4_gunTransformTime;
xc_speed = 1.f / x4_gunTransformTime;
} else if (x20_gunState != kGS_InWipe) {
x8_remTime = x4_gunTransformTime - x8_remTime;
}
x1c_dir = dir;
x20_gunState = x1c_dir == kD_In ? kGS_InWipe : kGS_OutWipe;
x24_24_morphing = true;
}
CPlayerGun::CGunMorph::EMorphEvent CPlayerGun::CGunMorph::Update(float inY, float outY, float dt) {
EMorphEvent ret = kME_None;
switch (x20_gunState) {
case kGS_InWipeDone:
x14_remHoldTime -= dt;
if (x14_remHoldTime <= 0.f && x24_25_weaponChanged) {
StartWipe(kD_Out);
x24_25_weaponChanged = false;
x14_remHoldTime = 0.f;
ret = kME_InWipeDone;
}
// explicitly no break
case kGS_OutWipeDone:
case kGS_InWipe:
case kGS_OutWipe:
default:
if (x24_24_morphing) {
float omt = x8_remTime * xc_speed;
float t = 1.f - omt;
if (x1c_dir == kD_In) {
x0_yLerp = omt * outY + t * inY;
x18_transitionFactor = omt;
} else {
x0_yLerp = omt * inY + t * outY;
x18_transitionFactor = t;
}
if (x8_remTime <= 0.f) {
x24_24_morphing = false;
x8_remTime = 0.f;
if (x1c_dir == kD_In) {
x20_gunState = kGS_InWipeDone;
x18_transitionFactor = 0.f;
} else {
x18_transitionFactor = 1.f;
x20_gunState = kGS_OutWipeDone;
x1c_dir = kD_Done;
ret = kME_OutWipeDone;
}
} else {
x8_remTime -= dt;
}
}
}
return ret;
}
void CPlayerGun::UpdateWeaponFire(float dt, CPlayerState& playerState, CStateManager& mgr) {
uint oldFiring = x2ec_lastFireButtonStates;
x2ec_lastFireButtonStates = x2f4_fireButtonStates;
uint pressedStates = x2f4_fireButtonStates & (oldFiring ^ x2f4_fireButtonStates);
x2f0_pressedFireButtonStates = pressedStates;
uint releasedStates = oldFiring & (oldFiring ^ x2f4_fireButtonStates);
x832_28_readyForShot = false;
CPlayer& player = *mgr.Player();
if (!x832_24_coolingCharge && !x834_30_inBigStrike) {
float coolDown = x72c_currentBeam->GetWeaponInfo().x0_coolDown;
if ((pressedStates & 0x1) == 0) {
if (x390_cooldown >= coolDown) {
x390_cooldown = coolDown;
if (player.GetMorphballTransitionState() == CPlayer::kMS_Unmorphed &&
playerState.ItemEnabled(CPlayerState::kIT_ChargeBeam) &&
player.GetGunHolsterState() == CPlayer::kGH_Drawn &&
player.GetGrappleState() == CPlayer::kGS_None &&
playerState.GetTransitioningVisor() != CPlayerState::kPV_Scan &&
playerState.GetCurrentVisor() != CPlayerState::kPV_Scan &&
(x2ec_lastFireButtonStates & 0x1) != 0 && x32c_chargePhase == kCP_NotCharging) {
x832_28_readyForShot = true;
pressedStates |= 0x1;
x390_cooldown = 0.f;
}
}
} else if (x390_cooldown >= coolDown) {
x832_28_readyForShot = true;
x390_cooldown = 0.f;
}
x390_cooldown += dt;
}
if (x834_28_requestImmediateRecharge)
x834_28_requestImmediateRecharge = (x2ec_lastFireButtonStates & 0x1) != 0;
if (player.GetMorphballTransitionState() == CPlayer::kMS_Morphed) {
x835_28_bombReady = false;
x835_29_powerBombReady = false;
if (!x835_31_actorAttached) {
x835_28_bombReady = true;
if (x53a_powerBomb != kInvalidUniqueId &&
!mgr.CanCreateProjectile(x538_playerId, kWT_PowerBomb, 1)) {
const CPowerBomb* pb = static_cast< const CPowerBomb* >(mgr.GetObjectById(x53a_powerBomb));
if (pb && pb->GetCurTime() <= 4.25f) {
x835_28_bombReady = false;
} else {
x53a_powerBomb = kInvalidUniqueId;
}
}
if (((pressedStates & 0x1) != 0 || x32c_chargePhase != kCP_NotCharging) &&
playerState.HasPowerUp(CPlayerState::kIT_MorphBallBombs)) {
if (x835_28_bombReady)
DropBomb(kBW_Bomb, mgr);
} else if (playerState.HasPowerUp(CPlayerState::kIT_PowerBombs) &&
playerState.GetItemAmount(CPlayerState::kIT_PowerBombs) > 0) {
x835_29_powerBombReady = mgr.CanCreateProjectile(x538_playerId, kWT_PowerBomb, 1) &&
mgr.CanCreateProjectile(x538_playerId, kWT_Bomb, 1);
if ((pressedStates & 0x2) != 0 && x835_29_powerBombReady)
DropBomb(kBW_PowerBomb, mgr);
}
}
} else if ((x2f8_stateFlags & 0x8) != 0x8 &&
player.GetMorphballTransitionState() == CPlayer::kMS_Unmorphed) {
if ((pressedStates & 0x2) != 0 && x318_comboAmmoIdx == 0 && (x2f8_stateFlags & 0x2) != 0x2 &&
x32c_chargePhase == kCP_NotCharging) {
uint missileCount = playerState.GetItemAmount(CPlayerState::kIT_Missiles);
if (x338_nextState != kNS_EnterMissile && x338_nextState != kNS_ExitMissile) {
if (playerState.HasPowerUp(CPlayerState::kIT_Missiles) && missileCount > 0) {
x300_remainingMissiles = missileCount;
if (x300_remainingMissiles > 5)
x300_remainingMissiles = 5;
if (!x835_25_inPhazonBeam) {
x2f8_stateFlags &= ~0x1;
x2f8_stateFlags |= 0x6;
x318_comboAmmoIdx = 1;
x31c_missileMode = kMM_Active;
}
FireSecondary(dt, mgr);
} else {
if (!CSfxManager::IsPlaying(x2e4_invalidSfx)) {
x2e4_invalidSfx =
NWeaponTypes::play_sfx(SFXwpn_invalid_action, x834_27_underwater, false, 0x4a);
} else {
x2e4_invalidSfx.Clear();
}
}
}
} else {
if (x3a4_fidget.GetState() == CFidget::kS_NoFidget) {
if ((x2f8_stateFlags & 0x10) == 0x10 && x744_auxWeapon->IsComboFxActive(mgr)) {
if (x2ec_lastFireButtonStates == 0 ||
(x310_currentBeam == CPlayerState::kBI_Wave && x833_29_pointBlankWorldSurface)) {
StopContinuousBeam(mgr, (x2f8_stateFlags & 0x8) == 0x8);
}
} else {
if (mgr.GetPlayerState()->ItemEnabled(CPlayerState::kIT_ChargeBeam) &&
x33c_phazonBeamState == kPBS_Inactive)
ProcessChargeState(releasedStates, pressedStates, mgr, dt);
else
ProcessNormalState(releasedStates, pressedStates, mgr, dt);
}
}
}
}
}
void CPlayerGun::ResetIdle(CStateManager& mgr) {
CFidget::EState fidgetState = x3a4_fidget.GetState();
x370_gunMotionSpeedMult = 1.f;
x550_camBob.SetState(CPlayerCameraBob::kCBS_GunFireNoBob, mgr);
if (fidgetState != CFidget::kS_NoFidget) {
if (fidgetState == CFidget::kS_Loading) {
UnLoadFidget();
}
ReturnArmAndGunToDefault(mgr, true);
}
x3a4_fidget.ResetAll();
ReturnToRestPose();
if (x324_idleState != kIS_NotIdle)
x324_idleState = kIS_NotIdle;
if (!x740_grappleArm->GetActive())
x834_26_animPlaying = false;
}
void CPlayerGun::UpdateGunIdle(bool inStrikeCooldown, float camBobT, float dt, CStateManager& mgr) {
CPlayer& player = *mgr.Player();
if (player.IsInFreeLook() && !x832_29_lockedOn && !x740_grappleArm->IsGrappling() &&
x3a4_fidget.GetState() != CFidget::kS_HolsterBeam &&
player.GetGunHolsterState() == CPlayer::kGH_Drawn && !x834_30_inBigStrike) {
if ((x2f8_stateFlags & 0x8) != 0x8) {
if (!x833_31_inFreeLook && !x834_26_animPlaying) {
if (x388_enterFreeLookDelayTimer < 0.25f)
x388_enterFreeLookDelayTimer += dt;
if (x388_enterFreeLookDelayTimer >= 0.25f && !x740_grappleArm->IsSuitLoading()) {
EnterFreeLook(mgr);
x833_31_inFreeLook = true;
}
} else {
x388_enterFreeLookDelayTimer = 0.f;
if (x834_26_animPlaying)
ResetIdle(mgr);
}
}
} else {
if (x833_31_inFreeLook) {
if ((x2f8_stateFlags & 0x10) != 0x10) {
x73c_gunMotion->ReturnToDefault(mgr, x834_30_inBigStrike);
x740_grappleArm->ReturnToDefault(mgr, 0.f, false);
}
x833_31_inFreeLook = false;
}
x388_enterFreeLookDelayTimer = 0.f;
if (player.GetMorphballTransitionState() != CPlayer::kMS_Morphed) {
x833_24_notFidgeting =
!(player.GetSurfaceRestraint() != CPlayer::kSR_Water &&
mgr.GetPlayerState()->GetCurrentVisor() != CPlayerState::kPV_Scan &&
(x2f4_fireButtonStates & 0x3) == 0 && x32c_chargePhase == kCP_NotCharging &&
!x832_29_lockedOn && (x2f8_stateFlags & 0x8) != 0x8 && x364_gunStrikeCoolTimer <= 0.f &&
player.GetPlayerMovementState() == NPlayer::kMS_OnGround && !player.IsInFreeLook() &&
!player.GetFreeLookStickState() && player.GetOrbitState() == CPlayer::kOS_NoOrbit &&
fabs(player.GetAngularVelocityOR().GetAngle()) <= 0.1f && camBobT <= 0.01f &&
!mgr.GetCameraManager()->IsInCinematicCamera() &&
player.GetGunHolsterState() == CPlayer::kGH_Drawn &&
player.GetGrappleState() == CPlayer::kGS_None && !x834_30_inBigStrike &&
!x835_25_inPhazonBeam);
if (x833_24_notFidgeting) {
if (!x834_30_inBigStrike) {
bool doWander = camBobT > 0.01f && (x2f4_fireButtonStates & 0x3) == 0;
if (doWander) {
x370_gunMotionSpeedMult = 1.f;
x374_ = 0.f;
if (x364_gunStrikeCoolTimer <= 0.f && x368_idleWanderDelayTimer <= 0.f) {
x368_idleWanderDelayTimer = 8.f;
x73c_gunMotion->PlayPasAnim(SamusGun::kAS_Wander, mgr, 0.f, false);
x324_idleState = kIS_Wander;
x550_camBob.SetState(CPlayerCameraBob::kCBS_Walk, mgr);
}
x368_idleWanderDelayTimer -= dt;
x360_ -= dt;
}
if (!doWander || x834_26_animPlaying)
ResetIdle(mgr);
} else if (x394_damageTimer > 0.f) {
x394_damageTimer -= dt;
} else if (!x834_31_gunMotionInFidgetBasePosition) {
x394_damageTimer = 0.f;
x834_31_gunMotionInFidgetBasePosition = true;
x73c_gunMotion->BasePosition(true);
} else if (!x73c_gunMotion->GetModelData().GetAnimationData()->IsAnimTimeRemaining(
0.001f, rstl::string_l("Whole Body"))) {
x834_30_inBigStrike = false;
x834_31_gunMotionInFidgetBasePosition = false;
}
} else {
switch (x3a4_fidget.Update(x2ec_lastFireButtonStates, camBobT > 0.01f, inStrikeCooldown, dt,
mgr)) {
case CFidget::kS_NoFidget:
if (x324_idleState != kIS_Idle) {
x73c_gunMotion->PlayPasAnim(SamusGun::kAS_Idle, mgr, 0.f, false);
x324_idleState = kIS_Idle;
}
x550_camBob.SetState(CPlayerCameraBob::kCBS_WalkNoBob, mgr);
break;
case CFidget::kS_MinorFidget:
case CFidget::kS_MajorFidget:
case CFidget::kS_HolsterBeam:
if (x324_idleState != kIS_NotIdle) {
x73c_gunMotion->BasePosition(false);
x324_idleState = kIS_NotIdle;
}
AsyncLoadFidget(mgr);
break;
case CFidget::kS_Loading:
if (IsFidgetLoaded())
EnterFidget(mgr);
break;
case CFidget::kS_StillMinorFidget:
case CFidget::kS_StillMajorFidget:
x550_camBob.SetState(CPlayerCameraBob::kCBS_Walk, mgr);
x833_24_notFidgeting = false;
x834_26_animPlaying =
x834_25_gunMotionFidgeting
? x73c_gunMotion->IsAnimPlaying()
: x72c_currentBeam->GetSolidModelData().GetAnimationData()->IsAnimTimeRemaining(
0.001f, rstl::string_l("Whole Body"));
if (!x834_26_animPlaying) {
x3a4_fidget.ResetMinor();
ReturnToRestPose();
}
break;
default:
break;
}
}
x550_camBob.Update(dt, mgr);
}
}
}
void CPlayerGun::CMotionState::Update(bool firing, float dt, CTransform4f& xf, CStateManager& mgr) {
if (firing) {
x24_fireState = kFS_StartFire;
x8_fireTime = 0.f;
} else if (x24_fireState != kFS_NotFiring) {
if (x8_fireTime > dt)
x24_fireState = kFS_Firing;
x8_fireTime += dt;
}
if (x0_24_extendParabola && x20_state == kMS_LockOn) {
float extendT = xc_curExtendDist * (1.0f / gGunExtendDistance);
CTransform4f other =
CTransform4f::RotateZ(CRelAngle::FromDegrees(extendT * -4.f * (extendT - 1.f) * 15.f));
other.SetTranslation(CVector3f(0.f, xc_curExtendDist, 0.f));
xf = xf * other;
} else if (x24_fireState == kFS_StartFire || x24_fireState == kFS_Firing) {
if (fabs(x14_rotationT - 1.f) < 0.1f) {
x18_startRotation = x1c_endRotation;
x14_rotationT = 0.f;
if (x24_fireState == kFS_StartFire) {
x1c_endRotation = mgr.Random()->Next() % 15;
x1c_endRotation *= (mgr.Random()->Next() % 100) > 45 ? 1.f : -1.f;
} else {
x1c_endRotation = 0.f;
if (x18_startRotation == x1c_endRotation) {
x10_curRotation = x1c_endRotation;
x24_fireState = kFS_NotFiring;
}
}
} else {
x10_curRotation = (x1c_endRotation - x18_startRotation) * x14_rotationT + x18_startRotation;
}
x14_rotationT += (1.f - x14_rotationT) * 0.8f * (10.f * dt);
CQuaternion quat = CQuaternion::AxisAngle(CUnitVector3f(xf.GetForward()),
CRelAngle::FromDegrees(x10_curRotation));
CTransform4f tmpXf = quat.BuildTransform4f() * xf.GetRotation();
tmpXf.SetTranslation(xf.GetTranslation());
xf = tmpXf * CTransform4f::Translate(0.f, xc_curExtendDist, 0.f);
} else {
xf = xf * CTransform4f::Translate(0.f, xc_curExtendDist, 0.f);
}
switch (x20_state) {
case kMS_LockOn:
xc_curExtendDist += 3.f * dt;
if (xc_curExtendDist > gGunExtendDistance) {
xc_curExtendDist = gGunExtendDistance;
x20_state = kMS_One;
x0_24_extendParabola = false;
}
break;
case kMS_CancelLockOn:
xc_curExtendDist -= 3.f * dt;
if (xc_curExtendDist < 0.f) {
xc_curExtendDist = 0.f;
x20_state = kMS_Zero;
}
break;
default:
break;
}
if (x0_24_extendParabola != true) {
if (x4_extendParabolaDelayTimer < 30.f) {
x4_extendParabolaDelayTimer += dt;
} else {
x0_24_extendParabola = true;
x4_extendParabolaDelayTimer = 0.f;
}
}
}
void CPlayerGun::DamageRumble(const CVector3f&, const CStateManager&) {}
void CPlayerGun::TakeDamage(bool bigStrike, bool notFromMetroid, CStateManager& mgr) {
const CPlayer& player = *mgr.GetPlayer();
bool hasStrikeAngle = false;
float angle = 0.f;
if (x398_damageAmt >= 10.f && !bigStrike && (x2f8_stateFlags & 0x10) != 0x10 &&
!x832_26_comboFiring && x384_gunStrikeDelayTimer <= 0.f) {
x384_gunStrikeDelayTimer = 20.f;
x364_gunStrikeCoolTimer = 0.75f;
if (x678_morph.GetGunState() == CGunMorph::kGS_OutWipeDone) {
CVector3f localDamageLoc = player.GetTransform().TransposeRotate(x3dc_damageLocation);
angle =
CAbsAngle::FromRadians(atan2(localDamageLoc.GetY(), localDamageLoc.GetX())).AsDegrees();
hasStrikeAngle = true;
}
}
if (hasStrikeAngle || bigStrike) {
if (mgr.GetPlayerState()->GetCurrentVisor() != CPlayerState::kPV_Scan) {
x73c_gunMotion->PlayPasAnim(SamusGun::kAS_Struck, mgr, angle, bigStrike);
if ((bigStrike && notFromMetroid) || x833_31_inFreeLook)
x740_grappleArm->EnterStruck(mgr, angle, bigStrike, !x833_31_inFreeLook);
}
}
x398_damageAmt = 0.f;
x3dc_damageLocation = CVector3f::Zero();
}
void CPlayerGun::StopChargeSound(CStateManager&) {}
void CPlayerGun::CancelFiring(CStateManager&) {}
void CPlayerGun::AcceptScriptMsg(EScriptObjectMessage, TUniqueId, CStateManager&) {}
void CPlayerGun::StopContinuousBeam(CStateManager&, bool) {}
void CPlayerGun::RenderEnergyDrainEffects(const CStateManager&) const {}
void CPlayerGun::DoUserAnimEvents(float, CStateManager&) {}
void CPlayerGun::DoUserAnimEvent(float, CStateManager&, const CInt32POINode&, EUserEventType) {}
void CPlayerGun::CancelCharge(CStateManager&, bool) {}
void CPlayerGun::EnterFreeLook(CStateManager&) {}
void CPlayerGun::EnterFidget(CStateManager&) {}
void CPlayerGun::UpdateLeftArmTransform(const CModelData&, const CStateManager&) {}
void CPlayerGun::ReturnArmAndGunToDefault(CStateManager&, bool) {}
void CPlayerGun::UpdateAuxWeapons(float, const CTransform4f&, CStateManager&) {}
void CPlayerGun::CancelLockOn() {}
void CPlayerGun::CreateGunLight(CStateManager&) {}
void CPlayerGun::DeleteGunLight(CStateManager&) {}
void CPlayerGun::UpdateGunLight(const CTransform4f&, CStateManager&) {}
void CPlayerGun::SetGunLightActive(bool, CStateManager&) {}
void CPlayerGun::LoadHandAnimTokens() {}
void CPlayerGun::ProcessPhazonGunMorph(float, CStateManager&) {}
void CPlayerGun::ProcessGunMorph(float, CStateManager&) {}
void CPlayerGun::AsyncLoadFidget(CStateManager&) {}
void CPlayerGun::UnLoadFidget() {}
bool CPlayerGun::IsFidgetLoaded() { return false; }
void CPlayerGun::SetFidgetAnimBits(int, bool) {}
void CPlayerGun::AsyncLoadSuit(CStateManager&) {}
void CPlayerGun::ReturnToRestPose() {}
void CPlayerGun::DropPowerBomb(CStateManager&) const {}
void CPlayerGun::SetPhazonBeamFeedback(bool) {}