2019-12-22 20:04:07 +00:00
|
|
|
#include "Runtime/Weapon/CGrappleArm.hpp"
|
|
|
|
|
2020-03-16 23:07:41 +00:00
|
|
|
#include <array>
|
|
|
|
|
2019-12-22 20:04:07 +00:00
|
|
|
#include "Runtime/CDependencyGroup.hpp"
|
|
|
|
#include "Runtime/CSimplePool.hpp"
|
|
|
|
#include "Runtime/GameGlobalObjects.hpp"
|
|
|
|
#include "Runtime/Camera/CGameCamera.hpp"
|
|
|
|
#include "Runtime/Graphics/CSkinnedModel.hpp"
|
|
|
|
#include "Runtime/Graphics/CVertexMorphEffect.hpp"
|
|
|
|
#include "Runtime/Particle/CElementGen.hpp"
|
|
|
|
#include "Runtime/World/CPlayer.hpp"
|
|
|
|
|
2019-09-21 13:07:13 +00:00
|
|
|
#include "TCastTo.hpp" // Generated file, do not modify include path
|
2016-08-15 01:19:04 +00:00
|
|
|
|
2021-04-10 08:42:06 +00:00
|
|
|
namespace metaforce {
|
2016-08-15 01:19:04 +00:00
|
|
|
|
2017-09-04 02:22:46 +00:00
|
|
|
float CGrappleArm::g_GrappleBeamAnglePhaseDelta = 0.875f;
|
|
|
|
float CGrappleArm::g_GrappleBeamXWaveAmplitude = 0.25f;
|
|
|
|
float CGrappleArm::g_GrappleBeamZWaveAmplitude = 0.125f;
|
|
|
|
float CGrappleArm::g_GrappleBeamSpeed = 5.f;
|
|
|
|
|
|
|
|
CGrappleArm::CGrappleArm(const zeus::CVector3f& scale)
|
2018-12-08 05:30:43 +00:00
|
|
|
: x0_grappleArmModel(CAnimRes(g_tweakGunRes->x8_grappleArm, 0, scale, 41, false))
|
|
|
|
, xa0_grappleGearModel(CStaticRes(NWeaponTypes::get_asset_id_from_name("GrappleGear"), scale))
|
|
|
|
, xec_grapNoz1Model(CStaticRes(NWeaponTypes::get_asset_id_from_name("GrapNoz1"), scale))
|
|
|
|
, x138_grapNoz2Model(CStaticRes(NWeaponTypes::get_asset_id_from_name("GrapNoz2"), scale))
|
|
|
|
, x184_grappleArm(g_SimplePool->GetObj(SObjectTag{FOURCC('ANCS'), g_tweakGunRes->x8_grappleArm}))
|
|
|
|
, x31c_scale(scale)
|
|
|
|
, x354_grappleSegmentDesc(g_SimplePool->GetObj(SObjectTag{FOURCC('PART'), g_tweakGunRes->xb4_grappleSegment}))
|
|
|
|
, x360_grappleClawDesc(g_SimplePool->GetObj(SObjectTag{FOURCC('PART'), g_tweakGunRes->xb8_grappleClaw}))
|
|
|
|
, x36c_grappleHitDesc(g_SimplePool->GetObj(SObjectTag{FOURCC('PART'), g_tweakGunRes->xbc_grappleHit}))
|
|
|
|
, x378_grappleMuzzleDesc(g_SimplePool->GetObj(SObjectTag{FOURCC('PART'), g_tweakGunRes->xc0_grappleMuzzle}))
|
|
|
|
, x384_grappleSwooshDesc(g_SimplePool->GetObj(SObjectTag{FOURCC('SWHC'), g_tweakGunRes->xc4_grappleSwoosh}))
|
|
|
|
, x390_grappleSegmentGen(std::make_unique<CElementGen>(x354_grappleSegmentDesc))
|
|
|
|
, x394_grappleClawGen(std::make_unique<CElementGen>(x360_grappleClawDesc))
|
|
|
|
, x398_grappleHitGen(std::make_unique<CElementGen>(x36c_grappleHitDesc))
|
|
|
|
, x39c_grappleMuzzleGen(std::make_unique<CElementGen>(x378_grappleMuzzleDesc))
|
|
|
|
, x3a0_grappleSwooshGen(std::make_unique<CParticleSwoosh>(x384_grappleSwooshDesc, 0))
|
2020-04-20 04:57:50 +00:00
|
|
|
, x3a4_rainSplashGenerator(std::make_unique<CRainSplashGenerator>(scale, 20, 2, 0.f, 0.125f)) {
|
2018-12-08 05:30:43 +00:00
|
|
|
x0_grappleArmModel->SetSortThermal(true);
|
|
|
|
xa0_grappleGearModel.SetSortThermal(true);
|
|
|
|
xec_grapNoz1Model.SetSortThermal(true);
|
|
|
|
x138_grapNoz2Model.SetSortThermal(true);
|
|
|
|
|
|
|
|
g_GrappleBeamAnglePhaseDelta = g_tweakPlayer->GetGrappleBeamAnglePhaseDelta();
|
|
|
|
g_GrappleBeamXWaveAmplitude = g_tweakPlayer->GetGrappleBeamXWaveAmplitude();
|
|
|
|
g_GrappleBeamZWaveAmplitude = g_tweakPlayer->GetGrappleBeamZWaveAmplitude();
|
|
|
|
g_GrappleBeamSpeed = g_tweakPlayer->GetGrappleBeamSpeed();
|
|
|
|
|
|
|
|
x39c_grappleMuzzleGen->SetParticleEmission(false);
|
|
|
|
x390_grappleSegmentGen->SetParticleEmission(false);
|
|
|
|
x3a0_grappleSwooshGen->DoGrappleWarmup();
|
|
|
|
|
|
|
|
BuildSuitDependencyList();
|
|
|
|
LoadAnimations();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CGrappleArm::FillTokenVector(const std::vector<SObjectTag>& tags, std::vector<CToken>& objects) {
|
|
|
|
objects.reserve(tags.size());
|
|
|
|
for (const SObjectTag& tag : tags)
|
|
|
|
objects.push_back(g_SimplePool->GetObj(tag));
|
2017-09-04 02:22:46 +00:00
|
|
|
}
|
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
void CGrappleArm::BuildSuitDependencyList() {
|
2020-03-16 23:12:52 +00:00
|
|
|
static constexpr std::array dependencyNames{
|
2020-03-16 23:07:41 +00:00
|
|
|
"PowerSuit_DGRP"sv, "GravitySuit_DGRP"sv, "VariaSuit_DGRP"sv, "PhazonSuit_DGRP"sv,
|
|
|
|
"FusionSuit_DGRP"sv, "FusionSuitG_DGRP"sv, "FusionSuitV_DGRP"sv, "FusionSuitP_DGRP"sv,
|
|
|
|
};
|
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
x184_grappleArm.Lock();
|
2020-03-16 23:12:52 +00:00
|
|
|
for (const auto& name : dependencyNames) {
|
2018-12-08 05:30:43 +00:00
|
|
|
TLockedToken<CDependencyGroup> dgrp = g_SimplePool->GetObj(name);
|
2020-03-13 20:32:24 +00:00
|
|
|
std::vector<CToken>& depsOut = x19c_suitDeps.emplace_back();
|
2018-12-08 05:30:43 +00:00
|
|
|
FillTokenVector(dgrp->GetObjectTagVector(), depsOut);
|
|
|
|
}
|
2016-08-15 01:19:04 +00:00
|
|
|
}
|
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
void CGrappleArm::LoadAnimations() {
|
|
|
|
NWeaponTypes::get_token_vector(*x0_grappleArmModel->GetAnimationData(), 0, 42, x18c_anims, true);
|
2019-06-12 02:05:17 +00:00
|
|
|
x0_grappleArmModel = std::nullopt;
|
2016-08-15 01:19:04 +00:00
|
|
|
}
|
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
void CGrappleArm::AsyncLoadSuit(CStateManager& mgr) {
|
|
|
|
CPlayerState::EPlayerSuit suit = NWeaponTypes::get_current_suit(mgr);
|
|
|
|
if (suit == x3a8_loadedSuit)
|
|
|
|
return;
|
2017-07-17 03:04:14 +00:00
|
|
|
|
2019-06-12 02:05:17 +00:00
|
|
|
x0_grappleArmModel = std::nullopt;
|
2018-12-08 05:30:43 +00:00
|
|
|
x3b2_29_suitLoading = true;
|
|
|
|
if (x3a8_loadedSuit != CPlayerState::EPlayerSuit::Invalid) {
|
|
|
|
NWeaponTypes::unlock_tokens(x19c_suitDeps[int(x3a8_loadedSuit)]);
|
|
|
|
x19c_suitDeps[int(x3a8_loadedSuit)].clear();
|
|
|
|
}
|
2017-09-04 02:22:46 +00:00
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
if (suit < CPlayerState::EPlayerSuit::Power || suit > CPlayerState::EPlayerSuit::FusionPhazon)
|
|
|
|
x3a8_loadedSuit = CPlayerState::EPlayerSuit::Power;
|
|
|
|
else
|
|
|
|
x3a8_loadedSuit = suit;
|
2017-09-04 02:22:46 +00:00
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
NWeaponTypes::lock_tokens(x19c_suitDeps[int(x3a8_loadedSuit)]);
|
2017-09-04 02:22:46 +00:00
|
|
|
}
|
2017-07-18 06:11:37 +00:00
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
void CGrappleArm::ResetAuxParams(bool resetGunController) {
|
|
|
|
x3b2_24_active = false;
|
|
|
|
x3b2_27_armMoving = false;
|
2019-02-24 07:15:54 +00:00
|
|
|
x2e0_auxXf = zeus::CTransform();
|
2018-12-08 05:30:43 +00:00
|
|
|
if (resetGunController)
|
|
|
|
x328_gunController->Reset();
|
2017-07-18 06:11:37 +00:00
|
|
|
}
|
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
void CGrappleArm::DisconnectGrappleBeam() {
|
|
|
|
x394_grappleClawGen->SetParticleEmission(false);
|
|
|
|
x3b2_25_beamActive = false;
|
|
|
|
GrappleBeamDisconnected();
|
2017-07-18 06:11:37 +00:00
|
|
|
}
|
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
void CGrappleArm::SetAnimState(EArmState state) {
|
|
|
|
if (x334_animState == state)
|
|
|
|
return;
|
2017-07-31 05:19:05 +00:00
|
|
|
|
2019-08-14 14:58:54 +00:00
|
|
|
x0_grappleArmModel->GetAnimationData()->EnableLooping(false);
|
2018-12-08 05:30:43 +00:00
|
|
|
x3b2_28_isGrappling = true;
|
|
|
|
|
|
|
|
switch (state) {
|
|
|
|
case EArmState::IntoGrapple: {
|
|
|
|
ResetAuxParams(true);
|
2020-04-12 00:49:56 +00:00
|
|
|
constexpr CAnimPlaybackParms parms(0, -1, 1.f, true);
|
2019-08-14 14:58:54 +00:00
|
|
|
x0_grappleArmModel->GetAnimationData()->SetAnimation(parms, false);
|
2018-12-08 05:30:43 +00:00
|
|
|
x3b2_25_beamActive = false;
|
|
|
|
x3b2_24_active = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case EArmState::IntoGrappleIdle: {
|
2020-04-12 00:49:56 +00:00
|
|
|
constexpr CAnimPlaybackParms parms(1, -1, 1.f, true);
|
2019-08-14 14:58:54 +00:00
|
|
|
x0_grappleArmModel->GetAnimationData()->EnableLooping(true);
|
|
|
|
x0_grappleArmModel->GetAnimationData()->SetAnimation(parms, false);
|
2018-12-08 05:30:43 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case EArmState::FireGrapple: {
|
2020-04-12 00:49:56 +00:00
|
|
|
constexpr CAnimPlaybackParms parms(2, -1, 1.f, true);
|
2019-08-14 14:58:54 +00:00
|
|
|
x0_grappleArmModel->GetAnimationData()->SetAnimation(parms, false);
|
2018-12-08 05:30:43 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case EArmState::ConnectGrapple: {
|
2020-04-12 00:49:56 +00:00
|
|
|
constexpr CAnimPlaybackParms parms(3, -1, 1.f, true);
|
2019-08-14 14:58:54 +00:00
|
|
|
x0_grappleArmModel->GetAnimationData()->SetAnimation(parms, false);
|
2018-12-08 05:30:43 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case EArmState::Connected: {
|
2020-04-12 00:49:56 +00:00
|
|
|
constexpr CAnimPlaybackParms parms(3, -1, 1.f, true);
|
2019-08-14 14:58:54 +00:00
|
|
|
x0_grappleArmModel->GetAnimationData()->SetAnimation(parms, false);
|
2018-12-08 05:30:43 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case EArmState::OutOfGrapple: {
|
2020-04-12 00:49:56 +00:00
|
|
|
constexpr CAnimPlaybackParms parms(4, -1, 1.f, true);
|
2019-08-14 14:58:54 +00:00
|
|
|
x0_grappleArmModel->GetAnimationData()->SetAnimation(parms, false);
|
2018-12-08 05:30:43 +00:00
|
|
|
DisconnectGrappleBeam();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case EArmState::Done:
|
|
|
|
x3b2_28_isGrappling = false;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
x334_animState = state;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CGrappleArm::Activate(bool intoGrapple) {
|
|
|
|
SetAnimState(intoGrapple ? EArmState::IntoGrapple : EArmState::OutOfGrapple);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CGrappleArm::GrappleBeamDisconnected() {
|
|
|
|
if (x32c_grappleLoopSfx) {
|
|
|
|
CSfxManager::SfxStop(x32c_grappleLoopSfx);
|
|
|
|
x32c_grappleLoopSfx.reset();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CGrappleArm::GrappleBeamConnected() {
|
|
|
|
if (!x32c_grappleLoopSfx)
|
|
|
|
x32c_grappleLoopSfx = NWeaponTypes::play_sfx(SFXsam_grapple_lp, false, true, -0.15f);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CGrappleArm::RenderGrappleBeam(const CStateManager& mgr, const zeus::CVector3f& pos) {
|
2020-04-23 05:54:54 +00:00
|
|
|
if (!x3b2_24_active || x3b2_29_suitLoading) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const zeus::CTransform tmpXf = zeus::CTransform::Translate(pos) * x220_xf;
|
|
|
|
if (!x3b2_25_beamActive) {
|
|
|
|
return;
|
2018-12-08 05:30:43 +00:00
|
|
|
}
|
2020-04-23 05:54:54 +00:00
|
|
|
|
|
|
|
if (x3b2_26_grappleHit) {
|
|
|
|
x398_grappleHitGen->Render();
|
|
|
|
}
|
|
|
|
|
|
|
|
x394_grappleClawGen->Render();
|
|
|
|
x3a0_grappleSwooshGen->Render();
|
|
|
|
x390_grappleSegmentGen->Render();
|
|
|
|
const zeus::CTransform backupViewMtx = CGraphics::g_ViewMatrix;
|
|
|
|
CGraphics::SetViewPointMatrix(tmpXf.inverse() * backupViewMtx);
|
|
|
|
CGraphics::SetModelMatrix(zeus::CTransform());
|
|
|
|
x39c_grappleMuzzleGen->Render();
|
|
|
|
CGraphics::SetViewPointMatrix(backupViewMtx);
|
2018-12-08 05:30:43 +00:00
|
|
|
}
|
|
|
|
|
2022-02-25 07:45:25 +00:00
|
|
|
void CGrappleArm::TouchModel(const CStateManager& mgr) {
|
2020-04-23 05:54:54 +00:00
|
|
|
if (!x3b2_24_active || x3b2_29_suitLoading) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
x0_grappleArmModel->Touch(mgr, 0);
|
|
|
|
if (x50_grappleArmSkeletonModel) {
|
|
|
|
x50_grappleArmSkeletonModel->Touch(mgr, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mgr.GetPlayerState()->HasPowerUp(CPlayerState::EItemType::GrappleBeam)) {
|
|
|
|
xa0_grappleGearModel.Touch(mgr, 0);
|
|
|
|
xec_grapNoz1Model.Touch(mgr, 0);
|
|
|
|
x138_grapNoz2Model.Touch(mgr, 0);
|
2018-12-08 05:30:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CGrappleArm::LoadSuitPoll() {
|
2020-04-23 05:54:54 +00:00
|
|
|
if (!NWeaponTypes::are_tokens_ready(x19c_suitDeps[size_t(x3a8_loadedSuit)])) {
|
|
|
|
return;
|
2018-12-08 05:30:43 +00:00
|
|
|
}
|
2020-04-23 05:54:54 +00:00
|
|
|
|
|
|
|
x0_grappleArmModel.emplace(CAnimRes(g_tweakGunRes->x8_grappleArm, int(x3a8_loadedSuit), x31c_scale, 41, false));
|
|
|
|
x0_grappleArmModel->SetSortThermal(true);
|
|
|
|
x328_gunController = std::make_unique<CGunController>(*x0_grappleArmModel);
|
|
|
|
x3b2_29_suitLoading = false;
|
2017-09-04 02:22:46 +00:00
|
|
|
}
|
2017-08-25 06:18:09 +00:00
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
void CGrappleArm::BuildXRayModel() {
|
|
|
|
x50_grappleArmSkeletonModel.emplace(CAnimRes(g_tweakGunRes->x8_grappleArm, 8, x31c_scale,
|
|
|
|
!x328_gunController ? 41 : x328_gunController->GetCurAnimId(), false));
|
|
|
|
x50_grappleArmSkeletonModel->SetSortThermal(true);
|
2017-08-25 06:18:09 +00:00
|
|
|
}
|
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
void CGrappleArm::DoUserAnimEvent(CStateManager& mgr, const CInt32POINode& node, EUserEventType type) {
|
|
|
|
switch (type) {
|
|
|
|
case EUserEventType::Projectile:
|
|
|
|
if (x3b2_27_armMoving)
|
|
|
|
return;
|
|
|
|
x3b2_25_beamActive = true;
|
|
|
|
x398_grappleHitGen = std::make_unique<CElementGen>(x36c_grappleHitDesc);
|
|
|
|
x39c_grappleMuzzleGen = std::make_unique<CElementGen>(x378_grappleMuzzleDesc);
|
|
|
|
x338_beamT = 0.f;
|
|
|
|
x33c_beamDist = 0.f;
|
|
|
|
x340_anglePhase = 0.f;
|
|
|
|
x344_xAmplitude = g_GrappleBeamXWaveAmplitude;
|
|
|
|
x348_zAmplitude = g_GrappleBeamZWaveAmplitude;
|
|
|
|
x398_grappleHitGen->SetParticleEmission(false);
|
|
|
|
x394_grappleClawGen->SetParticleEmission(true);
|
|
|
|
NWeaponTypes::play_sfx(SFXsam_grapple_fire, false, false, -0.15f);
|
|
|
|
mgr.GetRumbleManager().Rumble(mgr, ERumbleFxId::PlayerGrappleFire, 1.f, ERumblePriority::Three);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CGrappleArm::DoUserAnimEvents(CStateManager& mgr) {
|
|
|
|
zeus::CVector3f armToCam = mgr.GetCameraManager()->GetCurrentCamera(mgr)->GetTranslation() - x220_xf.origin;
|
|
|
|
const CAnimData& animData = *x0_grappleArmModel->GetAnimationData();
|
2020-03-16 23:07:41 +00:00
|
|
|
for (size_t i = 0; i < animData.GetPassedSoundPOICount(); ++i) {
|
2018-12-08 05:30:43 +00:00
|
|
|
const CSoundPOINode& node = CAnimData::g_SoundPOINodes[i];
|
|
|
|
if (node.GetPoiType() != EPOIType::Sound ||
|
|
|
|
(node.GetCharacterIndex() != -1 && animData.x204_charIdx != node.GetCharacterIndex()))
|
|
|
|
continue;
|
|
|
|
NWeaponTypes::do_sound_event(x34c_animSfx, x3ac_pitchBend, false, node.GetSfxId(), node.GetWeight(),
|
|
|
|
node.GetFlags(), node.GetFalloff(), node.GetMaxDist(), 0.16f, 1.f, armToCam,
|
|
|
|
x220_xf.origin, mgr.GetPlayer().GetAreaIdAlways(), mgr);
|
|
|
|
}
|
2020-03-16 23:07:41 +00:00
|
|
|
for (size_t i = 0; i < animData.GetPassedIntPOICount(); ++i) {
|
2018-12-08 05:30:43 +00:00
|
|
|
const CInt32POINode& node = CAnimData::g_Int32POINodes[i];
|
|
|
|
switch (node.GetPoiType()) {
|
|
|
|
case EPOIType::UserEvent:
|
|
|
|
DoUserAnimEvent(mgr, node, EUserEventType(node.GetValue()));
|
|
|
|
break;
|
|
|
|
case EPOIType::SoundInt32:
|
|
|
|
if (node.GetCharacterIndex() != -1 && animData.x204_charIdx != node.GetCharacterIndex())
|
2017-09-04 02:22:46 +00:00
|
|
|
break;
|
2018-12-08 05:30:43 +00:00
|
|
|
NWeaponTypes::do_sound_event(x34c_animSfx, x3ac_pitchBend, false, u32(node.GetValue()), node.GetWeight(),
|
|
|
|
node.GetFlags(), 0.1f, 150.f, 0.16f, 1.f, armToCam, x220_xf.origin,
|
|
|
|
mgr.GetPlayer().GetAreaIdAlways(), mgr);
|
|
|
|
break;
|
2017-09-04 02:22:46 +00:00
|
|
|
default:
|
2018-12-08 05:30:43 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CGrappleArm::UpdateArmMovement(float dt, CStateManager& mgr) {
|
|
|
|
DoUserAnimEvents(mgr);
|
|
|
|
if (x328_gunController->Update(dt, mgr))
|
|
|
|
ResetAuxParams(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CGrappleArm::UpdateGrappleBeamFx(const zeus::CVector3f& beamGunPos, const zeus::CVector3f& beamAirPos,
|
|
|
|
CStateManager& mgr) {
|
|
|
|
x394_grappleClawGen->SetTranslation(beamAirPos);
|
|
|
|
x390_grappleSegmentGen->SetParticleEmission(true);
|
|
|
|
|
|
|
|
zeus::CVector3f segmentDelta = beamAirPos - beamGunPos;
|
|
|
|
zeus::CVector3f swooshSegmentDelta = segmentDelta * 0.02f;
|
|
|
|
int numSegments = int(2.f * segmentDelta.magnitude() + 1.f);
|
|
|
|
segmentDelta = (1.f / float(numSegments)) * segmentDelta;
|
|
|
|
|
|
|
|
zeus::CVector3f segmentPos = beamGunPos;
|
|
|
|
zeus::CTransform rotation = x220_xf.getRotation();
|
|
|
|
for (int i = 0; i < numSegments; ++i) {
|
|
|
|
zeus::CVector3f vec;
|
|
|
|
if (i > 0)
|
|
|
|
vec = rotation *
|
|
|
|
zeus::CVector3f(std::cos(i + x340_anglePhase) * x344_xAmplitude, 0.f, std::sin(float(i)) * x348_zAmplitude);
|
|
|
|
x390_grappleSegmentGen->SetTranslation(vec * segmentPos);
|
|
|
|
x390_grappleSegmentGen->ForceParticleCreation(1);
|
|
|
|
segmentPos += segmentDelta;
|
|
|
|
}
|
|
|
|
|
|
|
|
x390_grappleSegmentGen->SetParticleEmission(false);
|
|
|
|
x3a0_grappleSwooshGen->DoGrappleUpdate(beamGunPos, rotation, x340_anglePhase, x344_xAmplitude, x348_zAmplitude,
|
|
|
|
swooshSegmentDelta);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CGrappleArm::UpdateGrappleBeam(float dt, const zeus::CTransform& beamLoc, CStateManager& mgr) {
|
|
|
|
bool beamConnected = false;
|
|
|
|
if (TCastToConstPtr<CActor> act = mgr.GetObjectById(mgr.GetPlayer().GetOrbitTargetId()))
|
|
|
|
x310_grapplePointPos = act->GetTranslation();
|
|
|
|
else
|
|
|
|
x310_grapplePointPos = x220_xf.origin;
|
|
|
|
|
|
|
|
zeus::CVector3f beamGunPos = (x220_xf * beamLoc).origin;
|
|
|
|
zeus::CVector3f beamAirPos = beamGunPos * (1.f - x338_beamT) + x310_grapplePointPos * x338_beamT;
|
|
|
|
|
|
|
|
switch (x334_animState) {
|
|
|
|
case EArmState::FireGrapple:
|
|
|
|
case EArmState::Three: {
|
|
|
|
float gunToPointMag = (x310_grapplePointPos - beamGunPos).magnitude();
|
|
|
|
if (gunToPointMag > 0.f)
|
|
|
|
x338_beamT = x33c_beamDist / gunToPointMag;
|
|
|
|
else
|
|
|
|
x338_beamT = 1.f;
|
|
|
|
float speedMult = mgr.GetPlayer().GetPlayerMovementState() != CPlayer::EPlayerMovementState::OnGround ? 2.f : 1.f;
|
|
|
|
x33c_beamDist += speedMult * (dt * g_GrappleBeamSpeed);
|
|
|
|
if (x338_beamT >= 1.f) {
|
|
|
|
x338_beamT = 1.f;
|
|
|
|
beamConnected = true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case EArmState::ConnectGrapple: {
|
|
|
|
float delta = 4.f * dt;
|
|
|
|
x344_xAmplitude -= delta;
|
|
|
|
x348_zAmplitude -= delta;
|
|
|
|
if (x344_xAmplitude < 0.f)
|
|
|
|
x344_xAmplitude = 0.f;
|
|
|
|
if (x348_zAmplitude < 0.f)
|
|
|
|
x348_zAmplitude = 0.f;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (x3b2_25_beamActive) {
|
|
|
|
x340_anglePhase += g_GrappleBeamAnglePhaseDelta;
|
|
|
|
UpdateGrappleBeamFx(beamGunPos, beamAirPos, mgr);
|
|
|
|
x394_grappleClawGen->Update(dt);
|
|
|
|
x390_grappleSegmentGen->Update(dt);
|
|
|
|
}
|
|
|
|
|
|
|
|
return beamConnected;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CGrappleArm::UpdateSwingAction(float grappleSwingT, float dt, CStateManager& mgr) {
|
|
|
|
if (x3b2_29_suitLoading)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (x334_animState == EArmState::FireGrapple)
|
2017-09-04 02:22:46 +00:00
|
|
|
DoUserAnimEvents(mgr);
|
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
zeus::CTransform beamLocXf = x0_grappleArmModel->GetScaledLocatorTransform("LGBeam");
|
|
|
|
bool grappleConnected = UpdateGrappleBeam(dt, beamLocXf, mgr);
|
2017-09-04 02:22:46 +00:00
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
if ((grappleSwingT > 0.175f && grappleSwingT < 0.3f) || (grappleSwingT > 0.7f && grappleSwingT < 0.9f)) {
|
|
|
|
if (!CSfxManager::IsPlaying(x330_swooshSfx)) {
|
|
|
|
x330_swooshSfx = NWeaponTypes::play_sfx(SFXsam_grapple_swoosh, false, false, -0.15f);
|
|
|
|
if (x3b0_rumbleHandle != -1)
|
|
|
|
mgr.GetRumbleManager().StopRumble(x3b0_rumbleHandle);
|
|
|
|
x3b0_rumbleHandle =
|
|
|
|
mgr.GetRumbleManager().Rumble(mgr, ERumbleFxId::PlayerGrappleSwoosh, 1.f, ERumblePriority::Three);
|
|
|
|
}
|
|
|
|
}
|
2017-09-04 02:22:46 +00:00
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
if (!x0_grappleArmModel->GetAnimationData()->IsAnimTimeRemaining(dt, "Whole Body")) {
|
|
|
|
switch (x334_animState) {
|
|
|
|
case EArmState::IntoGrapple:
|
|
|
|
case EArmState::Seven:
|
|
|
|
SetAnimState(EArmState::IntoGrappleIdle);
|
|
|
|
break;
|
2017-09-04 02:22:46 +00:00
|
|
|
case EArmState::FireGrapple:
|
2018-12-08 05:30:43 +00:00
|
|
|
if (grappleConnected) {
|
|
|
|
SetAnimState(EArmState::ConnectGrapple);
|
|
|
|
x3b2_26_grappleHit = true;
|
|
|
|
x398_grappleHitGen->SetParticleEmission(true);
|
|
|
|
GrappleBeamConnected();
|
|
|
|
if (x3b0_rumbleHandle != -1)
|
|
|
|
mgr.GetRumbleManager().StopRumble(x3b0_rumbleHandle);
|
|
|
|
}
|
|
|
|
break;
|
2017-09-04 02:22:46 +00:00
|
|
|
case EArmState::ConnectGrapple:
|
2018-12-08 05:30:43 +00:00
|
|
|
if (x344_xAmplitude == 0.f)
|
|
|
|
SetAnimState(EArmState::Connected);
|
|
|
|
break;
|
|
|
|
case EArmState::OutOfGrapple:
|
|
|
|
if (x3b0_rumbleHandle != -1)
|
|
|
|
mgr.GetRumbleManager().StopRumble(x3b0_rumbleHandle);
|
|
|
|
SetAnimState(EArmState::Done);
|
|
|
|
x3b2_24_active = false;
|
|
|
|
break;
|
2017-09-04 02:22:46 +00:00
|
|
|
default:
|
2018-12-08 05:30:43 +00:00
|
|
|
break;
|
2017-09-04 02:22:46 +00:00
|
|
|
}
|
2018-12-08 05:30:43 +00:00
|
|
|
}
|
2017-09-04 02:22:46 +00:00
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
if (x3b2_25_beamActive) {
|
|
|
|
x39c_grappleMuzzleGen->SetTranslation(beamLocXf.origin);
|
|
|
|
x39c_grappleMuzzleGen->Update(dt);
|
|
|
|
if (x3b2_26_grappleHit) {
|
|
|
|
x3b2_26_grappleHit = !x398_grappleHitGen->IsSystemDeletable();
|
|
|
|
x398_grappleHitGen->SetTranslation(x310_grapplePointPos);
|
|
|
|
x398_grappleHitGen->Update(dt);
|
2017-09-04 02:22:46 +00:00
|
|
|
}
|
2018-12-08 05:30:43 +00:00
|
|
|
}
|
2017-09-04 02:22:46 +00:00
|
|
|
}
|
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
void CGrappleArm::Update(float grappleSwingT, float dt, CStateManager& mgr) {
|
|
|
|
if (!(x3b2_24_active && !x3b2_29_suitLoading)) {
|
2017-09-04 02:22:46 +00:00
|
|
|
if (x3b2_29_suitLoading)
|
2018-12-08 05:30:43 +00:00
|
|
|
LoadSuitPoll();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mgr.GetPlayerState()->GetCurrentVisor() == CPlayerState::EPlayerVisor::XRay) {
|
|
|
|
if (!x50_grappleArmSkeletonModel)
|
|
|
|
BuildXRayModel();
|
|
|
|
} else {
|
|
|
|
if (x50_grappleArmSkeletonModel)
|
2019-06-12 02:05:17 +00:00
|
|
|
x50_grappleArmSkeletonModel = std::nullopt;
|
2018-12-08 05:30:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
float speed = 1.f;
|
|
|
|
if (!x3b2_27_armMoving)
|
|
|
|
speed = (mgr.GetPlayer().GetPlayerMovementState() != CPlayer::EPlayerMovementState::OnGround &&
|
|
|
|
x334_animState != EArmState::OutOfGrapple)
|
|
|
|
? 4.f
|
|
|
|
: 1.f;
|
|
|
|
x0_grappleArmModel->AdvanceAnimation(speed * dt, mgr, kInvalidAreaId, true);
|
|
|
|
if (mgr.GetPlayerState()->HasPowerUp(CPlayerState::EItemType::GrappleBeam)) {
|
|
|
|
x250_grapLocatorXf = x0_grappleArmModel->GetScaledLocatorTransformDynamic("grapLocator_SDK", nullptr);
|
|
|
|
x280_grapNozLoc1Xf = x0_grappleArmModel->GetScaledLocatorTransform("gNozLoc1_SDK");
|
|
|
|
x2b0_grapNozLoc2Xf = x0_grappleArmModel->GetScaledLocatorTransform("gNozLoc1_SDK");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (x3b2_27_armMoving)
|
|
|
|
UpdateArmMovement(dt, mgr);
|
|
|
|
else
|
|
|
|
UpdateSwingAction(grappleSwingT, dt, mgr);
|
|
|
|
|
|
|
|
if (x3a4_rainSplashGenerator)
|
|
|
|
x3a4_rainSplashGenerator->Update(dt, mgr);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CGrappleArm::PreRender(const CStateManager& mgr, const zeus::CFrustum& frustum, const zeus::CVector3f& camPos) {
|
2020-04-23 05:54:54 +00:00
|
|
|
if (!x3b2_24_active || x3b2_29_suitLoading) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
x0_grappleArmModel->GetAnimationData()->PreRender();
|
|
|
|
if (x50_grappleArmSkeletonModel) {
|
|
|
|
x50_grappleArmSkeletonModel->GetAnimationData()->PreRender();
|
2018-12-08 05:30:43 +00:00
|
|
|
}
|
|
|
|
}
|
2017-09-04 02:22:46 +00:00
|
|
|
|
2020-03-16 23:51:13 +00:00
|
|
|
void CGrappleArm::RenderXRayModel(const CStateManager& mgr, const zeus::CTransform& modelXf, const CModelFlags& flags) {
|
2018-12-08 05:30:43 +00:00
|
|
|
CGraphics::SetModelMatrix(modelXf * zeus::CTransform::Scale(x0_grappleArmModel->GetScale()));
|
2022-02-25 07:45:25 +00:00
|
|
|
// TODO
|
2018-12-08 05:30:43 +00:00
|
|
|
// CGraphics::DisableAllLights();
|
2019-02-24 07:15:54 +00:00
|
|
|
// g_Renderer->SetAmbientColor(zeus::skWhite);
|
2020-04-10 00:18:43 +00:00
|
|
|
CSkinnedModel& model = *x50_grappleArmSkeletonModel->GetAnimationData()->GetModelData();
|
2022-02-25 07:45:25 +00:00
|
|
|
// model.GetModelInst()->ActivateLights({CLight::BuildLocalAmbient({}, zeus::skWhite)});
|
2020-04-05 12:15:45 +00:00
|
|
|
x0_grappleArmModel->GetAnimationData()->Render(model, flags, std::nullopt, nullptr);
|
2019-02-24 07:15:54 +00:00
|
|
|
// g_Renderer->SetAmbientColor(zeus::skWhite);
|
2018-12-08 05:30:43 +00:00
|
|
|
// CGraphics::DisableAllLights();
|
|
|
|
}
|
2017-09-04 02:22:46 +00:00
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
void CGrappleArm::PointGenerator(void* ctx, const std::vector<std::pair<zeus::CVector3f, zeus::CVector3f>>& vn) {
|
2020-03-16 23:16:43 +00:00
|
|
|
static_cast<CRainSplashGenerator*>(ctx)->GeneratePoints(vn);
|
2017-09-04 02:22:46 +00:00
|
|
|
}
|
2017-08-31 02:42:37 +00:00
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
void CGrappleArm::Render(const CStateManager& mgr, const zeus::CVector3f& pos, const CModelFlags& flags,
|
2020-03-16 23:51:13 +00:00
|
|
|
const CActorLights* lights) {
|
2020-04-23 05:54:54 +00:00
|
|
|
if (!x3b2_24_active || x3b2_29_suitLoading) {
|
|
|
|
return;
|
|
|
|
}
|
2017-09-04 02:22:46 +00:00
|
|
|
|
2020-04-23 05:54:54 +00:00
|
|
|
SCOPED_GRAPHICS_DEBUG_GROUP("CGrappleArm::Render", zeus::skOrange);
|
|
|
|
const zeus::CTransform modelXf = zeus::CTransform::Translate(pos) * x220_xf * x2e0_auxXf;
|
|
|
|
if (x50_grappleArmSkeletonModel) {
|
|
|
|
RenderXRayModel(mgr, modelXf, flags);
|
|
|
|
}
|
2017-09-04 02:22:46 +00:00
|
|
|
|
2020-04-23 05:54:54 +00:00
|
|
|
CModelFlags useFlags;
|
|
|
|
const CActorLights* useLights;
|
|
|
|
if (mgr.GetPlayerState()->GetCurrentVisor() == CPlayerState::EPlayerVisor::XRay) {
|
|
|
|
useFlags = CModelFlags(5, 0, 3, zeus::CColor(1.f, 0.25f));
|
|
|
|
useLights = nullptr;
|
|
|
|
} else {
|
|
|
|
useFlags = flags;
|
|
|
|
useLights = lights;
|
|
|
|
}
|
2017-09-04 02:22:46 +00:00
|
|
|
|
2020-04-23 05:54:54 +00:00
|
|
|
if (x3a4_rainSplashGenerator && x3a4_rainSplashGenerator->IsRaining()) {
|
|
|
|
CSkinnedModel::SetPointGeneratorFunc(x3a4_rainSplashGenerator.get(), PointGenerator);
|
|
|
|
}
|
2017-08-25 06:18:09 +00:00
|
|
|
|
2020-04-23 05:54:54 +00:00
|
|
|
x0_grappleArmModel->Render(mgr, modelXf, useLights, useFlags);
|
|
|
|
|
|
|
|
if (x3a4_rainSplashGenerator && x3a4_rainSplashGenerator->IsRaining()) {
|
|
|
|
CSkinnedModel::ClearPointGeneratorFunc();
|
|
|
|
x3a4_rainSplashGenerator->Draw(modelXf);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mgr.GetPlayerState()->HasPowerUp(CPlayerState::EItemType::GrappleBeam)) {
|
|
|
|
xa0_grappleGearModel.Render(mgr, modelXf * x250_grapLocatorXf, useLights, useFlags);
|
|
|
|
xec_grapNoz1Model.Render(mgr, modelXf * x280_grapNozLoc1Xf, useLights, useFlags);
|
|
|
|
x138_grapNoz2Model.Render(mgr, modelXf * x2b0_grapNozLoc2Xf, useLights, useFlags);
|
2018-12-08 05:30:43 +00:00
|
|
|
}
|
2017-09-04 02:22:46 +00:00
|
|
|
}
|
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
void CGrappleArm::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId sender, CStateManager& mgr) {
|
|
|
|
if (msg == EScriptObjectMessage::Registered)
|
|
|
|
AsyncLoadSuit(mgr);
|
2017-09-04 02:22:46 +00:00
|
|
|
}
|
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
void CGrappleArm::EnterStruck(CStateManager& mgr, float angle, bool bigStrike, bool notInFreeLook) {
|
|
|
|
if (x3b2_29_suitLoading)
|
|
|
|
return;
|
2017-09-04 02:22:46 +00:00
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
if (x3b2_28_isGrappling) {
|
|
|
|
DisconnectGrappleBeam();
|
|
|
|
x3b2_28_isGrappling = false;
|
|
|
|
}
|
2017-09-04 02:22:46 +00:00
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
if (!x3b2_27_armMoving) {
|
|
|
|
x3b2_24_active = true;
|
|
|
|
x3b2_27_armMoving = true;
|
|
|
|
x334_animState = EArmState::GunControllerAnimation;
|
|
|
|
}
|
2017-09-04 02:22:46 +00:00
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
x328_gunController->EnterStruck(mgr, angle, bigStrike, notInFreeLook);
|
2017-08-25 06:18:09 +00:00
|
|
|
}
|
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
void CGrappleArm::EnterIdle(CStateManager& mgr) {
|
|
|
|
if (x3b2_29_suitLoading)
|
|
|
|
return;
|
2017-08-25 06:18:09 +00:00
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
x328_gunController->EnterIdle(mgr);
|
2017-08-25 06:18:09 +00:00
|
|
|
}
|
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
void CGrappleArm::EnterFidget(CStateManager& mgr, SamusGun::EFidgetType type, s32 gunId, s32 animSet) {
|
|
|
|
if (x3b2_29_suitLoading)
|
|
|
|
return;
|
2017-08-27 03:02:18 +00:00
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
x3b2_24_active = true;
|
|
|
|
x3b2_27_armMoving = true;
|
|
|
|
x334_animState = EArmState::GunControllerAnimation;
|
2017-09-04 02:22:46 +00:00
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
x328_gunController->EnterFidget(mgr, s32(type), gunId, animSet);
|
2017-08-27 03:02:18 +00:00
|
|
|
}
|
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
void CGrappleArm::EnterFreeLook(s32 gunId, s32 setId, CStateManager& mgr) {
|
|
|
|
if (x3b2_29_suitLoading)
|
|
|
|
return;
|
2017-09-04 02:22:46 +00:00
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
x3b2_24_active = true;
|
|
|
|
x3b2_27_armMoving = true;
|
|
|
|
x334_animState = EArmState::GunControllerAnimation;
|
2017-08-27 03:02:18 +00:00
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
x328_gunController->EnterFreeLook(mgr, gunId, setId);
|
2017-08-27 03:02:18 +00:00
|
|
|
}
|
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
void CGrappleArm::EnterComboFire(s32 gunId, CStateManager& mgr) {
|
|
|
|
if (x3b2_29_suitLoading)
|
|
|
|
return;
|
2017-09-04 02:22:46 +00:00
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
x3b2_24_active = true;
|
|
|
|
x3b2_27_armMoving = true;
|
|
|
|
x334_animState = EArmState::GunControllerAnimation;
|
2017-09-02 04:06:05 +00:00
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
x328_gunController->EnterComboFire(mgr, gunId);
|
2017-09-02 04:06:05 +00:00
|
|
|
}
|
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
void CGrappleArm::ReturnToDefault(CStateManager& mgr, float dt, bool setState) {
|
|
|
|
if (x3b2_29_suitLoading)
|
|
|
|
return;
|
2017-08-26 04:36:25 +00:00
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
x328_gunController->ReturnToDefault(mgr, dt, setState);
|
2017-08-26 04:36:25 +00:00
|
|
|
}
|
|
|
|
|
2021-04-10 08:42:06 +00:00
|
|
|
} // namespace metaforce
|