metaforce/Runtime/GuiSys/CCompoundTargetReticle.cpp

1074 lines
47 KiB
C++

#include <cstdlib>
#include "CCompoundTargetReticle.hpp"
#include "GameGlobalObjects.hpp"
#include "Camera/CGameCamera.hpp"
#include "CSimplePool.hpp"
#include "CStateManager.hpp"
#include "TCastTo.hpp"
#include "World/CScriptGrapplePoint.hpp"
#include "World/CPlayer.hpp"
#include "World/CWorld.hpp"
namespace urde
{
const CTargetReticleRenderState CTargetReticleRenderState::skZeroRenderState(kInvalidUniqueId, 1.f,
zeus::CVector3f::skZero, 0.f, 1.f, true);
static float offshoot_func(float f1, float f2, float f3) { return (f1 * 0.5f) + zeus::fastSinF((f3 - 0.5f) * f2); }
static float calculate_premultiplied_overshoot_offset(float f1) { return 2.f * (M_PIF - std::asin(1.f / f1)); }
CCompoundTargetReticle::SOuterItemInfo::SOuterItemInfo(const char* res) : x0_model(g_SimplePool->GetObj(res)) {}
CCompoundTargetReticle::CCompoundTargetReticle(const CStateManager& mgr)
: x0_leadingOrientation(mgr.GetCameraManager()->GetCurrentCamera(mgr)->GetTransform().buildMatrix3f())
, x10_laggingOrientation(mgr.GetCameraManager()->GetCurrentCamera(mgr)->GetTransform().buildMatrix3f())
, x2c_overshootOffsetHalf(0.5f * g_tweakTargeting->GetChargeGaugeOvershootOffset())
, x30_premultOvershootOffset(
calculate_premultiplied_overshoot_offset(g_tweakTargeting->GetChargeGaugeOvershootOffset()))
, x34_crosshairs(g_SimplePool->GetObj(skCrosshairsReticleAssetName))
, x40_seeker(g_SimplePool->GetObj(skSeekerAssetName))
, x4c_lockConfirm(g_SimplePool->GetObj(skLockConfirmAssetName))
, x58_targetFlower(g_SimplePool->GetObj(skTargetFlowerAssetName))
, x64_missileBracket(g_SimplePool->GetObj(skMissileBracketAssetName))
, x70_innerBeamIcon(g_SimplePool->GetObj(skInnerBeamIconName))
, x7c_lockFire(g_SimplePool->GetObj(skLockFireAssetName))
, x88_lockDagger(g_SimplePool->GetObj(skLockDaggerAssetName))
, x94_grapple(g_SimplePool->GetObj(skGrappleReticleAssetName))
, xa0_chargeTickFirst(g_SimplePool->GetObj(skChargeBeamTickAssetName))
, xac_xrayRetRing(g_SimplePool->GetObj(skXRayRingModelName))
, xb8_thermalReticle(g_SimplePool->GetObj(skThermalReticleAssetName))
, xc4_chargeGauge(skChargeGaugeAssetName)
, xf4_targetPos(CalculateOrbitZoneReticlePosition(mgr, false))
, x100_laggingTargetPos(CalculateOrbitZoneReticlePosition(mgr, true))
, x208_lockonTimer(g_tweakTargeting->GetLockonDuration())
{
xe0_outerBeamIconSquares.reserve(9);
for (u32 i = 0; i < 9; ++i)
{
char name[1024];
sprintf(name, "%s%d", skOuterBeamIconSquareNameBase, i);
xe0_outerBeamIconSquares.emplace_back(name);
}
x34_crosshairs.Lock();
}
CCompoundTargetReticle::SScanReticuleRenderer::SScanReticuleRenderer()
{
CGraphics::CommitResources([this](boo::IGraphicsDataFactory::Context& ctx)
{
for (int i=0 ; i<2 ; ++i)
{
m_lineRenderers[i].emplace(ctx, CLineRenderer::EPrimitiveMode::Lines, 8, nullptr, true, true);
for (int j=0 ; j<4 ; ++j)
m_stripRenderers[i][j].emplace(ctx, CLineRenderer::EPrimitiveMode::LineStrip, 4, nullptr, true, true);
}
return true;
});
}
CCompoundTargetReticle::EReticleState CCompoundTargetReticle::GetDesiredReticleState(const CStateManager& mgr) const
{
switch (mgr.GetPlayerState()->GetCurrentVisor())
{
case CPlayerState::EPlayerVisor::Scan:
return EReticleState::Scan;
case CPlayerState::EPlayerVisor::XRay:
return EReticleState::XRay;
case CPlayerState::EPlayerVisor::Combat:
default:
return EReticleState::Combat;
case CPlayerState::EPlayerVisor::Thermal:
return EReticleState::Thermal;
}
}
void CCompoundTargetReticle::Update(float dt, const CStateManager& mgr)
{
float angle = x10_laggingOrientation.angleFrom(x0_leadingOrientation).asDegrees();
float t;
if (angle < 0.1f || angle > 45.f)
t = 1.f;
else
t = std::min(1.f, g_tweakTargeting->GetAngularLagSpeed() * dt / angle);
x10_laggingOrientation = t == 1.f ? x0_leadingOrientation :
zeus::CQuaternion::slerp(x10_laggingOrientation, x0_leadingOrientation, t);
xf4_targetPos = CalculateOrbitZoneReticlePosition(mgr, false);
x100_laggingTargetPos = CalculateOrbitZoneReticlePosition(mgr, true);
UpdateCurrLockOnGroup(dt, mgr);
UpdateNextLockOnGroup(dt, mgr);
UpdateOrbitZoneGroup(dt, mgr);
EReticleState desiredState = GetDesiredReticleState(mgr);
if (desiredState != x20_prevState && x20_prevState == x24_nextState)
{
x24_nextState = desiredState;
x28_noDrawTicks = 2;
}
if (x20_prevState != x24_nextState && x28_noDrawTicks <= 0)
{
x20_prevState = x24_nextState;
float combat = false;
float scan = false;
float xray = false;
float thermal = false;
switch (x24_nextState)
{
case EReticleState::Combat:
combat = true;
break;
case EReticleState::Scan:
scan = true;
break;
case EReticleState::XRay:
xray = true;
break;
case EReticleState::Thermal:
thermal = true;
break;
default:
break;
}
if (combat)
x40_seeker.Lock();
else
x40_seeker.Unlock();
if (combat)
x4c_lockConfirm.Lock();
else
x4c_lockConfirm.Unlock();
if (combat)
x58_targetFlower.Lock();
else
x58_targetFlower.Unlock();
if (combat)
x64_missileBracket.Lock();
else
x64_missileBracket.Unlock();
if (combat)
x70_innerBeamIcon.Lock();
else
x70_innerBeamIcon.Unlock();
if (combat)
x7c_lockFire.Lock();
else
x7c_lockFire.Unlock();
if (combat)
x88_lockDagger.Lock();
else
x88_lockDagger.Unlock();
if (combat)
xa0_chargeTickFirst.Lock();
else
xa0_chargeTickFirst.Unlock();
if (xray)
xac_xrayRetRing.Lock();
else
xac_xrayRetRing.Unlock();
if (thermal)
xb8_thermalReticle.Lock();
else
xb8_thermalReticle.Unlock();
if (combat)
xc4_chargeGauge.x0_model.Lock();
else
xc4_chargeGauge.x0_model.Unlock();
if (scan)
x94_grapple.Lock();
else
x94_grapple.Unlock();
for (SOuterItemInfo& info : xe0_outerBeamIconSquares)
{
if (combat)
info.x0_model.Lock();
else
info.x0_model.Unlock();
}
}
CPlayerGun* gun = mgr.GetPlayer().GetPlayerGun();
bool fullyCharged = (gun->IsCharging() ? gun->GetChargeBeamFactor() : 0.f) >= 1.f;
if (fullyCharged != x21a_fullyCharged)
x21a_fullyCharged = fullyCharged;
if (x21a_fullyCharged)
x214_fullChargeFadeTimer =
std::min(dt / g_tweakTargeting->GetFullChargeFadeDuration() + x214_fullChargeFadeTimer,
g_tweakTargeting->GetFullChargeFadeDuration());
else
x214_fullChargeFadeTimer =
std::max(x214_fullChargeFadeTimer - dt / g_tweakTargeting->GetFullChargeFadeDuration(), 0.f);
bool missileActive = gun->GetMissleMode() == CPlayerGun::EMissleMode::Active;
if (missileActive != x1f4_missileActive)
{
if (x1f8_missileBracketTimer != 0.f)
x1f8_missileBracketTimer = FLT_EPSILON - x1f8_missileBracketTimer;
else
x1f8_missileBracketTimer = FLT_EPSILON;
x1f4_missileActive = missileActive;
}
CPlayerState::EBeamId beam = gun->GetCurrentBeam();
if (beam != x200_beam)
{
x204_chargeGaugeOvershootTimer = g_tweakTargeting->GetChargeGaugeOvershootDuration();
for (int i=0 ; i<9 ; ++i)
{
zeus::CRelAngle baseAngle = g_tweakTargeting->GetOuterBeamSquareAngles(int(beam))[i];
SOuterItemInfo& icon = xe0_outerBeamIconSquares[i];
zeus::CRelAngle offshootAngleDelta = baseAngle.asRadians() - icon.x10_rotAng;
if ((i & 0x1) == 1)
offshootAngleDelta = (baseAngle > 0.f) ? zeus::CRelAngle(-2.f * M_PIF - baseAngle) :
zeus::CRelAngle(2.f * M_PIF + baseAngle);
icon.xc_offshootBaseAngle = icon.x10_rotAng;
icon.x18_offshootAngleDelta = offshootAngleDelta;
icon.x14_baseAngle = baseAngle;
}
zeus::CRelAngle baseAngle = g_tweakTargeting->GetChargeGaugeAngle(int(beam));
float offshootAngleDelta = baseAngle.asRadians() - xc4_chargeGauge.x10_rotAng;
if ((rand() & 0x1) == 1)
offshootAngleDelta = (offshootAngleDelta > 0.f) ?
-2.f * M_PIF - offshootAngleDelta : 2.f * M_PIF + offshootAngleDelta;
xc4_chargeGauge.xc_offshootBaseAngle = xc4_chargeGauge.x10_rotAng;
xc4_chargeGauge.x18_offshootAngleDelta = offshootAngleDelta;
xc4_chargeGauge.x14_baseAngle = baseAngle;
x200_beam = beam;
x208_lockonTimer = 0.f;
}
if (gun->GetLastFireButtonStates() & 0x1)
{
if (!x218_beamShot)
x210_lockFireTimer = g_tweakTargeting->GetLockFireDuration();
x218_beamShot = true;
}
else
{
x218_beamShot = false;
}
if (gun->GetLastFireButtonStates() & 0x2)
{
if (!x219_missileShot)
x1fc_missileBracketScaleTimer = g_tweakTargeting->GetMissileBracketScaleDuration();
x219_missileShot = true;
}
else
{
x219_missileShot = false;
}
if (TCastToConstPtr<CScriptGrapplePoint> point = mgr.GetObjectById(xf2_nextTargetId))
{
if (point->GetUniqueId() != x1dc_grapplePoint0)
{
float tmp;
if (point->GetUniqueId() == x1de_grapplePoint1)
tmp = std::max(FLT_EPSILON, x1e4_grapplePoint1T);
else
tmp = FLT_EPSILON;
x1de_grapplePoint1 = x1dc_grapplePoint0;
x1e4_grapplePoint1T = x1e0_grapplePoint0T;
x1e0_grapplePoint0T = tmp;
x1dc_grapplePoint0 = point->GetUniqueId();
}
}
else if (x1dc_grapplePoint0 != kInvalidUniqueId)
{
x1de_grapplePoint1 = x1dc_grapplePoint0;
x1e4_grapplePoint1T = x1e0_grapplePoint0T;
x1e0_grapplePoint0T = 0.f;
x1dc_grapplePoint0 = kInvalidUniqueId;
}
if (x1e0_grapplePoint0T > 0.f)
x1e0_grapplePoint0T = std::min(dt / 0.5f + x1e0_grapplePoint0T, 1.f);
if (x1e4_grapplePoint1T > 0.f)
{
x1e4_grapplePoint1T = std::max(0.f, x1e4_grapplePoint1T - dt / 0.5f);
if (x1e4_grapplePoint1T == 0.f)
x1de_grapplePoint1 = kInvalidUniqueId;
}
x1f0_xrayRetAngle =
zeus::CRelAngle(zeus::degToRad(g_tweakTargeting->GetXRayRetAngleSpeed() * dt) + x1f0_xrayRetAngle);
x1ec_seekerAngle =
zeus::CRelAngle(zeus::degToRad(g_tweakTargeting->GetSeekerAngleSpeed() * dt) + x1ec_seekerAngle);
}
void CTargetReticleRenderState::InterpolateWithClamp(const CTargetReticleRenderState& a,
CTargetReticleRenderState& out,
const CTargetReticleRenderState& b, float t)
{
t = zeus::clamp(0.f, t, 1.f);
float omt = 1.f - t;
out.x4_radiusWorld = omt * a.x4_radiusWorld + t * b.x4_radiusWorld;
out.x14_factor = omt * a.x14_factor + t * b.x14_factor;
out.x18_minVpClampScale = omt * a.x18_minVpClampScale + t * b.x18_minVpClampScale;
out.x8_positionWorld = zeus::CVector3f::lerp(a.x8_positionWorld, b.x8_positionWorld, t);
if (t == 1.f)
out.x0_target = b.x0_target;
else if (t == 0.f)
out.x0_target = a.x0_target;
else
out.x0_target = kInvalidUniqueId;
}
static bool IsDamageOrbit(CPlayer::EPlayerOrbitRequest req)
{
switch (req)
{
case CPlayer::EPlayerOrbitRequest::Five:
case CPlayer::EPlayerOrbitRequest::ActivateOrbitSource:
case CPlayer::EPlayerOrbitRequest::ProjectileCollide:
case CPlayer::EPlayerOrbitRequest::Freeze:
case CPlayer::EPlayerOrbitRequest::DamageOnGrapple:
return true;
default:
return false;
}
}
void CCompoundTargetReticle::UpdateCurrLockOnGroup(float dt, const CStateManager& mgr)
{
TUniqueId targetId = mgr.GetPlayer().GetOrbitTargetId();
if (targetId != xf0_targetId)
{
if (targetId != kInvalidUniqueId)
{
if (TCastToConstPtr<CScriptGrapplePoint> point = mgr.GetObjectById(targetId))
CSfxManager::SfxStart(1393, 1.f, 0.f, false, 0x7f, false, kInvalidAreaId);
else
CSfxManager::SfxStart(1377, 1.f, 0.f, false, 0x7f, false, kInvalidAreaId);
}
if (targetId == kInvalidUniqueId)
{
x12c_currGroupA = x10c_currGroupInterp;
x14c_currGroupB.SetFactor(0.f);
x16c_currGroupDur = IsDamageOrbit(mgr.GetPlayer().GetOrbitRequest()) ? 0.65f :
g_tweakTargeting->GetCurrLockOnEnterDuration();
}
else
{
x12c_currGroupA = x10c_currGroupInterp;
if (xf0_targetId == kInvalidUniqueId)
x12c_currGroupA.SetTargetId(targetId);
x14c_currGroupB = CTargetReticleRenderState(targetId, 1.f, zeus::CVector3f::skZero, 1.f,
IsGrappleTarget(targetId, mgr) ? g_tweakTargeting->GetGrappleMinClampScale() : 1.f, false);
x16c_currGroupDur = xf0_targetId == kInvalidUniqueId ? g_tweakTargeting->GetCurrLockOnExitDuration() :
g_tweakTargeting->GetCurrLockOnSwitchDuration();
x170_currGroupTimer = x16c_currGroupDur;
xf0_targetId = targetId;
}
}
if (x170_currGroupTimer > 0.f)
{
UpdateTargetParameters(x12c_currGroupA, mgr);
UpdateTargetParameters(x14c_currGroupB, mgr);
x170_currGroupTimer = std::max(0.f, x170_currGroupTimer - dt);
CTargetReticleRenderState::InterpolateWithClamp(x12c_currGroupA, x10c_currGroupInterp, x14c_currGroupB,
1.f - x170_currGroupTimer / x16c_currGroupDur);
}
else
{
UpdateTargetParameters(x10c_currGroupInterp, mgr);
}
if (x1f8_missileBracketTimer != 0.f && x1f8_missileBracketTimer < g_tweakTargeting->GetMissileBracketDuration())
{
if (x1f8_missileBracketTimer < 0.f)
x1f8_missileBracketTimer =
std::min(0.f, x1f8_missileBracketTimer + dt);
else
x1f8_missileBracketTimer =
std::min(g_tweakTargeting->GetMissileBracketDuration(), x1f8_missileBracketTimer + dt);
}
if (x204_chargeGaugeOvershootTimer > 0.f)
{
x204_chargeGaugeOvershootTimer = std::max(0.f, x204_chargeGaugeOvershootTimer - dt);
if (x204_chargeGaugeOvershootTimer == 0.f)
{
for (int i=0 ; i<9 ; ++i)
xe0_outerBeamIconSquares[i].x10_rotAng = xe0_outerBeamIconSquares[i].x14_baseAngle;
xc4_chargeGauge.x10_rotAng = xc4_chargeGauge.x14_baseAngle;
x208_lockonTimer = FLT_EPSILON;
}
else
{
float offshoot = offshoot_func(x2c_overshootOffsetHalf, x30_premultOvershootOffset,
1.f - x204_chargeGaugeOvershootTimer /
g_tweakTargeting->GetChargeGaugeOvershootDuration());
for (int i=0 ; i<9 ; ++i)
{
SOuterItemInfo& item = xe0_outerBeamIconSquares[i];
item.x10_rotAng = zeus::CRelAngle(item.x18_offshootAngleDelta * offshoot + item.xc_offshootBaseAngle);
}
xc4_chargeGauge.x10_rotAng = zeus::CRelAngle(xc4_chargeGauge.x18_offshootAngleDelta * offshoot +
xc4_chargeGauge.xc_offshootBaseAngle);
}
}
if (x208_lockonTimer > 0.f && x208_lockonTimer < g_tweakTargeting->GetLockonDuration())
x208_lockonTimer = std::min(g_tweakTargeting->GetLockonDuration(), x208_lockonTimer + dt);
if (x210_lockFireTimer > 0.f)
x210_lockFireTimer = std::max(0.f, x210_lockFireTimer - dt);
if (x1fc_missileBracketScaleTimer > 0.f)
x1fc_missileBracketScaleTimer = std::max(0.f, x1fc_missileBracketScaleTimer - dt);
}
void CCompoundTargetReticle::UpdateNextLockOnGroup(float dt, const CStateManager& mgr)
{
TUniqueId nextTargetId = mgr.GetPlayer().GetOrbitNextTargetId();
if (mgr.GetPlayerState()->GetCurrentVisor() == CPlayerState::EPlayerVisor::Scan &&
mgr.GetPlayer().GetOrbitTargetId() != kInvalidUniqueId)
nextTargetId = mgr.GetPlayer().GetOrbitTargetId();
if (nextTargetId != xf2_nextTargetId)
{
if (nextTargetId == kInvalidUniqueId)
{
x194_nextGroupA = x174_nextGroupInterp;
x1b4_nextGroupB = CTargetReticleRenderState(kInvalidUniqueId, 1.f,
(x20_prevState == EReticleState::XRay || x20_prevState == EReticleState::Thermal) ?
x100_laggingTargetPos : xf4_targetPos, 0.f, 1.f, true);
x1d4_nextGroupDur = x1d8_nextGroupTimer = g_tweakTargeting->GetNextLockOnExitDuration();
xf2_nextTargetId = nextTargetId;
}
else
{
x194_nextGroupA = x174_nextGroupInterp;
x1b4_nextGroupB = CTargetReticleRenderState(nextTargetId, 1.f, zeus::CVector3f::skZero, 1.f,
IsGrappleTarget(nextTargetId, mgr) ? g_tweakTargeting->GetGrappleMinClampScale() : 1.f, true);
x1d4_nextGroupDur = x1d8_nextGroupTimer = xf2_nextTargetId == kInvalidUniqueId ?
g_tweakTargeting->GetNextLockOnEnterDuration() :
g_tweakTargeting->GetNextLockOnSwitchDuration();
xf2_nextTargetId = nextTargetId;
}
}
if (x1d8_nextGroupTimer > 0.f)
{
UpdateTargetParameters(x194_nextGroupA, mgr);
UpdateTargetParameters(x1b4_nextGroupB, mgr);
x1d8_nextGroupTimer = std::max(0.f, x1d8_nextGroupTimer - dt);
CTargetReticleRenderState::InterpolateWithClamp(x194_nextGroupA, x174_nextGroupInterp, x1b4_nextGroupB,
1.f - x1d8_nextGroupTimer / x1d4_nextGroupDur);
}
else
{
UpdateTargetParameters(x174_nextGroupInterp, mgr);
}
}
void CCompoundTargetReticle::UpdateOrbitZoneGroup(float dt, const CStateManager& mgr)
{
if (xf0_targetId == kInvalidUniqueId && xf2_nextTargetId != kInvalidUniqueId)
x20c_ = std::min(1.f, 2.f * dt + x20c_);
else
x20c_ = std::max(0.f, x20c_ - 2.f * dt);
if (mgr.GetPlayer().IsShowingCrosshairs() &&
mgr.GetPlayerState()->GetCurrentVisor() != CPlayerState::EPlayerVisor::Scan)
x1e8_crosshairsScale =
std::min(1.f, dt / g_tweakTargeting->GetCrosshairsScaleDuration() + x1e8_crosshairsScale);
else
x1e8_crosshairsScale =
std::max(0.f, x1e8_crosshairsScale - dt / g_tweakTargeting->GetCrosshairsScaleDuration());
}
void CCompoundTargetReticle::Draw(const CStateManager& mgr, bool hideLockon) const
{
if (mgr.GetPlayer().GetMorphballTransitionState() == CPlayer::EPlayerMorphBallState::Unmorphed &&
!mgr.GetCameraManager()->IsInCinematicCamera())
{
zeus::CTransform camXf = mgr.GetCameraManager()->GetCurrentCameraTransform(mgr);
CGraphics::SetViewPointMatrix(camXf);
if (!hideLockon)
{
DrawCurrLockOnGroup(camXf.basis, mgr);
DrawNextLockOnGroup(camXf.basis, mgr);
DrawOrbitZoneGroup(camXf.basis, mgr);
}
DrawGrappleGroup(camXf.basis, mgr, hideLockon);
}
if (x28_noDrawTicks > 0)
--x28_noDrawTicks;
}
void CCompoundTargetReticle::DrawGrapplePoint(const CScriptGrapplePoint& point, float t, const CStateManager& mgr,
const zeus::CMatrix3f& rot, bool zEqual) const
{
zeus::CVector3f orbitPos = point.GetOrbitPosition(mgr);
zeus::CColor color;
if (point.GetGrappleParameters().GetLockSwingTurn())
color = g_tweakTargeting->GetLockedGrapplePointSelectColor();
else
color = g_tweakTargeting->GetGrapplePointSelectColor();
color = zeus::CColor::lerp(color, g_tweakTargeting->GetGrapplePointColor(), t);
zeus::CMatrix3f scale(
CalculateClampedScale(orbitPos, 1.f, g_tweakTargeting->GetGrappleClampMin(),
g_tweakTargeting->GetGrappleClampMax(), mgr) *
(1.f - t) * g_tweakTargeting->GetGrappleScale() + t * g_tweakTargeting->GetGrappleSelectScale());
zeus::CTransform modelXf(scale, orbitPos);
CGraphics::SetModelMatrix(modelXf);
CModelFlags flags(7, 0, 0, color);
x94_grapple->Draw(flags);
}
void CCompoundTargetReticle::DrawGrappleGroup(const zeus::CMatrix3f& rot,
const CStateManager& mgr, bool hideLockon) const
{
if (x28_noDrawTicks > 0)
return;
if (mgr.GetPlayerState()->HasPowerUp(CPlayerState::EItemType::GrappleBeam) &&
x94_grapple.IsLoaded() && x20_prevState != EReticleState::Scan)
{
if (hideLockon)
{
for (const CEntity* ent : mgr.GetAllObjectList())
{
if (TCastToConstPtr<CScriptGrapplePoint> point = ent)
{
if (point->GetActive())
{
if (point->GetAreaIdAlways() != kInvalidAreaId)
{
const CGameArea* area = mgr.GetWorld()->GetAreaAlways(point->GetAreaIdAlways());
CGameArea::EOcclusionState occState = area->IsPostConstructed() ?
area->GetOcclusionState() :
CGameArea::EOcclusionState::Occluded;
if (occState != CGameArea::EOcclusionState::Visible)
continue;
}
float t = 0.f;
if (point->GetUniqueId() == x1dc_grapplePoint0)
t = x1e0_grapplePoint0T;
else if (point->GetUniqueId() == x1de_grapplePoint1)
t = x1e4_grapplePoint1T;
if (std::fabs(t) < 0.00001f)
DrawGrapplePoint(*point, t, mgr, rot, true);
}
}
}
}
else
{
TCastToConstPtr<CScriptGrapplePoint> point0 = mgr.GetObjectById(x1dc_grapplePoint0);
TCastToConstPtr<CScriptGrapplePoint> point1 = mgr.GetObjectById(x1de_grapplePoint1);
for (int i=0 ; i<2 ; ++i)
{
const CScriptGrapplePoint* point = i == 0 ? point0.GetPtr() : point1.GetPtr();
float t = i == 0 ? x1e0_grapplePoint0T : x1e4_grapplePoint1T;
if (point)
DrawGrapplePoint(*point, t, mgr, rot, false);
}
}
}
}
void CCompoundTargetReticle::DrawCurrLockOnGroup(const zeus::CMatrix3f& rot, const CStateManager& mgr) const
{
if (x28_noDrawTicks > 0)
return;
if (x1e0_grapplePoint0T + x1e4_grapplePoint1T > 0 || x10c_currGroupInterp.GetFactor() == 0.f)
return;
float lockBreakAlpha = x10c_currGroupInterp.GetFactor();
float visorFactor = mgr.GetPlayerState()->GetVisorTransitionFactor();
bool lockConfirm = false;
bool lockReticule = false;
switch (x20_prevState)
{
case EReticleState::Combat:
lockConfirm = true;
lockReticule = true;
break;
case EReticleState::Scan:
lockConfirm = true;
break;
default:
break;
}
zeus::CMatrix3f lockBreakXf;
zeus::CColor lockBreakColor = zeus::CColor::skClear;
if (IsDamageOrbit(mgr.GetPlayer().GetOrbitRequest()) && x14c_currGroupB.GetFactor() == 0)
{
zeus::CMatrix3f lockBreakRM;
for (int i=0 ; i<4 ; ++i)
{
int a = rand() % 9;
auto b = std::div(a, 3);
lockBreakRM[b.rem][b.quot] += rand() / float(RAND_MAX) - 0.5f;
}
lockBreakXf = lockBreakRM.transposed();
if (x10c_currGroupInterp.GetFactor() > 0.8f)
lockBreakColor = zeus::CColor(1.f, (x10c_currGroupInterp.GetFactor() - 0.8f) * 0.3f / 0.2f);
lockBreakAlpha = x10c_currGroupInterp.GetFactor() > 0.75f ?
1.f : std::max(0.f, (x10c_currGroupInterp.GetFactor() - 0.55f) / 0.2f);
}
if (lockConfirm && x4c_lockConfirm.IsLoaded())
{
zeus::CMatrix3f scale(
CalculateClampedScale(x10c_currGroupInterp.GetTargetPositionWorld(),
x10c_currGroupInterp.GetRadiusWorld(),
x10c_currGroupInterp.GetMinViewportClampScale() *
g_tweakTargeting->GetLockConfirmClampMin(),
g_tweakTargeting->GetLockConfirmClampMax(), mgr) *
g_tweakTargeting->GetLockConfirmScale() / x10c_currGroupInterp.GetFactor());
zeus::CTransform modelXf(lockBreakXf * (rot * zeus::CMatrix3f::RotateY(x1ec_seekerAngle) * scale),
x10c_currGroupInterp.GetTargetPositionWorld());
CGraphics::SetModelMatrix(modelXf);
zeus::CColor color = g_tweakTargeting->GetLockConfirmColor();
color.a *= lockBreakAlpha;
CModelFlags flags(7, 0, 0, lockBreakColor + color);
x4c_lockConfirm->Draw(flags);
}
if (lockReticule)
{
if (x58_targetFlower.IsLoaded())
{
zeus::CMatrix3f scale(
CalculateClampedScale(x10c_currGroupInterp.GetTargetPositionWorld(),
x10c_currGroupInterp.GetRadiusWorld(),
x10c_currGroupInterp.GetMinViewportClampScale() *
g_tweakTargeting->GetTargetFlowerClampMin(),
g_tweakTargeting->GetTargetFlowerClampMax(), mgr) *
g_tweakTargeting->GetTargetFlowerScale() / lockBreakAlpha);
zeus::CTransform modelXf(lockBreakXf * (rot * zeus::CMatrix3f::RotateY(x1f0_xrayRetAngle) * scale),
x10c_currGroupInterp.GetTargetPositionWorld());
CGraphics::SetModelMatrix(modelXf);
zeus::CColor color = g_tweakTargeting->GetTargetFlowerColor();
color.a *= lockBreakAlpha * visorFactor;
CModelFlags flags(7, 0, 0, lockBreakColor + color);
x58_targetFlower->Draw(flags);
}
if (x1f8_missileBracketTimer != 0.f && x64_missileBracket.IsLoaded())
{
float t = std::fabs((x1fc_missileBracketScaleTimer - 0.5f *
g_tweakTargeting->GetMissileBracketScaleDuration())
/ 0.5f * g_tweakTargeting->GetMissileBracketScaleDuration());
float tscale = ((1.f - t) * g_tweakTargeting->GetMissileBracketScaleEnd() +
t * g_tweakTargeting->GetMissileBracketScaleStart());
zeus::CMatrix3f scale(
CalculateClampedScale(x10c_currGroupInterp.GetTargetPositionWorld(),
x10c_currGroupInterp.GetRadiusWorld(),
x10c_currGroupInterp.GetMinViewportClampScale() *
g_tweakTargeting->GetMissileBracketClampMin(),
g_tweakTargeting->GetMissileBracketClampMax(), mgr) *
std::fabs(x1f8_missileBracketTimer) / g_tweakTargeting->GetMissileBracketDuration() *
tscale / x10c_currGroupInterp.GetFactor());
for (int i=0 ; i<4 ; ++i)
{
zeus::CTransform modelXf(
lockBreakXf * rot *
zeus::CMatrix3f(zeus::CVector3f{i < 2 ? 1.f : -1.f, 1.f, i & 0x1 ? 1.f : -1.f}) * scale,
x10c_currGroupInterp.GetTargetPositionWorld());
CGraphics::SetModelMatrix(modelXf);
zeus::CColor color = g_tweakTargeting->GetMissileBracketColor();
color.a *= lockBreakAlpha * visorFactor;
CModelFlags flags(7, 0, 0, lockBreakColor + color);
x64_missileBracket->Draw(flags);
}
}
zeus::CMatrix3f scale(
CalculateClampedScale(x10c_currGroupInterp.GetTargetPositionWorld(),
x10c_currGroupInterp.GetRadiusWorld(),
x10c_currGroupInterp.GetMinViewportClampScale() *
g_tweakTargeting->GetChargeGaugeClampMin(),
g_tweakTargeting->GetChargeGaugeClampMax(), mgr) *
1.f / x10c_currGroupInterp.GetFactor() * g_tweakTargeting->GetOuterBeamSquaresScale());
zeus::CMatrix3f outerBeamXf = rot * scale;
for (int i=0 ; i<9 ; ++i)
{
const SOuterItemInfo& info = xe0_outerBeamIconSquares[i];
if (info.x0_model.IsLoaded())
{
zeus::CTransform modelXf(lockBreakXf * outerBeamXf * zeus::CMatrix3f::RotateY(info.x10_rotAng),
x10c_currGroupInterp.GetTargetPositionWorld());
CGraphics::SetModelMatrix(modelXf);
zeus::CColor color = g_tweakTargeting->GetOuterBeamSquareColor();
color.a *= lockBreakAlpha * visorFactor;
CModelFlags flags(7, 0, 0, lockBreakColor + color);
info.x0_model->Draw(flags);
}
}
if (xc4_chargeGauge.x0_model.IsLoaded())
{
zeus::CMatrix3f scale(
CalculateClampedScale(x10c_currGroupInterp.GetTargetPositionWorld(),
x10c_currGroupInterp.GetRadiusWorld(),
x10c_currGroupInterp.GetMinViewportClampScale() *
g_tweakTargeting->GetChargeGaugeClampMin(),
g_tweakTargeting->GetChargeGaugeClampMax(), mgr) *
g_tweakTargeting->GetChargeGaugeScale() / x10c_currGroupInterp.GetFactor());
zeus::CMatrix3f chargeGaugeXf = rot * scale * zeus::CMatrix3f::RotateY(xc4_chargeGauge.x10_rotAng);
float pulseT = std::fabs(std::fmod(CGraphics::GetSecondsMod900(),
g_tweakTargeting->GetChargeGaugePulsePeriod()));
zeus::CColor gaugeColor = zeus::CColor::lerp(g_tweakTargeting->GetChargeGaugeNonFullColor(),
zeus::CColor::lerp(g_tweakTargeting->GetChargeGaugePulseColorHigh(),
g_tweakTargeting->GetChargeGaugePulseColorLow(),
pulseT < 0.5f * g_tweakTargeting->GetChargeGaugePulsePeriod() ?
pulseT / (0.5f * g_tweakTargeting->GetChargeGaugePulsePeriod()) :
(g_tweakTargeting->GetChargeGaugePulsePeriod() - pulseT) /
(0.5f * g_tweakTargeting->GetChargeGaugePulsePeriod())),
x214_fullChargeFadeTimer / g_tweakTargeting->GetFullChargeFadeDuration());
zeus::CTransform modelXf(lockBreakXf * chargeGaugeXf, x10c_currGroupInterp.GetTargetPositionWorld());
CGraphics::SetModelMatrix(modelXf);
zeus::CColor color = gaugeColor;
color.a *= lockBreakAlpha * visorFactor;
CModelFlags flags(7, 0, 0, lockBreakColor + color);
xc4_chargeGauge.x0_model->Draw(flags);
if (xa0_chargeTickFirst.IsLoaded())
{
const CPlayerGun* gun = mgr.GetPlayer().GetPlayerGun();
int numTicks = int(g_tweakTargeting->GetChargeTickCount() *
(gun->IsCharging() ? gun->GetChargeBeamFactor() : 0.f));
for (int i=0 ; i<numTicks ; ++i)
{
CModelFlags flags(7, 0, 0, lockBreakColor + color);
xa0_chargeTickFirst->Draw(flags);
modelXf.rotateLocalY(g_tweakTargeting->GetChargeTickAnglePitch());
CGraphics::SetModelMatrix(modelXf);
}
}
}
if (x208_lockonTimer > 0.f && x70_innerBeamIcon.IsLoaded())
{
const zeus::CColor* iconColor;
switch (x200_beam)
{
case CPlayerState::EBeamId::Power:
iconColor = &g_tweakTargeting->GetInnerBeamColorPower();
break;
case CPlayerState::EBeamId::Ice:
iconColor = &g_tweakTargeting->GetInnerBeamColorIce();
break;
case CPlayerState::EBeamId::Wave:
iconColor = &g_tweakTargeting->GetInnerBeamColorWave();
break;
default:
iconColor = &g_tweakTargeting->GetInnerBeamColorPlasma();
break;
}
zeus::CMatrix3f scale(
CalculateClampedScale(x10c_currGroupInterp.GetTargetPositionWorld(),
x10c_currGroupInterp.GetRadiusWorld(),
x10c_currGroupInterp.GetMinViewportClampScale() *
g_tweakTargeting->GetInnerBeamClampMin(),
g_tweakTargeting->GetInnerBeamClampMax(), mgr) *
g_tweakTargeting->GetInnerBeamScale() * (x208_lockonTimer / g_tweakTargeting->GetLockonDuration()) /
x10c_currGroupInterp.GetFactor());
zeus::CTransform modelXf(lockBreakXf * rot * scale, x10c_currGroupInterp.GetTargetPositionWorld());
CGraphics::SetModelMatrix(modelXf);
zeus::CColor color = *iconColor;
color.a *= lockBreakAlpha * visorFactor;
CModelFlags flags(7, 0, 0, lockBreakColor + color);
x70_innerBeamIcon->Draw(flags);
}
if (x210_lockFireTimer > 0.f && x7c_lockFire.IsLoaded())
{
zeus::CMatrix3f scale(
CalculateClampedScale(x10c_currGroupInterp.GetTargetPositionWorld(),
x10c_currGroupInterp.GetRadiusWorld(),
x10c_currGroupInterp.GetMinViewportClampScale() *
g_tweakTargeting->GetLockFireClampMin(),
g_tweakTargeting->GetLockFireClampMax(), mgr) *
g_tweakTargeting->GetLockFireScale() / x10c_currGroupInterp.GetFactor());
zeus::CTransform modelXf(lockBreakXf * rot * scale * zeus::CMatrix3f::RotateY(x1f0_xrayRetAngle),
x10c_currGroupInterp.GetTargetPositionWorld());
CGraphics::SetModelMatrix(modelXf);
zeus::CColor color = g_tweakTargeting->GetLockFireColor();
color.a *= visorFactor * lockBreakAlpha * (x210_lockFireTimer / g_tweakTargeting->GetLockFireDuration());
CModelFlags flags(7, 0, 0, lockBreakColor + color);
x7c_lockFire->Draw(flags);
}
if (x208_lockonTimer > 0.f && x88_lockDagger.IsLoaded())
{
float t = std::fabs((x210_lockFireTimer - 0.5f * g_tweakTargeting->GetLockFireDuration()) /
0.5f * g_tweakTargeting->GetLockFireDuration());
float tscale = ((1.f - t) * g_tweakTargeting->GetLockDaggerScaleEnd() +
t * g_tweakTargeting->GetLockDaggerScaleStart());
zeus::CMatrix3f scale(
CalculateClampedScale(x10c_currGroupInterp.GetTargetPositionWorld(),
x10c_currGroupInterp.GetRadiusWorld(),
x10c_currGroupInterp.GetMinViewportClampScale() *
g_tweakTargeting->GetLockDaggerClampMin(),
g_tweakTargeting->GetLockDaggerClampMax(), mgr) * tscale *
(x208_lockonTimer / g_tweakTargeting->GetLockonDuration()) / x10c_currGroupInterp.GetFactor());
zeus::CMatrix3f lockDaggerXf = rot * scale;
for (int i=0 ; i<3 ; ++i)
{
float ang;
switch (i)
{
case 0:
ang = g_tweakTargeting->GetLockDaggerAngle0();
break;
case 1:
ang = g_tweakTargeting->GetLockDaggerAngle1();
break;
default:
ang = g_tweakTargeting->GetLockDaggerAngle2();
break;
}
zeus::CTransform modelXf(lockBreakXf * lockDaggerXf * zeus::CMatrix3f::RotateY(ang),
x10c_currGroupInterp.GetTargetPositionWorld());
CGraphics::SetModelMatrix(modelXf);
zeus::CColor color = g_tweakTargeting->GetLockDaggerColor();
color.a *= visorFactor * lockBreakAlpha;
CModelFlags flags(7, 0, 0, lockBreakColor + color);
x88_lockDagger->Draw(flags);
}
}
}
}
void CCompoundTargetReticle::DrawNextLockOnGroup(const zeus::CMatrix3f& rot, const CStateManager& mgr) const
{
if (x28_noDrawTicks > 0)
return;
zeus::CVector3f position = x174_nextGroupInterp.GetTargetPositionWorld();
float visorFactor = mgr.GetPlayerState()->GetVisorTransitionFactor();
bool scanRet = false;
bool xrayRet = false;
bool thermalRet = false;
switch (x20_prevState)
{
case EReticleState::Scan:
scanRet = true;
break;
case EReticleState::XRay:
xrayRet = true;
break;
case EReticleState::Thermal:
thermalRet = true;
break;
default:
break;
}
if (!xrayRet && x174_nextGroupInterp.GetFactor() > 0.f && x40_seeker.IsLoaded())
{
zeus::CMatrix3f scale(
CalculateClampedScale(position, x174_nextGroupInterp.GetRadiusWorld(),
x174_nextGroupInterp.GetMinViewportClampScale() *
g_tweakTargeting->GetSeekerClampMin(),
g_tweakTargeting->GetSeekerClampMax(), mgr) *
g_tweakTargeting->GetSeekerScale());
zeus::CTransform modelXf(rot * zeus::CMatrix3f::RotateY(x1ec_seekerAngle) * scale,
x174_nextGroupInterp.GetTargetPositionWorld());
CGraphics::SetModelMatrix(modelXf);
zeus::CColor color = g_tweakTargeting->GetSeekerColor();
color.a *= x174_nextGroupInterp.GetFactor();
CModelFlags flags(7, 0, 0, color);
x40_seeker->Draw(flags);
}
if (xrayRet && xac_xrayRetRing.IsLoaded())
{
zeus::CMatrix3f scale(
CalculateClampedScale(position, x174_nextGroupInterp.GetRadiusWorld(),
x174_nextGroupInterp.GetMinViewportClampScale() *
g_tweakTargeting->GetReticuleClampMin(),
g_tweakTargeting->GetReticuleClampMax(), mgr) *
g_tweakTargeting->GetReticuleScale());
zeus::CTransform modelXf(rot * scale * zeus::CMatrix3f::RotateY(x1f0_xrayRetAngle),
x174_nextGroupInterp.GetTargetPositionWorld());
CGraphics::SetModelMatrix(modelXf);
zeus::CColor color = g_tweakTargeting->GetXRayRetRingColor();
color.a *= visorFactor;
CModelFlags flags(7, 0, 0, color);
xac_xrayRetRing->Draw(flags);
}
if (thermalRet && xb8_thermalReticle.IsLoaded())
{
zeus::CMatrix3f scale(
CalculateClampedScale(position, x174_nextGroupInterp.GetRadiusWorld(),
x174_nextGroupInterp.GetMinViewportClampScale() *
g_tweakTargeting->GetReticuleClampMin(),
g_tweakTargeting->GetReticuleClampMax(), mgr) *
g_tweakTargeting->GetReticuleScale());
zeus::CTransform modelXf(rot * scale, x174_nextGroupInterp.GetTargetPositionWorld());
CGraphics::SetModelMatrix(modelXf);
zeus::CColor color = g_tweakTargeting->GetThermalReticuleColor();
color.a *= visorFactor;
CModelFlags flags(7, 0, 0, color);
xb8_thermalReticle->Draw(flags);
}
if (scanRet && visorFactor > 0.f)
{
float factor = visorFactor * x174_nextGroupInterp.GetFactor();
zeus::CMatrix3f scale(
CalculateClampedScale(position, x174_nextGroupInterp.GetRadiusWorld(),
x174_nextGroupInterp.GetMinViewportClampScale() *
g_tweakTargeting->GetScanTargetClampMin(),
g_tweakTargeting->GetScanTargetClampMax(), mgr) *
(1.f / factor));
zeus::CTransform modelXf(rot * scale, x174_nextGroupInterp.GetTargetPositionWorld());
CGraphics::SetModelMatrix(modelXf);
// compare, GX_LESS, no update
float alpha = 0.5f * factor;
zeus::CColor color = g_tweakGuiColors->GetScanReticuleColor();
color.a *= alpha;
for (int i=0 ; i<2 ; ++i)
{
float lineWidth = i ? 2.5f : 1.f;
auto& rend = *m_scanRetRenderer.m_lineRenderers[i];
rend.Reset();
rend.AddVertex({-0.5f, 0.f, 0.f}, color, lineWidth);
rend.AddVertex({-20.5f, 0.f, 0.f}, color, lineWidth);
rend.AddVertex({0.5f, 0.f, 0.f}, color, lineWidth);
rend.AddVertex({20.5f, 0.f, 0.f}, color, lineWidth);
rend.AddVertex({0.f, 0.f, -0.5f}, color, lineWidth);
rend.AddVertex({0.f, 0.f, -20.5f}, color, lineWidth);
rend.AddVertex({0.f, 0.f, 0.5f}, color, lineWidth);
rend.AddVertex({0.f, 0.f, 20.5f}, color, lineWidth);
rend.Render();
for (int j=0 ; j<4 ; ++j)
{
float xSign = j < 2 ? -1.f : 1.f;
float zSign = (j & 0x1) ? -1.f : 1.f;
// begin line strip
auto& rend = *m_scanRetRenderer.m_stripRenderers[i][j];
rend.Reset();
rend.AddVertex({0.5f * xSign, 0.f, 0.1f * zSign}, color, lineWidth);
rend.AddVertex({0.5f * xSign, 0.f, 0.35f * zSign}, color, lineWidth);
rend.AddVertex({0.35f * xSign, 0.f, 0.5f * zSign}, color, lineWidth);
rend.AddVertex({0.1f * xSign, 0.f, 0.5f * zSign}, color, lineWidth);
rend.Render();
}
}
}
}
void CCompoundTargetReticle::DrawOrbitZoneGroup(const zeus::CMatrix3f& rot, const CStateManager& mgr) const
{
if (x28_noDrawTicks > 0)
return;
if (x1e8_crosshairsScale > 0.f && x34_crosshairs.IsLoaded())
{
CGraphics::SetModelMatrix(zeus::CTransform(rot, xf4_targetPos) * zeus::CTransform::Scale(x1e8_crosshairsScale));
zeus::CColor color = g_tweakTargeting->GetCrosshairsColor();
color.a *= x1e8_crosshairsScale;
CModelFlags flags(7, 0, 0, color);
x34_crosshairs->Draw(flags);
}
}
void CCompoundTargetReticle::UpdateTargetParameters(CTargetReticleRenderState& state, const CStateManager& mgr)
{
if (auto act = TCastToConstPtr<CActor>(mgr.GetAllObjectList().GetObjectById(state.GetTargetId())))
{
state.SetRadiusWorld(CalculateRadiusWorld(*act, mgr));
state.SetTargetPositionWorld(CalculatePositionWorld(*act, mgr));
}
else if (state.GetIsOrbitZoneIdlePosition())
{
state.SetRadiusWorld(1.f);
state.SetTargetPositionWorld((x20_prevState == EReticleState::XRay || x20_prevState == EReticleState::Thermal) ?
x100_laggingTargetPos : xf4_targetPos);
}
}
float CCompoundTargetReticle::CalculateRadiusWorld(const CActor& act, const CStateManager& mgr) const
{
auto tb = act.GetTouchBounds();
zeus::CAABox aabb = tb ? *tb : zeus::CAABox(act.GetAimPosition(mgr, 0.f), act.GetAimPosition(mgr, 0.f));
float radius;
zeus::CVector3f delta = aabb.max - aabb.min;
switch (g_tweakTargeting->GetTargetRadiusMode())
{
case 0:
{
radius = std::min(delta.x, std::min(delta.y, delta.z)) * 0.5f;
break;
}
case 1:
{
radius = std::max(delta.x, std::max(delta.y, delta.z)) * 0.5f;
break;
}
default:
{
radius = (delta.x + delta.y + delta.z) / 6.f;
break;
}
}
return radius > 0.f ? radius : 1.f;
}
zeus::CVector3f CCompoundTargetReticle::CalculatePositionWorld(const CActor& act, const CStateManager& mgr) const
{
if (x20_prevState == EReticleState::Scan)
return act.GetOrbitPosition(mgr);
return act.GetAimPosition(mgr, 0.f);
}
zeus::CVector3f
CCompoundTargetReticle::CalculateOrbitZoneReticlePosition(const CStateManager& mgr, bool lag) const
{
const CGameCamera* curCam = mgr.GetCameraManager()->GetCurrentCamera(mgr);
float distMul = 224.f / float(g_tweakPlayer->GetOrbitScreenBoxHalfExtentY(0)) /
std::tan(zeus::degToRad(0.5f * curCam->GetFov()));
zeus::CTransform camXf = mgr.GetCameraManager()->GetCurrentCameraTransform(mgr);
zeus::CVector3f lookDir = camXf.basis[1];
if (lag)
lookDir = x10_laggingOrientation.transform(lookDir);
return lookDir * distMul + camXf.origin;
}
bool CCompoundTargetReticle::IsGrappleTarget(TUniqueId uid, const CStateManager& mgr) const
{
return TCastToConstPtr<CScriptGrapplePoint>(mgr.GetAllObjectList().GetObjectById(uid)).operator bool();
}
float CCompoundTargetReticle::CalculateClampedScale(const zeus::CVector3f& pos, float scale,
float clampMin, float clampMax,
const CStateManager& mgr)
{
const CGameCamera* cam = mgr.GetCameraManager()->GetCurrentCamera(mgr);
mgr.GetCameraManager()->GetCurrentCameraTransform(mgr);
zeus::CVector3f viewPos = cam->GetTransform().transposeRotate(pos - cam->GetTransform().origin);
viewPos = zeus::CVector3f(viewPos.x, viewPos.z, -viewPos.y);
float realX = cam->GetPerspectiveMatrix().multiplyOneOverW(viewPos).x;
float offsetX = cam->GetPerspectiveMatrix().multiplyOneOverW(viewPos + zeus::CVector3f(scale, 0.f, 0.f)).x;
float unclampedX = (offsetX - realX) * 640;
return zeus::clamp(clampMin, unclampedX, clampMax) / unclampedX * scale;
}
void CCompoundTargetReticle::Touch()
{
if (x34_crosshairs.IsLoaded())
x34_crosshairs->Touch(0);
if (x40_seeker.IsLoaded())
x40_seeker->Touch(0);
if (x4c_lockConfirm.IsLoaded())
x4c_lockConfirm->Touch(0);
if (x58_targetFlower.IsLoaded())
x58_targetFlower->Touch(0);
if (x64_missileBracket.IsLoaded())
x64_missileBracket->Touch(0);
if (x70_innerBeamIcon.IsLoaded())
x70_innerBeamIcon->Touch(0);
if (x7c_lockFire.IsLoaded())
x7c_lockFire->Touch(0);
if (x88_lockDagger.IsLoaded())
x88_lockDagger->Touch(0);
if (x94_grapple.IsLoaded())
x94_grapple->Touch(0);
if (xa0_chargeTickFirst.IsLoaded())
xa0_chargeTickFirst->Touch(0);
if (xac_xrayRetRing.IsLoaded())
xac_xrayRetRing->Touch(0);
if (xb8_thermalReticle.IsLoaded())
xb8_thermalReticle->Touch(0);
if (xc4_chargeGauge.x0_model.IsLoaded())
xc4_chargeGauge.x0_model->Touch(0);
for (SOuterItemInfo& info : xe0_outerBeamIconSquares)
if (info.x0_model.IsLoaded())
info.x0_model->Touch(0);
}
}