#include "CInventoryScreen.hpp" #include "GuiSys/CGuiTableGroup.hpp" #include "GuiSys/CGuiTextPane.hpp" #include "GuiSys/CGuiModel.hpp" #include "Input/ControlMapper.hpp" #include "GameGlobalObjects.hpp" namespace urde::MP1 { struct SInventoryItem { u32 idx; u32 nameStrIdx; u32 entryStrIdx; }; static const SInventoryItem ArmCannonItems[] = { {0, 0x24, 0x46}, // Power Beam {1, 0x25, 0x48}, // Ice Beam {2, 0x26, 0x4a}, // Wave Beam {3, 0x27, 0x4c}, // Plasma Beam {4, 0x28, 0x4e}, // Phazon Beam }; static const SInventoryItem MorphballItems[] = { {5, 0x2e, 0x57}, // Morph Ball {6, 0x2f, 0x58}, // Boost Ball {7, 0x30, 0x59}, // Spider Ball {8, 0x31, 0x5a}, // Morph Ball Bomb {9, 0x32, 0x5b}, // Power Bomb }; static const SInventoryItem SuitItems[] = { {10, 0x33, 0x52}, // Power Suit {11, 0x34, 0x53}, // Varia Suit {12, 0x35, 0x54}, // Gravity Suit {13, 0x36, 0x55}, // Phazon Suit {14, 0x37, 0x56}, // Energy Tank }; static const SInventoryItem VisorItems[] = { {15, 0x38, 0x42}, // Combat Visor {16, 0x39, 0x43}, // Scan Visor {17, 0x3a, 0x44}, // X-Ray Visor {18, 0x3b, 0x45}, // Thermal Visor }; static const SInventoryItem SecondaryItems[] = { {19, 0x3c, 0x4f}, // Space Jump Boots {20, 0x3d, 0x50}, // Grapple Beam {21, 0x3e, 0x51}, // Missile Launcher {22, 0x3f, 0x5c}, // Charge Beam {23, 0x40, 0x5d}, // Beam Combo }; static const std::pair InventoryRegistry[] = { {5, ArmCannonItems}, {5, MorphballItems}, {5, SuitItems}, {4, VisorItems}, {5, SecondaryItems}, }; CInventoryScreen::CInventoryScreen(const CStateManager& mgr, CGuiFrame& frame, const CStringTable& pauseStrg, const CDependencyGroup& suitDgrp, const CDependencyGroup& ballDgrp) : CPauseScreenBase(mgr, frame, pauseStrg) { CPlayerState& playerState = *mgr.GetPlayerState(); x19c_samusDoll = std::make_unique(suitDgrp, ballDgrp, CPlayerState::EPlayerSuit(int(playerState.GetCurrentSuit()) + playerState.IsFusionEnabled() * 4), playerState.GetCurrentBeam(), playerState.HasPowerUp(CPlayerState::EItemType::SpiderBall), playerState.HasPowerUp(CPlayerState::EItemType::GrappleBeam)); } bool CInventoryScreen::InputDisabled() const { return std::fabs(x19c_samusDoll->GetViewInterpolation()) > 0 || x1a8_state == EState::Leaving; } void CInventoryScreen::TransitioningAway() { x1a8_state = EState::Leaving; } void CInventoryScreen::Update(float dt, CRandom16& rand, CArchitectureQueue& archQueue) { CPauseScreenBase::Update(dt, rand, archQueue); x19c_samusDoll->Update(dt, rand); if (x10_mode == EMode::TextScroll) { if (x1ad_textViewing) x1a4_textBodyAlpha = std::min(4.f * dt + x1a4_textBodyAlpha, 1.f); else x1a4_textBodyAlpha = std::max(0.f, x1a4_textBodyAlpha - 4.f * dt); x174_textpane_body->SetColor(zeus::CColor(1.f, x1a4_textBodyAlpha)); x180_basewidget_yicon->SetColor(zeus::CColor(1.f, 1.f - x1a4_textBodyAlpha)); if (x1a4_textBodyAlpha == 0.f && x1a8_state == EState::Active) ChangeMode(EMode::RightTable); } x19c_samusDoll->SetInMorphball( x70_tablegroup_leftlog->GetUserSelection() == 1 && x10_mode != EMode::LeftTable); UpdateSamusDollPulses(); if (x1a8_state == EState::Leaving && x1a4_textBodyAlpha == 0.f) x1a8_state = EState::Inactive; } void CInventoryScreen::Touch() { CPauseScreenBase::Touch(); x19c_samusDoll->Touch(); } void CInventoryScreen::ProcessControllerInput(const CFinalInput& input) { float viewInterp = x19c_samusDoll->GetViewInterpolation(); if (x1a8_state == EState::Inactive || (viewInterp != 0.f && viewInterp != 1.f)) return; float absViewInterp = std::fabs(viewInterp); if (input.PY() && x19c_samusDoll->IsLoaded() && (absViewInterp > 0.f || x10_mode != EMode::TextScroll)) x19c_samusDoll->BeginViewInterpolate(absViewInterp == 0.f); if (absViewInterp == 1.f) { if (input.PStart()) { x19c_samusDoll->BeginViewInterpolate(false); x198_26_exitPauseScreen = true; } else if (input.PB()) { x19c_samusDoll->BeginViewInterpolate(false); } } if (std::fabs(x19c_samusDoll->GetViewInterpolation()) > 0.f) { float motionAmt = input.DeltaTime() * 6.f; float circleUp = ControlMapper::GetAnalogInput(ControlMapper::ECommands::MapCircleUp, input); float circleDown = ControlMapper::GetAnalogInput(ControlMapper::ECommands::MapCircleDown, input); float circleLeft = ControlMapper::GetAnalogInput(ControlMapper::ECommands::MapCircleLeft, input); float circleRight = ControlMapper::GetAnalogInput(ControlMapper::ECommands::MapCircleRight, input); float moveForward = ControlMapper::GetAnalogInput(ControlMapper::ECommands::MapMoveForward, input); float moveBack = ControlMapper::GetAnalogInput(ControlMapper::ECommands::MapMoveBack, input); float moveLeft = ControlMapper::GetAnalogInput(ControlMapper::ECommands::MapMoveLeft, input); float moveRight = ControlMapper::GetAnalogInput(ControlMapper::ECommands::MapMoveRight, input); float zoomIn = ControlMapper::GetAnalogInput(ControlMapper::ECommands::MapZoomIn, input); float zoomOut = ControlMapper::GetAnalogInput(ControlMapper::ECommands::MapZoomOut, input); zeus::CVector3f moveVec = {(moveRight - moveLeft) * 0.25f * motionAmt, (zoomIn - zoomOut) * 0.5f * motionAmt, (moveForward - moveBack) * 0.25f * motionAmt}; x19c_samusDoll->SetOffset(moveVec, input.DeltaTime()); x19c_samusDoll->SetRotation(0.5f * motionAmt * (circleDown - circleUp), 0.5f * motionAmt * (circleRight - circleLeft), input.DeltaTime()); } else { x1ad_textViewing = false; if (x10_mode == EMode::TextScroll) { int oldPage = x174_textpane_body->TextSupport().GetPageCounter(); int newPage = oldPage; int totalCount = x174_textpane_body->TextSupport().GetTotalPageCount(); bool lastPage = totalCount - 1 == oldPage; if (totalCount != -1) { if (input.PLAUp()) newPage = std::max(oldPage - 1, 0); else if (input.PLADown() || (input.PA() && !lastPage)) newPage = std::min(oldPage + 1, totalCount - 1); x174_textpane_body->TextSupport().SetPage(newPage); if (oldPage != newPage) CSfxManager::SfxStart(1444, 1.f, 0.f, false, 0x7f, false, kInvalidAreaId); x198_28_pulseTextArrowTop = newPage > 0; x198_29_pulseTextArrowBottom = !lastPage; } else { x198_29_pulseTextArrowBottom = false; x198_28_pulseTextArrowTop = false; } if (!x1ac_textLeaveRequested) x1ac_textLeaveRequested = input.PB() || (input.PA() && lastPage); x1ad_textViewing = !x1ac_textLeaveRequested; } else { x198_29_pulseTextArrowBottom = false; x198_28_pulseTextArrowTop = false; } if (x1a8_state != EState::Active) x1ad_textViewing = false; CPauseScreenBase::ProcessControllerInput(input); } } void CInventoryScreen::Draw(float transInterp, float totalAlpha, float yOff) { CPauseScreenBase::Draw(transInterp, totalAlpha, std::fabs(x19c_samusDoll->GetViewInterpolation())); x19c_samusDoll->Draw(x4_mgr, transInterp * (1.f - x1a4_textBodyAlpha)); } float CInventoryScreen::GetCameraYBias() const { return std::fabs(x19c_samusDoll->GetViewInterpolation()); } bool CInventoryScreen::VReady() const { return true; } bool CInventoryScreen::HasLeftInventoryItem(int idx) const { CPlayerState& playerState = *x4_mgr.GetPlayerState(); switch (idx) { case 0: // Arm Cannon return true; case 1: // Morphball return playerState.HasPowerUp(CPlayerState::EItemType::MorphBall); case 2: // Suit return true; case 3: // Visor return true; case 4: // Secondary return playerState.HasPowerUp(CPlayerState::EItemType::SpaceJumpBoots) || playerState.HasPowerUp(CPlayerState::EItemType::GrappleBeam) || playerState.HasPowerUp(CPlayerState::EItemType::Missiles) || playerState.HasPowerUp(CPlayerState::EItemType::ChargeBeam) || playerState.HasPowerUp(CPlayerState::EItemType::SuperMissile) || playerState.HasPowerUp(CPlayerState::EItemType::IceSpreader) || playerState.HasPowerUp(CPlayerState::EItemType::Wavebuster) || playerState.HasPowerUp(CPlayerState::EItemType::Flamethrower); default: return false; } } void CInventoryScreen::VActivate() { for (int i=0 ; i<5 ; ++i) { if (HasLeftInventoryItem(i)) { xa8_textpane_categories[i]->TextSupport().SetText(xc_pauseStrg.GetString(i + 10)); } else { xa8_textpane_categories[i]->TextSupport().SetText(u"??????"); x70_tablegroup_leftlog->GetWorkerWidget(i)->SetIsSelectable(false); } } x178_textpane_title->TextSupport().SetText(xc_pauseStrg.GetString(9)); x180_basewidget_yicon->SetVisibility(true, ETraversalMode::Children); } void CInventoryScreen::RightTableSelectionChanged(int oldSel, int newSel) {} void CInventoryScreen::UpdateTextBody() { x1ac_textLeaveRequested = false; const SInventoryItem& sel = InventoryRegistry[x70_tablegroup_leftlog->GetUserSelection()].second[x1c_rightSel]; std::u16string entryText = xc_pauseStrg.GetString(sel.entryStrIdx); if (sel.idx == 23) // Beam combo { CPlayerState& playerState = *x4_mgr.GetPlayerState(); entryText += xc_pauseStrg.GetString(playerState.HasPowerUp(CPlayerState::EItemType::SuperMissile) ? 71 : 65); entryText += xc_pauseStrg.GetString(playerState.HasPowerUp(CPlayerState::EItemType::IceSpreader) ? 73 : 65); entryText += xc_pauseStrg.GetString(playerState.HasPowerUp(CPlayerState::EItemType::Wavebuster) ? 75 : 65); entryText += xc_pauseStrg.GetString(playerState.HasPowerUp(CPlayerState::EItemType::Flamethrower) ? 77 : 65); } x174_textpane_body->TextSupport().SetText(entryText, true); x174_textpane_body->TextSupport().SetPage(0); } void CInventoryScreen::ChangedMode(EMode oldMode) { if (x10_mode == EMode::TextScroll) { x1ad_textViewing = true; UpdateTextBody(); } } bool CInventoryScreen::HasRightInventoryItem(int idx) const { CPlayerState& playerState = *x4_mgr.GetPlayerState(); switch (idx) { case 0: // Power Beam return true; case 1: // Ice Beam return playerState.HasPowerUp(CPlayerState::EItemType::IceBeam); case 2: // Wave Beam return playerState.HasPowerUp(CPlayerState::EItemType::WaveBeam); case 3: // Plasma Beam return playerState.HasPowerUp(CPlayerState::EItemType::PlasmaBeam); case 4: // Phazon Beam return playerState.HasPowerUp(CPlayerState::EItemType::PhazonSuit); case 5: // Morph Ball return playerState.HasPowerUp(CPlayerState::EItemType::MorphBall); case 6: // Boost Ball return playerState.HasPowerUp(CPlayerState::EItemType::BoostBall); case 7: // Spider Ball return playerState.HasPowerUp(CPlayerState::EItemType::SpiderBall); case 8: // Morph Ball Bomb return playerState.HasPowerUp(CPlayerState::EItemType::MorphBallBombs); case 9: // Power Bomb return playerState.HasPowerUp(CPlayerState::EItemType::PowerBombs); case 10: // Power Suit return true; case 11: // Varia Suit return playerState.HasPowerUp(CPlayerState::EItemType::VariaSuit); case 12: // Gravity Suit return playerState.HasPowerUp(CPlayerState::EItemType::GravitySuit); case 13: // Phazon Suit return playerState.HasPowerUp(CPlayerState::EItemType::PhazonSuit); case 14: // Energy Tank return playerState.HasPowerUp(CPlayerState::EItemType::EnergyTanks); case 15: // Combat Visor return true; case 16: // Scan Visor return playerState.HasPowerUp(CPlayerState::EItemType::ScanVisor); case 17: // X-Ray Visor return playerState.HasPowerUp(CPlayerState::EItemType::XRayVisor); case 18: // Thermal Visor return playerState.HasPowerUp(CPlayerState::EItemType::ThermalVisor); case 19: // Space Jump Boots return playerState.HasPowerUp(CPlayerState::EItemType::SpaceJumpBoots); case 20: // Grapple Beam return playerState.HasPowerUp(CPlayerState::EItemType::GrappleBeam); case 21: // Missile Launcher return playerState.HasPowerUp(CPlayerState::EItemType::Missiles); case 22: // Charge Beam return playerState.HasPowerUp(CPlayerState::EItemType::ChargeBeam); case 23: // Beam Combo return playerState.HasPowerUp(CPlayerState::EItemType::SuperMissile) || playerState.HasPowerUp(CPlayerState::EItemType::IceSpreader) || playerState.HasPowerUp(CPlayerState::EItemType::Wavebuster) || playerState.HasPowerUp(CPlayerState::EItemType::Flamethrower); default: return false; } } bool CInventoryScreen::IsRightInventoryItemEquipped(int idx) const { CPlayerState& playerState = *x4_mgr.GetPlayerState(); switch (idx) { case 0: // Power Beam return playerState.GetCurrentBeam() == CPlayerState::EBeamId::Power; case 1: // Ice Beam return playerState.GetCurrentBeam() == CPlayerState::EBeamId::Ice; case 2: // Wave Beam return playerState.GetCurrentBeam() == CPlayerState::EBeamId::Wave; case 3: // Plasma Beam return playerState.GetCurrentBeam() == CPlayerState::EBeamId::Plasma; case 4: // Phazon Beam return playerState.GetCurrentBeam() == CPlayerState::EBeamId::Phazon2; case 5: // Morph Ball return playerState.HasPowerUp(CPlayerState::EItemType::MorphBall); case 6: // Boost Ball return playerState.HasPowerUp(CPlayerState::EItemType::BoostBall); case 7: // Spider Ball return playerState.HasPowerUp(CPlayerState::EItemType::SpiderBall); case 8: // Morph Ball Bomb return playerState.HasPowerUp(CPlayerState::EItemType::MorphBallBombs); case 9: // Power Bomb return playerState.HasPowerUp(CPlayerState::EItemType::PowerBombs); case 10: // Power Suit return playerState.GetCurrentSuit() == CPlayerState::EPlayerSuit::Power; case 11: // Varia Suit return playerState.GetCurrentSuit() == CPlayerState::EPlayerSuit::Varia; case 12: // Gravity Suit return playerState.GetCurrentSuit() == CPlayerState::EPlayerSuit::Gravity; case 13: // Phazon Suit return playerState.GetCurrentSuit() == CPlayerState::EPlayerSuit::Phazon; case 14: // Energy Tank return playerState.HasPowerUp(CPlayerState::EItemType::EnergyTanks); case 15: // Combat Visor return playerState.GetCurrentVisor() == CPlayerState::EPlayerVisor::Combat; case 16: // Scan Visor return playerState.GetCurrentVisor() == CPlayerState::EPlayerVisor::Scan; case 17: // X-Ray Visor return playerState.GetCurrentVisor() == CPlayerState::EPlayerVisor::XRay; case 18: // Thermal Visor return playerState.GetCurrentVisor() == CPlayerState::EPlayerVisor::Thermal; case 19: // Space Jump Boots return playerState.HasPowerUp(CPlayerState::EItemType::SpaceJumpBoots); case 20: // Grapple Beam return playerState.HasPowerUp(CPlayerState::EItemType::GrappleBeam); case 21: // Missile Launcher return playerState.HasPowerUp(CPlayerState::EItemType::Missiles); case 22: // Charge Beam return playerState.HasPowerUp(CPlayerState::EItemType::ChargeBeam); case 23: // Beam Combo return playerState.HasPowerUp(CPlayerState::EItemType::SuperMissile) || playerState.HasPowerUp(CPlayerState::EItemType::IceSpreader) || playerState.HasPowerUp(CPlayerState::EItemType::Wavebuster) || playerState.HasPowerUp(CPlayerState::EItemType::Flamethrower); default: return false; } } void CInventoryScreen::UpdateRightTable() { CPauseScreenBase::UpdateRightTable(); const std::pair& category = InventoryRegistry[x70_tablegroup_leftlog->GetUserSelection()]; int minSel = INT_MAX; for (int i=0 ; i<5 ; ++i) { CGuiTextPane* title = xd8_textpane_titles[i]; if (i < category.first) { if (HasRightInventoryItem(category.second[i].idx)) { title->TextSupport().SetText(xc_pauseStrg.GetString(category.second[i].nameStrIdx)); x84_tablegroup_rightlog->GetWorkerWidget(i + 1)->SetIsSelectable(true); if (i < minSel) minSel = i; } else { title->TextSupport().SetText(u"??????"); x84_tablegroup_rightlog->GetWorkerWidget(i + 1)->SetIsSelectable(false); } } else { title->TextSupport().SetText(u"??????"); } } if (minSel != INT_MAX) { x1c_rightSel = minSel; SetRightTableSelection(x1c_rightSel, x1c_rightSel); } x84_tablegroup_rightlog->GetWorkerWidget(0)->SetIsSelectable(false); x84_tablegroup_rightlog->GetWorkerWidget(x84_tablegroup_rightlog->GetElementCount() - 1)->SetIsSelectable(false); zeus::CColor inactiveColor = g_tweakGuiColors->GetPauseItemAmberColor(); inactiveColor.a = 0.5f; UpdateRightLogColors(false, g_tweakGuiColors->GetPauseItemAmberColor(), inactiveColor); } bool CInventoryScreen::ShouldLeftTableAdvance() const { return x19c_samusDoll->IsLoaded(); } bool CInventoryScreen::ShouldRightTableAdvance() const { return std::fabs(x19c_samusDoll->GetViewInterpolation()) == 0.f; } u32 CInventoryScreen::GetRightTableCount() const { return InventoryRegistry[x70_tablegroup_leftlog->GetUserSelection()].first; } bool CInventoryScreen::IsRightLogDynamic() const { return true; } void CInventoryScreen::UpdateRightLogColors(bool active, const zeus::CColor& activeColor, const zeus::CColor& inactiveColor) { x80_basewidget_rightlog->SetColor(active ? zeus::CColor::skWhite : zeus::CColor(1.f, 0.71f)); const std::pair& cat = InventoryRegistry[x70_tablegroup_leftlog->GetUserSelection()]; for (u32 i=0 ; i<5 ; ++i) { if (i < cat.first && IsRightInventoryItemEquipped(cat.second[i].idx)) { x15c_model_righttitledecos[i]->SetColor(g_tweakGuiColors->GetPauseItemBlueColor()); xd8_textpane_titles[i]->TextSupport().SetFontColor(g_tweakGuiColors->GetPauseItemBlueColor()); } else { x15c_model_righttitledecos[i]->SetColor(activeColor); xd8_textpane_titles[i]->TextSupport().SetFontColor(activeColor); } } } void CInventoryScreen::UpdateRightLogHighlight(bool active, int idx, const zeus::CColor& activeColor, const zeus::CColor& inactiveColor) { zeus::CColor actColor = g_tweakGuiColors->GetPauseItemAmberColor() * activeColor; zeus::CColor inactColor = g_tweakGuiColors->GetPauseItemAmberColor() * inactiveColor; const std::pair& cat = InventoryRegistry[x70_tablegroup_leftlog->GetUserSelection()]; for (u32 i=0 ; i<5 ; ++i) { bool act = i == idx && active; if (i < cat.first && IsRightInventoryItemEquipped(cat.second[i].idx) && act) x8c_model_righthighlight->SetColor(g_tweakGuiColors->GetPauseItemBlueColor()); else if (act) x8c_model_righthighlight->SetColor(actColor); x144_model_titles[i]->SetColor(act ? actColor : inactColor); } } void CInventoryScreen::UpdateSamusDollPulses() { bool pulseSuit = false; bool pulseBeam = false; bool pulseGrapple = false; bool pulseBoots = false; bool pulseVisor = false; int userSel = x70_tablegroup_leftlog->GetUserSelection(); if (x10_mode == EMode::RightTable) { if (userSel == 2) pulseSuit = true; else if (userSel == 0) pulseBeam = true; else if (userSel == 3) pulseVisor = true; else if (userSel == 4) { pulseGrapple = SecondaryItems[x1c_rightSel].idx == 20; pulseBoots = SecondaryItems[x1c_rightSel].idx == 19; if (SecondaryItems[x1c_rightSel].idx == 21) pulseBeam = true; } } x19c_samusDoll->SetPulseSuit(pulseSuit); x19c_samusDoll->SetPulseBeam(pulseBeam); x19c_samusDoll->SetPulseGrapple(pulseGrapple); x19c_samusDoll->SetPulseBoots(pulseBoots); x19c_samusDoll->SetPulseVisor(pulseVisor); } }