mirror of
https://github.com/TombEngine/TombEngine.git
synced 2025-04-28 15:57:59 +03:00
3599 lines
96 KiB
C++
3599 lines
96 KiB
C++
#include "framework.h"
|
|
#include "Game/Gui.h"
|
|
|
|
#include <OISKeyboard.h>
|
|
|
|
#include "Game/animation.h"
|
|
#include "Game/camera.h"
|
|
#include "Game/control/control.h"
|
|
#include "Game/control/volume.h"
|
|
#include "Game/effects/DisplaySprite.h"
|
|
#include "Game/items.h"
|
|
#include "Game/Lara/lara.h"
|
|
#include "Game/Lara/lara_fire.h"
|
|
#include "Game/Lara/lara_helpers.h"
|
|
#include "Game/Lara/Optics.h"
|
|
#include "Game/Lara/lara_one_gun.h"
|
|
#include "Game/Lara/lara_two_guns.h"
|
|
#include "Game/pickup/pickup.h"
|
|
#include "Game/savegame.h"
|
|
#include "Game/spotcam.h"
|
|
#include "Renderer/Renderer.h"
|
|
#include "Scripting/Include/ScriptInterfaceGame.h"
|
|
#include "Scripting/Include/ScriptInterfaceLevel.h"
|
|
#include "Sound/sound.h"
|
|
#include "Specific/Input/Input.h"
|
|
#include "Specific/clock.h"
|
|
#include "Specific/configuration.h"
|
|
#include "Specific/level.h"
|
|
#include "Specific/trutils.h"
|
|
#include "Specific/winmain.h"
|
|
|
|
using namespace TEN::Effects::DisplaySprite;
|
|
using namespace TEN::Input;
|
|
using namespace TEN::Renderer;
|
|
using namespace TEN::Utils;
|
|
|
|
namespace TEN::Gui
|
|
{
|
|
constexpr int LINE_HEIGHT = 25;
|
|
constexpr int PHD_CENTER_X = DISPLAY_SPACE_RES.x / 2;
|
|
constexpr int PHD_CENTER_Y = DISPLAY_SPACE_RES.y / 2;
|
|
constexpr int OBJLIST_SPACING = PHD_CENTER_X / 2;
|
|
|
|
constexpr auto VOLUME_MAX = 100;
|
|
constexpr auto VOLUME_STEP = VOLUME_MAX / 20;
|
|
constexpr auto MOUSE_SENSITIVITY_MAX = 35;
|
|
constexpr auto MOUSE_SENSITIVITY_MIN = 1;
|
|
constexpr auto MOUSE_SMOOTHING_MAX = 5;
|
|
constexpr auto MOUSE_SMOOTHING_MIN = 0;
|
|
|
|
GuiController g_Gui;
|
|
|
|
std::vector<std::string> OptionStrings =
|
|
{
|
|
STRING_USE,
|
|
STRING_CHOOSE_AMMO,
|
|
STRING_COMBINE,
|
|
STRING_SEPARATE,
|
|
STRING_EQUIP,
|
|
STRING_COMBINE_WITH,
|
|
STRING_LOAD_GAME,
|
|
STRING_SAVE_GAME,
|
|
STRING_EXAMINE,
|
|
STRING_VIEW,
|
|
STRING_CHOOSE_WEAPON,
|
|
""
|
|
};
|
|
|
|
std::vector<std::string> GeneralActionStrings =
|
|
{
|
|
STRING_ACTIONS_FORWARD,
|
|
STRING_ACTIONS_BACKWARD,
|
|
STRING_ACTIONS_LEFT,
|
|
STRING_ACTIONS_RIGHT,
|
|
STRING_ACTIONS_STEP_LEFT,
|
|
STRING_ACTIONS_STEP_RIGHT,
|
|
STRING_ACTIONS_WALK,
|
|
STRING_ACTIONS_SPRINT,
|
|
STRING_ACTIONS_CROUCH,
|
|
STRING_ACTIONS_JUMP,
|
|
STRING_ACTIONS_ROLL,
|
|
STRING_ACTIONS_ACTION,
|
|
STRING_ACTIONS_DRAW,
|
|
STRING_ACTIONS_LOOK
|
|
};
|
|
|
|
std::vector<std::string> VehicleActionStrings =
|
|
{
|
|
STRING_ACTIONS_ACCELERATE,
|
|
STRING_ACTIONS_REVERSE,
|
|
STRING_ACTIONS_SPEED,
|
|
STRING_ACTIONS_SLOW,
|
|
STRING_ACTIONS_BRAKE,
|
|
STRING_ACTIONS_FIRE
|
|
};
|
|
|
|
std::vector<std::string> QuickActionStrings =
|
|
{
|
|
STRING_ACTIONS_FLARE,
|
|
STRING_ACTIONS_SMALL_MEDIPACK,
|
|
STRING_ACTIONS_LARGE_MEDIPACK,
|
|
STRING_ACTIONS_PREVIOUS_WEAPON,
|
|
STRING_ACTIONS_NEXT_WEAPON,
|
|
STRING_ACTIONS_WEAPON_1,
|
|
STRING_ACTIONS_WEAPON_2,
|
|
STRING_ACTIONS_WEAPON_3,
|
|
STRING_ACTIONS_WEAPON_4,
|
|
STRING_ACTIONS_WEAPON_5,
|
|
STRING_ACTIONS_WEAPON_6,
|
|
STRING_ACTIONS_WEAPON_7,
|
|
STRING_ACTIONS_WEAPON_8,
|
|
STRING_ACTIONS_WEAPON_9,
|
|
STRING_ACTIONS_WEAPON_10
|
|
};
|
|
|
|
std::vector<std::string> MenuActionStrings =
|
|
{
|
|
STRING_ACTIONS_SELECT,
|
|
STRING_ACTIONS_DESELECT,
|
|
STRING_ACTIONS_PAUSE,
|
|
STRING_ACTIONS_INVENTORY,
|
|
STRING_ACTIONS_SAVE,
|
|
STRING_ACTIONS_LOAD
|
|
};
|
|
|
|
bool GuiController::GuiIsPulsed(InputActionID actionID) const
|
|
{
|
|
constexpr auto DELAY = 0.1f;
|
|
constexpr auto INITIAL_DELAY = 0.4f;
|
|
|
|
// Action already held prior to entering menu; lock input.
|
|
if (GetActionTimeActive(actionID) >= TimeInMenu)
|
|
return false;
|
|
|
|
// Pulse only directional inputs.
|
|
auto oppositeAction = std::optional<InputActionID>(std::nullopt);
|
|
switch (actionID)
|
|
{
|
|
case In::Forward:
|
|
oppositeAction = In::Back;
|
|
break;
|
|
|
|
case In::Back:
|
|
oppositeAction = In::Forward;
|
|
break;
|
|
|
|
case In::Left:
|
|
oppositeAction = In::Right;
|
|
break;
|
|
|
|
case In::Right:
|
|
oppositeAction = In::Left;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// Opposite action held; lock input.
|
|
bool isActionLocked = oppositeAction.has_value() ? IsHeld(*oppositeAction) : false;
|
|
if (isActionLocked)
|
|
return false;
|
|
|
|
return IsPulsed(actionID, DELAY, INITIAL_DELAY);
|
|
}
|
|
|
|
bool GuiController::GuiIsSelected(bool onClicked) const
|
|
{
|
|
if (onClicked)
|
|
{
|
|
return ((IsClicked(In::Select) || IsClicked(In::Action)) && CanSelect());
|
|
}
|
|
else
|
|
{
|
|
return ((IsReleased(In::Select) || IsReleased(In::Action)) && CanSelect());
|
|
}
|
|
}
|
|
|
|
bool GuiController::GuiIsDeselected() const
|
|
{
|
|
return ((IsClicked(In::Deselect) || IsClicked(In::Draw)) && CanDeselect());
|
|
}
|
|
|
|
bool GuiController::CanSelect() const
|
|
{
|
|
// Holding Deselect safely cancels select actions.
|
|
if (IsHeld(In::Deselect))
|
|
return false;
|
|
|
|
// Avoid Select or Action release interference when entering inventory.
|
|
if (GetActionTimeActive(In::Select) < TimeInMenu && GetActionTimeActive(In::Action) < TimeInMenu)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
bool GuiController::CanDeselect() const
|
|
{
|
|
return !(IsHeld(In::Select) || IsHeld(In::Action));
|
|
}
|
|
|
|
SettingsData& GuiController::GetCurrentSettings()
|
|
{
|
|
return CurrentSettings;
|
|
}
|
|
|
|
const InventoryRing& GuiController::GetRing(RingTypes ringType)
|
|
{
|
|
return Rings[(int)ringType];
|
|
}
|
|
|
|
int GuiController::GetSelectedOption()
|
|
{
|
|
return SelectedOption;
|
|
}
|
|
|
|
Menu GuiController::GetMenuToDisplay()
|
|
{
|
|
return MenuToDisplay;
|
|
}
|
|
|
|
void GuiController::SetSelectedOption(int menu)
|
|
{
|
|
SelectedOption = menu;
|
|
}
|
|
|
|
void GuiController::SetMenuToDisplay(Menu menu)
|
|
{
|
|
MenuToDisplay = menu;
|
|
}
|
|
|
|
InventoryMode GuiController::GetInventoryMode()
|
|
{
|
|
return InvMode;
|
|
}
|
|
|
|
void GuiController::SetInventoryMode(InventoryMode mode)
|
|
{
|
|
if (mode != InvMode)
|
|
{
|
|
TimeInMenu = 0;
|
|
InvMode = mode;
|
|
}
|
|
}
|
|
|
|
void GuiController::SetInventoryItemChosen(int number)
|
|
{
|
|
InventoryItemChosen = number;
|
|
}
|
|
|
|
int GuiController::GetInventoryItemChosen()
|
|
{
|
|
return InventoryItemChosen;
|
|
}
|
|
|
|
void GuiController::SetEnterInventory(int number)
|
|
{
|
|
EnterInventory = number;
|
|
}
|
|
|
|
int GuiController::GetEnterInventory()
|
|
{
|
|
return EnterInventory;
|
|
}
|
|
|
|
int GuiController::GetLastInventoryItem()
|
|
{
|
|
return LastInvItem;
|
|
}
|
|
|
|
void GuiController::SetLastInventoryItem(int itemNumber)
|
|
{
|
|
LastInvItem = itemNumber;
|
|
}
|
|
|
|
void GuiController::DrawInventory()
|
|
{
|
|
g_Renderer.RenderInventory();
|
|
g_Renderer.Lock(); // TODO: When inventory is converted to 60 FPS, move this lock call outside of render loop.
|
|
}
|
|
|
|
InventoryResult GuiController::TitleOptions(ItemInfo* item)
|
|
{
|
|
enum TitleOption
|
|
{
|
|
NewGame,
|
|
HomeLevel,
|
|
LoadGame,
|
|
Options,
|
|
ExitGame,
|
|
|
|
Count
|
|
};
|
|
|
|
constexpr auto TITLE_OPTION_COUNT = TitleOption::Count - 1;
|
|
constexpr auto LOAD_GAME_OPTION_COUNT = SAVEGAME_MAX - 1;
|
|
constexpr auto OPTION_OPTION_COUNT = 2;
|
|
|
|
static int selectedOptionBackup;
|
|
auto inventoryResult = InventoryResult::None;
|
|
|
|
TimeInMenu++;
|
|
|
|
// Stuff for credits goes here!
|
|
|
|
switch (MenuToDisplay)
|
|
{
|
|
case Menu::Title:
|
|
OptionCount = TITLE_OPTION_COUNT;
|
|
|
|
if (!g_GameFlow->IsHomeLevelEnabled())
|
|
OptionCount--;
|
|
|
|
if (!g_GameFlow->IsLoadSaveEnabled())
|
|
OptionCount--;
|
|
|
|
break;
|
|
|
|
case Menu::SelectLevel:
|
|
inventoryResult = InventoryResult::None;
|
|
OptionCount = g_GameFlow->GetNumLevels() - 2;
|
|
|
|
if (g_GameFlow->IsHomeLevelEnabled())
|
|
OptionCount--;
|
|
|
|
break;
|
|
|
|
case Menu::LoadGame:
|
|
OptionCount = LOAD_GAME_OPTION_COUNT;
|
|
break;
|
|
|
|
case Menu::Options:
|
|
OptionCount = OPTION_OPTION_COUNT;
|
|
break;
|
|
|
|
case Menu::Display:
|
|
HandleDisplaySettingsInput(false);
|
|
return inventoryResult;
|
|
|
|
case Menu::GeneralActions:
|
|
case Menu::VehicleActions:
|
|
case Menu::QuickActions:
|
|
case Menu::MenuActions:
|
|
HandleControlSettingsInput(item, false);
|
|
return inventoryResult;
|
|
|
|
case Menu::OtherSettings:
|
|
HandleOtherSettingsInput(false);
|
|
return inventoryResult;
|
|
}
|
|
|
|
if (MenuToDisplay == Menu::LoadGame)
|
|
{
|
|
switch (DoLoad())
|
|
{
|
|
case LoadResult::Load:
|
|
inventoryResult = InventoryResult::LoadGame;
|
|
break;
|
|
|
|
case LoadResult::Cancel:
|
|
MenuToDisplay = Menu::Title;
|
|
SelectedOption = selectedOptionBackup;
|
|
SoundEffect(SFX_TR4_MENU_SELECT, nullptr, SoundEnvironment::Always);
|
|
break;
|
|
|
|
case LoadResult::None:
|
|
break;
|
|
}
|
|
}
|
|
else if (MenuToDisplay == Menu::Title ||
|
|
MenuToDisplay == Menu::SelectLevel ||
|
|
MenuToDisplay == Menu::Options)
|
|
{
|
|
SelectedOption = GetLoopedSelectedOption(SelectedOption, OptionCount, g_Configuration.MenuOptionLoopingMode == MenuOptionLoopingMode::AllMenus);
|
|
|
|
if (GuiIsDeselected() && MenuToDisplay != Menu::Title)
|
|
{
|
|
MenuToDisplay = Menu::Title;
|
|
SelectedOption = selectedOptionBackup;
|
|
SoundEffect(SFX_TR4_MENU_SELECT, nullptr, SoundEnvironment::Always);
|
|
}
|
|
|
|
if (GuiIsSelected())
|
|
{
|
|
SoundEffect(SFX_TR4_MENU_SELECT, nullptr, SoundEnvironment::Always);
|
|
|
|
if (MenuToDisplay == Menu::Title)
|
|
{
|
|
int realSelectedOption = SelectedOption;
|
|
|
|
// Skip Home Level entry if home level is disabled.
|
|
if (!g_GameFlow->IsHomeLevelEnabled() && realSelectedOption > TitleOption::NewGame)
|
|
realSelectedOption++;
|
|
|
|
// Skip Load Game entry if loading and saving is disabled.
|
|
if (!g_GameFlow->IsLoadSaveEnabled() && realSelectedOption > TitleOption::HomeLevel)
|
|
realSelectedOption++;
|
|
|
|
switch (realSelectedOption)
|
|
{
|
|
case TitleOption::NewGame:
|
|
if (g_GameFlow->IsLevelSelectEnabled())
|
|
{
|
|
selectedOptionBackup = SelectedOption;
|
|
SelectedOption = 0;
|
|
MenuToDisplay = Menu::SelectLevel;
|
|
}
|
|
else
|
|
{
|
|
inventoryResult = InventoryResult::NewGame;
|
|
}
|
|
|
|
break;
|
|
|
|
case TitleOption::HomeLevel:
|
|
inventoryResult = InventoryResult::HomeLevel;
|
|
break;
|
|
|
|
case TitleOption::LoadGame:
|
|
selectedOptionBackup = SelectedOption;
|
|
SelectedOption = 0;
|
|
MenuToDisplay = Menu::LoadGame;
|
|
SaveGame::LoadHeaders();
|
|
break;
|
|
|
|
case TitleOption::Options:
|
|
selectedOptionBackup = SelectedOption;
|
|
SelectedOption = 0;
|
|
MenuToDisplay = Menu::Options;
|
|
break;
|
|
|
|
case TitleOption::ExitGame:
|
|
inventoryResult = InventoryResult::ExitGame;
|
|
break;
|
|
}
|
|
}
|
|
else if (MenuToDisplay == Menu::SelectLevel)
|
|
{
|
|
// Level 0 is Title Level; increment option to offset it.
|
|
g_GameFlow->SelectedLevelForNewGame = SelectedOption + 1;
|
|
|
|
// Level 1 reserved for Home Level; increment option if enabled to offset it.
|
|
if (g_GameFlow->IsHomeLevelEnabled())
|
|
g_GameFlow->SelectedLevelForNewGame++;
|
|
|
|
MenuToDisplay = Menu::Title;
|
|
SelectedOption = 0;
|
|
inventoryResult = InventoryResult::NewGameSelectedLevel;
|
|
}
|
|
else if (MenuToDisplay == Menu::Options)
|
|
HandleOptionsInput();
|
|
}
|
|
}
|
|
|
|
return inventoryResult;
|
|
}
|
|
|
|
void GuiController::FillDisplayOptions()
|
|
{
|
|
// Copy configuration to a temporary object
|
|
BackupOptions();
|
|
|
|
// Get current display mode
|
|
CurrentSettings.SelectedScreenResolution = 0;
|
|
for (int i = 0; i < g_Configuration.SupportedScreenResolutions.size(); i++)
|
|
{
|
|
auto screenResolution = g_Configuration.SupportedScreenResolutions[i];
|
|
if (screenResolution.x == CurrentSettings.Configuration.ScreenWidth &&
|
|
screenResolution.y == CurrentSettings.Configuration.ScreenHeight)
|
|
{
|
|
CurrentSettings.SelectedScreenResolution = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void GuiController::HandleDisplaySettingsInput(bool fromPauseMenu)
|
|
{
|
|
enum DisplaySettingsOption
|
|
{
|
|
ScreenResolution,
|
|
Windowed,
|
|
ShadowType,
|
|
Caustics,
|
|
Antialiasing,
|
|
AmbientOcclusion,
|
|
HighFramerate,
|
|
Save,
|
|
Cancel
|
|
};
|
|
|
|
static const int numDisplaySettingsOptions = 8;
|
|
|
|
OptionCount = numDisplaySettingsOptions;
|
|
|
|
if (GuiIsDeselected())
|
|
{
|
|
SoundEffect(SFX_TR4_MENU_SELECT, nullptr);
|
|
MenuToDisplay = Menu::Options;
|
|
SelectedOption = 0;
|
|
return;
|
|
}
|
|
|
|
if (GuiIsPulsed(In::Left))
|
|
{
|
|
switch (SelectedOption)
|
|
{
|
|
case DisplaySettingsOption::ScreenResolution:
|
|
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
|
if (CurrentSettings.SelectedScreenResolution > 0)
|
|
CurrentSettings.SelectedScreenResolution--;
|
|
|
|
break;
|
|
|
|
case DisplaySettingsOption::Windowed:
|
|
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
|
CurrentSettings.Configuration.EnableWindowedMode = !CurrentSettings.Configuration.EnableWindowedMode;
|
|
break;
|
|
|
|
case DisplaySettingsOption::ShadowType:
|
|
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
|
|
|
if (CurrentSettings.Configuration.ShadowType == ShadowMode::None)
|
|
CurrentSettings.Configuration.ShadowType = ShadowMode::All;
|
|
else
|
|
CurrentSettings.Configuration.ShadowType = ShadowMode(int(CurrentSettings.Configuration.ShadowType) - 1);
|
|
|
|
break;
|
|
|
|
case DisplaySettingsOption::Caustics:
|
|
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
|
CurrentSettings.Configuration.EnableCaustics = !CurrentSettings.Configuration.EnableCaustics;
|
|
break;
|
|
|
|
case DisplaySettingsOption::Antialiasing:
|
|
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
|
|
|
if (CurrentSettings.Configuration.AntialiasingMode == AntialiasingMode::None)
|
|
CurrentSettings.Configuration.AntialiasingMode = AntialiasingMode::High;
|
|
else
|
|
CurrentSettings.Configuration.AntialiasingMode = AntialiasingMode(int(CurrentSettings.Configuration.AntialiasingMode) - 1);
|
|
|
|
break;
|
|
|
|
case DisplaySettingsOption::AmbientOcclusion:
|
|
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
|
CurrentSettings.Configuration.EnableAmbientOcclusion = !CurrentSettings.Configuration.EnableAmbientOcclusion;
|
|
break;
|
|
|
|
case DisplaySettingsOption::HighFramerate:
|
|
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
|
CurrentSettings.Configuration.EnableHighFramerate = !CurrentSettings.Configuration.EnableHighFramerate;
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
if (GuiIsPulsed(In::Right))
|
|
{
|
|
switch (SelectedOption)
|
|
{
|
|
case DisplaySettingsOption::ScreenResolution:
|
|
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
|
if (CurrentSettings.SelectedScreenResolution < g_Configuration.SupportedScreenResolutions.size() - 1)
|
|
CurrentSettings.SelectedScreenResolution++;
|
|
break;
|
|
|
|
case DisplaySettingsOption::Windowed:
|
|
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
|
CurrentSettings.Configuration.EnableWindowedMode = !CurrentSettings.Configuration.EnableWindowedMode;
|
|
break;
|
|
|
|
case DisplaySettingsOption::ShadowType:
|
|
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
|
if (CurrentSettings.Configuration.ShadowType == ShadowMode::All)
|
|
CurrentSettings.Configuration.ShadowType = ShadowMode::None;
|
|
else
|
|
CurrentSettings.Configuration.ShadowType = ShadowMode(int(CurrentSettings.Configuration.ShadowType) + 1);
|
|
|
|
break;
|
|
|
|
case DisplaySettingsOption::Caustics:
|
|
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
|
CurrentSettings.Configuration.EnableCaustics = !CurrentSettings.Configuration.EnableCaustics;
|
|
break;
|
|
|
|
case DisplaySettingsOption::Antialiasing:
|
|
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
|
|
|
if (CurrentSettings.Configuration.AntialiasingMode == AntialiasingMode::High)
|
|
CurrentSettings.Configuration.AntialiasingMode = AntialiasingMode::None;
|
|
else
|
|
CurrentSettings.Configuration.AntialiasingMode = AntialiasingMode(int(CurrentSettings.Configuration.AntialiasingMode) + 1);
|
|
|
|
break;
|
|
|
|
case DisplaySettingsOption::AmbientOcclusion:
|
|
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
|
CurrentSettings.Configuration.EnableAmbientOcclusion = !CurrentSettings.Configuration.EnableAmbientOcclusion;
|
|
break;
|
|
|
|
case DisplaySettingsOption::HighFramerate:
|
|
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
|
CurrentSettings.Configuration.EnableHighFramerate = !CurrentSettings.Configuration.EnableHighFramerate;
|
|
break;
|
|
}
|
|
}
|
|
|
|
SelectedOption = GetLoopedSelectedOption(SelectedOption, OptionCount, g_Configuration.MenuOptionLoopingMode == MenuOptionLoopingMode::AllMenus);
|
|
|
|
if (GuiIsSelected())
|
|
{
|
|
SoundEffect(SFX_TR4_MENU_SELECT, nullptr, SoundEnvironment::Always);
|
|
|
|
if (SelectedOption == DisplaySettingsOption::Save)
|
|
{
|
|
// Save the configuration.
|
|
auto screenResolution = g_Configuration.SupportedScreenResolutions[CurrentSettings.SelectedScreenResolution];
|
|
|
|
bool screenResolutionChanged = CurrentSettings.Configuration.ScreenWidth != screenResolution.x ||
|
|
CurrentSettings.Configuration.ScreenHeight != screenResolution.y;
|
|
|
|
CurrentSettings.Configuration.ScreenWidth = screenResolution.x;
|
|
CurrentSettings.Configuration.ScreenHeight = screenResolution.y;
|
|
|
|
// Determine whether we should update AA shaders.
|
|
bool shouldRecompileAAShaders = CurrentSettings.Configuration.AntialiasingMode != AntialiasingMode::Low &&
|
|
(screenResolutionChanged || g_Configuration.AntialiasingMode != CurrentSettings.Configuration.AntialiasingMode);
|
|
|
|
g_Configuration = CurrentSettings.Configuration;
|
|
SaveConfiguration();
|
|
|
|
// Reset screen and go back.
|
|
g_Renderer.ChangeScreenResolution(CurrentSettings.Configuration.ScreenWidth, CurrentSettings.Configuration.ScreenHeight,
|
|
CurrentSettings.Configuration.EnableWindowedMode);
|
|
|
|
g_Renderer.ReloadShaders(shouldRecompileAAShaders);
|
|
g_Renderer.SetGraphicsSettingsChanged();
|
|
|
|
MenuToDisplay = fromPauseMenu ? Menu::Pause : Menu::Options;
|
|
SelectedOption = fromPauseMenu ? 1 : 0;
|
|
}
|
|
else if (SelectedOption == DisplaySettingsOption::Cancel)
|
|
{
|
|
MenuToDisplay = fromPauseMenu ? Menu::Pause : Menu::Options;
|
|
SelectedOption = fromPauseMenu ? 1 : 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
void GuiController::HandleControlSettingsInput(ItemInfo* item, bool fromPauseMenu)
|
|
{
|
|
unsigned int numControlSettingsOptions = 0;
|
|
switch (MenuToDisplay)
|
|
{
|
|
default:
|
|
case Menu::GeneralActions:
|
|
numControlSettingsOptions = (int)GeneralActionStrings.size() + 2;
|
|
break;
|
|
|
|
case Menu::VehicleActions:
|
|
numControlSettingsOptions = (int)VehicleActionStrings.size() + 2;
|
|
break;
|
|
|
|
case Menu::QuickActions:
|
|
numControlSettingsOptions = (int)QuickActionStrings.size() + 2;
|
|
break;
|
|
|
|
case Menu::MenuActions:
|
|
numControlSettingsOptions = (int)MenuActionStrings.size() + 2;
|
|
break;
|
|
}
|
|
|
|
OptionCount = numControlSettingsOptions;
|
|
CurrentSettings.NewKeyWaitTimer = 0.0f;
|
|
|
|
if (CurrentSettings.IgnoreInput)
|
|
{
|
|
if (NoAction())
|
|
CurrentSettings.IgnoreInput = false;
|
|
|
|
return;
|
|
}
|
|
|
|
if (GuiIsSelected() &&
|
|
SelectedOption <= (numControlSettingsOptions - 3))
|
|
{
|
|
SoundEffect(SFX_TR4_MENU_SELECT, nullptr, SoundEnvironment::Always);
|
|
CurrentSettings.NewKeyWaitTimer = SettingsData::NEW_KEY_WAIT_TIMEOUT;
|
|
CurrentSettings.IgnoreInput = true;
|
|
}
|
|
|
|
if (CurrentSettings.NewKeyWaitTimer > 0.0f)
|
|
{
|
|
ClearAllActions();
|
|
|
|
g_Synchronizer.Init();
|
|
|
|
bool legacy30FpsDoneDraw = false;
|
|
bool decreaseCounter = false;
|
|
|
|
while (CurrentSettings.NewKeyWaitTimer > 0.0f)
|
|
{
|
|
g_Synchronizer.Sync();
|
|
|
|
while (g_Synchronizer.Synced())
|
|
{
|
|
CurrentSettings.NewKeyWaitTimer -= 1.0f;
|
|
if (CurrentSettings.NewKeyWaitTimer <= 0.0f)
|
|
CurrentSettings.NewKeyWaitTimer = 0.0f;
|
|
|
|
if (!fromPauseMenu)
|
|
{
|
|
ControlPhase(true);
|
|
}
|
|
else
|
|
{
|
|
g_Renderer.PrepareScene(); // Just for updating blink time.
|
|
UpdateInputActions(item);
|
|
}
|
|
|
|
if (CurrentSettings.IgnoreInput)
|
|
{
|
|
if (NoAction())
|
|
CurrentSettings.IgnoreInput = false;
|
|
}
|
|
else
|
|
{
|
|
int selectedKeyID = 0;
|
|
for (selectedKeyID = 0; selectedKeyID < KEY_COUNT; selectedKeyID++)
|
|
{
|
|
if (KeyMap[selectedKeyID])
|
|
break;
|
|
}
|
|
|
|
if (selectedKeyID == KEY_COUNT)
|
|
selectedKeyID = 0;
|
|
|
|
if (selectedKeyID && !GetKeyName(selectedKeyID).empty())
|
|
{
|
|
unsigned int baseIndex = 0;
|
|
switch (MenuToDisplay)
|
|
{
|
|
case Menu::VehicleActions:
|
|
baseIndex = (unsigned int)GeneralActionStrings.size();
|
|
break;
|
|
|
|
case Menu::QuickActions:
|
|
baseIndex = unsigned int(GeneralActionStrings.size() + VehicleActionStrings.size());
|
|
break;
|
|
|
|
case Menu::MenuActions:
|
|
baseIndex = unsigned int(GeneralActionStrings.size() + VehicleActionStrings.size() + QuickActionStrings.size());
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
g_Bindings.SetKeyBinding(InputDeviceID::Custom, InputActionID(baseIndex + SelectedOption), selectedKeyID);
|
|
DefaultConflict();
|
|
|
|
CurrentSettings.NewKeyWaitTimer = 0.0f;
|
|
CurrentSettings.IgnoreInput = true;
|
|
return;
|
|
}
|
|
}
|
|
|
|
g_Synchronizer.Step();
|
|
|
|
legacy30FpsDoneDraw = false;
|
|
}
|
|
|
|
if (!g_Configuration.EnableHighFramerate)
|
|
{
|
|
if (!legacy30FpsDoneDraw)
|
|
{
|
|
if (fromPauseMenu)
|
|
{
|
|
g_Renderer.RenderInventory();
|
|
}
|
|
else
|
|
{
|
|
g_Renderer.RenderTitle(0);
|
|
}
|
|
g_Renderer.Lock();
|
|
legacy30FpsDoneDraw = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//g_Renderer.PrepareScene();
|
|
|
|
if (fromPauseMenu)
|
|
{
|
|
g_Renderer.RenderInventory();
|
|
}
|
|
else
|
|
{
|
|
g_Renderer.RenderTitle(0);
|
|
}
|
|
g_Renderer.Lock();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SelectedOption = GetLoopedSelectedOption(SelectedOption, OptionCount, g_Configuration.MenuOptionLoopingMode == MenuOptionLoopingMode::AllMenus);
|
|
|
|
// HACK: Menu screen scroll.
|
|
if (GuiIsPulsed(In::Left) || GuiIsPulsed(In::Right))
|
|
{
|
|
auto menu = std::optional<Menu>(std::nullopt);
|
|
|
|
if (GuiIsPulsed(In::Left))
|
|
{
|
|
if ((int)MenuToDisplay == (int)Menu::GeneralActions)
|
|
{
|
|
menu = Menu::MenuActions;
|
|
}
|
|
else
|
|
{
|
|
menu = Menu((int)MenuToDisplay - 1);
|
|
}
|
|
}
|
|
else if (GuiIsPulsed(In::Right))
|
|
{
|
|
if ((int)MenuToDisplay == (int)Menu::MenuActions)
|
|
{
|
|
menu = Menu::GeneralActions;
|
|
}
|
|
else
|
|
{
|
|
menu = Menu((int)MenuToDisplay + 1);
|
|
}
|
|
}
|
|
|
|
if (menu.has_value())
|
|
{
|
|
MenuToDisplay = *menu;
|
|
SelectedOption = 0;
|
|
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (GuiIsSelected())
|
|
{
|
|
// Defaults.
|
|
if (SelectedOption == (OptionCount - 2))
|
|
{
|
|
SoundEffect(SFX_TR4_MENU_SELECT, nullptr, SoundEnvironment::Always);
|
|
ApplyDefaultBindings();
|
|
return;
|
|
}
|
|
|
|
// Apply.
|
|
if (SelectedOption == (OptionCount - 1))
|
|
{
|
|
SoundEffect(SFX_TR4_MENU_SELECT, nullptr, SoundEnvironment::Always);
|
|
CurrentSettings.Configuration.Bindings = g_Bindings.GetBindingProfile(InputDeviceID::Custom);
|
|
g_Configuration.Bindings = g_Bindings.GetBindingProfile(InputDeviceID::Custom);
|
|
SaveConfiguration();
|
|
MenuToDisplay = fromPauseMenu ? Menu::Pause : Menu::Options;
|
|
SelectedOption = 2;
|
|
return;
|
|
}
|
|
|
|
// Cancel.
|
|
if (SelectedOption == OptionCount)
|
|
{
|
|
SoundEffect(SFX_TR4_MENU_SELECT, nullptr, SoundEnvironment::Always);
|
|
g_Bindings.SetBindingProfile(InputDeviceID::Custom, CurrentSettings.Configuration.Bindings);
|
|
MenuToDisplay = fromPauseMenu ? Menu::Pause : Menu::Options;
|
|
SelectedOption = 2;
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (GuiIsDeselected())
|
|
{
|
|
SoundEffect(SFX_TR4_MENU_SELECT, nullptr, SoundEnvironment::Always);
|
|
|
|
MenuToDisplay = Menu::Options;
|
|
SelectedOption = 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
void GuiController::BackupOptions()
|
|
{
|
|
CurrentSettings.Configuration = g_Configuration;
|
|
}
|
|
|
|
void GuiController::HandleOptionsInput()
|
|
{
|
|
enum OptionsOption
|
|
{
|
|
Display,
|
|
OtherSettings,
|
|
Controls
|
|
};
|
|
|
|
switch (SelectedOption)
|
|
{
|
|
case OptionsOption::Display:
|
|
FillDisplayOptions();
|
|
MenuToDisplay = Menu::Display;
|
|
SelectedOption = 0;
|
|
break;
|
|
|
|
case OptionsOption::OtherSettings:
|
|
BackupOptions();
|
|
MenuToDisplay = Menu::OtherSettings;
|
|
SelectedOption = 0;
|
|
break;
|
|
|
|
case OptionsOption::Controls:
|
|
BackupOptions();
|
|
MenuToDisplay = Menu::GeneralActions;
|
|
SelectedOption = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void GuiController::HandleOtherSettingsInput(bool fromPauseMenu)
|
|
{
|
|
enum OtherSettingsOption
|
|
{
|
|
Reverb,
|
|
MusicVolume,
|
|
SfxVolume,
|
|
|
|
Subtitles,
|
|
AutoMonkeySwingJump,
|
|
AutoTargeting,
|
|
TargetHighlighter,
|
|
ToggleRumble,
|
|
ThumbstickCameraControl,
|
|
|
|
MouseSensitivity,
|
|
|
|
Apply,
|
|
Cancel,
|
|
|
|
Count
|
|
};
|
|
|
|
OptionCount = (int)OtherSettingsOption::Count - 1;
|
|
|
|
if (GuiIsDeselected())
|
|
{
|
|
SoundEffect(SFX_TR4_MENU_SELECT, nullptr, SoundEnvironment::Always);
|
|
|
|
MenuToDisplay = Menu::Options;
|
|
SelectedOption = 1;
|
|
|
|
SetVolumeTracks(g_Configuration.MusicVolume);
|
|
SetVolumeFX(g_Configuration.SfxVolume);
|
|
return;
|
|
}
|
|
|
|
if (GuiIsPulsed(In::Left) || GuiIsPulsed(In::Right))
|
|
{
|
|
switch (SelectedOption)
|
|
{
|
|
case OtherSettingsOption::Reverb:
|
|
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
|
CurrentSettings.Configuration.EnableReverb = !CurrentSettings.Configuration.EnableReverb;
|
|
break;
|
|
|
|
case OtherSettingsOption::AutoMonkeySwingJump:
|
|
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
|
CurrentSettings.Configuration.EnableAutoMonkeySwingJump = !CurrentSettings.Configuration.EnableAutoMonkeySwingJump;
|
|
break;
|
|
|
|
case OtherSettingsOption::Subtitles:
|
|
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
|
CurrentSettings.Configuration.EnableSubtitles = !CurrentSettings.Configuration.EnableSubtitles;
|
|
break;
|
|
|
|
case OtherSettingsOption::AutoTargeting:
|
|
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
|
CurrentSettings.Configuration.EnableAutoTargeting = !CurrentSettings.Configuration.EnableAutoTargeting;
|
|
break;
|
|
|
|
case OtherSettingsOption::TargetHighlighter:
|
|
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
|
CurrentSettings.Configuration.EnableTargetHighlighter = !CurrentSettings.Configuration.EnableTargetHighlighter;
|
|
break;
|
|
|
|
case OtherSettingsOption::ToggleRumble:
|
|
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
|
CurrentSettings.Configuration.EnableRumble = !CurrentSettings.Configuration.EnableRumble;
|
|
break;
|
|
|
|
case OtherSettingsOption::ThumbstickCameraControl:
|
|
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
|
CurrentSettings.Configuration.EnableThumbstickCamera = !CurrentSettings.Configuration.EnableThumbstickCamera;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (IsPulsed(In::Left, 0.05f, 0.4f))
|
|
{
|
|
bool isVolumeAdjusted = false;
|
|
switch (SelectedOption)
|
|
{
|
|
case OtherSettingsOption::MusicVolume:
|
|
if (CurrentSettings.Configuration.MusicVolume > 0)
|
|
{
|
|
CurrentSettings.Configuration.MusicVolume -= VOLUME_STEP;
|
|
if (CurrentSettings.Configuration.MusicVolume < 0)
|
|
CurrentSettings.Configuration.MusicVolume = 0;
|
|
|
|
SetVolumeTracks(CurrentSettings.Configuration.MusicVolume);
|
|
isVolumeAdjusted = true;
|
|
}
|
|
|
|
break;
|
|
|
|
case OtherSettingsOption::SfxVolume:
|
|
if (CurrentSettings.Configuration.SfxVolume > 0)
|
|
{
|
|
CurrentSettings.Configuration.SfxVolume -= VOLUME_STEP;
|
|
if (CurrentSettings.Configuration.SfxVolume < 0)
|
|
CurrentSettings.Configuration.SfxVolume = 0;
|
|
|
|
SetVolumeFX(CurrentSettings.Configuration.SfxVolume);
|
|
isVolumeAdjusted = true;
|
|
}
|
|
|
|
break;
|
|
|
|
case OtherSettingsOption::MouseSensitivity:
|
|
if (CurrentSettings.Configuration.MouseSensitivity > MOUSE_SENSITIVITY_MIN)
|
|
{
|
|
CurrentSettings.Configuration.MouseSensitivity -= 1;
|
|
if (CurrentSettings.Configuration.MouseSensitivity < MOUSE_SENSITIVITY_MIN)
|
|
CurrentSettings.Configuration.MouseSensitivity = MOUSE_SENSITIVITY_MIN;
|
|
|
|
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
if (isVolumeAdjusted)
|
|
{
|
|
if (IsClicked(In::Left))
|
|
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
|
}
|
|
}
|
|
|
|
if (IsPulsed(In::Right, 0.05f, 0.4f))
|
|
{
|
|
bool isVolumeAdjusted = false;
|
|
switch (SelectedOption)
|
|
{
|
|
case OtherSettingsOption::MusicVolume:
|
|
if (CurrentSettings.Configuration.MusicVolume < VOLUME_MAX)
|
|
{
|
|
CurrentSettings.Configuration.MusicVolume += VOLUME_STEP;
|
|
if (CurrentSettings.Configuration.MusicVolume > VOLUME_MAX)
|
|
CurrentSettings.Configuration.MusicVolume = VOLUME_MAX;
|
|
|
|
SetVolumeTracks(CurrentSettings.Configuration.MusicVolume);
|
|
isVolumeAdjusted = true;
|
|
}
|
|
|
|
break;
|
|
|
|
case OtherSettingsOption::SfxVolume:
|
|
if (CurrentSettings.Configuration.SfxVolume < VOLUME_MAX)
|
|
{
|
|
CurrentSettings.Configuration.SfxVolume += VOLUME_STEP;
|
|
if (CurrentSettings.Configuration.SfxVolume > VOLUME_MAX)
|
|
CurrentSettings.Configuration.SfxVolume = VOLUME_MAX;
|
|
|
|
SetVolumeFX(CurrentSettings.Configuration.SfxVolume);
|
|
isVolumeAdjusted = true;
|
|
}
|
|
|
|
break;
|
|
|
|
case OtherSettingsOption::MouseSensitivity:
|
|
if (CurrentSettings.Configuration.MouseSensitivity < MOUSE_SENSITIVITY_MAX)
|
|
{
|
|
CurrentSettings.Configuration.MouseSensitivity += 1;
|
|
if (CurrentSettings.Configuration.MouseSensitivity > MOUSE_SENSITIVITY_MAX)
|
|
CurrentSettings.Configuration.MouseSensitivity = MOUSE_SENSITIVITY_MAX;
|
|
|
|
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
if (isVolumeAdjusted)
|
|
{
|
|
if (IsClicked(In::Right))
|
|
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
|
}
|
|
}
|
|
|
|
SelectedOption = GetLoopedSelectedOption(SelectedOption, OptionCount, g_Configuration.MenuOptionLoopingMode == MenuOptionLoopingMode::AllMenus);
|
|
|
|
if (GuiIsSelected())
|
|
{
|
|
SoundEffect(SFX_TR4_MENU_SELECT, nullptr, SoundEnvironment::Always);
|
|
|
|
if (SelectedOption == OtherSettingsOption::Apply)
|
|
{
|
|
// Was rumble setting changed?
|
|
bool indicateRumble = CurrentSettings.Configuration.EnableRumble && !g_Configuration.EnableRumble;
|
|
|
|
// Save the configuration.
|
|
g_Configuration = CurrentSettings.Configuration;
|
|
SaveConfiguration();
|
|
|
|
// Rumble if setting was changed.
|
|
if (indicateRumble)
|
|
Rumble(0.5f);
|
|
|
|
MenuToDisplay = fromPauseMenu ? Menu::Pause : Menu::Options;
|
|
SelectedOption = 1;
|
|
}
|
|
else if (SelectedOption == OtherSettingsOption::Cancel)
|
|
{
|
|
SoundEffect(SFX_TR4_MENU_SELECT, nullptr, SoundEnvironment::Always);
|
|
SetVolumeTracks(g_Configuration.MusicVolume);
|
|
SetVolumeFX(g_Configuration.SfxVolume);
|
|
MenuToDisplay = fromPauseMenu ? Menu::Pause : Menu::Options;
|
|
SelectedOption = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
InventoryResult GuiController::DoPauseMenu(ItemInfo* item)
|
|
{
|
|
enum PauseMenuOption
|
|
{
|
|
Statistics,
|
|
Options,
|
|
ExitToTitle
|
|
};
|
|
|
|
static const int numPauseOptions = 2;
|
|
static const int numStatisticsOptions = 0;
|
|
static const int numOptionsOptions = 2;
|
|
|
|
TimeInMenu++;
|
|
UpdateInputActions(item);
|
|
|
|
switch (MenuToDisplay)
|
|
{
|
|
case Menu::Pause:
|
|
OptionCount = numPauseOptions;
|
|
break;
|
|
|
|
case Menu::Statistics:
|
|
OptionCount = numStatisticsOptions;
|
|
break;
|
|
|
|
case Menu::Options:
|
|
OptionCount = numOptionsOptions;
|
|
break;
|
|
|
|
case Menu::Display:
|
|
HandleDisplaySettingsInput(true);
|
|
return InventoryResult::None;
|
|
|
|
case Menu::GeneralActions:
|
|
case Menu::VehicleActions:
|
|
case Menu::QuickActions:
|
|
case Menu::MenuActions:
|
|
HandleControlSettingsInput(item, true);
|
|
return InventoryResult::None;
|
|
|
|
case Menu::OtherSettings:
|
|
HandleOtherSettingsInput(true);
|
|
return InventoryResult::None;
|
|
}
|
|
|
|
if (MenuToDisplay == Menu::Pause ||
|
|
MenuToDisplay == Menu::Options)
|
|
{
|
|
SelectedOption = GetLoopedSelectedOption(SelectedOption, OptionCount, g_Configuration.MenuOptionLoopingMode == MenuOptionLoopingMode::AllMenus);
|
|
}
|
|
|
|
if (GuiIsDeselected() || IsClicked(In::Pause))
|
|
{
|
|
if (MenuToDisplay == Menu::Pause)
|
|
{
|
|
SetInventoryMode(InventoryMode::None);
|
|
SoundEffect(SFX_TR4_MENU_SELECT, nullptr, SoundEnvironment::Always);
|
|
return InventoryResult::None;
|
|
}
|
|
|
|
if (MenuToDisplay == Menu::Statistics ||
|
|
MenuToDisplay == Menu::Options)
|
|
{
|
|
SelectedOption = ((MenuToDisplay == Menu::Statistics) ? PauseMenuOption::Statistics : PauseMenuOption::Options);
|
|
MenuToDisplay = Menu::Pause;
|
|
SoundEffect(SFX_TR4_MENU_SELECT, nullptr, SoundEnvironment::Always);
|
|
}
|
|
}
|
|
|
|
if (GuiIsSelected())
|
|
{
|
|
switch (MenuToDisplay)
|
|
{
|
|
case Menu::Pause:
|
|
|
|
switch (SelectedOption)
|
|
{
|
|
case PauseMenuOption::Statistics:
|
|
SelectedOption = 0;
|
|
MenuToDisplay = Menu::Statistics;
|
|
break;
|
|
|
|
case PauseMenuOption::Options:
|
|
SelectedOption = 0;
|
|
MenuToDisplay = Menu::Options;
|
|
break;
|
|
|
|
case PauseMenuOption::ExitToTitle:
|
|
SetInventoryMode(InventoryMode::None);
|
|
App.ResetClock = true;
|
|
return InventoryResult::ExitToTitle;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
case Menu::Options:
|
|
HandleOptionsInput();
|
|
break;
|
|
|
|
case Menu::Statistics:
|
|
MenuToDisplay = Menu::Pause;
|
|
SoundEffect(SFX_TR4_MENU_SELECT, nullptr, SoundEnvironment::Always);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return InventoryResult::None;
|
|
}
|
|
|
|
//----------
|
|
// Inventory
|
|
//----------
|
|
|
|
bool GuiController::DoObjectsCombine(int objectNumber1, int objectNumber2)
|
|
{
|
|
for (int n = 0; n < MAX_COMBINES; n++)
|
|
{
|
|
if (CombineTable[n].Item1 == objectNumber1 &&
|
|
CombineTable[n].Item2 == objectNumber2)
|
|
return true;
|
|
|
|
if (CombineTable[n].Item1 == objectNumber2 &&
|
|
CombineTable[n].Item2 == objectNumber1)
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool GuiController::IsItemCurrentlyCombinable(int objectNumber)
|
|
{
|
|
static const int numSmallWaterskins = INV_OBJECT_SMALL_WATERSKIN_3L - INV_OBJECT_SMALL_WATERSKIN_EMPTY + 1;
|
|
static const int numBigWaterskins = INV_OBJECT_BIG_WATERSKIN_5L - INV_OBJECT_BIG_WATERSKIN_EMPTY + 1;
|
|
|
|
if (objectNumber < INV_OBJECT_SMALL_WATERSKIN_EMPTY || objectNumber > INV_OBJECT_BIG_WATERSKIN_5L)//trash
|
|
{
|
|
for (int n = 0; n < MAX_COMBINES; n++)
|
|
{
|
|
if (CombineTable[n].Item1 == objectNumber)
|
|
{
|
|
if (IsItemInInventory(CombineTable[n].Item2))
|
|
return true;
|
|
}
|
|
|
|
if (CombineTable[n].Item2 == objectNumber)
|
|
{
|
|
if (IsItemInInventory(CombineTable[n].Item1))
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
else if (objectNumber > INV_OBJECT_SMALL_WATERSKIN_3L)
|
|
{
|
|
for (int n = 0; n < numSmallWaterskins; n++)
|
|
{
|
|
if (IsItemInInventory(n + INV_OBJECT_SMALL_WATERSKIN_EMPTY))
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int n = 0; n < numBigWaterskins; n++)
|
|
{
|
|
if (IsItemInInventory(n + INV_OBJECT_BIG_WATERSKIN_EMPTY))
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool GuiController::IsItemInInventory(int objectNumber)
|
|
{
|
|
const auto& ring = Rings[(int)RingTypes::Inventory];
|
|
for (int i = 0; i < INVENTORY_TABLE_SIZE; i++)
|
|
{
|
|
const auto& listObject = ring.CurrentObjectList[i];
|
|
if (listObject.InventoryItem == objectNumber)
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void GuiController::CombineObjects(ItemInfo* item, int objectNumber1, int objectNumber2)
|
|
{
|
|
int n;
|
|
for (n = 0; n < MAX_COMBINES; n++)
|
|
{
|
|
if (CombineTable[n].Item1 == objectNumber1 &&
|
|
CombineTable[n].Item2 == objectNumber2)
|
|
break;
|
|
|
|
if (CombineTable[n].Item1 == objectNumber2 &&
|
|
CombineTable[n].Item2 == objectNumber1)
|
|
break;
|
|
}
|
|
|
|
CombineTable[n].CombineRoutine(item, false);
|
|
ConstructObjectList(item);
|
|
SetupObjectListStartPosition(CombineTable[n].CombinedItem);
|
|
HandleObjectChangeover((int)RingTypes::Inventory);
|
|
}
|
|
|
|
void GuiController::SeparateObject(ItemInfo* item, int objectNumber)
|
|
{
|
|
int n = 0;
|
|
for (n = 0; n < MAX_COMBINES; n++)
|
|
{
|
|
if (CombineTable[n].CombinedItem == objectNumber)
|
|
break;
|
|
}
|
|
|
|
CombineTable[n].CombineRoutine(item, true);
|
|
ConstructObjectList(item);
|
|
SetupObjectListStartPosition(CombineTable[n].Item1);
|
|
}
|
|
|
|
void GuiController::SetupObjectListStartPosition(int newObjectNumber)
|
|
{
|
|
auto& ring = Rings[(int)RingTypes::Inventory];
|
|
for (int i = 0; i < INVENTORY_TABLE_SIZE; i++)
|
|
{
|
|
const auto& listObject = ring.CurrentObjectList[i];
|
|
if (listObject.InventoryItem == newObjectNumber)
|
|
ring.CurrentObjectInList = i;
|
|
}
|
|
}
|
|
|
|
void GuiController::HandleObjectChangeover(int ringIndex)
|
|
{
|
|
CurrentSelectedOption = 0;
|
|
MenuActive = true;
|
|
SetupAmmoSelector();
|
|
}
|
|
|
|
void GuiController::SetupAmmoSelector()
|
|
{
|
|
const auto& ring = Rings[(int)RingTypes::Inventory];
|
|
const auto& invObject = InventoryObjectTable[ring.CurrentObjectList[ring.CurrentObjectInList].InventoryItem];
|
|
|
|
int number = 0;
|
|
unsigned __int64 options = invObject.Options;
|
|
AmmoSelectorFlag = 0;
|
|
NumAmmoSlots = 0;
|
|
|
|
if (Rings[(int)RingTypes::Ammo].RingActive)
|
|
return;
|
|
|
|
AmmoObjectList[0].Orientation = EulerAngles::Identity;
|
|
AmmoObjectList[1].Orientation = EulerAngles::Identity;
|
|
AmmoObjectList[2].Orientation = EulerAngles::Identity;
|
|
|
|
if (options &
|
|
(OPT_CHOOSE_AMMO_UZI | OPT_CHOOSE_AMMO_PISTOLS | OPT_CHOOSE_AMMO_REVOLVER | OPT_CHOOSE_AMMO_CROSSBOW |
|
|
OPT_CHOOSE_AMMO_HK | OPT_CHOOSE_AMMO_SHOTGUN | OPT_CHOOSE_AMMO_GRENADEGUN | OPT_CHOOSE_AMMO_HARPOON | OPT_CHOOSE_AMMO_ROCKET))
|
|
{
|
|
AmmoSelectorFlag = 1;
|
|
AmmoSelectorFadeDir = 1;
|
|
|
|
if (options & OPT_CHOOSE_AMMO_UZI)
|
|
{
|
|
AmmoObjectList[0].InventoryItem = INV_OBJECT_UZI_AMMO;
|
|
AmmoObjectList[0].Amount = Ammo.AmountUziAmmo;
|
|
number++;
|
|
NumAmmoSlots = number;
|
|
CurrentAmmoType = &Ammo.CurrentUziAmmoType;
|
|
}
|
|
|
|
if (options & OPT_CHOOSE_AMMO_PISTOLS)
|
|
{
|
|
number++;
|
|
AmmoObjectList[0].InventoryItem = INV_OBJECT_PISTOLS_AMMO;
|
|
AmmoObjectList[0].Amount = Ammo.AmountPistolsAmmo;
|
|
NumAmmoSlots = number;
|
|
CurrentAmmoType = &Ammo.CurrentPistolsAmmoType;
|
|
}
|
|
|
|
if (options & OPT_CHOOSE_AMMO_REVOLVER)
|
|
{
|
|
number++;
|
|
AmmoObjectList[0].InventoryItem = INV_OBJECT_REVOLVER_AMMO;
|
|
AmmoObjectList[0].Amount = Ammo.AmountRevolverAmmo;
|
|
NumAmmoSlots = number;
|
|
CurrentAmmoType = &Ammo.CurrentRevolverAmmoType;
|
|
}
|
|
|
|
if (options & OPT_CHOOSE_AMMO_CROSSBOW)
|
|
{
|
|
AmmoObjectList[number].InventoryItem = INV_OBJECT_CROSSBOW_AMMO_1;
|
|
AmmoObjectList[number].Amount = Ammo.AmountCrossBowAmmo1;
|
|
number++;
|
|
AmmoObjectList[number].InventoryItem = INV_OBJECT_CROSSBOW_AMMO_2;
|
|
AmmoObjectList[number].Amount = Ammo.AmountCrossBowAmmo2;
|
|
number++;
|
|
AmmoObjectList[number].InventoryItem = INV_OBJECT_CROSSBOW_AMMO_3;
|
|
AmmoObjectList[number].Amount = Ammo.AmountCrossBowAmmo3;
|
|
number++;
|
|
NumAmmoSlots = number;
|
|
CurrentAmmoType = &Ammo.CurrentCrossBowAmmoType;
|
|
}
|
|
|
|
if (options & OPT_CHOOSE_AMMO_HK)
|
|
{
|
|
AmmoObjectList[number].InventoryItem = INV_HK_MODE1;
|
|
AmmoObjectList[number].Amount = Ammo.AmountHKAmmo1;
|
|
number++;
|
|
AmmoObjectList[number].InventoryItem = INV_HK_MODE2;
|
|
AmmoObjectList[number].Amount = Ammo.AmountHKAmmo1;
|
|
number++;
|
|
AmmoObjectList[number].InventoryItem = INV_HK_MODE3;
|
|
AmmoObjectList[number].Amount = Ammo.AmountHKAmmo1;
|
|
number++;
|
|
NumAmmoSlots = number;
|
|
CurrentAmmoType = &Ammo.CurrentHKAmmoType;
|
|
}
|
|
|
|
if (options & OPT_CHOOSE_AMMO_SHOTGUN)
|
|
{
|
|
AmmoObjectList[number].InventoryItem = INV_OBJECT_SHOTGUN_AMMO_1;
|
|
AmmoObjectList[number].Amount = Ammo.AmountShotGunAmmo1;
|
|
number++;
|
|
AmmoObjectList[number].InventoryItem = INV_OBJECT_SHOTGUN_AMMO_2;
|
|
AmmoObjectList[number].Amount = Ammo.AmountShotGunAmmo2;
|
|
number++;
|
|
NumAmmoSlots = number;
|
|
CurrentAmmoType = &Ammo.CurrentShotGunAmmoType;
|
|
}
|
|
|
|
if (options & OPT_CHOOSE_AMMO_GRENADEGUN)
|
|
{
|
|
AmmoObjectList[number].InventoryItem = INV_OBJECT_GRENADE_AMMO_1;
|
|
AmmoObjectList[number].Amount = Ammo.AmountGrenadeAmmo1;
|
|
number++;
|
|
AmmoObjectList[number].InventoryItem = INV_OBJECT_GRENADE_AMMO_2;
|
|
AmmoObjectList[number].Amount = Ammo.AmountGrenadeAmmo2;
|
|
number++;
|
|
AmmoObjectList[number].InventoryItem = INV_OBJECT_GRENADE_AMMO_3;
|
|
AmmoObjectList[number].Amount = Ammo.AmountGrenadeAmmo3;
|
|
number++;
|
|
NumAmmoSlots = number;
|
|
CurrentAmmoType = &Ammo.CurrentGrenadeGunAmmoType;
|
|
}
|
|
|
|
if (options & OPT_CHOOSE_AMMO_HARPOON)
|
|
{
|
|
AmmoObjectList[number].InventoryItem = INV_OBJECT_HARPOON_AMMO;
|
|
AmmoObjectList[number].Amount = Ammo.AmountHarpoonAmmo;
|
|
number++;
|
|
NumAmmoSlots = number;
|
|
CurrentAmmoType = &Ammo.CurrentHarpoonAmmoType;
|
|
}
|
|
|
|
if (options & OPT_CHOOSE_AMMO_ROCKET)
|
|
{
|
|
AmmoObjectList[number].InventoryItem = INV_OBJECT_ROCKET_AMMO;
|
|
AmmoObjectList[number].Amount = Ammo.AmountRocketsAmmo;
|
|
number++;
|
|
NumAmmoSlots = number;
|
|
CurrentAmmoType = &Ammo.CurrentRocketAmmoType;
|
|
}
|
|
}
|
|
}
|
|
|
|
void GuiController::InsertObjectIntoList(int objectNumber)
|
|
{
|
|
Rings[(int)RingTypes::Inventory].CurrentObjectList[Rings[(int)RingTypes::Inventory].NumObjectsInList].InventoryItem = objectNumber;
|
|
Rings[(int)RingTypes::Inventory].CurrentObjectList[Rings[(int)RingTypes::Inventory].NumObjectsInList].Orientation = EulerAngles::Identity;
|
|
Rings[(int)RingTypes::Inventory].CurrentObjectList[Rings[(int)RingTypes::Inventory].NumObjectsInList].Bright = 32;
|
|
Rings[(int)RingTypes::Inventory].NumObjectsInList++;
|
|
}
|
|
|
|
void GuiController::InsertObjectIntoList_v2(int objectNumber)
|
|
{
|
|
unsigned __int64 options = InventoryObjectTable[objectNumber].Options;
|
|
|
|
if (options & (OPT_COMBINABLE | OPT_ALWAYS_COMBINE))
|
|
{
|
|
if (Rings[(int)RingTypes::Inventory].CurrentObjectList[Rings[(int)RingTypes::Inventory].CurrentObjectInList].InventoryItem != objectNumber)
|
|
{
|
|
Rings[(int)RingTypes::Ammo].CurrentObjectList[Rings[(int)RingTypes::Ammo].NumObjectsInList].InventoryItem = objectNumber;
|
|
Rings[(int)RingTypes::Ammo].CurrentObjectList[Rings[(int)RingTypes::Ammo].NumObjectsInList].Orientation = EulerAngles::Identity;
|
|
Rings[(int)RingTypes::Ammo].CurrentObjectList[Rings[(int)RingTypes::Ammo].NumObjectsInList++].Bright = 32;
|
|
}
|
|
}
|
|
}
|
|
|
|
void GuiController::ConstructObjectList(ItemInfo* item)
|
|
{
|
|
auto& player = GetLaraInfo(*item);
|
|
|
|
Rings[(int)RingTypes::Inventory].NumObjectsInList = 0;
|
|
|
|
for (int i = 0; i < INVENTORY_TABLE_SIZE; i++)
|
|
Rings[(int)RingTypes::Inventory].CurrentObjectList[i].InventoryItem = NO_VALUE;
|
|
|
|
Ammo.CurrentPistolsAmmoType = 0;
|
|
Ammo.CurrentUziAmmoType = 0;
|
|
Ammo.CurrentRevolverAmmoType = 0;
|
|
Ammo.CurrentShotGunAmmoType = 0;
|
|
Ammo.CurrentGrenadeGunAmmoType = 0;
|
|
Ammo.CurrentCrossBowAmmoType = 0;
|
|
|
|
if (player.Weapons[(int)LaraWeaponType::Pistol].Present)
|
|
{
|
|
InsertObjectIntoList(INV_OBJECT_PISTOLS);
|
|
}
|
|
else if (Ammo.AmountPistolsAmmo)
|
|
{
|
|
InsertObjectIntoList(INV_OBJECT_PISTOLS_AMMO);
|
|
}
|
|
|
|
if (player.Weapons[(int)LaraWeaponType::Uzi].Present)
|
|
{
|
|
InsertObjectIntoList(INV_OBJECT_UZIS);
|
|
}
|
|
else if (Ammo.AmountUziAmmo)
|
|
{
|
|
InsertObjectIntoList(INV_OBJECT_UZI_AMMO);
|
|
}
|
|
|
|
if (player.Weapons[(int)LaraWeaponType::Revolver].Present)
|
|
{
|
|
if (player.Weapons[(int)LaraWeaponType::Revolver].HasLasersight)
|
|
{
|
|
InsertObjectIntoList(INV_OBJECT_REVOLVER_LASER);
|
|
}
|
|
else
|
|
{
|
|
InsertObjectIntoList(INV_OBJECT_REVOLVER);
|
|
}
|
|
}
|
|
else if (Ammo.AmountRevolverAmmo)
|
|
{
|
|
InsertObjectIntoList(INV_OBJECT_REVOLVER_AMMO);
|
|
}
|
|
|
|
if (player.Weapons[(int)LaraWeaponType::Shotgun].Present)
|
|
{
|
|
InsertObjectIntoList(INV_OBJECT_SHOTGUN);
|
|
|
|
if (player.Weapons[(int)LaraWeaponType::Shotgun].SelectedAmmo == WeaponAmmoType::Ammo2)
|
|
Ammo.CurrentShotGunAmmoType = 1;
|
|
}
|
|
else
|
|
{
|
|
if (Ammo.AmountShotGunAmmo1)
|
|
InsertObjectIntoList(INV_OBJECT_SHOTGUN_AMMO_1);
|
|
|
|
if (Ammo.AmountShotGunAmmo2)
|
|
InsertObjectIntoList(INV_OBJECT_SHOTGUN_AMMO_2);
|
|
}
|
|
|
|
if (player.Weapons[(int)LaraWeaponType::HK].Present)
|
|
{
|
|
if (player.Weapons[(int)LaraWeaponType::HK].HasLasersight)
|
|
{
|
|
InsertObjectIntoList(INV_OBJECT_HK_LASERSIGHT);
|
|
}
|
|
else
|
|
{
|
|
InsertObjectIntoList(INV_OBJECT_HK);
|
|
}
|
|
|
|
if (player.Weapons[(int)LaraWeaponType::HK].WeaponMode == LaraWeaponTypeCarried::WTYPE_AMMO_2)
|
|
Ammo.CurrentHKAmmoType = 1;
|
|
|
|
if (player.Weapons[(int)LaraWeaponType::HK].WeaponMode == LaraWeaponTypeCarried::WTYPE_AMMO_3)
|
|
Ammo.CurrentHKAmmoType = 2;
|
|
}
|
|
else if (Ammo.AmountHKAmmo1)
|
|
{
|
|
InsertObjectIntoList(INV_OBJECT_HK_AMMO);
|
|
}
|
|
|
|
if (player.Weapons[(int)LaraWeaponType::Crossbow].Present)
|
|
{
|
|
if (player.Weapons[(int)LaraWeaponType::Crossbow].HasLasersight)
|
|
{
|
|
InsertObjectIntoList(INV_OBJECT_CROSSBOW_LASER);
|
|
}
|
|
else
|
|
{
|
|
InsertObjectIntoList(INV_OBJECT_CROSSBOW);
|
|
}
|
|
|
|
if (player.Weapons[(int)LaraWeaponType::Crossbow].SelectedAmmo == WeaponAmmoType::Ammo2)
|
|
Ammo.CurrentCrossBowAmmoType = 1;
|
|
|
|
if (player.Weapons[(int)LaraWeaponType::Crossbow].SelectedAmmo == WeaponAmmoType::Ammo3)
|
|
Ammo.CurrentCrossBowAmmoType = 2;
|
|
}
|
|
else
|
|
{
|
|
if (Ammo.AmountCrossBowAmmo1)
|
|
InsertObjectIntoList(INV_OBJECT_CROSSBOW_AMMO_1);
|
|
|
|
if (Ammo.AmountCrossBowAmmo2)
|
|
InsertObjectIntoList(INV_OBJECT_CROSSBOW_AMMO_2);
|
|
|
|
if (Ammo.AmountCrossBowAmmo3)
|
|
InsertObjectIntoList(INV_OBJECT_CROSSBOW_AMMO_3);
|
|
}
|
|
|
|
if (player.Weapons[(int)LaraWeaponType::GrenadeLauncher].Present)
|
|
{
|
|
InsertObjectIntoList(INV_OBJECT_GRENADE_LAUNCHER);
|
|
|
|
if (player.Weapons[(int)LaraWeaponType::GrenadeLauncher].SelectedAmmo == WeaponAmmoType::Ammo2)
|
|
Ammo.CurrentGrenadeGunAmmoType = 1;
|
|
|
|
if (player.Weapons[(int)LaraWeaponType::GrenadeLauncher].SelectedAmmo == WeaponAmmoType::Ammo3)
|
|
Ammo.CurrentGrenadeGunAmmoType = 2;
|
|
}
|
|
else
|
|
{
|
|
if (Ammo.AmountGrenadeAmmo1)
|
|
InsertObjectIntoList(INV_OBJECT_GRENADE_AMMO_1);
|
|
|
|
if (Ammo.AmountGrenadeAmmo2)
|
|
InsertObjectIntoList(INV_OBJECT_GRENADE_AMMO_2);
|
|
|
|
if (Ammo.AmountGrenadeAmmo3)
|
|
InsertObjectIntoList(INV_OBJECT_GRENADE_AMMO_3);
|
|
}
|
|
|
|
if (player.Weapons[(int)LaraWeaponType::RocketLauncher].Present)
|
|
{
|
|
InsertObjectIntoList(INV_OBJECT_ROCKET_LAUNCHER);
|
|
}
|
|
else if (Ammo.AmountRocketsAmmo)
|
|
{
|
|
InsertObjectIntoList(INV_OBJECT_ROCKET_AMMO);
|
|
}
|
|
|
|
if (player.Weapons[(int)LaraWeaponType::HarpoonGun].Present)
|
|
{
|
|
InsertObjectIntoList(INV_OBJECT_HARPOON_GUN);
|
|
}
|
|
else if (Ammo.AmountHarpoonAmmo)
|
|
{
|
|
InsertObjectIntoList(INV_OBJECT_HARPOON_AMMO);
|
|
}
|
|
|
|
if (player.Inventory.HasLasersight)
|
|
InsertObjectIntoList(INV_OBJECT_LASERSIGHT);
|
|
|
|
if (player.Inventory.HasSilencer)
|
|
InsertObjectIntoList(INV_OBJECT_SILENCER);
|
|
|
|
if (player.Inventory.HasBinoculars)
|
|
InsertObjectIntoList(INV_OBJECT_BINOCULARS);
|
|
|
|
if (player.Inventory.TotalFlares)
|
|
InsertObjectIntoList(INV_OBJECT_FLARES);
|
|
|
|
if (player.Inventory.HasStopwatch)
|
|
InsertObjectIntoList(INV_OBJECT_STOPWATCH);
|
|
|
|
if (player.Inventory.TotalSmallMedipacks)
|
|
InsertObjectIntoList(INV_OBJECT_SMALL_MEDIPACK);
|
|
|
|
if (player.Inventory.TotalLargeMedipacks)
|
|
InsertObjectIntoList(INV_OBJECT_LARGE_MEDIPACK);
|
|
|
|
if (player.Inventory.HasCrowbar)
|
|
InsertObjectIntoList(INV_OBJECT_CROWBAR);
|
|
|
|
if (player.Inventory.BeetleComponents)
|
|
{
|
|
if (player.Inventory.BeetleComponents & BEETLECOMP_FLAG_BEETLE)
|
|
InsertObjectIntoList(INV_OBJECT_BEETLE);
|
|
|
|
if (player.Inventory.BeetleComponents & BEETLECOMP_FLAG_COMBO_1)
|
|
InsertObjectIntoList(INV_OBJECT_BEETLE_PART1);
|
|
|
|
if (player.Inventory.BeetleComponents & BEETLECOMP_FLAG_COMBO_2)
|
|
InsertObjectIntoList(INV_OBJECT_BEETLE_PART2);
|
|
}
|
|
|
|
if (player.Inventory.SmallWaterskin)
|
|
InsertObjectIntoList((player.Inventory.SmallWaterskin - 1) + INV_OBJECT_SMALL_WATERSKIN_EMPTY);
|
|
|
|
if (player.Inventory.BigWaterskin)
|
|
InsertObjectIntoList((player.Inventory.BigWaterskin - 1) + INV_OBJECT_BIG_WATERSKIN_EMPTY);
|
|
|
|
for (int i = 0; i < NUM_PUZZLES; i++)
|
|
{
|
|
if (player.Inventory.Puzzles[i])
|
|
InsertObjectIntoList(INV_OBJECT_PUZZLE1 + i);
|
|
}
|
|
|
|
for (int i = 0; i < NUM_PUZZLE_PIECES; i++)
|
|
{
|
|
if (player.Inventory.PuzzlesCombo[i])
|
|
InsertObjectIntoList(INV_OBJECT_PUZZLE1_COMBO1 + i);
|
|
}
|
|
|
|
for (int i = 0; i < NUM_KEYS; i++)
|
|
{
|
|
if (player.Inventory.Keys[i])
|
|
InsertObjectIntoList(INV_OBJECT_KEY1 + i);
|
|
}
|
|
|
|
for (int i = 0; i < NUM_KEY_PIECES; i++)
|
|
{
|
|
if (player.Inventory.KeysCombo[i])
|
|
InsertObjectIntoList(INV_OBJECT_KEY1_COMBO1 + i);
|
|
}
|
|
|
|
for (int i = 0; i < NUM_PICKUPS; i++)
|
|
{
|
|
if (player.Inventory.Pickups[i])
|
|
InsertObjectIntoList(INV_OBJECT_PICKUP1 + i);
|
|
}
|
|
|
|
for (int i = 0; i < NUM_PICKUPS_PIECES; i++)
|
|
{
|
|
if (player.Inventory.PickupsCombo[i])
|
|
InsertObjectIntoList(INV_OBJECT_PICKUP1_COMBO1 + i);
|
|
}
|
|
|
|
for (int i = 0; i < NUM_EXAMINES; i++)
|
|
{
|
|
if (player.Inventory.Examines[i])
|
|
InsertObjectIntoList(INV_OBJECT_EXAMINE1 + i);
|
|
}
|
|
|
|
for (int i = 0; i < NUM_EXAMINES_PIECES; i++)
|
|
{
|
|
if (player.Inventory.ExaminesCombo[i])
|
|
InsertObjectIntoList(INV_OBJECT_EXAMINE1_COMBO1 + i);
|
|
}
|
|
|
|
if (player.Inventory.HasDiary)
|
|
InsertObjectIntoList(INV_OBJECT_DIARY);
|
|
|
|
if (g_GameFlow->IsLoadSaveEnabled())
|
|
{
|
|
if (player.Inventory.HasLoad)
|
|
InsertObjectIntoList(INV_OBJECT_LOAD_FLOPPY);
|
|
if (player.Inventory.HasSave)
|
|
InsertObjectIntoList(INV_OBJECT_SAVE_FLOPPY);
|
|
}
|
|
|
|
Rings[(int)RingTypes::Inventory].ObjectListMovement = 0;
|
|
Rings[(int)RingTypes::Inventory].CurrentObjectInList = 0;
|
|
Rings[(int)RingTypes::Inventory].RingActive = true;
|
|
Rings[(int)RingTypes::Ammo].ObjectListMovement = 0;
|
|
Rings[(int)RingTypes::Ammo].CurrentObjectInList = 0;
|
|
Rings[(int)RingTypes::Ammo].RingActive = false;
|
|
HandleObjectChangeover((int)RingTypes::Inventory);
|
|
AmmoActive = 0;
|
|
}
|
|
|
|
void GuiController::ConstructCombineObjectList(ItemInfo* item)
|
|
{
|
|
auto& player = GetLaraInfo(*item);
|
|
|
|
Rings[(int)RingTypes::Ammo].NumObjectsInList = 0;
|
|
|
|
for (int i = 0; i < INVENTORY_TABLE_SIZE; i++)
|
|
Rings[(int)RingTypes::Ammo].CurrentObjectList[i].InventoryItem = NO_VALUE;
|
|
|
|
if (player.Weapons[(int)LaraWeaponType::Revolver].Present)
|
|
{
|
|
if (player.Weapons[(int)LaraWeaponType::Revolver].HasLasersight)
|
|
InsertObjectIntoList_v2(INV_OBJECT_REVOLVER_LASER);
|
|
else
|
|
InsertObjectIntoList_v2(INV_OBJECT_REVOLVER);
|
|
}
|
|
|
|
if (player.Weapons[(int)LaraWeaponType::HK].Present)
|
|
{
|
|
if (player.Weapons[(int)LaraWeaponType::HK].HasLasersight)
|
|
InsertObjectIntoList_v2(INV_OBJECT_HK_LASERSIGHT);
|
|
else
|
|
InsertObjectIntoList_v2(INV_OBJECT_HK);
|
|
}
|
|
|
|
if (player.Weapons[(int)LaraWeaponType::Crossbow].Present)
|
|
{
|
|
if (player.Weapons[(int)LaraWeaponType::Crossbow].HasLasersight)
|
|
InsertObjectIntoList_v2(INV_OBJECT_CROSSBOW_LASER);
|
|
else
|
|
InsertObjectIntoList_v2(INV_OBJECT_CROSSBOW);
|
|
}
|
|
|
|
if (player.Inventory.HasLasersight)
|
|
InsertObjectIntoList_v2(INV_OBJECT_LASERSIGHT);
|
|
|
|
if (player.Inventory.HasSilencer)
|
|
InsertObjectIntoList_v2(INV_OBJECT_SILENCER);
|
|
|
|
if (player.Inventory.BeetleComponents)
|
|
{
|
|
if (player.Inventory.BeetleComponents & 2)
|
|
InsertObjectIntoList_v2(INV_OBJECT_BEETLE_PART1);
|
|
|
|
if (player.Inventory.BeetleComponents & 4)
|
|
InsertObjectIntoList_v2(INV_OBJECT_BEETLE_PART2);
|
|
}
|
|
|
|
if (player.Inventory.SmallWaterskin)
|
|
InsertObjectIntoList_v2(player.Inventory.SmallWaterskin - 1 + INV_OBJECT_SMALL_WATERSKIN_EMPTY);
|
|
|
|
if (player.Inventory.BigWaterskin)
|
|
InsertObjectIntoList_v2(player.Inventory.BigWaterskin - 1 + INV_OBJECT_BIG_WATERSKIN_EMPTY);
|
|
|
|
for (int i = 0; i < NUM_PUZZLE_PIECES; i++)
|
|
{
|
|
if (player.Inventory.PuzzlesCombo[i])
|
|
InsertObjectIntoList_v2(INV_OBJECT_PUZZLE1_COMBO1 + i);
|
|
}
|
|
|
|
for (int i = 0; i < NUM_KEY_PIECES; i++)
|
|
{
|
|
if (player.Inventory.KeysCombo[i])
|
|
InsertObjectIntoList_v2(INV_OBJECT_KEY1_COMBO1 + i);
|
|
}
|
|
|
|
for (int i = 0; i < NUM_PICKUPS_PIECES; i++)
|
|
{
|
|
if (player.Inventory.PickupsCombo[i])
|
|
InsertObjectIntoList_v2(INV_OBJECT_PICKUP1_COMBO1 + i);
|
|
}
|
|
|
|
for (int i = 0; i < NUM_EXAMINES_PIECES; i++)
|
|
{
|
|
if (player.Inventory.ExaminesCombo[i])
|
|
InsertObjectIntoList_v2(INV_OBJECT_EXAMINE1_COMBO1 + i);
|
|
}
|
|
|
|
Rings[(int)RingTypes::Ammo].ObjectListMovement = 0;
|
|
Rings[(int)RingTypes::Ammo].CurrentObjectInList = 0;
|
|
Rings[(int)RingTypes::Ammo].RingActive = false;
|
|
}
|
|
|
|
void GuiController::Initialize()
|
|
{
|
|
g_Gui.SetMenuToDisplay(Menu::Title);
|
|
g_Gui.SetSelectedOption(0);
|
|
g_Gui.SetLastInventoryItem(NO_VALUE);
|
|
}
|
|
|
|
void GuiController::InitializeInventory(ItemInfo* item)
|
|
{
|
|
auto& player = GetLaraInfo(*item);
|
|
|
|
AlterFOV(ANGLE(DEFAULT_FOV), false);
|
|
player.Inventory.IsBusy = false;
|
|
InventoryItemChosen = NO_VALUE;
|
|
ItemUsed = false;
|
|
|
|
if (player.Weapons[(int)LaraWeaponType::Shotgun].Ammo[0].HasInfinite())
|
|
{
|
|
Ammo.AmountShotGunAmmo1 = -1;
|
|
}
|
|
else
|
|
{
|
|
Ammo.AmountShotGunAmmo1 = player.Weapons[(int)LaraWeaponType::Shotgun].Ammo[0].GetCount() / 6;
|
|
}
|
|
|
|
if (player.Weapons[(int)LaraWeaponType::Shotgun].Ammo[1].HasInfinite())
|
|
{
|
|
Ammo.AmountShotGunAmmo2 = -1;
|
|
}
|
|
else
|
|
{
|
|
Ammo.AmountShotGunAmmo2 = player.Weapons[(int)LaraWeaponType::Shotgun].Ammo[1].GetCount() / 6;
|
|
}
|
|
|
|
Ammo.AmountShotGunAmmo1 = player.Weapons[(int)LaraWeaponType::Shotgun].Ammo[(int)WeaponAmmoType::Ammo1].HasInfinite() ? -1 : player.Weapons[(int)LaraWeaponType::Shotgun].Ammo[(int)WeaponAmmoType::Ammo1].GetCount();
|
|
Ammo.AmountShotGunAmmo2 = player.Weapons[(int)LaraWeaponType::Shotgun].Ammo[(int)WeaponAmmoType::Ammo2].HasInfinite() ? -1 : player.Weapons[(int)LaraWeaponType::Shotgun].Ammo[(int)WeaponAmmoType::Ammo2].GetCount();
|
|
Ammo.AmountHKAmmo1 = player.Weapons[(int)LaraWeaponType::HK].Ammo[(int)WeaponAmmoType::Ammo1].HasInfinite() ? -1 : player.Weapons[(int)LaraWeaponType::HK].Ammo[(int)WeaponAmmoType::Ammo1].GetCount();
|
|
Ammo.AmountCrossBowAmmo1 = player.Weapons[(int)LaraWeaponType::Crossbow].Ammo[(int)WeaponAmmoType::Ammo1].HasInfinite() ? -1 : player.Weapons[(int)LaraWeaponType::Crossbow].Ammo[(int)WeaponAmmoType::Ammo1].GetCount();
|
|
Ammo.AmountCrossBowAmmo2 = player.Weapons[(int)LaraWeaponType::Crossbow].Ammo[(int)WeaponAmmoType::Ammo2].HasInfinite() ? -1 : player.Weapons[(int)LaraWeaponType::Crossbow].Ammo[(int)WeaponAmmoType::Ammo2].GetCount();
|
|
Ammo.AmountCrossBowAmmo3 = player.Weapons[(int)LaraWeaponType::Crossbow].Ammo[(int)WeaponAmmoType::Ammo3].HasInfinite() ? -1 : player.Weapons[(int)LaraWeaponType::Crossbow].Ammo[(int)WeaponAmmoType::Ammo3].GetCount();
|
|
Ammo.AmountUziAmmo = player.Weapons[(int)LaraWeaponType::Uzi].Ammo[(int)WeaponAmmoType::Ammo1].HasInfinite() ? -1 : player.Weapons[(int)LaraWeaponType::Uzi].Ammo[(int)WeaponAmmoType::Ammo1].GetCount();
|
|
Ammo.AmountRevolverAmmo = player.Weapons[(int)LaraWeaponType::Revolver].Ammo[(int)WeaponAmmoType::Ammo1].HasInfinite() ? -1 : player.Weapons[(int)LaraWeaponType::Revolver].Ammo[(int)WeaponAmmoType::Ammo1].GetCount();
|
|
Ammo.AmountPistolsAmmo = player.Weapons[(int)LaraWeaponType::Pistol].Ammo[(int)WeaponAmmoType::Ammo1].HasInfinite() ? -1 : player.Weapons[(int)LaraWeaponType::Pistol].Ammo[(int)WeaponAmmoType::Ammo1].GetCount();
|
|
Ammo.AmountRocketsAmmo = player.Weapons[(int)LaraWeaponType::RocketLauncher].Ammo[(int)WeaponAmmoType::Ammo1].HasInfinite() ? -1 : player.Weapons[(int)LaraWeaponType::RocketLauncher].Ammo[(int)WeaponAmmoType::Ammo1].GetCount();
|
|
Ammo.AmountHarpoonAmmo = player.Weapons[(int)LaraWeaponType::HarpoonGun].Ammo[(int)WeaponAmmoType::Ammo1].HasInfinite()? -1 : player.Weapons[(int)LaraWeaponType::HarpoonGun].Ammo[(int)WeaponAmmoType::Ammo1].GetCount();
|
|
Ammo.AmountGrenadeAmmo1 = player.Weapons[(int)LaraWeaponType::GrenadeLauncher].Ammo[(int)WeaponAmmoType::Ammo1].HasInfinite() ? -1 : player.Weapons[(int)LaraWeaponType::GrenadeLauncher].Ammo[(int)WeaponAmmoType::Ammo1].GetCount();
|
|
Ammo.AmountGrenadeAmmo2 = player.Weapons[(int)LaraWeaponType::GrenadeLauncher].Ammo[(int)WeaponAmmoType::Ammo2].HasInfinite() ? -1 : player.Weapons[(int)LaraWeaponType::GrenadeLauncher].Ammo[(int)WeaponAmmoType::Ammo2].GetCount();
|
|
Ammo.AmountGrenadeAmmo3 = player.Weapons[(int)LaraWeaponType::GrenadeLauncher].Ammo[(int)WeaponAmmoType::Ammo3].HasInfinite() ? -1 : player.Weapons[(int)LaraWeaponType::GrenadeLauncher].Ammo[(int)WeaponAmmoType::Ammo3].GetCount();
|
|
ConstructObjectList(item);
|
|
|
|
if (EnterInventory == NO_VALUE)
|
|
{
|
|
if (LastInvItem != NO_VALUE)
|
|
{
|
|
if (IsItemInInventory(LastInvItem))
|
|
{
|
|
SetupObjectListStartPosition(LastInvItem);
|
|
}
|
|
else
|
|
{
|
|
if (LastInvItem >= INV_OBJECT_SMALL_WATERSKIN_EMPTY && LastInvItem <= INV_OBJECT_SMALL_WATERSKIN_3L)
|
|
{
|
|
for (int i = INV_OBJECT_SMALL_WATERSKIN_EMPTY; i <= INV_OBJECT_SMALL_WATERSKIN_3L; i++)
|
|
{
|
|
if (IsItemInInventory(i))
|
|
{
|
|
SetupObjectListStartPosition(i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if (LastInvItem >= INV_OBJECT_BIG_WATERSKIN_EMPTY && LastInvItem <= INV_OBJECT_BIG_WATERSKIN_5L)
|
|
{
|
|
for (int i = INV_OBJECT_BIG_WATERSKIN_EMPTY; i <= INV_OBJECT_BIG_WATERSKIN_5L; i++)
|
|
{
|
|
if (IsItemInInventory(i))
|
|
{
|
|
SetupObjectListStartPosition(i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LastInvItem = NO_VALUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (IsObjectInInventory(EnterInventory))
|
|
SetupObjectListStartPosition2(EnterInventory);
|
|
}
|
|
|
|
AmmoSelectorFadeVal = 0;
|
|
AmmoSelectorFadeDir = 0;
|
|
CombineRingFadeVal = 0;
|
|
CombineRingFadeDir = 0;
|
|
CombineTypeFlag = 0;
|
|
SeperateTypeFlag = 0;
|
|
CombineObject1 = 0;
|
|
CombineObject2 = 0;
|
|
NormalRingFadeVal = 128;
|
|
NormalRingFadeDir = 0;
|
|
HandleObjectChangeover((int)RingTypes::Inventory);
|
|
}
|
|
|
|
int GuiController::IsObjectInInventory(int objectNumber)
|
|
{
|
|
return GetInventoryCount(from_underlying((short)objectNumber));
|
|
}
|
|
|
|
void GuiController::SetupObjectListStartPosition2(int newObjectNumber)
|
|
{
|
|
for (int i = 0; i < INVENTORY_TABLE_SIZE; i++)
|
|
{
|
|
if (InventoryObjectTable[Rings[(int)RingTypes::Inventory].CurrentObjectList[i].InventoryItem].ObjectNumber == newObjectNumber)
|
|
Rings[(int)RingTypes::Inventory].CurrentObjectInList = i;
|
|
}
|
|
}
|
|
|
|
int GuiController::ConvertObjectToInventoryItem(int objectNumber)
|
|
{
|
|
for (int i = 0; i < INVENTORY_TABLE_SIZE; i++)
|
|
{
|
|
if (InventoryObjectTable[i].ObjectNumber == objectNumber)
|
|
return i;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
int GuiController::ConvertInventoryItemToObject(int objectNumber)
|
|
{
|
|
return InventoryObjectTable[objectNumber].ObjectNumber;
|
|
}
|
|
|
|
void GuiController::FadeAmmoSelector()
|
|
{
|
|
if (Rings[(int)RingTypes::Inventory].RingActive)
|
|
{
|
|
AmmoSelectorFadeVal = 0;
|
|
}
|
|
else if (AmmoSelectorFadeDir == 1)
|
|
{
|
|
if (AmmoSelectorFadeVal < 128)
|
|
AmmoSelectorFadeVal += 32 / g_Renderer.GetFramerateMultiplier();
|
|
|
|
if (AmmoSelectorFadeVal > 128)
|
|
{
|
|
AmmoSelectorFadeVal = 128;
|
|
AmmoSelectorFadeDir = 0;
|
|
}
|
|
}
|
|
else if (AmmoSelectorFadeDir == 2)
|
|
{
|
|
if (AmmoSelectorFadeVal > 0)
|
|
AmmoSelectorFadeVal -= 32 / g_Renderer.GetFramerateMultiplier();
|
|
|
|
if (AmmoSelectorFadeVal < 0)
|
|
{
|
|
AmmoSelectorFadeVal = 0;
|
|
AmmoSelectorFadeDir = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
void GuiController::UseItem(ItemInfo& item, int objectNumber)
|
|
{
|
|
const auto CROUCH_STATES = std::vector<int>
|
|
{
|
|
LS_CROUCH_IDLE,
|
|
LS_CROUCH_TURN_LEFT,
|
|
LS_CROUCH_TURN_RIGHT,
|
|
LS_CROUCH_TURN_180
|
|
};
|
|
const auto CRAWL_STATES = std::vector<int>
|
|
{
|
|
LS_CRAWL_IDLE,
|
|
LS_CRAWL_FORWARD,
|
|
LS_CRAWL_BACK,
|
|
LS_CRAWL_TURN_LEFT,
|
|
LS_CRAWL_TURN_RIGHT,
|
|
LS_CRAWL_TURN_180,
|
|
LS_CRAWL_TO_HANG
|
|
};
|
|
|
|
auto& player = GetLaraInfo(item);
|
|
|
|
player.Inventory.OldBusy = false;
|
|
item.MeshBits = ALL_JOINT_BITS;
|
|
|
|
InventoryItemChosen = objectNumber;
|
|
|
|
// Use item event handling.
|
|
g_GameScript->OnUseItem((GAME_OBJECT_ID)InventoryItemChosen);
|
|
HandleAllGlobalEvents(EventType::UseItem, (Activator)short(item.Index));
|
|
|
|
// Quickly discard further processing if chosen item was reset in script.
|
|
if (InventoryItemChosen == NO_VALUE)
|
|
return;
|
|
|
|
if (InventoryItemChosen == ID_PISTOLS_ITEM ||
|
|
InventoryItemChosen == ID_UZI_ITEM ||
|
|
InventoryItemChosen == ID_REVOLVER_ITEM)
|
|
{
|
|
if (player.Control.WaterStatus != WaterStatus::Dry &&
|
|
player.Control.WaterStatus != WaterStatus::Wade)
|
|
{
|
|
return;
|
|
}
|
|
|
|
switch (InventoryItemChosen)
|
|
{
|
|
case ID_PISTOLS_ITEM:
|
|
player.Control.Weapon.RequestGunType = LaraWeaponType::Pistol;
|
|
break;
|
|
|
|
case ID_UZI_ITEM:
|
|
player.Control.Weapon.RequestGunType = LaraWeaponType::Uzi;
|
|
break;
|
|
|
|
case ID_REVOLVER_ITEM:
|
|
player.Control.Weapon.RequestGunType = LaraWeaponType::Revolver;
|
|
break;
|
|
|
|
default:
|
|
return;
|
|
}
|
|
|
|
if (player.Control.HandStatus == HandStatus::Free &&
|
|
player.Control.Weapon.GunType == player.Control.Weapon.RequestGunType)
|
|
{
|
|
player.Control.HandStatus = HandStatus::WeaponDraw;
|
|
}
|
|
|
|
InventoryItemChosen = NO_VALUE;
|
|
return;
|
|
}
|
|
|
|
if (InventoryItemChosen == ID_SHOTGUN_ITEM ||
|
|
InventoryItemChosen == ID_HK_ITEM ||
|
|
InventoryItemChosen == ID_CROSSBOW_ITEM ||
|
|
InventoryItemChosen == ID_GRENADE_GUN_ITEM ||
|
|
InventoryItemChosen == ID_ROCKET_LAUNCHER_ITEM ||
|
|
InventoryItemChosen == ID_HARPOON_ITEM)
|
|
{
|
|
if (InventoryItemChosen != ID_HARPOON_ITEM &&
|
|
player.Control.WaterStatus != WaterStatus::Dry &&
|
|
player.Control.WaterStatus != WaterStatus::Wade)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (TestState(item.Animation.ActiveState, CROUCH_STATES) ||
|
|
TestState(item.Animation.ActiveState, CRAWL_STATES))
|
|
{
|
|
return;
|
|
}
|
|
|
|
switch (InventoryItemChosen)
|
|
{
|
|
case ID_SHOTGUN_ITEM:
|
|
player.Control.Weapon.RequestGunType = LaraWeaponType::Shotgun;
|
|
break;
|
|
|
|
case ID_REVOLVER_ITEM:
|
|
player.Control.Weapon.RequestGunType = LaraWeaponType::Revolver;
|
|
break;
|
|
|
|
case ID_HK_ITEM:
|
|
player.Control.Weapon.RequestGunType = LaraWeaponType::HK;
|
|
break;
|
|
|
|
case ID_CROSSBOW_ITEM:
|
|
player.Control.Weapon.RequestGunType = LaraWeaponType::Crossbow;
|
|
break;
|
|
|
|
case ID_GRENADE_GUN_ITEM:
|
|
player.Control.Weapon.RequestGunType = LaraWeaponType::GrenadeLauncher;
|
|
break;
|
|
|
|
case ID_HARPOON_ITEM:
|
|
player.Control.Weapon.RequestGunType = LaraWeaponType::HarpoonGun;
|
|
break;
|
|
|
|
case ID_ROCKET_LAUNCHER_ITEM:
|
|
player.Control.Weapon.RequestGunType = LaraWeaponType::RocketLauncher;
|
|
break;
|
|
|
|
default:
|
|
return;
|
|
}
|
|
|
|
if (player.Control.HandStatus == HandStatus::Free &&
|
|
player.Control.Weapon.GunType == player.Control.Weapon.RequestGunType)
|
|
{
|
|
player.Control.HandStatus = HandStatus::WeaponDraw;
|
|
}
|
|
|
|
InventoryItemChosen = NO_VALUE;
|
|
return;
|
|
}
|
|
|
|
switch (InventoryItemChosen)
|
|
{
|
|
case ID_FLARE_INV_ITEM:
|
|
if (player.Control.HandStatus != HandStatus::Free)
|
|
return;
|
|
|
|
if (!TestState(item.Animation.ActiveState, CRAWL_STATES))
|
|
{
|
|
if (player.Control.Weapon.GunType != LaraWeaponType::Flare)
|
|
{
|
|
// HACK.
|
|
ClearAllActions();
|
|
ActionMap[In::Flare].Update(1.0f);
|
|
|
|
HandleWeapon(item);
|
|
ClearAllActions();
|
|
}
|
|
}
|
|
|
|
InventoryItemChosen = NO_VALUE;
|
|
return;
|
|
|
|
case ID_BINOCULARS_ITEM:
|
|
if (((item.Animation.ActiveState == LS_IDLE && item.Animation.AnimNumber == LA_STAND_IDLE) ||
|
|
(player.Control.IsLow && !IsHeld(In::Crouch))) &&
|
|
!UseSpotCam && !TrackCameraInit)
|
|
{
|
|
SetScreenFadeIn(OPTICS_FADE_SPEED);
|
|
BinocularOldCamera = Camera.oldType;
|
|
player.Control.Look.OpticRange = OPTICS_RANGE_DEFAULT;
|
|
player.Control.Look.IsUsingBinoculars = true;
|
|
player.Inventory.OldBusy = true;
|
|
}
|
|
|
|
InventoryItemChosen = NO_VALUE;
|
|
return;
|
|
|
|
case ID_SMALLMEDI_ITEM:
|
|
if ((item.HitPoints <= 0 || item.HitPoints >= LARA_HEALTH_MAX) &&
|
|
player.Status.Poison == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (player.Inventory.TotalSmallMedipacks != 0)
|
|
{
|
|
if (player.Inventory.TotalSmallMedipacks != NO_VALUE)
|
|
player.Inventory.TotalSmallMedipacks--;
|
|
|
|
player.Status.Poison = 0;
|
|
item.HitPoints += LARA_HEALTH_MAX / 2;
|
|
|
|
if (item.HitPoints > LARA_HEALTH_MAX)
|
|
item.HitPoints = LARA_HEALTH_MAX;
|
|
|
|
SoundEffect(SFX_TR4_MENU_MEDI, nullptr, SoundEnvironment::Always);
|
|
SaveGame::Statistics.Level.HealthUsed++;
|
|
SaveGame::Statistics.Game.HealthUsed++;
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
|
|
InventoryItemChosen = NO_VALUE;
|
|
return;
|
|
|
|
case ID_BIGMEDI_ITEM:
|
|
if ((item.HitPoints <= 0 || item.HitPoints >= LARA_HEALTH_MAX) &&
|
|
player.Status.Poison == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (player.Inventory.TotalLargeMedipacks != 0)
|
|
{
|
|
if (player.Inventory.TotalLargeMedipacks != NO_VALUE)
|
|
player.Inventory.TotalLargeMedipacks--;
|
|
|
|
player.Status.Poison = 0;
|
|
item.HitPoints = LARA_HEALTH_MAX;
|
|
|
|
SoundEffect(SFX_TR4_MENU_MEDI, nullptr, SoundEnvironment::Always);
|
|
SaveGame::Statistics.Level.HealthUsed++;
|
|
SaveGame::Statistics.Game.HealthUsed++;
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
|
|
InventoryItemChosen = NO_VALUE;
|
|
return;
|
|
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
|
|
void GuiController::DoInventory(ItemInfo* item)
|
|
{
|
|
auto& player = GetLaraInfo(*item);
|
|
auto& invRing = Rings[(int)RingTypes::Inventory];
|
|
auto& ammoRing = Rings[(int)RingTypes::Ammo];
|
|
|
|
if (ammoRing.RingActive)
|
|
{
|
|
auto optionString = g_GameFlow->GetString(OptionStrings[5].c_str());
|
|
g_Renderer.AddString(PHD_CENTER_X, PHD_CENTER_Y, optionString, PRINTSTRING_COLOR_WHITE, (int)PrintStringFlags::Blink | (int)PrintStringFlags::Center | (int)PrintStringFlags::Outline);
|
|
|
|
if (invRing.ObjectListMovement)
|
|
return;
|
|
|
|
if (ammoRing.ObjectListMovement)
|
|
return;
|
|
|
|
if (GuiIsSelected(false))
|
|
{
|
|
short invItem = invRing.CurrentObjectList[invRing.CurrentObjectInList].InventoryItem;
|
|
short ammoItem = ammoRing.CurrentObjectList[ammoRing.CurrentObjectInList].InventoryItem;
|
|
|
|
if (DoObjectsCombine(invItem, ammoItem))
|
|
{
|
|
CombineRingFadeDir = 2;
|
|
CombineTypeFlag = 1;
|
|
CombineObject1 = invItem;
|
|
CombineObject2 = ammoItem;
|
|
SoundEffect(SFX_TR4_MENU_COMBINE, nullptr, SoundEnvironment::Always);
|
|
}
|
|
else if (ammoItem >= INV_OBJECT_SMALL_WATERSKIN_EMPTY &&
|
|
ammoItem <= INV_OBJECT_SMALL_WATERSKIN_3L &&
|
|
invItem >= INV_OBJECT_BIG_WATERSKIN_EMPTY &&
|
|
invItem <= INV_OBJECT_BIG_WATERSKIN_5L)
|
|
{
|
|
if (PerformWaterskinCombine(item, true))
|
|
{
|
|
CombineTypeFlag = 2;
|
|
CombineRingFadeDir = 2;
|
|
SoundEffect(SFX_TR4_MENU_COMBINE, nullptr, SoundEnvironment::Always);
|
|
return;
|
|
}
|
|
|
|
SayNo();
|
|
CombineRingFadeDir = 2;
|
|
}
|
|
else if (invItem >= INV_OBJECT_SMALL_WATERSKIN_EMPTY &&
|
|
invItem <= INV_OBJECT_SMALL_WATERSKIN_3L &&
|
|
ammoItem >= INV_OBJECT_BIG_WATERSKIN_EMPTY &&
|
|
ammoItem <= INV_OBJECT_BIG_WATERSKIN_5L)
|
|
{
|
|
if (PerformWaterskinCombine(item, false))
|
|
{
|
|
CombineTypeFlag = 2;
|
|
CombineRingFadeDir = 2;
|
|
SoundEffect(SFX_TR4_MENU_COMBINE, nullptr, SoundEnvironment::Always);
|
|
return;
|
|
}
|
|
|
|
SayNo();
|
|
CombineRingFadeDir = 2;
|
|
}
|
|
else
|
|
{
|
|
SayNo();
|
|
CombineRingFadeDir = 2;
|
|
}
|
|
}
|
|
|
|
if (GuiIsDeselected())
|
|
{
|
|
SoundEffect(SFX_TR4_MENU_SELECT, nullptr, SoundEnvironment::Always);
|
|
CombineRingFadeDir = 2;
|
|
}
|
|
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
int num = invRing.CurrentObjectList[invRing.CurrentObjectInList].InventoryItem;
|
|
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
CurrentOptions[i].Type = MenuType::None;
|
|
CurrentOptions[i].Text = {};
|
|
}
|
|
|
|
int n = 0;
|
|
unsigned long options;
|
|
if (!AmmoActive)
|
|
{
|
|
options = InventoryObjectTable[invRing.CurrentObjectList[invRing.CurrentObjectInList].InventoryItem].Options;
|
|
|
|
if (options & OPT_LOAD)
|
|
{
|
|
CurrentOptions[0].Type = MenuType::Load;
|
|
CurrentOptions[0].Text = g_GameFlow->GetString(OptionStrings[6].c_str());
|
|
n = 1;
|
|
}
|
|
|
|
if (options & OPT_SAVE)
|
|
{
|
|
CurrentOptions[n].Type = MenuType::Save;
|
|
CurrentOptions[n].Text = g_GameFlow->GetString(OptionStrings[7].c_str());
|
|
n++;
|
|
}
|
|
|
|
if (options & OPT_EXAMINABLE)
|
|
{
|
|
CurrentOptions[n].Type = MenuType::Examine;
|
|
CurrentOptions[n].Text = g_GameFlow->GetString(OptionStrings[8].c_str());
|
|
n++;
|
|
}
|
|
|
|
if (options & OPT_STATS)
|
|
{
|
|
CurrentOptions[n].Type = MenuType::Statistics;
|
|
CurrentOptions[n].Text = g_GameFlow->GetString(OptionStrings[9].c_str());
|
|
n++;
|
|
}
|
|
|
|
if (options & OPT_USE)
|
|
{
|
|
CurrentOptions[n].Type = MenuType::Use;
|
|
CurrentOptions[n].Text = g_GameFlow->GetString(OptionStrings[0].c_str());
|
|
n++;
|
|
}
|
|
|
|
if (options & OPT_EQUIP)
|
|
{
|
|
CurrentOptions[n].Type = MenuType::Equip;
|
|
CurrentOptions[n].Text = g_GameFlow->GetString(OptionStrings[4].c_str());
|
|
n++;
|
|
}
|
|
|
|
if (options & (OPT_CHOOSE_AMMO_SHOTGUN | OPT_CHOOSE_AMMO_CROSSBOW | OPT_CHOOSE_AMMO_GRENADEGUN | OPT_CHOOSE_AMMO_HK))
|
|
{
|
|
CurrentOptions[n].Type = MenuType::ChooseAmmo;
|
|
CurrentOptions[n].Text = g_GameFlow->GetString(OptionStrings[1].c_str());
|
|
n++;
|
|
}
|
|
|
|
if (options & OPT_COMBINABLE)
|
|
{
|
|
if (IsItemCurrentlyCombinable(num))
|
|
{
|
|
CurrentOptions[n].Type = MenuType::Combine;
|
|
CurrentOptions[n].Text = g_GameFlow->GetString(OptionStrings[2].c_str());
|
|
n++;
|
|
}
|
|
}
|
|
|
|
if (options & OPT_ALWAYS_COMBINE)
|
|
{
|
|
CurrentOptions[n].Type = MenuType::Combine;
|
|
CurrentOptions[n].Text = g_GameFlow->GetString(OptionStrings[2].c_str());
|
|
n++;
|
|
}
|
|
|
|
if (options & OPT_SEPERABLE)
|
|
{
|
|
CurrentOptions[n].Type = MenuType::Seperate;
|
|
CurrentOptions[n].Text = g_GameFlow->GetString(OptionStrings[3].c_str());
|
|
n++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CurrentOptions[0].Type = MenuType::Ammo1;
|
|
CurrentOptions[0].Text = g_GameFlow->GetString(InventoryObjectTable[AmmoObjectList[0].InventoryItem].ObjectName);
|
|
CurrentOptions[1].Type = MenuType::Ammo2;
|
|
CurrentOptions[1].Text = g_GameFlow->GetString(InventoryObjectTable[AmmoObjectList[1].InventoryItem].ObjectName);
|
|
n = 2;
|
|
|
|
options = InventoryObjectTable[invRing.CurrentObjectList[invRing.CurrentObjectInList].InventoryItem].Options;
|
|
|
|
if (options & (OPT_CHOOSE_AMMO_CROSSBOW | OPT_CHOOSE_AMMO_GRENADEGUN | OPT_CHOOSE_AMMO_HK))
|
|
{
|
|
n = 3;
|
|
CurrentOptions[2].Type = MenuType::Ammo3;
|
|
CurrentOptions[2].Text = g_GameFlow->GetString(InventoryObjectTable[AmmoObjectList[2].InventoryItem].ObjectName);
|
|
}
|
|
|
|
CurrentSelectedOption = *CurrentAmmoType;
|
|
}
|
|
|
|
int yPos = 310 - LINE_HEIGHT;
|
|
|
|
if (n == 1)
|
|
{
|
|
yPos += LINE_HEIGHT;
|
|
}
|
|
else if (n == 2)
|
|
{
|
|
yPos += LINE_HEIGHT / 2;
|
|
}
|
|
|
|
if (n > 0)
|
|
{
|
|
for (int i = 0; i < n; i++)
|
|
{
|
|
auto optionString = CurrentOptions[i].Text;
|
|
|
|
if (i == CurrentSelectedOption)
|
|
{
|
|
g_Renderer.AddString(PHD_CENTER_X, yPos, optionString.c_str(), PRINTSTRING_COLOR_WHITE, (int)PrintStringFlags::Blink | (int)PrintStringFlags::Center | (int)PrintStringFlags::Outline);
|
|
yPos += LINE_HEIGHT;
|
|
}
|
|
else
|
|
{
|
|
g_Renderer.AddString(PHD_CENTER_X, yPos, optionString.c_str(), PRINTSTRING_COLOR_WHITE, (int)PrintStringFlags::Center | (int)PrintStringFlags::Outline);
|
|
yPos += LINE_HEIGHT;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (MenuActive &&
|
|
!invRing.ObjectListMovement &&
|
|
!ammoRing.ObjectListMovement)
|
|
{
|
|
CurrentSelectedOption = GetLoopedSelectedOption(CurrentSelectedOption, n - 1, g_Configuration.MenuOptionLoopingMode == MenuOptionLoopingMode::AllMenus);
|
|
|
|
if (AmmoActive)
|
|
*CurrentAmmoType = CurrentSelectedOption;
|
|
|
|
if (GuiIsSelected(false))
|
|
{
|
|
if (CurrentOptions[CurrentSelectedOption].Type != MenuType::Equip &&
|
|
CurrentOptions[CurrentSelectedOption].Type != MenuType::Use)
|
|
{
|
|
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
|
}
|
|
|
|
switch (CurrentOptions[CurrentSelectedOption].Type)
|
|
{
|
|
case MenuType::ChooseAmmo:
|
|
invRing.RingActive = false;
|
|
AmmoActive = 1;
|
|
Ammo.StashedCurrentSelectedOption = CurrentSelectedOption;
|
|
Ammo.StashedCurrentPistolsAmmoType = Ammo.CurrentPistolsAmmoType;
|
|
Ammo.StashedCurrentUziAmmoType = Ammo.CurrentUziAmmoType;
|
|
Ammo.StashedCurrentRevolverAmmoType = Ammo.CurrentRevolverAmmoType;
|
|
Ammo.StashedCurrentShotGunAmmoType = Ammo.CurrentShotGunAmmoType;
|
|
Ammo.StashedCurrentGrenadeGunAmmoType = Ammo.CurrentGrenadeGunAmmoType;
|
|
Ammo.StashedCurrentCrossBowAmmoType = Ammo.CurrentCrossBowAmmoType;
|
|
Ammo.StashedCurrentHKAmmoType = Ammo.CurrentHKAmmoType;
|
|
Ammo.StashedCurrentHarpoonAmmoType = Ammo.CurrentHarpoonAmmoType;
|
|
Ammo.StashedCurrentRocketAmmoType = Ammo.CurrentRocketAmmoType;
|
|
break;
|
|
|
|
case MenuType::Load:
|
|
SaveGame::LoadHeaders();
|
|
SetInventoryMode(InventoryMode::Load);
|
|
break;
|
|
|
|
case MenuType::Save:
|
|
SaveGame::LoadHeaders();
|
|
SetInventoryMode(InventoryMode::Save);
|
|
break;
|
|
|
|
case MenuType::Examine:
|
|
SetInventoryMode(InventoryMode::Examine);
|
|
break;
|
|
|
|
case MenuType::Statistics:
|
|
SetInventoryMode(InventoryMode::Statistics);
|
|
break;
|
|
|
|
case MenuType::Ammo1:
|
|
case MenuType::Ammo2:
|
|
case MenuType::Ammo3:
|
|
AmmoActive = 0;
|
|
invRing.RingActive = true;
|
|
CurrentSelectedOption = 0;
|
|
break;
|
|
|
|
case MenuType::Combine:
|
|
ConstructCombineObjectList(item);
|
|
invRing.RingActive = false;
|
|
ammoRing.RingActive = true;
|
|
AmmoSelectorFlag = 0;
|
|
MenuActive = false;
|
|
CombineRingFadeDir = 1;
|
|
break;
|
|
|
|
case MenuType::Seperate:
|
|
SeperateTypeFlag = 1;
|
|
NormalRingFadeDir = 2;
|
|
break;
|
|
|
|
case MenuType::Equip:
|
|
case MenuType::Use:
|
|
MenuActive = false;
|
|
ItemUsed = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (GuiIsDeselected() && AmmoActive)
|
|
{
|
|
SoundEffect(SFX_TR4_MENU_SELECT, nullptr, SoundEnvironment::Always);
|
|
AmmoActive = 0;
|
|
invRing.RingActive = true;
|
|
Ammo.CurrentPistolsAmmoType = Ammo.StashedCurrentPistolsAmmoType;
|
|
Ammo.CurrentUziAmmoType = Ammo.StashedCurrentUziAmmoType;
|
|
Ammo.CurrentRevolverAmmoType = Ammo.StashedCurrentRevolverAmmoType;
|
|
Ammo.CurrentShotGunAmmoType = Ammo.StashedCurrentShotGunAmmoType;
|
|
Ammo.CurrentGrenadeGunAmmoType = Ammo.StashedCurrentGrenadeGunAmmoType;
|
|
Ammo.CurrentCrossBowAmmoType = Ammo.StashedCurrentCrossBowAmmoType;
|
|
Ammo.CurrentHKAmmoType = Ammo.StashedCurrentHKAmmoType;
|
|
Ammo.CurrentHarpoonAmmoType = Ammo.StashedCurrentHarpoonAmmoType;
|
|
Ammo.CurrentRocketAmmoType = Ammo.StashedCurrentRocketAmmoType;
|
|
CurrentSelectedOption = Ammo.StashedCurrentSelectedOption;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Update the selected ammo of weapons that require it, and only these.
|
|
void GuiController::UpdateWeaponStatus(ItemInfo* item)
|
|
{
|
|
auto& player = GetLaraInfo(*item);
|
|
|
|
if (player.Weapons[(int)LaraWeaponType::Shotgun].Present)
|
|
{
|
|
if (Ammo.CurrentShotGunAmmoType)
|
|
player.Weapons[(int)LaraWeaponType::Shotgun].SelectedAmmo = WeaponAmmoType::Ammo2;
|
|
else
|
|
player.Weapons[(int)LaraWeaponType::Shotgun].SelectedAmmo = WeaponAmmoType::Ammo1;
|
|
}
|
|
|
|
if (player.Weapons[(int)LaraWeaponType::Crossbow].Present)
|
|
{
|
|
player.Weapons[(int)LaraWeaponType::Crossbow].SelectedAmmo = WeaponAmmoType::Ammo1;
|
|
|
|
if (Ammo.CurrentCrossBowAmmoType == 1)
|
|
player.Weapons[(int)LaraWeaponType::Crossbow].SelectedAmmo = WeaponAmmoType::Ammo2;
|
|
else if (Ammo.CurrentCrossBowAmmoType == 2)
|
|
player.Weapons[(int)LaraWeaponType::Crossbow].SelectedAmmo = WeaponAmmoType::Ammo3;
|
|
}
|
|
|
|
if (player.Weapons[(int)LaraWeaponType::HK].Present)
|
|
{
|
|
player.Weapons[(int)LaraWeaponType::HK].WeaponMode = LaraWeaponTypeCarried::WTYPE_AMMO_1;
|
|
player.Weapons[(int)LaraWeaponType::HK].SelectedAmmo = WeaponAmmoType::Ammo1;
|
|
|
|
if (Ammo.CurrentHKAmmoType == 1)
|
|
{
|
|
player.Weapons[(int)LaraWeaponType::HK].WeaponMode = LaraWeaponTypeCarried::WTYPE_AMMO_2;
|
|
player.Weapons[(int)LaraWeaponType::HK].SelectedAmmo = WeaponAmmoType::Ammo1;
|
|
}
|
|
else if (Ammo.CurrentHKAmmoType == 2)
|
|
{
|
|
player.Weapons[(int)LaraWeaponType::HK].WeaponMode = LaraWeaponTypeCarried::WTYPE_AMMO_3;
|
|
player.Weapons[(int)LaraWeaponType::HK].SelectedAmmo = WeaponAmmoType::Ammo1;
|
|
}
|
|
}
|
|
|
|
if (player.Weapons[(int)LaraWeaponType::GrenadeLauncher].Present)
|
|
{
|
|
player.Weapons[(int)LaraWeaponType::GrenadeLauncher].SelectedAmmo = WeaponAmmoType::Ammo1;
|
|
|
|
if (Ammo.CurrentGrenadeGunAmmoType == 1)
|
|
player.Weapons[(int)LaraWeaponType::GrenadeLauncher].SelectedAmmo = WeaponAmmoType::Ammo2;
|
|
else if (Ammo.CurrentGrenadeGunAmmoType == 2)
|
|
player.Weapons[(int)LaraWeaponType::GrenadeLauncher].SelectedAmmo = WeaponAmmoType::Ammo3;
|
|
}
|
|
}
|
|
|
|
void GuiController::SpinBack(EulerAngles& orient)
|
|
{
|
|
orient.Lerp(EulerAngles::Identity, 1.0f / (8.0f * g_Renderer.GetFramerateMultiplier()));
|
|
}
|
|
|
|
void GuiController::DrawAmmoSelector()
|
|
{
|
|
if (!AmmoSelectorFlag)
|
|
return;
|
|
|
|
int xPos = (2 * PHD_CENTER_X - OBJLIST_SPACING) / 2;
|
|
if (NumAmmoSlots == 2)
|
|
xPos -= OBJLIST_SPACING / 2;
|
|
else if (NumAmmoSlots == 3)
|
|
xPos -= OBJLIST_SPACING;
|
|
|
|
if (NumAmmoSlots > 0)
|
|
{
|
|
for (int n = 0; n < NumAmmoSlots; n++)
|
|
{
|
|
auto* invObject = &InventoryObjectTable[AmmoObjectList[n].InventoryItem];
|
|
|
|
if (n == *CurrentAmmoType)
|
|
{
|
|
if (invObject->RotFlags & INV_ROT_X)
|
|
AmmoObjectList[n].Orientation.x += ANGLE(5.0f / g_Renderer.GetFramerateMultiplier());
|
|
|
|
if (invObject->RotFlags & INV_ROT_Y)
|
|
AmmoObjectList[n].Orientation.y += ANGLE(5.0f / g_Renderer.GetFramerateMultiplier());
|
|
|
|
if (invObject->RotFlags & INV_ROT_Z)
|
|
AmmoObjectList[n].Orientation.z += ANGLE(5.0f / g_Renderer.GetFramerateMultiplier());
|
|
}
|
|
else
|
|
SpinBack(AmmoObjectList[n].Orientation);
|
|
|
|
int x = PHD_CENTER_X - 300 + xPos;
|
|
int y = 480;
|
|
short objectNumber = ConvertInventoryItemToObject(AmmoObjectList[n].InventoryItem);
|
|
float scaler = InventoryObjectTable[AmmoObjectList[n].InventoryItem].Scale1;
|
|
|
|
if (n == *CurrentAmmoType)
|
|
{
|
|
char invTextBuffer[256];
|
|
|
|
if (AmmoObjectList[n].Amount == -1)
|
|
{
|
|
sprintf(&invTextBuffer[0], g_GameFlow->GetString(STRING_UNLIMITED), g_GameFlow->GetString(InventoryObjectTable[AmmoObjectList[n].InventoryItem].ObjectName));
|
|
}
|
|
else
|
|
{
|
|
sprintf(&invTextBuffer[0], "%d x %s", AmmoObjectList[n].Amount, g_GameFlow->GetString(InventoryObjectTable[AmmoObjectList[n].InventoryItem].ObjectName));
|
|
}
|
|
|
|
// CHECK: AmmoSelectorFadeVal is never true and therefore the string is never printed.
|
|
//if (AmmoSelectorFadeVal)
|
|
g_Renderer.AddString(PHD_CENTER_X, 380, &invTextBuffer[0], PRINTSTRING_COLOR_YELLOW, (int)PrintStringFlags::Center | (int)PrintStringFlags::Outline);
|
|
|
|
if (n == *CurrentAmmoType)
|
|
g_Renderer.DrawObjectIn2DSpace(objectNumber, Vector2(x, y), AmmoObjectList[n].Orientation, scaler);
|
|
else
|
|
g_Renderer.DrawObjectIn2DSpace(objectNumber, Vector2(x, y), AmmoObjectList[n].Orientation, scaler);
|
|
}
|
|
else
|
|
{
|
|
g_Renderer.DrawObjectIn2DSpace(objectNumber, Vector2(x, y), AmmoObjectList[n].Orientation, scaler);
|
|
}
|
|
|
|
xPos += OBJLIST_SPACING;
|
|
}
|
|
}
|
|
}
|
|
|
|
void GuiController::DrawCurrentObjectList(ItemInfo* item, RingTypes ringType)
|
|
{
|
|
const auto& player = GetLaraInfo(*item);
|
|
auto& ring = Rings[(int)ringType];
|
|
|
|
if (ring.CurrentObjectList <= 0)
|
|
return;
|
|
|
|
if (ringType == RingTypes::Ammo)
|
|
{
|
|
AmmoSelectorFadeVal = 0;
|
|
AmmoSelectorFadeDir = 0;
|
|
|
|
if (CombineRingFadeDir == 1)
|
|
{
|
|
if (CombineRingFadeVal < 128)
|
|
CombineRingFadeVal += 32;
|
|
|
|
if (CombineRingFadeVal > 128)
|
|
{
|
|
CombineRingFadeVal = 128;
|
|
CombineRingFadeDir = 0;
|
|
}
|
|
}
|
|
else if (CombineRingFadeDir == 2)
|
|
{
|
|
CombineRingFadeVal -= 32;
|
|
|
|
if (CombineRingFadeVal <= 0)
|
|
{
|
|
CombineRingFadeVal = 0;
|
|
CombineRingFadeDir = 0;
|
|
|
|
if (CombineTypeFlag)
|
|
{
|
|
NormalRingFadeDir = 2;
|
|
}
|
|
else
|
|
{
|
|
Rings[(int)RingTypes::Inventory].RingActive = true;
|
|
MenuActive = true;
|
|
Rings[(int)RingTypes::Ammo].RingActive = false;
|
|
HandleObjectChangeover((int)RingTypes::Inventory);
|
|
}
|
|
|
|
Rings[(int)RingTypes::Ammo].RingActive = false;
|
|
}
|
|
}
|
|
}
|
|
else if (NormalRingFadeDir == 1)
|
|
{
|
|
if (NormalRingFadeVal < 128)
|
|
NormalRingFadeVal += 32;
|
|
|
|
if (NormalRingFadeVal > 128)
|
|
{
|
|
NormalRingFadeVal = 128;
|
|
NormalRingFadeDir = 0;
|
|
Rings[(int)RingTypes::Inventory].RingActive = true;
|
|
MenuActive = true;
|
|
}
|
|
|
|
}
|
|
else if (NormalRingFadeDir == 2)
|
|
{
|
|
NormalRingFadeVal -= 32;
|
|
|
|
if (NormalRingFadeVal <= 0)
|
|
{
|
|
NormalRingFadeVal = 0;
|
|
NormalRingFadeDir = 1;
|
|
|
|
if (CombineTypeFlag == 1)
|
|
{
|
|
CombineTypeFlag = 0;
|
|
CombineObjects(item, CombineObject1, CombineObject2);
|
|
}
|
|
else if (CombineTypeFlag == 2)
|
|
{
|
|
CombineTypeFlag = 0;
|
|
ConstructObjectList(item);
|
|
SetupObjectListStartPosition(CombineObject1);
|
|
}
|
|
else if (SeperateTypeFlag)
|
|
{
|
|
SeparateObject(item, Rings[(int)RingTypes::Inventory].CurrentObjectList[Rings[(int)RingTypes::Inventory].CurrentObjectInList].InventoryItem);
|
|
}
|
|
|
|
HandleObjectChangeover((int)RingTypes::Inventory);
|
|
}
|
|
}
|
|
|
|
int minObj = 0;
|
|
int maxObj = 0;
|
|
int xOffset = 0;
|
|
int n = 0;
|
|
|
|
if (ring.NumObjectsInList != 1)
|
|
xOffset = (OBJLIST_SPACING * ring.ObjectListMovement) >> 16;
|
|
|
|
if (ring.NumObjectsInList == 2)
|
|
{
|
|
minObj = -1;
|
|
maxObj = 0;
|
|
n = ring.CurrentObjectInList - 1;
|
|
}
|
|
|
|
if (ring.NumObjectsInList == 3 || ring.NumObjectsInList == 4)
|
|
{
|
|
minObj = -2;
|
|
maxObj = 1;
|
|
n = ring.CurrentObjectInList - 2;
|
|
}
|
|
|
|
if (ring.NumObjectsInList >= 5)
|
|
{
|
|
minObj = -3;
|
|
maxObj = 2;
|
|
n = ring.CurrentObjectInList - 3;
|
|
}
|
|
|
|
if (n < 0)
|
|
n += ring.NumObjectsInList;
|
|
|
|
if (ring.ObjectListMovement < 0)
|
|
maxObj++;
|
|
|
|
if (minObj <= maxObj)
|
|
{
|
|
for (int i = minObj; i <= maxObj; i++)
|
|
{
|
|
int shade = 0;
|
|
|
|
if (minObj == i)
|
|
{
|
|
if (ring.ObjectListMovement < 0)
|
|
{
|
|
shade = 0;
|
|
}
|
|
else
|
|
{
|
|
shade = ring.ObjectListMovement >> 9;
|
|
}
|
|
}
|
|
else if (i != minObj + 1 || maxObj == minObj + 1)
|
|
{
|
|
if (i != maxObj)
|
|
{
|
|
shade = 128;
|
|
}
|
|
else
|
|
{
|
|
if (ring.ObjectListMovement < 0)
|
|
{
|
|
shade = (-128 * ring.ObjectListMovement) >> 16;
|
|
}
|
|
else
|
|
{
|
|
shade = 128 - short(ring.ObjectListMovement >> 9);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (ring.ObjectListMovement < 0)
|
|
{
|
|
shade = 128 - ((-128 * ring.ObjectListMovement) >> 16);
|
|
}
|
|
else
|
|
{
|
|
shade = 128;
|
|
}
|
|
}
|
|
|
|
if (!minObj && !maxObj)
|
|
shade = 128;
|
|
|
|
if (ringType == RingTypes::Ammo && CombineRingFadeVal < 128 && shade)
|
|
{
|
|
shade = CombineRingFadeVal;
|
|
}
|
|
else if (ringType == RingTypes::Inventory && NormalRingFadeVal < 128 && shade)
|
|
{
|
|
shade = NormalRingFadeVal;
|
|
}
|
|
|
|
auto& listObject = ring.CurrentObjectList[n];
|
|
const auto& invObject = InventoryObjectTable[listObject.InventoryItem];
|
|
|
|
if (!i)
|
|
{
|
|
int numItems = 0;
|
|
int count = 0;
|
|
char textBuffer[128];
|
|
|
|
switch (invObject.ObjectNumber)
|
|
{
|
|
case ID_BIGMEDI_ITEM:
|
|
numItems = player.Inventory.TotalLargeMedipacks;
|
|
break;
|
|
|
|
case ID_SMALLMEDI_ITEM:
|
|
numItems = player.Inventory.TotalSmallMedipacks;
|
|
break;
|
|
|
|
case ID_FLARE_INV_ITEM:
|
|
numItems = player.Inventory.TotalFlares;
|
|
break;
|
|
|
|
default:
|
|
if (invObject.ObjectNumber < ID_PUZZLE_ITEM1 ||
|
|
invObject.ObjectNumber > ID_PUZZLE_ITEM16)
|
|
{
|
|
switch (invObject.ObjectNumber)
|
|
{
|
|
case ID_PISTOLS_AMMO_ITEM:
|
|
numItems = player.Weapons[(int)LaraWeaponType::Pistol].Ammo[(int)WeaponAmmoType::Ammo1].GetCount();
|
|
break;
|
|
|
|
case ID_SHOTGUN_AMMO1_ITEM:
|
|
numItems = player.Weapons[(int)LaraWeaponType::Shotgun].Ammo[(int)WeaponAmmoType::Ammo1].GetCount();
|
|
break;
|
|
|
|
case ID_SHOTGUN_AMMO2_ITEM:
|
|
numItems = player.Weapons[(int)LaraWeaponType::Shotgun].Ammo[(int)WeaponAmmoType::Ammo2].GetCount();
|
|
break;
|
|
|
|
case ID_HK_AMMO_ITEM:
|
|
numItems = player.Weapons[(int)LaraWeaponType::HK].Ammo[(int)WeaponAmmoType::Ammo1].GetCount();
|
|
break;
|
|
|
|
case ID_CROSSBOW_AMMO1_ITEM:
|
|
count = player.Weapons[(int)LaraWeaponType::Crossbow].Ammo[(int)WeaponAmmoType::Ammo1].GetCount();
|
|
numItems = count;
|
|
break;
|
|
|
|
case ID_CROSSBOW_AMMO2_ITEM:
|
|
count = player.Weapons[(int)LaraWeaponType::Crossbow].Ammo[(int)WeaponAmmoType::Ammo2].GetCount();
|
|
numItems = count;
|
|
break;
|
|
|
|
case ID_CROSSBOW_AMMO3_ITEM:
|
|
count = player.Weapons[(int)LaraWeaponType::Crossbow].Ammo[(int)WeaponAmmoType::Ammo3].GetCount();
|
|
numItems = count;
|
|
break;
|
|
|
|
case ID_GRENADE_AMMO1_ITEM:
|
|
count = player.Weapons[(int)LaraWeaponType::GrenadeLauncher].Ammo[(int)WeaponAmmoType::Ammo1].GetCount();
|
|
numItems = count;
|
|
break;
|
|
|
|
case ID_GRENADE_AMMO2_ITEM:
|
|
count = player.Weapons[(int)LaraWeaponType::GrenadeLauncher].Ammo[(int)WeaponAmmoType::Ammo2].GetCount();
|
|
numItems = count;
|
|
break;
|
|
|
|
case ID_GRENADE_AMMO3_ITEM:
|
|
count = player.Weapons[(int)LaraWeaponType::GrenadeLauncher].Ammo[(int)WeaponAmmoType::Ammo3].GetCount();
|
|
numItems = count;
|
|
break;
|
|
|
|
case ID_ROCKET_LAUNCHER_AMMO_ITEM:
|
|
numItems = player.Weapons[(int)LaraWeaponType::RocketLauncher].Ammo[(int)WeaponAmmoType::Ammo1].GetCount();
|
|
break;
|
|
|
|
case ID_HARPOON_AMMO_ITEM:
|
|
numItems = player.Weapons[(int)LaraWeaponType::HarpoonGun].Ammo[(int)WeaponAmmoType::Ammo1].GetCount();
|
|
break;
|
|
|
|
case ID_REVOLVER_AMMO_ITEM:
|
|
numItems = player.Weapons[(int)LaraWeaponType::Revolver].Ammo[(int)WeaponAmmoType::Ammo1].GetCount();
|
|
break;
|
|
|
|
case ID_UZI_AMMO_ITEM:
|
|
numItems = player.Weapons[(int)LaraWeaponType::Uzi].Ammo[(int)WeaponAmmoType::Ammo1].GetCount();
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
numItems = player.Inventory.Puzzles[invObject.ObjectNumber - ID_PUZZLE_ITEM1];
|
|
if (numItems <= 1)
|
|
{
|
|
sprintf(textBuffer, g_GameFlow->GetString(invObject.ObjectName));
|
|
}
|
|
else
|
|
{
|
|
sprintf(textBuffer, "%d x %s", numItems, g_GameFlow->GetString(invObject.ObjectName));
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
if (invObject.ObjectNumber < ID_PUZZLE_ITEM1 ||
|
|
invObject.ObjectNumber > ID_PUZZLE_ITEM16)
|
|
{
|
|
if (numItems)
|
|
{
|
|
if (numItems == -1)
|
|
{
|
|
sprintf(textBuffer, g_GameFlow->GetString(STRING_UNLIMITED), g_GameFlow->GetString(invObject.ObjectName));
|
|
}
|
|
else
|
|
{
|
|
sprintf(textBuffer, "%d x %s", numItems, g_GameFlow->GetString(invObject.ObjectName));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sprintf(textBuffer, g_GameFlow->GetString(invObject.ObjectName));
|
|
}
|
|
}
|
|
|
|
int objectNumber;
|
|
if (ringType == RingTypes::Inventory)
|
|
{
|
|
objectNumber = int(PHD_CENTER_Y - (DISPLAY_SPACE_RES.y + 1) * 0.0625 * 2.5);
|
|
}
|
|
else
|
|
{
|
|
objectNumber = int(PHD_CENTER_Y + (DISPLAY_SPACE_RES.y + 1) * 0.0625 * 2.0);
|
|
}
|
|
|
|
g_Renderer.AddString(PHD_CENTER_X, objectNumber, textBuffer, PRINTSTRING_COLOR_YELLOW, (int)PrintStringFlags::Center | (int)PrintStringFlags::Outline);
|
|
}
|
|
|
|
if (!i && !ring.ObjectListMovement)
|
|
{
|
|
if (invObject.RotFlags & INV_ROT_X)
|
|
listObject.Orientation.x += ANGLE(5.0f / g_Renderer.GetFramerateMultiplier());
|
|
|
|
if (invObject.RotFlags & INV_ROT_Y)
|
|
listObject.Orientation.y += ANGLE(5.0f / g_Renderer.GetFramerateMultiplier());
|
|
|
|
if (invObject.RotFlags & INV_ROT_Z)
|
|
listObject.Orientation.z += ANGLE(5.0f / g_Renderer.GetFramerateMultiplier());
|
|
}
|
|
else
|
|
{
|
|
SpinBack(listObject.Orientation);
|
|
}
|
|
|
|
int activeNum = 0;
|
|
if (ring.ObjectListMovement)
|
|
{
|
|
if (ring.ObjectListMovement > 0)
|
|
{
|
|
activeNum = -1;
|
|
}
|
|
else
|
|
{
|
|
activeNum = 1;
|
|
}
|
|
}
|
|
|
|
if (i == activeNum)
|
|
{
|
|
if (listObject.Bright < 160)
|
|
listObject.Bright += 16;
|
|
|
|
if (listObject.Bright > 160)
|
|
listObject.Bright = 160;
|
|
}
|
|
else
|
|
{
|
|
if (listObject.Bright > 32)
|
|
listObject.Bright -= 16;
|
|
|
|
if (listObject.Bright < 32)
|
|
listObject.Bright = 32;
|
|
}
|
|
|
|
int x = 400 + xOffset + i * OBJLIST_SPACING;
|
|
int y = 150;
|
|
int y2 = 480; // Combine.
|
|
short objectNumber = ConvertInventoryItemToObject(listObject.InventoryItem);
|
|
float scaler = invObject.Scale1;
|
|
auto& orient = listObject.Orientation;
|
|
int bits = invObject.MeshBits;
|
|
|
|
g_Renderer.DrawObjectIn2DSpace(objectNumber, Vector2(x, (ringType == RingTypes::Inventory) ? y : y2), orient, scaler, 1.0f, bits);
|
|
|
|
if (++n >= ring.NumObjectsInList)
|
|
n = 0;
|
|
}
|
|
|
|
if (ring.RingActive)
|
|
{
|
|
if (ring.NumObjectsInList != 1 && (ringType != RingTypes::Ammo || CombineRingFadeVal == 128))
|
|
{
|
|
if (ring.ObjectListMovement > 0)
|
|
ring.ObjectListMovement += ANGLE(45.0f / g_Renderer.GetFramerateMultiplier());
|
|
|
|
if (ring.ObjectListMovement < 0)
|
|
ring.ObjectListMovement -= ANGLE(45.0f / g_Renderer.GetFramerateMultiplier());
|
|
|
|
if (IsHeld(In::Left))
|
|
{
|
|
if (!ring.ObjectListMovement)
|
|
{
|
|
SoundEffect(SFX_TR4_MENU_ROTATE, nullptr, SoundEnvironment::Always);
|
|
ring.ObjectListMovement += ANGLE(45.0f / g_Renderer.GetFramerateMultiplier());
|
|
|
|
if (AmmoSelectorFlag)
|
|
AmmoSelectorFadeDir = 2;
|
|
}
|
|
}
|
|
|
|
if (IsHeld(In::Right))
|
|
{
|
|
if (!ring.ObjectListMovement)
|
|
{
|
|
SoundEffect(SFX_TR4_MENU_ROTATE, nullptr, SoundEnvironment::Always);
|
|
ring.ObjectListMovement -= ANGLE(45.0f / g_Renderer.GetFramerateMultiplier());
|
|
|
|
if (AmmoSelectorFlag)
|
|
AmmoSelectorFadeDir = 2;
|
|
}
|
|
}
|
|
|
|
if (ring.ObjectListMovement < 65536)
|
|
{
|
|
if (ring.ObjectListMovement < -65535)
|
|
{
|
|
ring.CurrentObjectInList++;
|
|
|
|
if (ring.CurrentObjectInList >= ring.NumObjectsInList)
|
|
ring.CurrentObjectInList = 0;
|
|
|
|
ring.ObjectListMovement = 0;
|
|
|
|
if (ringType == RingTypes::Inventory)
|
|
HandleObjectChangeover(0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ring.CurrentObjectInList--;
|
|
|
|
if (ring.CurrentObjectInList < 0)
|
|
ring.CurrentObjectInList = ring.NumObjectsInList - 1;
|
|
|
|
ring.ObjectListMovement = 0;
|
|
|
|
if (ringType == RingTypes::Inventory)
|
|
HandleObjectChangeover(0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool GuiController::CallPause()
|
|
{
|
|
g_Renderer.DumpGameScene(SceneRenderMode::NoHud);
|
|
PauseAllSounds(SoundPauseMode::Pause);
|
|
SoundEffect(SFX_TR4_MENU_SELECT, nullptr, SoundEnvironment::Always);
|
|
|
|
g_Gui.SetInventoryMode(InventoryMode::Pause);
|
|
g_Gui.SetMenuToDisplay(Menu::Pause);
|
|
g_Gui.SetSelectedOption(0);
|
|
|
|
bool doExitToTitle = false;
|
|
|
|
g_Synchronizer.Init();
|
|
|
|
bool legacy30FpsDoneDraw = false;
|
|
|
|
while (g_Gui.GetInventoryMode() == InventoryMode::Pause)
|
|
{
|
|
if (ThreadEnded)
|
|
{
|
|
App.ResetClock = true;
|
|
return false;
|
|
}
|
|
|
|
g_Synchronizer.Sync();
|
|
|
|
while (g_Synchronizer.Synced())
|
|
{
|
|
g_Renderer.PrepareScene();
|
|
|
|
if (g_Gui.DoPauseMenu(LaraItem) == InventoryResult::ExitToTitle)
|
|
{
|
|
doExitToTitle = true;
|
|
break;
|
|
}
|
|
|
|
g_Synchronizer.Step();
|
|
|
|
legacy30FpsDoneDraw = false;
|
|
}
|
|
|
|
if (doExitToTitle)
|
|
break;
|
|
|
|
if (!g_Configuration.EnableHighFramerate)
|
|
{
|
|
if (!legacy30FpsDoneDraw)
|
|
{
|
|
g_Renderer.RenderInventory();
|
|
g_Renderer.Lock();
|
|
g_Renderer.Synchronize();
|
|
legacy30FpsDoneDraw = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
g_Renderer.RenderInventory();
|
|
g_Renderer.Lock();
|
|
}
|
|
}
|
|
|
|
if (doExitToTitle)
|
|
{
|
|
StopAllSounds();
|
|
}
|
|
else
|
|
{
|
|
ResumeAllSounds(SoundPauseMode::Pause);
|
|
}
|
|
|
|
App.ResetClock = true;
|
|
|
|
return doExitToTitle;
|
|
}
|
|
|
|
bool GuiController::CallInventory(ItemInfo* item, bool resetMode)
|
|
{
|
|
auto& player = GetLaraInfo(*item);
|
|
|
|
bool doLoad = false;
|
|
|
|
player.Inventory.OldBusy = player.Inventory.IsBusy;
|
|
|
|
g_Renderer.DumpGameScene(SceneRenderMode::NoHud);
|
|
PauseAllSounds(SoundPauseMode::Inventory);
|
|
SoundEffect(SFX_TR4_MENU_SELECT, nullptr, SoundEnvironment::Always);
|
|
|
|
if (resetMode)
|
|
SetInventoryMode(InventoryMode::InGame);
|
|
|
|
InitializeInventory(item);
|
|
|
|
g_Synchronizer.Init();
|
|
|
|
bool legacy30FpsDoneDraw = false;
|
|
bool exitLoop = false;
|
|
|
|
while (!exitLoop)
|
|
{
|
|
if (ThreadEnded)
|
|
{
|
|
App.ResetClock = true;
|
|
return false;
|
|
}
|
|
|
|
g_Synchronizer.Sync();
|
|
|
|
while (g_Synchronizer.Synced())
|
|
{
|
|
TimeInMenu++;
|
|
GlobalCounter++;
|
|
SaveGame::Statistics.Game.TimeTaken++;
|
|
SaveGame::Statistics.Level.TimeTaken++;
|
|
|
|
UpdateInputActions(item);
|
|
|
|
if (GuiIsDeselected() || IsClicked(In::Inventory))
|
|
{
|
|
SoundEffect(SFX_TR4_MENU_SELECT, nullptr, SoundEnvironment::Always);
|
|
exitLoop = true;
|
|
}
|
|
|
|
g_Renderer.PrepareScene();
|
|
|
|
switch (InvMode)
|
|
{
|
|
case InventoryMode::InGame:
|
|
DoInventory(item);
|
|
break;
|
|
|
|
case InventoryMode::Statistics:
|
|
DoStatisticsMode();
|
|
break;
|
|
|
|
case InventoryMode::Examine:
|
|
DoExamineMode();
|
|
break;
|
|
|
|
case InventoryMode::Load:
|
|
switch (DoLoad())
|
|
{
|
|
case LoadResult::Load:
|
|
doLoad = true;
|
|
exitLoop = true;
|
|
break;
|
|
|
|
case LoadResult::Cancel:
|
|
exitLoop = !resetMode;
|
|
|
|
if (resetMode)
|
|
SetInventoryMode(InventoryMode::InGame);
|
|
|
|
break;
|
|
|
|
case LoadResult::None:
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
case InventoryMode::Save:
|
|
if (DoSave())
|
|
{
|
|
exitLoop = !resetMode;
|
|
if (resetMode)
|
|
SetInventoryMode(InventoryMode::InGame);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
if (ItemUsed && NoAction())
|
|
exitLoop = true;
|
|
|
|
SetEnterInventory(NO_VALUE);
|
|
g_Synchronizer.Step();
|
|
|
|
legacy30FpsDoneDraw = false;
|
|
}
|
|
|
|
if (!g_Configuration.EnableHighFramerate)
|
|
{
|
|
if (!legacy30FpsDoneDraw)
|
|
{
|
|
g_Renderer.RenderInventory();
|
|
g_Renderer.Lock();
|
|
g_Renderer.Synchronize();
|
|
legacy30FpsDoneDraw = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
g_Renderer.RenderInventory();
|
|
g_Renderer.Lock();
|
|
}
|
|
}
|
|
|
|
LastInvItem = Rings[(int)RingTypes::Inventory].CurrentObjectList[Rings[(int)RingTypes::Inventory].CurrentObjectInList].InventoryItem;
|
|
UpdateWeaponStatus(item);
|
|
|
|
if (ItemUsed)
|
|
UseItem(*item, InventoryObjectTable[LastInvItem].ObjectNumber);
|
|
|
|
AlterFOV(LastFOV);
|
|
g_Renderer.PrepareScene();
|
|
ResumeAllSounds(SoundPauseMode::Inventory);
|
|
|
|
player.Inventory.IsBusy = player.Inventory.OldBusy;
|
|
SetInventoryMode(InventoryMode::None);
|
|
|
|
App.ResetClock = true;
|
|
|
|
return doLoad;
|
|
}
|
|
|
|
void GuiController::DoStatisticsMode()
|
|
{
|
|
SetInventoryMode(InventoryMode::Statistics);
|
|
|
|
if (GuiIsDeselected())
|
|
{
|
|
SoundEffect(SFX_TR4_MENU_SELECT, nullptr, SoundEnvironment::Always);
|
|
SetInventoryMode(InventoryMode::InGame);
|
|
}
|
|
}
|
|
|
|
void GuiController::DoExamineMode()
|
|
{
|
|
SetInventoryMode(InventoryMode::Examine);
|
|
|
|
if (GuiIsDeselected())
|
|
{
|
|
SoundEffect(SFX_TR4_MENU_SELECT, nullptr, SoundEnvironment::Always);
|
|
SetInventoryMode(InventoryMode::None);
|
|
}
|
|
}
|
|
|
|
void GuiController::CancelInventorySelection()
|
|
{
|
|
if (GetInventoryItemChosen() != NO_VALUE)
|
|
{
|
|
SetInventoryItemChosen(NO_VALUE);
|
|
SayNo();
|
|
}
|
|
}
|
|
|
|
void GuiController::DrawCompass(ItemInfo* item)
|
|
{
|
|
if (!Lara.Inventory.HasCompass)
|
|
return;
|
|
|
|
constexpr auto POS_2D = Vector2(130.0f, 450.0f);
|
|
constexpr auto LERP_ALPHA = 0.1f;
|
|
|
|
auto needleOrient = EulerAngles(0, CompassNeedleAngle, 0);
|
|
needleOrient.Lerp(EulerAngles(0, item->Pose.Orientation.y, 0), LERP_ALPHA);
|
|
|
|
float wibble = std::sin((float(GlobalCounter & 0x3F) / (float)0x3F) * PI_MUL_2);
|
|
CompassNeedleAngle = needleOrient.y + ANGLE(wibble);
|
|
|
|
// HACK: Needle is rotated in the draw function.
|
|
const auto& invObject = InventoryObjectTable[INV_OBJECT_COMPASS];
|
|
g_Renderer.DrawObjectIn2DSpace(ID_COMPASS_ITEM, POS_2D, EulerAngles::Identity, invObject.Scale1 * 1.5f);
|
|
}
|
|
|
|
int GuiController::GetLoadSaveSelection()
|
|
{
|
|
return SelectedSaveSlot;
|
|
}
|
|
|
|
int GuiController::GetLoopedSelectedOption(int selectedOption, int optionCount, bool canLoop)
|
|
{
|
|
if (GuiIsPulsed(In::Forward))
|
|
{
|
|
if (selectedOption <= 0)
|
|
{
|
|
if (IsClicked(In::Forward) && canLoop)
|
|
{
|
|
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
|
return optionCount;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
|
return (selectedOption - 1);
|
|
}
|
|
}
|
|
else if (GuiIsPulsed(In::Back))
|
|
{
|
|
if (selectedOption >= optionCount)
|
|
{
|
|
if (IsClicked(In::Back) && canLoop)
|
|
{
|
|
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
|
return (selectedOption + 1);
|
|
}
|
|
}
|
|
|
|
return selectedOption;
|
|
}
|
|
|
|
LoadResult GuiController::DoLoad()
|
|
{
|
|
constexpr auto DEATH_NO_INPUT_LOAD_TIMEOUT = FPS / 2;
|
|
|
|
bool canLoop = g_Configuration.MenuOptionLoopingMode == MenuOptionLoopingMode::SaveLoadOnly ||
|
|
g_Configuration.MenuOptionLoopingMode == MenuOptionLoopingMode::AllMenus;
|
|
|
|
// If load menu is accessed after death, delay input polling to allow player to stop spamming input.
|
|
if (GetLaraInfo(*LaraItem).Control.Count.Death > 0 && TimeInMenu < DEATH_NO_INPUT_LOAD_TIMEOUT)
|
|
return LoadResult::None;
|
|
|
|
SelectedSaveSlot = GetLoopedSelectedOption(SelectedSaveSlot, SAVEGAME_MAX - 1, canLoop);
|
|
|
|
if (GuiIsSelected())
|
|
{
|
|
if (!SaveGame::Infos[SelectedSaveSlot].Present)
|
|
SayNo();
|
|
else
|
|
{
|
|
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
|
g_GameFlow->SelectedSaveGame = SelectedSaveSlot;
|
|
return LoadResult::Load;
|
|
}
|
|
}
|
|
|
|
if (GuiIsDeselected() || IsClicked(In::Load))
|
|
return LoadResult::Cancel;
|
|
|
|
return LoadResult::None;
|
|
}
|
|
|
|
bool GuiController::DoSave()
|
|
{
|
|
bool canLoop = g_Configuration.MenuOptionLoopingMode == MenuOptionLoopingMode::SaveLoadOnly ||
|
|
g_Configuration.MenuOptionLoopingMode == MenuOptionLoopingMode::AllMenus;
|
|
SelectedSaveSlot = GetLoopedSelectedOption(SelectedSaveSlot, SAVEGAME_MAX - 1, canLoop);
|
|
|
|
if (GuiIsSelected())
|
|
{
|
|
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
|
SaveGame::Save(SelectedSaveSlot);
|
|
return true;
|
|
}
|
|
|
|
if (GuiIsDeselected() || IsClicked(In::Save))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
bool GuiController::PerformWaterskinCombine(ItemInfo* item, bool flag)
|
|
{
|
|
auto& player = GetLaraInfo(*item);
|
|
|
|
int smallLiters = player.Inventory.SmallWaterskin - 1; // How many liters in the small one?
|
|
int bigLiters = player.Inventory.BigWaterskin - 1; // How many liters in the big one?
|
|
int smallCapacity = 3 - smallLiters; // How many more liters can fit in the small one?
|
|
int bigCapacity = 5 - bigLiters; // How many more liters can fit in the big one?
|
|
|
|
int i;
|
|
if (flag)
|
|
{
|
|
// Big one isn't empty and the small one isn't full.
|
|
if (player.Inventory.BigWaterskin != 1 && smallCapacity)
|
|
{
|
|
i = bigLiters;
|
|
|
|
do
|
|
{
|
|
if (smallCapacity)
|
|
{
|
|
smallLiters++;
|
|
smallCapacity--;
|
|
bigLiters--;
|
|
}
|
|
|
|
i--;
|
|
} while (i);
|
|
|
|
player.Inventory.SmallWaterskin = smallLiters + 1;
|
|
player.Inventory.BigWaterskin = bigLiters + 1;
|
|
CombineObject1 = (smallLiters + 1) + (INV_OBJECT_SMALL_WATERSKIN_EMPTY - 1);
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Small one isn't empty and the big one isn't full.
|
|
if (player.Inventory.SmallWaterskin != 1 && bigCapacity)
|
|
{
|
|
i = player.Inventory.SmallWaterskin - 1;
|
|
|
|
do
|
|
{
|
|
if (bigCapacity)
|
|
{
|
|
bigLiters++;
|
|
bigCapacity--;
|
|
smallLiters--;
|
|
}
|
|
|
|
i--;
|
|
} while (i);
|
|
|
|
player.Inventory.SmallWaterskin = smallLiters + 1;
|
|
player.Inventory.BigWaterskin = bigLiters + 1;
|
|
CombineObject1 = (bigLiters + 1) + (INV_OBJECT_BIG_WATERSKIN_EMPTY - 1);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|