#include "CHudMissileInterface.hpp" #include "CGuiFrame.hpp" #include "CAuiEnergyBarT01.hpp" #include "CGuiTextPane.hpp" #include "GameGlobalObjects.hpp" #include "CStateManager.hpp" #include "CGuiModel.hpp" #include "CStringTable.hpp" namespace urde { static const CAuiEnergyBarT01::FCoordFunc CoordFuncs[] = { CHudMissileInterface::CombatMissileBarCoordFunc, nullptr, CHudMissileInterface::XRayMissileBarCoordFunc, CHudMissileInterface::ThermalMissileBarCoordFunc, nullptr }; static const float IconTranslateRanges[] = { 6.05f, 0.f, 0.f, 8.4f, 0.f }; CHudMissileInterface::CHudMissileInterface(CGuiFrame& selHud, int missileCapacity, int numMissiles, float chargeFactor, bool missilesActive, EHudType hudType, const CStateManager& mgr) : x0_hudType(hudType), x4_missileCapacity(missileCapacity), x8_numMissles(numMissiles), x4c_chargeBeamFactor(chargeFactor) { x58_24_missilesActive = missilesActive; x58_25_visibleDebug = true; x58_26_visibleGame = true; x5c_basewidget_missileicon = selHud.FindWidget("basewidget_missileicon"); x60_textpane_missiledigits = static_cast(selHud.FindWidget("textpane_missiledigits")); x64_energybart01_missilebar = static_cast(selHud.FindWidget("energybart01_missilebar")); x68_textpane_missilewarning = static_cast(selHud.FindWidget("textpane_missilewarning")); x6c_model_missilearrowup = static_cast(selHud.FindWidget("model_missilearrowup")); x70_model_missilearrowdown = static_cast(selHud.FindWidget("model_missilearrowdown")); x74_basewidget_missileicon = selHud.FindWidget("basewidget_missileicon"); x58_27_hasArrows = x6c_model_missilearrowup && x70_model_missilearrowdown; x58_28_notXRay = hudType != EHudType::XRay; x10_missleIconXf = x74_basewidget_missileicon->GetLocalTransform(); x60_textpane_missiledigits->TextSupport().SetFontColor(g_tweakGuiColors->GetMissileDigitsFont()); x60_textpane_missiledigits->TextSupport().SetOutlineColor(g_tweakGuiColors->GetMissileDigitsOutline()); x74_basewidget_missileicon->SetColor(g_tweakGuiColors->GetMissileIconColorInactive()); x64_energybart01_missilebar->SetEmptyColor(g_tweakGuiColors->GetMissileBarEmpty()); x64_energybart01_missilebar->SetFilledColor(g_tweakGuiColors->GetMissileBarFilled()); x64_energybart01_missilebar->SetShadowColor(g_tweakGuiColors->GetMissileBarShadow()); x64_energybart01_missilebar->SetCoordFunc(CoordFuncs[int(hudType)]); x64_energybart01_missilebar->SetTesselation(hudType == EHudType::Combat ? 1.f : 0.1f); x64_energybart01_missilebar->SetMaxEnergy(5.f); x64_energybart01_missilebar->SetFilledDrainSpeed(g_tweakGui->GetEnergyBarFilledSpeed()); x64_energybart01_missilebar->SetShadowDrainSpeed(g_tweakGui->GetEnergyBarShadowSpeed()); x64_energybart01_missilebar->SetShadowDrainDelay(g_tweakGui->GetEnergyBarDrainDelay()); x64_energybart01_missilebar->SetIsAlwaysResetTimer(true); if (x68_textpane_missilewarning) { x68_textpane_missilewarning->TextSupport().SetFontColor(g_tweakGuiColors->GetMissileWarningFont()); x68_textpane_missilewarning->TextSupport().SetOutlineColor(g_tweakGuiColors->GetMissileWarningOutline()); } SetNumMissiles(x8_numMissles, mgr); x44_latestStatus = GetMissileInventoryStatus(); } void CHudMissileInterface::UpdateVisibility(const CStateManager& mgr) { bool vis = x58_25_visibleDebug && x58_26_visibleGame; x5c_basewidget_missileicon->SetVisibility(vis, ETraversalMode::Children); x64_energybart01_missilebar->SetVisibility(vis, ETraversalMode::Children); if (vis) Update(0.f, mgr); } void CHudMissileInterface::Update(float dt, const CStateManager& mgr) { if (x4_missileCapacity < 1) x5c_basewidget_missileicon->SetIsVisible(false); else x5c_basewidget_missileicon->SetIsVisible(true); if (x54_missileIconIncrement < 0.f) { x54_missileIconIncrement -= 3.f * dt; if (x54_missileIconIncrement <= -1.f) x54_missileIconIncrement = 1.f; } else if (x54_missileIconIncrement > 0.f) { x54_missileIconIncrement = std::max(0.f, x54_missileIconIncrement - dt); } zeus::CColor addColor = g_tweakGuiColors->GetMissileIconColorActive() * x54_missileIconIncrement; if (x50_missileIconAltDeplete > 0.f) { x74_basewidget_missileicon->SetColor( zeus::CColor::lerp(g_tweakGuiColors->GetMissileIconColorInactive(), g_tweakGuiColors->GetMissileIconColorDepleteAlt(), x50_missileIconAltDeplete) + addColor); } else { if (x4c_chargeBeamFactor > 0.f) { float factor = std::min(x4c_chargeBeamFactor / CPlayerState::GetMissileComboChargeFactor(), 1.f); if (x8_numMissles > mgr.GetPlayerState()->GetMissileCostForAltAttack()) { x74_basewidget_missileicon->SetColor( zeus::CColor::lerp(g_tweakGuiColors->GetMissileIconColorInactive(), g_tweakGuiColors->GetMissileIconColorChargedCanAlt(), factor) + addColor); } else { x74_basewidget_missileicon->SetColor( zeus::CColor::lerp(g_tweakGuiColors->GetMissileIconColorInactive(), g_tweakGuiColors->GetMissileIconColorChargedNoAlt(), factor) + addColor); } } else { if (x58_24_missilesActive) x74_basewidget_missileicon->SetColor(g_tweakGuiColors->GetMissileIconColorActive() + addColor); else x74_basewidget_missileicon->SetColor(g_tweakGuiColors->GetMissileIconColorInactive() + addColor); } } x50_missileIconAltDeplete = std::max(0.f, x50_missileIconAltDeplete - dt); x64_energybart01_missilebar->SetMaxEnergy(x4_missileCapacity); x64_energybart01_missilebar->SetCurrEnergy(x8_numMissles, CAuiEnergyBarT01::ESetMode::Normal); if (x58_28_notXRay) { x74_basewidget_missileicon->SetLocalTransform(x10_missleIconXf * zeus::CTransform::Translate(0.f, 0.f, x8_numMissles * IconTranslateRanges[int(x0_hudType)] / float(x4_missileCapacity))); } if (x58_27_hasArrows) { if (xc_arrowTimer > 0.f) { xc_arrowTimer = std::max(0.f, xc_arrowTimer - dt); zeus::CColor color = g_tweakGuiColors->GetMissileIconColorActive(); color.a *= xc_arrowTimer / g_tweakGui->GetMissileArrowVisTime(); x6c_model_missilearrowup->SetColor(color); x70_model_missilearrowdown->SetIsVisible(false); } else if (xc_arrowTimer < 0.f) { xc_arrowTimer = std::min(0.f, xc_arrowTimer + dt); zeus::CColor color = g_tweakGuiColors->GetMissileIconColorActive(); color.a *= -xc_arrowTimer / g_tweakGui->GetMissileArrowVisTime(); x70_model_missilearrowdown->SetColor(color); x6c_model_missilearrowup->SetIsVisible(false); } else { x6c_model_missilearrowup->SetIsVisible(false); x70_model_missilearrowdown->SetIsVisible(false); } } if (x68_textpane_missilewarning) { EInventoryStatus curStatus = GetMissileInventoryStatus(); if (curStatus != x44_latestStatus) { std::u16string string; switch (curStatus) { case EInventoryStatus::Warning: string = g_MainStringTable->GetString(12); // Missiles Low break; case EInventoryStatus::Depleted: string = g_MainStringTable->GetString(13); // Depleted default: break; } x68_textpane_missilewarning->TextSupport().SetText(string); if (x44_latestStatus == EInventoryStatus::Normal && curStatus == EInventoryStatus::Warning) { CSfxManager::SfxStart(1397, 1.f, 0.f, false, 0x7f, false, kInvalidAreaId); x48_missileWarningPulse = g_tweakGui->GetMissileWarningPulseTime(); } else if (curStatus == EInventoryStatus::Depleted) { CSfxManager::SfxStart(1397, 1.f, 0.f, false, 0x7f, false, kInvalidAreaId); x48_missileWarningPulse = g_tweakGui->GetMissileWarningPulseTime(); } x44_latestStatus = curStatus; } x48_missileWarningPulse = std::max(0.f, x48_missileWarningPulse - dt); float warnPulse = std::min(x48_missileWarningPulse, 1.f); if (x44_latestStatus != EInventoryStatus::Normal) x40_missileWarningAlpha = std::min(x40_missileWarningAlpha + 2.f * dt, 1.f); else x40_missileWarningAlpha = std::max(0.f, x40_missileWarningAlpha - 2.f * dt); float tmp = std::fabs(std::fmod(CGraphics::GetSecondsMod900(), 0.5f)); if (tmp < 0.25f) tmp = tmp / 0.25f; else tmp = (0.5f - tmp) / 0.25f; zeus::CColor color = zeus::CColor::skWhite; color.a = x40_missileWarningAlpha * tmp * warnPulse; x68_textpane_missilewarning->SetColor(color); if (x68_textpane_missilewarning->GetGeometryColor().a) x68_textpane_missilewarning->SetIsVisible(true); else x68_textpane_missilewarning->SetIsVisible(false); } } void CHudMissileInterface::SetIsVisibleGame(bool v, const CStateManager& mgr) { x58_26_visibleGame = v; UpdateVisibility(mgr); } void CHudMissileInterface::SetIsVisibleDebug(bool v, const CStateManager& mgr) { x58_25_visibleDebug = v; UpdateVisibility(mgr); } void CHudMissileInterface::SetIsMissilesActive(bool active) { x58_24_missilesActive = active; } void CHudMissileInterface::SetChargeBeamFactor(float t) { x4c_chargeBeamFactor = t; } void CHudMissileInterface::SetNumMissiles(int numMissiles, const CStateManager& mgr) { numMissiles = zeus::clamp(0, numMissiles, 999); x60_textpane_missiledigits->TextSupport().SetText(hecl::Format("%3d", numMissiles)); if (x8_numMissles < numMissiles) { xc_arrowTimer = g_tweakGui->GetMissileArrowVisTime(); x54_missileIconIncrement = -FLT_EPSILON; } else if (x8_numMissles > numMissiles) { xc_arrowTimer = -g_tweakGui->GetMissileArrowVisTime(); } if (mgr.GetPlayerState()->GetMissileCostForAltAttack() + numMissiles <= x8_numMissles) x50_missileIconAltDeplete = 1.f; x8_numMissles = numMissiles; } void CHudMissileInterface::SetMissileCapacity(int missileCapacity) { x4_missileCapacity = missileCapacity; } CHudMissileInterface::EInventoryStatus CHudMissileInterface::GetMissileInventoryStatus() { if (x64_energybart01_missilebar->GetSetEnergy() == 0.f) return EInventoryStatus::Depleted; return EInventoryStatus(x64_energybart01_missilebar->GetActualFraction() < g_tweakGui->GetMissileWarningFraction()); } std::pair CHudMissileInterface::CombatMissileBarCoordFunc(float t) { float z = t * IconTranslateRanges[int(EHudType::Combat)]; return {zeus::CVector3f(0.f, 0.f, z), zeus::CVector3f(0.3f, 0.f, z)}; } std::pair CHudMissileInterface::XRayMissileBarCoordFunc(float t) { float theta = 0.8f * (t - 0.5f); float x = 9.55f * std::cos(theta); float z = 9.55f * std::sin(theta); return {zeus::CVector3f(x - 0.4f, 0.f, z), zeus::CVector3f(x, 0.f, z)}; } std::pair CHudMissileInterface::ThermalMissileBarCoordFunc(float t) { float transRange = IconTranslateRanges[int(EHudType::Thermal)]; float a = 0.08f * transRange; float b = t * transRange; float c; if (b < a) c = b / a; else if (b < transRange - a) c = 1.f; else c = 1.f - (b - (transRange - a)) / a; return {zeus::CVector3f(-0.5f * c - 0.1f, 0.f, b), zeus::CVector3f(-0.1f, 0.f, b)}; } }