#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 skFromMissileSound{ // SFXwpn_from_missile_power, // SFXwpn_from_missile_ice, // SFXwpn_from_missile_wave, // SFXwpn_from_missile_plasma, // }; // constexpr std::array mFromBeamSound{ // SFXsfx0000, // SFXwpn_from_beam_ice, // SFXwpn_from_beam_wave, // SFXwpn_from_beam_plasma, // }; // constexpr std::array skToMissileSound{ // SFXwpn_to_missile_power, // SFXwpn_to_missile_ice, // SFXwpn_to_missile_wave, // SFXwpn_to_missile_plasma, // }; // constexpr std::array 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 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) {}