diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 583bfa372..c1c6dccfa 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -7,7 +7,9 @@ set(GAMEENGINE_INCLUDES game/client/drawable/update game/client/gui game/client/gui/controlbar + game/client/gui/disconnectmenu game/client/gui/gadget + game/client/gui/guicallbacks game/client/gui/shell game/client/input game/client/messagestream @@ -30,6 +32,7 @@ set(GAMEENGINE_INCLUDES game/logic/object game/logic/object/behavior game/logic/object/body + game/logic/object/create game/logic/object/collide game/logic/object/contain game/logic/object/damage @@ -105,6 +108,7 @@ set(GAMEENGINE_SRC game/client/gui/controlbar/controlbarscheme.cpp game/client/gui/controlbar/controlbarstructureinventory.cpp game/client/gui/controlbar/controlbarunderconstruction.cpp + game/client/gui/disconnectmenu/disconnectmenu.cpp game/client/gui/gadget/gadgetcheckbox.cpp game/client/gui/gadget/gadgetcombobox.cpp game/client/gui/gadget/gadgethorizontalslider.cpp @@ -123,6 +127,8 @@ set(GAMEENGINE_SRC game/client/gui/gamewindowmanagerscript.cpp game/client/gui/gamewindowtransitions.cpp game/client/gui/gamewindowtransitionsstyles.cpp + game/client/gui/guicallbacks/controlbarcallback.cpp + game/client/gui/guicallbacks/controlbarpopupdescription.cpp game/client/gui/headertemplate.cpp game/client/gui/imemanager.cpp game/client/gui/imemanagerinterface.cpp @@ -138,6 +144,7 @@ set(GAMEENGINE_SRC game/client/languagefilter.cpp game/client/line2d.cpp game/client/maputil.cpp + game/client/messagestream/commandxlat.cpp game/client/messagestream/hotkey.cpp game/client/messagestream/metaevent.cpp game/client/messagestream/selectionxlat.cpp @@ -297,6 +304,8 @@ set(GAMEENGINE_SRC game/logic/object/behavior/rebuildholebehavior.cpp game/logic/object/collide/collidemodule.cpp game/logic/object/collide/squishcollide.cpp + game/logic/object/create/veterancygaincreate.cpp + game/logic/object/create/createmodule.cpp game/logic/object/damage/damagemodule.cpp game/logic/object/die/diemodule.cpp game/logic/object/die/specialpowercompletiondie.cpp diff --git a/src/game/client/gui/controlbar/controlbar.cpp b/src/game/client/gui/controlbar/controlbar.cpp index 60275bef8..b98d118c7 100644 --- a/src/game/client/gui/controlbar/controlbar.cpp +++ b/src/game/client/gui/controlbar/controlbar.cpp @@ -14,11 +14,31 @@ */ #include "controlbar.h" #include "actionmanager.h" +#include "animatewindowmanager.h" #include "behaviormodule.h" #include "captainslog.h" +#include "colorspace.h" +#include "controlbarscheme.h" +#include "drawable.h" +#include "gadgetprogressbar.h" +#include "gadgetpushbutton.h" +#include "gameclient.h" #include "gamelogic.h" +#include "gamewindowmanager.h" +#include "gamewindowtransitions.h" +#include "hotkey.h" #include "image.h" +#include "multiplayersettings.h" +#include "object.h" #include "player.h" +#include "playerlist.h" +#include "playertemplate.h" +#include "scriptengine.h" +#include "specialpower.h" +#include "stealthupdate.h" +#include "thingfactory.h" +#include "windowlayout.h" +#include "windowvideomanager.h" #ifdef GAME_DLL #include "hooker.h" #endif @@ -27,6 +47,11 @@ ControlBar *g_theControlBar; #endif +ControlBar::ContainEntry ControlBar::s_containData[CommandSet::MAX_COMMAND_BUTTONS]; +const Image *ControlBar::s_rankEliteIcon; +const Image *ControlBar::s_rankHeroicIcon; +const Image *ControlBar::s_rankVeteranIcon; + FieldParse CommandSet::s_commandSetFieldParseTable[] = { { "1", &CommandSet::Parse_Command_Button, reinterpret_cast(0), offsetof(CommandSet, m_command) }, { "2", &CommandSet::Parse_Command_Button, reinterpret_cast(1), offsetof(CommandSet, m_command) }, @@ -87,7 +112,7 @@ void CommandSet::Parse_Command_Button(INI *ini, void *formal, void *store, const name); const CommandButton **buttons = static_cast(store); size_t index = reinterpret_cast(user_data); - captainslog_dbgassert(index >= MAX_COMMAND_BUTTONS, "Parse_Command_Button: button index '%d' out of range", index); + captainslog_dbgassert(index < MAX_COMMAND_BUTTONS, "Parse_Command_Button: button index '%d' out of range", index); buttons[index] = button; } @@ -205,7 +230,7 @@ FieldParse CommandButton::s_commandButtonFieldParseTable[] = { { "Upgrade", &INI::Parse_Upgrade_Template, nullptr, offsetof(CommandButton, m_upgradeTemplate) }, { "WeaponSlot", &INI::Parse_Lookup_List, s_theWeaponSlotTypeNamesLookupList, offsetof(CommandButton, m_weaponSlot) }, { "MaxShotsToFire", &INI::Parse_Int, nullptr, offsetof(CommandButton, m_maxShotsToFire) }, - { "Science", &ScienceStore::Parse_Science_Vector, nullptr, offsetof(CommandButton, m_maxShotsToFire) }, + { "Science", &ScienceStore::Parse_Science_Vector, nullptr, offsetof(CommandButton, m_sciences) }, { "SpecialPower", &INI::Parse_Special_Power_Template, nullptr, offsetof(CommandButton, m_specialPower) }, { "TextLabel", &INI::Parse_AsciiString, nullptr, offsetof(CommandButton, m_textLabel) }, { "DescriptLabel", &INI::Parse_AsciiString, nullptr, offsetof(CommandButton, m_descriptLabel) }, @@ -387,7 +412,7 @@ void CommandButton::Copy_Images_From(const CommandButton *button, bool set_dirty void CommandButton::Copy_Button_Text_From(const CommandButton *button, bool conflicting_label, bool set_dirty) { - bool is_dirty = true; + bool is_dirty = false; if (conflicting_label) { if (button->Get_Conflicting_Label().Is_Not_Empty()) { @@ -429,19 +454,1111 @@ void CommandButton::Cache_Button_Image() } } -void CommandButton::Set_Next(CommandButton **next) +void CommandButton::Friend_Add_To_List(CommandButton **next) { m_nextCommandButton = *next; *next = this; } +ControlBar::ControlBar() : + m_videoManager(nullptr), + m_controlBarAnimateWindowManager(nullptr), + m_specialPowerShortcutAnimateWindowManager(nullptr), + m_unkAnimateWindowManager(nullptr), + m_parentXPosition(0), + m_parentYPosition(0), + m_controlBarConfig(0), + m_UIDirty(false), + m_commandButtons(nullptr), + m_commandSets(nullptr), + m_controlBarSchemeManager(nullptr), + m_currentSelectedDrawable(nullptr), + m_currContext(CB_CONTEXT_NONE), + m_rallyPointDrawable(nullptr), + m_displayedConstructPercent(-1.0f), + m_oclTimerFrame(0), + m_displayedQueueCount(0), + m_lastRecordedInventoryCount(0), + m_rightHUDWindow(nullptr), + m_rightHUDCameoWindow(nullptr), + m_unitSelectedWindow(nullptr), + m_popupCommunicator(nullptr), + m_generalsPointsLayout(nullptr), + m_specialPowerShortcutButtonCount(0), + m_specialPowerShortcutBarLayout(nullptr), + m_specialPowerShortcutBarParent(nullptr), + m_cameoFlash(false), + m_unk1(false), + m_unk2(0), + m_unk3(0), + m_unk4(0), + m_unk5(0), + m_unk6(0), + m_unk7(0), + m_unk8(0), + m_unk9(0), + m_unkWindow(nullptr), + m_unk10(0), + m_buildUpClockColor(Make_Color(0, 0, 0, 100)), + m_isObserver(false), + m_observerPlayer(nullptr), + m_controlBarPopupDescriptionLayout(nullptr), + m_buildTooltipLayoutVisible(false), + m_unkColor(Make_Color(0, 0, 0, 100)), + m_barButtonGenStarOnIcon(nullptr), + m_barButtonGenStarOffIcon(nullptr), + m_toggleButtonUpInImage(nullptr), + m_toggleButtonUpOnImage(nullptr), + m_toggleButtonUpPushedImage(nullptr), + m_toggleButtonDownInImage(nullptr), + m_toggleButtonDownOnImage(nullptr), + m_toggleButtonDownPushedImage(nullptr), + m_unk11(0), + m_genArrowImage(nullptr), + m_generalButtonEnableImage(nullptr), + m_generalButtonHilitedImage(nullptr), + m_starHilight(false), + m_sciencePurchasePoints(0), + m_foregroundMarkerPosX(0), + m_foregroundMarkerPosY(0), + m_backgroundMarkerPosX(0), + m_backgroundMarkerPosY(0), + m_triggerRadarAttackGlow(false), + m_radarAttackGlowCounter(0), + m_radarAttackGlowWindow(nullptr) +{ + for (int i = 0; i < CommandSet::MAX_COMMAND_BUTTONS; i++) { + m_commonCommands[i] = nullptr; + } + + for (int i = 0; i < CONTEXT_PARENT_COUNT; i++) { + m_contextParent[i] = nullptr; + } + + for (int i = 0; i < CommandSet::MAX_COMMAND_BUTTONS; i++) { + m_commandWindows[i] = nullptr; + } + + for (int i = 0; i < UNIT_UPGRADE_WINDOW_COUNT; i++) { + m_unitUpgradeWindows[i] = nullptr; + } + + for (int i = 0; i < RANK_1_BUTTON_COUNT; i++) { + m_rank1Buttons[i] = nullptr; + } + + for (int i = 0; i < RANK_3_BUTTON_COUNT; i++) { + m_rank3Buttons[i] = nullptr; + } + + for (int i = 0; i < RANK_8_BUTTON_COUNT; i++) { + m_rank8Buttons[i] = nullptr; + } + + for (int i = 0; i < SPECIAL_POWER_SHORTCUT_BUTTON_COUNT; i++) { + m_specialPowerShortcutButtons[i] = 0; + m_specialPowerShortcutButtonParents[i] = 0; + m_specialPowerShortcutButtonUnk[i] = 0; + } + + Reset_Build_Queue_Data(); + Reset_Contain_Data(); + Update_Command_Bar_Border_Colors(0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF); + +#ifdef GAME_DEBUG_STRUCTS + m_uiDirtyCounter = 0; + m_uiDirtyFrame = 0; +#endif +} + +ControlBar::~ControlBar() +{ + if (m_generalsPointsLayout != nullptr) { + m_generalsPointsLayout->Destroy_Windows(); + m_generalsPointsLayout->Delete_Instance(); + } + + m_generalsPointsLayout = nullptr; + m_genArrowImage = nullptr; + + if (m_videoManager != nullptr) { + delete m_videoManager; + } + + m_videoManager = nullptr; + + if (m_specialPowerShortcutAnimateWindowManager != nullptr) { + delete m_specialPowerShortcutAnimateWindowManager; + } + + m_specialPowerShortcutAnimateWindowManager = nullptr; + + if (m_controlBarAnimateWindowManager != nullptr) { + delete m_controlBarAnimateWindowManager; + } + + m_controlBarAnimateWindowManager = nullptr; + + if (m_unkAnimateWindowManager != nullptr) { + delete m_unkAnimateWindowManager; + } + + m_unkAnimateWindowManager = nullptr; + + if (m_controlBarSchemeManager != nullptr) { + delete m_controlBarSchemeManager; + } + + m_controlBarSchemeManager = nullptr; + + while (m_commandSets != nullptr) { + CommandSet *next = m_commandSets->Get_Next_Command_Set(); + m_commandSets->Delete_Instance(); + m_commandSets = next; + } + + while (m_commandButtons != nullptr) { + CommandButton *next = m_commandButtons->Get_Next(); + m_commandButtons->Delete_Instance(); + m_commandButtons = next; + } + + if (m_controlBarPopupDescriptionLayout != nullptr) { + m_controlBarPopupDescriptionLayout->Destroy_Windows(); + m_controlBarPopupDescriptionLayout->Delete_Instance(); + m_controlBarPopupDescriptionLayout = nullptr; + } + + if (m_specialPowerShortcutBarLayout != nullptr) { + m_specialPowerShortcutBarLayout->Destroy_Windows(); + m_specialPowerShortcutBarLayout->Delete_Instance(); + m_specialPowerShortcutBarLayout = nullptr; + } + + m_radarAttackGlowWindow = nullptr; + + if (m_rightHUDCameoWindow != nullptr && m_rightHUDCameoWindow->Win_Get_User_Data() != nullptr) { + delete m_rightHUDCameoWindow->Win_Get_User_Data(); + } +} + +void ControlBar::Update_Command_Bar_Border_Colors(int build, int action, int upgrade, int system) +{ + m_commandButtonBorderBuildColor = build; + m_commandButtonBorderActionColor = action; + m_commandButtonBorderUpgradeColor = upgrade; + m_commandButtonBorderSystemColor = system; +} + +void Command_Button_Tooltip(GameWindow *window, WinInstanceData *instance, unsigned int mouse) +{ + g_theControlBar->Show_Build_Tooltip_Layout(window); +} + +void ControlBar::Init() +{ + INI ini; + m_unk1 = false; + ini.Load("Data\\INI\\Default\\CommandButton.ini", INI_LOAD_OVERWRITE, nullptr); + ini.Load("Data\\INI\\CommandButton.ini", INI_LOAD_OVERWRITE, nullptr); + ini.Load("Data\\INI\\CommandSet.ini", INI_LOAD_OVERWRITE, nullptr); + Post_Process_Commands(); + m_controlBarSchemeManager = new ControlBarSchemeManager(); + m_controlBarSchemeManager->Init(); + + if (g_theWindowManager != nullptr) { + m_contextParent[0] = g_theWindowManager->Win_Get_Window_From_Id( + nullptr, g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:ControlBarParent")); + m_contextParent[0]->Win_Get_Position(&m_parentXPosition, &m_parentYPosition); + m_generalsPointsLayout = g_theWindowManager->Win_Create_Layout("GeneralsExpPoints.wnd"); + m_generalsPointsLayout->Hide(true); + + m_contextParent[1] = g_theWindowManager->Win_Get_Window_From_Id( + nullptr, g_theNameKeyGenerator->Name_To_Key("GeneralsExpPoints.wnd:GenExpParent")); + m_contextParent[5] = g_theWindowManager->Win_Get_Window_From_Id( + nullptr, g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:UnderConstructionWindow")); + m_contextParent[8] = g_theWindowManager->Win_Get_Window_From_Id( + nullptr, g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:OCLTimerWindow")); + m_contextParent[4] = g_theWindowManager->Win_Get_Window_From_Id( + nullptr, g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:BeaconWindow")); + m_contextParent[2] = g_theWindowManager->Win_Get_Window_From_Id( + nullptr, g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:CommandWindow")); + m_contextParent[3] = g_theWindowManager->Win_Get_Window_From_Id( + nullptr, g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:ProductionQueueWindow")); + m_contextParent[7] = g_theWindowManager->Win_Get_Window_From_Id( + nullptr, g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:ObserverPlayerListWindow")); + m_contextParent[6] = g_theWindowManager->Win_Get_Window_From_Id( + nullptr, g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:ObserverPlayerInfoWindow")); + + Utf8String str; + + for (int i = 0; i < CommandSet::MAX_COMMAND_BUTTONS; i++) { + str.Format("ControlBar.wnd:ButtonCommand%02d", i + 1); + m_commandWindows[i] = g_theWindowManager->Win_Get_Window_From_Id( + m_contextParent[2], g_theNameKeyGenerator->Name_To_Key(str.Str())); + + if (m_commandWindows[i] != nullptr) { + m_commandWindows[i]->Win_Set_Status(WIN_STATUS_USE_OVERLAY_STATES); + } + } + + for (int i = 0; i < RANK_1_BUTTON_COUNT; i++) { + str.Format("GeneralsExpPoints.wnd:ButtonRank1Number%d", i); + m_rank1Buttons[i] = g_theWindowManager->Win_Get_Window_From_Id( + m_contextParent[1], g_theNameKeyGenerator->Name_To_Key(str.Str())); + m_rank1Buttons[i]->Win_Set_Status(WIN_STATUS_USE_OVERLAY_STATES); + } + + for (int i = 0; i < RANK_3_BUTTON_COUNT; i++) { + str.Format("GeneralsExpPoints.wnd:ButtonRank3Number%d", i); + m_rank3Buttons[i] = g_theWindowManager->Win_Get_Window_From_Id( + m_contextParent[1], g_theNameKeyGenerator->Name_To_Key(str.Str())); + m_rank3Buttons[i]->Win_Set_Status(WIN_STATUS_USE_OVERLAY_STATES); + } + + for (int i = 0; i < RANK_8_BUTTON_COUNT; i++) { + str.Format("GeneralsExpPoints.wnd:ButtonRank8Number%d", i); + m_rank8Buttons[i] = g_theWindowManager->Win_Get_Window_From_Id( + m_contextParent[1], g_theNameKeyGenerator->Name_To_Key(str.Str())); + m_rank8Buttons[i]->Win_Set_Status(WIN_STATUS_USE_OVERLAY_STATES); + } + + m_rightHUDWindow = g_theWindowManager->Win_Get_Window_From_Id( + nullptr, g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:RightHUD")); + m_unitSelectedWindow = g_theWindowManager->Win_Get_Window_From_Id( + nullptr, g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:WinUnitSelected")); + m_rightHUDCameoWindow = g_theWindowManager->Win_Get_Window_From_Id( + nullptr, g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:CameoWindow")); + + for (int i = 0; i < UNIT_UPGRADE_WINDOW_COUNT; i++) { + str.Format("ControlBar.wnd:UnitUpgrade%d", i + 1); + m_unitUpgradeWindows[i] = + g_theWindowManager->Win_Get_Window_From_Id(m_rightHUDWindow, g_theNameKeyGenerator->Name_To_Key(str.Str())); + m_unitUpgradeWindows[i]->Win_Set_Status(WIN_STATUS_USE_OVERLAY_STATES); + } + + m_popupCommunicator = g_theWindowManager->Win_Get_Window_From_Id( + nullptr, g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:PopupCommunicator")); + + Set_Control_Command(m_popupCommunicator, Find_Command_Button("NonCommand_Communicator")); + m_popupCommunicator->Win_Set_Tooltip_Func(Command_Button_Tooltip); + + GameWindow *button = g_theWindowManager->Win_Get_Window_From_Id( + nullptr, g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:ButtonOptions")); + + if (button != nullptr) { + Set_Control_Command(button, Find_Command_Button("NonCommand_Options")); + button->Win_Set_Tooltip_Func(Command_Button_Tooltip); + } + + button = g_theWindowManager->Win_Get_Window_From_Id( + nullptr, g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:ButtonIdleWorker")); + + if (button != nullptr) { + Set_Control_Command(button, Find_Command_Button("NonCommand_IdleWorker")); + button->Win_Set_Tooltip_Func(Command_Button_Tooltip); + } + + button = g_theWindowManager->Win_Get_Window_From_Id( + nullptr, g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:ButtonPlaceBeacon")); + + if (button != nullptr) { + Set_Control_Command(button, Find_Command_Button("NonCommand_Beacon")); + button->Win_Set_Tooltip_Func(Command_Button_Tooltip); + } + + button = g_theWindowManager->Win_Get_Window_From_Id( + nullptr, g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:ButtonGeneral")); + + if (button != nullptr) { + Set_Control_Command(button, Find_Command_Button("NonCommand_GeneralsExperience")); + button->Win_Set_Tooltip_Func(Command_Button_Tooltip); + } + + button = g_theWindowManager->Win_Get_Window_From_Id( + nullptr, g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:ButtonLarge")); + + if (button != nullptr) { + Set_Control_Command(button, Find_Command_Button("NonCommand_UpDown")); + button->Win_Set_Tooltip_Func(Command_Button_Tooltip); + } + + button = g_theWindowManager->Win_Get_Window_From_Id( + nullptr, g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:PowerWindow")); + + if (button != nullptr) { + button->Win_Set_Tooltip_Func(Command_Button_Tooltip); + } + + button = g_theWindowManager->Win_Get_Window_From_Id( + nullptr, g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:MoneyDisplay")); + + if (button != nullptr) { + button->Win_Set_Tooltip_Func(Command_Button_Tooltip); + } + + button = g_theWindowManager->Win_Get_Window_From_Id( + nullptr, g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:GeneralsExp")); + + if (button != nullptr) { + button->Win_Set_Tooltip_Func(Command_Button_Tooltip); + } + + m_radarAttackGlowWindow = g_theWindowManager->Win_Get_Window_From_Id( + nullptr, g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:WinUAttack")); + + button = g_theWindowManager->Win_Get_Window_From_Id( + nullptr, g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:BackgroundMarker")); + button->Win_Get_Screen_Position(&m_foregroundMarkerPosX, &m_foregroundMarkerPosY); + + button = g_theWindowManager->Win_Get_Window_From_Id( + nullptr, g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:BackgroundMarker")); + button->Win_Get_Screen_Position(&m_backgroundMarkerPosX, &m_backgroundMarkerPosY); + + if (m_videoManager == nullptr) { + m_videoManager = new WindowVideoManager(); + } + + if (m_controlBarAnimateWindowManager == nullptr) { + m_controlBarAnimateWindowManager = new AnimateWindowManager(); + } + + if (m_unkAnimateWindowManager == nullptr) { + m_unkAnimateWindowManager = new AnimateWindowManager(); + } + + if (m_specialPowerShortcutAnimateWindowManager == nullptr) { + m_specialPowerShortcutAnimateWindowManager = new AnimateWindowManager(); + } + + m_controlBarPopupDescriptionLayout = g_theWindowManager->Win_Create_Layout("ControlBarPopupDescription.wnd"); + + if (m_controlBarPopupDescriptionLayout != nullptr) { + m_controlBarPopupDescriptionLayout->Hide(true); + m_controlBarPopupDescriptionLayout->Set_Update(Control_Bar_Popup_Description_Update_Func); + } + + const Image *image; + + if (g_theMappedImageCollection != nullptr) { + image = g_theMappedImageCollection->Find_Image_By_Name("BarButtonGenStarON"); + } else { + image = nullptr; + } + + m_barButtonGenStarOnIcon = image; + + if (g_theMappedImageCollection != nullptr) { + image = g_theMappedImageCollection->Find_Image_By_Name("BarButtonGenStarOFF"); + } else { + image = nullptr; + } + + m_barButtonGenStarOffIcon = image; + m_starHilight = true; + m_sciencePurchasePoints = -1; + + if (g_theMappedImageCollection != nullptr) { + image = g_theMappedImageCollection->Find_Image_By_Name("SSChevron1L"); + } else { + image = nullptr; + } + + s_rankVeteranIcon = image; + + if (g_theMappedImageCollection != nullptr) { + image = g_theMappedImageCollection->Find_Image_By_Name("SSChevron2L"); + } else { + image = nullptr; + } + + s_rankEliteIcon = image; + + if (g_theMappedImageCollection != nullptr) { + image = g_theMappedImageCollection->Find_Image_By_Name("SSChevron3L"); + } else { + image = nullptr; + } + + s_rankHeroicIcon = image; + Init_Observer_Controls(); + Switch_To_Context(CB_CONTEXT_NONE, nullptr); + } +} + +void ControlBar::Get_Background_Marker_Pos(int *x, int *y) +{ + *x = m_backgroundMarkerPosX; + *y = m_backgroundMarkerPosY; +} + +void ControlBar::Post_Process_Commands() +{ + for (CommandButton *button = m_commandButtons; button != nullptr; button = button->Get_Next()) { + button->Cache_Button_Image(); + } +} + +void ControlBar::Set_Control_Command(GameWindow *button, const CommandButton *command_button) +{ + if (button->Win_Get_Input_Func() == Gadget_Push_Button_Input) { + if (command_button != nullptr) { + if ((command_button->Get_Options() & COMMAND_OPTION_CHECK_LIKE) != 0) { + Gadget_Button_Enable_Check_Like(button, true, false); + } else { + Gadget_Button_Enable_Check_Like(button, false, false); + } + + if (command_button->Get_Button_Image() != nullptr) { + Gadget_Button_Set_Enabled_Image(button, command_button->Get_Button_Image()); + } + + if (command_button->Get_Text_Label().Is_Empty() && command_button->Get_Sciences()->empty()) { + Gadget_Button_Set_Text(button, U_CHAR("")); + } else { + button->Win_Set_Tooltip_Func(Command_Button_Tooltip); + } + + Gadget_Button_Set_Data(button, const_cast(command_button)); + Set_Command_Bar_Border(button, command_button->Get_Border()); + + if (g_theHotKeyManager != nullptr) { + Utf8String key = g_theHotKeyManager->Search_Hot_Key(command_button->Get_Text_Label()); + + if (key.Is_Not_Empty()) { + g_theHotKeyManager->Add_Hot_Key(button, key); + } + } + + Gadget_Button_Set_Alt_Sound(button, "GUICommandBarClick"); + } else { + captainslog_dbgassert(false, "Set_Control_Command: NULL commandButton passed in"); + } + } else { + captainslog_dbgassert(false, "Set_Control_Command: Window is not a button"); + } +} + +void ControlBar::Set_Command_Bar_Border(GameWindow *button, CommandButtonMappedBorderType type) +{ + if (button != nullptr) { + switch (type) { + case COMMAND_BUTTON_BORDER_BUILD: + Gadget_Button_Set_Border(button, m_commandButtonBorderBuildColor, true); + break; + case COMMAND_BUTTON_BORDER_UPGRADE: + Gadget_Button_Set_Border(button, m_commandButtonBorderUpgradeColor, true); + break; + case COMMAND_BUTTON_BORDER_ACTION: + Gadget_Button_Set_Border(button, m_commandButtonBorderActionColor, true); + break; + case COMMAND_BUTTON_BORDER_SYSTEM: + Gadget_Button_Set_Border(button, m_commandButtonBorderSystemColor, true); + break; + default: + Gadget_Button_Set_Border(button, 0xFFFFFF, false); + break; + } + } +} + +void ControlBar::Reset() +{ + Hide_Special_Power_Shortcut(); + m_rallyPointDrawable = nullptr; + + if (m_radarAttackGlowWindow != nullptr) { + m_radarAttackGlowWindow->Win_Enable(true); + } + + m_triggerRadarAttackGlow = false; + m_radarAttackGlowCounter = 0; + m_displayedConstructPercent = -1.0f; + m_oclTimerFrame = 0; + m_isObserver = false; + m_observerPlayer = nullptr; + + if (m_controlBarPopupDescriptionLayout != nullptr) { + m_controlBarPopupDescriptionLayout->Hide(true); + } + + m_buildTooltipLayoutVisible = false; + + if (m_controlBarAnimateWindowManager != nullptr) { + m_controlBarAnimateWindowManager->Reset(); + } + + if (m_specialPowerShortcutAnimateWindowManager != nullptr) { + m_specialPowerShortcutAnimateWindowManager->Reset(); + } + + if (m_unkAnimateWindowManager != nullptr) { + m_unkAnimateWindowManager->Reset(); + } + + if (m_videoManager != nullptr) { + m_videoManager->Reset(); + } + + Switch_To_Context(CB_CONTEXT_NONE, nullptr); + m_unk1 = false; + + if (m_unkWindow != nullptr) { + g_theWindowManager->Win_Destroy(m_unkWindow); + m_unkWindow = nullptr; + } + + CommandSet *next_set; + + for (CommandSet *set = m_commandSets; set != nullptr; set = next_set) { + bool is_head = false; + next_set = set->Get_Next_Command_Set(); + + if (set == m_commandSets) { + is_head = true; + } + + if (!set->Delete_Overrides() && is_head) { + m_commandSets = next_set; + } + } + + CommandButton *next_button; + + for (CommandButton *button = m_commandButtons; button != nullptr; button = next_button) { + bool is_head = false; + next_button = button->Get_Next(); + + if (button == m_commandButtons) { + is_head = true; + } + + if (!button->Delete_Overrides() && is_head) { + m_commandButtons = next_button; + } + } + + if (g_theTransitionHandler != nullptr) { + g_theTransitionHandler->Remove("ControlBarArrow", false); + } + + m_genArrowImage = nullptr; + m_sciencePurchasePoints = -1; + m_starHilight = true; +} + +void ControlBar::Update() +{ + Get_Star_Image(); + Update_Radar_Attack_Glow(); + + if (m_controlBarSchemeManager != nullptr) { + m_controlBarSchemeManager->Update(); + } + + if (m_videoManager != nullptr) { + m_videoManager->Update(); + } + + if (m_controlBarAnimateWindowManager != nullptr) { + m_controlBarAnimateWindowManager->Update(); + } + + if (m_controlBarAnimateWindowManager != nullptr) { + if (m_controlBarAnimateWindowManager->Is_Finished()) { + if (m_controlBarAnimateWindowManager->Is_Reversed()) { + GameWindow *window = g_theWindowManager->Win_Get_Window_From_Id( + nullptr, g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:ControlBarParent")); + + if (window != nullptr) { + if (!window->Win_Is_Hidden()) { + window->Win_Hide(true); + } + } + } + } + } + + if (m_specialPowerShortcutAnimateWindowManager != nullptr) { + m_specialPowerShortcutAnimateWindowManager->Update(); + } + + if (m_specialPowerShortcutAnimateWindowManager != nullptr && m_specialPowerShortcutBarParent != nullptr + && m_specialPowerShortcutAnimateWindowManager->Is_Finished() + && m_specialPowerShortcutAnimateWindowManager->Is_Reversed() && m_specialPowerShortcutBarParent != nullptr + && !m_specialPowerShortcutBarParent->Win_Is_Hidden()) { + m_specialPowerShortcutBarParent->Win_Hide(true); + } + + if (!m_controlBarPopupDescriptionLayout->Is_Hidden()) { + m_controlBarPopupDescriptionLayout->Run_Update(nullptr); + m_buildTooltipLayoutVisible = false; + } + + Update_Special_Power_Shortcut(); + + if (m_isObserver) { + if (!(g_theGameLogic->Get_Frame() % 15)) { + Populate_Observer_Info_Window(); + } + + Drawable *drawable = nullptr; + + if (g_theInGameUI->Get_Select_Count() <= 1) { + drawable = g_theInGameUI->Get_All_Selected_Drawables()->front(); + } else { + drawable = g_theGameClient->Find_Drawable_By_ID(g_theInGameUI->Get_Solo_Nexus_Selected_Drawable_ID()); + } + + Object *obj; + + if (drawable != nullptr) { + obj = drawable->Get_Object(); + } else { + obj = nullptr; + } + + Set_Portrait_By_Object(obj); + } else { + if (m_cameoFlash) { + for (int i = 0; i < CommandSet::MAX_COMMAND_BUTTONS; i++) { + GameWindow *window = m_commandWindows[i]; + + if (window != nullptr) { + CommandButton *button = static_cast(Gadget_Button_Get_Data(window)); + + if (button != nullptr) { + if (button->Get_Cameo_Flash_Time() > 0 && !(g_theGameClient->Get_Frame() & 10)) { + if (button->Get_Cameo_Flash_Time() % 2) { + button->Set_Cameo_Flash_Time(button->Get_Cameo_Flash_Time() - 1); + window->Win_Clear_Status(WIN_STATUS_FLASHING); + + if (button->Get_Cameo_Flash_Time() == 0) { + Set_Cameo_Flash(false); + } + } else { + button->Set_Cameo_Flash_Time(button->Get_Cameo_Flash_Time() - 1); + window->Win_Set_Status(WIN_STATUS_FLASHING); + } + } + } + } + } + } + + if (!m_contextParent[1]->Win_Is_Hidden()) { + Update_Context_Purchase_Science(); + } + + if (m_UIDirty) { + Evaluate_Context_UI(); + Populate_Special_Power_Shortcut(g_thePlayerList->Get_Local_Player()); + Repopulate_Build_Tooltip_Layout(); + } + + if (g_thePlayerList != nullptr) { + if (g_thePlayerList->Get_Local_Player() != nullptr) { + if (g_thePlayerList->Get_Local_Player()->Get_Player_Template() != nullptr) { + ThingTemplate *thing = g_theThingFactory->Find_Template( + g_thePlayerList->Get_Local_Player()->Get_Player_Template()->Get_Beacon_Name(), true); + int count; + g_thePlayerList->Get_Local_Player()->Count_Objects_By_Thing_Template(1, &thing, false, &count, true); + static const NameKeyType s_beaconPlacementButtonID = + g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:ButtonPlaceBeacon"); + GameWindow *window = g_theWindowManager->Win_Get_Window_From_Id(nullptr, s_beaconPlacementButtonID); + + if (window != nullptr) { + if (count >= g_theMultiplayerSettings->Get_Max_Beacons_Per_Player()) { + window->Win_Enable(false); + } else { + window->Win_Enable(true); + } + } + } + } + } + + if (m_currContext == CB_CONTEXT_MULTI_SELECT) { + Update_Context_Multi_Select(); + } else if (m_currentSelectedDrawable != nullptr) { + Object *object = nullptr; + + if (m_currentSelectedDrawable != nullptr) { + object = m_currentSelectedDrawable->Get_Object(); + } + + if (object != nullptr) { + switch (m_currContext) { + case CB_CONTEXT_COMMAND: + Update_Context_Command(); + break; + case CB_CONTEXT_STRUCTURE_INVENTORY: + Update_Context_Structure_Inventory(); + break; + case CB_CONTEXT_BEACON: + Update_Context_Beacon(); + break; + case CB_CONTEXT_UNDER_CONSTRUCTION: + Update_Context_Under_Construction(); + break; + case CB_CONTEXT_OCL_TIMER: + Update_Context_OCL_Timer(); + break; + default: + return; + } + } else { + Switch_To_Context(CB_CONTEXT_NONE, nullptr); + } + } else { + captainslog_dbgassert(m_currContext == CB_CONTEXT_NONE, + "ControlBar::Update no selection, but we're not showing the default NONE context"); + } + } +} + +const Image *ControlBar::Get_Star_Image() +{ + if (m_sciencePurchasePoints <= g_thePlayerList->Get_Local_Player()->Get_Science_Purchase_Points() + && g_thePlayerList->Get_Local_Player()->Get_Science_Purchase_Points() > 0) { + m_sciencePurchasePoints = g_thePlayerList->Get_Local_Player()->Get_Science_Purchase_Points(); + } else { + m_starHilight = false; + } + + GameWindow *window = g_theWindowManager->Win_Get_Window_From_Id( + nullptr, g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:ButtonGeneral")); + + if (window == nullptr) { + return nullptr; + } + + if (m_starHilight) { + if (g_theGameLogic->Get_Frame() % 30 <= 15) { + Gadget_Button_Set_Enabled_Image(window, m_generalButtonEnableImage); + } else { + Gadget_Button_Set_Enabled_Image(window, m_generalButtonHilitedImage); + } + + return nullptr; + } else { + Gadget_Button_Set_Enabled_Image(window, m_generalButtonEnableImage); + return nullptr; + } +} + +void ControlBar::Update_Radar_Attack_Glow() +{ + if (m_triggerRadarAttackGlow && m_radarAttackGlowWindow != nullptr) { + m_radarAttackGlowCounter--; + + if (m_radarAttackGlowCounter > 0) { + if ((m_radarAttackGlowCounter % 15) == 0) { + m_radarAttackGlowWindow->Win_Enable((m_radarAttackGlowWindow->Win_Get_Status() & WIN_STATUS_ENABLED) == 0); + } + } else { + m_triggerRadarAttackGlow = false; + m_radarAttackGlowWindow->Win_Enable(true); + } + } +} + +void ControlBar::Update_Context_Purchase_Science() +{ + Player *player = g_thePlayerList->Get_Local_Player(); + GameWindow *window = g_theWindowManager->Win_Get_Window_From_Id( + m_contextParent[1], g_theNameKeyGenerator->Name_To_Key("GeneralsExpPoints.wnd:ProgressBarExperience")); + + if (window != nullptr) { + Gadget_Progress_Bar_Set_Progress(window, + (100 * (player->Get_Current_Skill_Points() - player->Get_Rank_Progress())) + / (player->Get_Skill_Points_Needed_For_Next_Rank() - player->Get_Rank_Progress())); + } +} + +void ControlBar::Set_Portrait_By_Object(Object *obj) +{ + if (obj != nullptr) { + if (obj->Is_KindOf(KINDOF_SHOW_PORTRAIT_WHEN_CONTROLLED) && !obj->Is_Locally_Controlled()) { + Set_Portrait_By_Object(nullptr); + return; + } + + const ThingTemplate *thing = obj->Get_Template(); + Player *player = obj->Get_Controlling_Player(); + Drawable *drawable = obj->Get_Drawable(); + + if (drawable != nullptr && drawable->Get_Stealth_Look() == STEALTHLOOK_DISGUISED) { + thing = drawable->Get_Template(); + + if (thing->Is_KindOf(KINDOF_SHOW_PORTRAIT_WHEN_CONTROLLED)) { + Set_Portrait_By_Object(nullptr); + return; + } + + StealthUpdate *update = obj->Get_Stealth_Update(); + + if (update != nullptr && update->Has_Disguised_Template()) { + player = g_thePlayerList->Get_Nth_Player(update->Get_Player_Index()); + } + } + + m_unitSelectedWindow->Win_Hide(false); + m_rightHUDCameoWindow->Win_Set_Enabled_Image(0, thing->Get_Selected_Portrait_Image()); + Gadget_Button_Draw_Overlay_Image(m_rightHUDCameoWindow, ControlBar::Calculate_Veterancy_Overlay_For_Object(obj)); + m_rightHUDWindow->Win_Clear_Status(WIN_STATUS_IMAGE); + m_rightHUDCameoWindow->Win_Set_Status(WIN_STATUS_IMAGE); + + for (int i = 0; i < UNIT_UPGRADE_WINDOW_COUNT; i++) { + Utf8String name = thing->Get_Upgrade_Cameo_Name(i); + const UpgradeTemplate *upgrade; + + if (name.Is_Empty() || (upgrade = g_theUpgradeCenter->Find_Upgrade(name)) == 0) { + m_unitUpgradeWindows[i]->Win_Hide(true); + } else { + m_unitUpgradeWindows[i]->Win_Hide(false); + m_unitUpgradeWindows[i]->Win_Set_Enabled_Image(0, upgrade->Get_Button_Image()); + + if (obj->Has_Upgrade(upgrade) || (player != nullptr && player->Has_Upgrade_Complete(upgrade))) { + m_unitUpgradeWindows[i]->Win_Enable(true); + } else { + m_unitUpgradeWindows[i]->Win_Enable(false); + } + } + } + } else { + m_unitSelectedWindow->Win_Hide(true); + m_rightHUDWindow->Win_Set_Status(WIN_STATUS_IMAGE); + m_rightHUDCameoWindow->Win_Clear_Status(WIN_STATUS_IMAGE); + + for (int i = 0; i < UNIT_UPGRADE_WINDOW_COUNT; i++) { + m_unitUpgradeWindows[i]->Win_Hide(true); + } + + Gadget_Button_Draw_Overlay_Image(m_rightHUDCameoWindow, nullptr); + } +} + +void ControlBar::Hide_Special_Power_Shortcut() +{ + if (m_specialPowerShortcutBarParent != nullptr) { + m_specialPowerShortcutBarParent->Win_Hide(true); + } +} + void ControlBar::Mark_UI_Dirty() { -#ifdef GAME_DLL - Call_Method(PICK_ADDRESS(0x0045B3F0, 0x00729C50), this); + m_UIDirty = true; +#ifdef GAME_DEBUG_STRUCTS + unsigned int frame = g_theGameLogic->Get_Frame(); + + if (frame != m_uiDirtyFrame) { + if (frame == m_uiDirtyFrame + 1) { + m_uiDirtyCounter++; + } else { + m_uiDirtyCounter = 1; + } + } + + m_uiDirtyFrame = frame; + captainslog_dbgassert(m_uiDirtyCounter > 20, + "Serious flaw in interface system! Either new code or INI has caused the interface to be marked dirty every frame. " + "This problem actually causes the interface to completely lockup not allowing you to click normal game buttons."); #endif } +void ControlBar::On_Player_Rank_Changed(const Player *player) +{ + if (player->Is_Local_Player()) { + Player *local_player = g_thePlayerList->Get_Local_Player(); + + if (m_sciencePurchasePoints <= local_player->Get_Science_Purchase_Points() && g_theTransitionHandler != nullptr + && g_theInGameUI->Get_Input_Enabled()) { + g_theTransitionHandler->Set_Group("ControlBarArrow", false); + } + + m_starHilight = true; + Mark_UI_Dirty(); + } +} + +void ControlBar::On_Player_Science_Purchase_Points_Changed(const Player *player) +{ + if (player->Is_Local_Player()) { + Player *local_player = g_thePlayerList->Get_Local_Player(); + + if (m_sciencePurchasePoints <= local_player->Get_Science_Purchase_Points() && g_theTransitionHandler != nullptr + && g_theInGameUI->Get_Input_Enabled()) { + g_theTransitionHandler->Set_Group("ControlBarArrow", false); + } + + m_starHilight = true; + Mark_UI_Dirty(); + } +} + +void ControlBar::Hide_Communicator(bool hide) +{ + if (m_popupCommunicator != nullptr) { + m_popupCommunicator->Win_Hide(hide); + } +} + +void ControlBar::Parse_Command_Button_Definition(INI *ini) +{ + Utf8String name; + name.Set(ini->Get_Next_Token()); + CommandButton *button = g_theControlBar->Find_Non_Const_Command_Button(name); + + if (button != nullptr) { + captainslog_relassert(ini->Get_Load_Type() == INI_LOAD_CREATE_OVERRIDES, + CODE_06, + "[LINE: %d - FILE: '%s'] Duplicate commandbutton '%s' found!", + ini->Get_Line_Number(), + ini->Get_Filename().Str(), + name.Str()); + button = g_theControlBar->New_Command_Button_Override(button); + } else { + button = g_theControlBar->New_Command_Button(name); + + if (ini->Get_Load_Type() == INI_LOAD_CREATE_OVERRIDES) { + button->Set_Is_Allocated(); + } + } + + ini->Init_From_INI(button, CommandButton::Get_Field_Parse()); + const SpecialPowerTemplate *power = button->Get_Special_Power(); + bool needs_power = (button->Get_Options() & COMMAND_OPTION_NEED_SPECIAL_POWER_SCIENCE) != 0; + + if (power == nullptr || needs_power) { + captainslog_dbgassert(power != nullptr || !needs_power, + "[LINE: %d in '%s'] CommandButton %s has Options = NEED_SPECIAL_POWER_SCIENCE but doesn't specify a " + "SpecialPower = xxxx. Please evaluate INI.", + ini->Get_Line_Number(), + ini->Get_Filename().Str(), + name.Str()); + } else { + captainslog_dbgassert(false, + "[LINE: %d in '%s'] CommandButton %s has SpecialPower = %s but the button also requires Options = " + "NEED_SPECIAL_POWER_SCIENCE. Failure to do so will cause bugs such as invisible side shortcut buttons", + ini->Get_Line_Number(), + ini->Get_Filename().Str(), + name.Str(), + power->Get_Name().Str()); + } +} + +void ControlBar::Parse_Command_Set_Definition(INI *ini) +{ + Utf8String name; + name.Set(ini->Get_Next_Token()); + CommandSet *commandset = g_theControlBar->Find_Non_Const_Command_Set(name); + + if (commandset != nullptr) { + captainslog_relassert(ini->Get_Load_Type() == INI_LOAD_CREATE_OVERRIDES, + CODE_06, + "[LINE: %d - FILE: '%s'] Duplicate commandset '%s' found!", + ini->Get_Line_Number(), + ini->Get_Filename().Str(), + name.Str()); + commandset = g_theControlBar->New_Command_Set_Override(commandset); + } else { + commandset = g_theControlBar->New_Command_Set(name); + + if (ini->Get_Load_Type() == INI_LOAD_CREATE_OVERRIDES) { + commandset->Set_Is_Allocated(); + } + } + + captainslog_dbgassert(commandset != nullptr, "Parse_Command_Set_Definition: Unable to allocate set '%s'", name.Str()); + ini->Init_From_INI(commandset, CommandSet::Get_Field_Parse()); +} + +CommandButton *ControlBar::Find_Non_Const_Command_Button(const Utf8String &name) +{ + for (CommandButton *button = m_commandButtons; button != nullptr; button = button->Get_Next()) { + if (button->Get_Name() == name) { + return static_cast(button->Friend_Get_Final_Override()); + } + } + + return nullptr; +} + +CommandSet *ControlBar::Find_Non_Const_Command_Set(const Utf8String &name) +{ + for (CommandSet *set = m_commandSets; set != nullptr; set = set->Get_Next_Command_Set()) { + if (set->Get_Name() == name) { + return set; + } + } + + return nullptr; +} + +const CommandSet *ControlBar::Find_Command_Set(const Utf8String &name) +{ + CommandSet *set = Find_Non_Const_Command_Set(name); + + if (set != nullptr) { + return static_cast(set->Friend_Get_Final_Override()); + } + + return nullptr; +} + +const CommandButton *ControlBar::Find_Command_Button(const Utf8String &name) +{ + CommandButton *button = Find_Non_Const_Command_Button(name); + + if (button != nullptr) { + return static_cast(button->Friend_Get_Final_Override()); + } + + return nullptr; +} + +CommandButton *ControlBar::New_Command_Button(const Utf8String &name) +{ + CommandButton *new_button = new CommandButton(); + new_button->Set_Name(name); + new_button->Friend_Add_To_List(&m_commandButtons); + return new_button; +} + +CommandButton *ControlBar::New_Command_Button_Override(CommandButton *button) +{ + if (button == nullptr) { + return nullptr; + } + + CommandButton *new_button = new CommandButton(); + *new_button = *button; + new_button->Set_Is_Allocated(); + button->Set_Next(new_button); + return new_button; +} + +CommandSet *ControlBar::New_Command_Set(const Utf8String &name) +{ + CommandSet *new_set = new CommandSet(name); + new_set->Friend_Add_To_List(&m_commandSets); + return new_set; +} + +CommandSet *ControlBar::New_Command_Set_Override(CommandSet *set) +{ + if (set == nullptr) { + return nullptr; + } + + CommandSet *new_set = new CommandSet(set->Get_Name()); + *new_set = *set; + new_set->Set_Is_Allocated(); + set->Set_Next(new_set); + return new_set; +} + void ControlBar::Set_Control_Bar_Scheme_By_Player(Player *p) { #ifdef GAME_DLL @@ -456,50 +1573,37 @@ void ControlBar::Set_Control_Bar_Scheme_By_Player_Template(PlayerTemplate *tmpla #endif } -// On_Player_Rank_Changed and On_Player_Science_Purchase_Points_Changed have identical addresses in game exe (because the -// code is identical) -void ControlBar::On_Player_Rank_Changed(const Player *player) +void ControlBar::Init_Special_Power_Shortcut_Bar(Player *player) { #ifdef GAME_DLL - Call_Method(PICK_ADDRESS(0x0045EB90, 0x001055D6), this, player); + Call_Method(PICK_ADDRESS(0x00461680, 0x0073027A), this, player); #endif } -void ControlBar::On_Player_Science_Purchase_Points_Changed(const Player *player) +void ControlBar::Switch_To_Context(ControlBarContext context, Drawable *draw) { #ifdef GAME_DLL - Call_Method(PICK_ADDRESS(0x0045EB90, 0x001056F2), this, player); + Call_Method(PICK_ADDRESS(0x0045F8C0, 0x0072E3D0), this, context, draw); #endif } -const CommandSet *ControlBar::Find_Command_Set(const Utf8String &name) +void ControlBar::Evaluate_Context_UI() { #ifdef GAME_DLL - return Call_Method(PICK_ADDRESS(0x0045F770, 0x0072E236), this, name); -#else - return nullptr; -#endif -} -const CommandButton *ControlBar::Find_Command_Button(const Utf8String &name) -{ -#ifdef GAME_DLL - return Call_Method( - PICK_ADDRESS(0x0045F6D0, 0x0072E204), this, name); -#else - return nullptr; + Call_Method(PICK_ADDRESS(0x0045EC00, 0x0072D9A7), this); #endif } -void ControlBar::Hide_Communicator(bool hide) +void ControlBar::Update_Special_Power_Shortcut() { #ifdef GAME_DLL - Call_Method(PICK_ADDRESS(0x00460AB0, 0x0072FA8D), this, hide); + Call_Method(PICK_ADDRESS(0x00462230, 0x00731139), this); #endif } -void ControlBar::Init_Special_Power_Shortcut_Bar(Player *player) +void ControlBar::Populate_Special_Power_Shortcut(Player *player) { #ifdef GAME_DLL - Call_Method(PICK_ADDRESS(0x00461680, 0x0073027A), this, player); + Call_Method(PICK_ADDRESS(0x00461B10, 0x0073067E), this, player); #endif } diff --git a/src/game/client/gui/controlbar/controlbar.h b/src/game/client/gui/controlbar/controlbar.h index 249bd1056..2e03d51ce 100644 --- a/src/game/client/gui/controlbar/controlbar.h +++ b/src/game/client/gui/controlbar/controlbar.h @@ -16,6 +16,7 @@ #include "always.h" #include "asciistring.h" #include "audioeventrts.h" +#include "behaviormodule.h" #include "gamewindow.h" #include "ingameui.h" @@ -28,12 +29,14 @@ class ControlBarSchemeManager; enum ControlBarContext { CB_CONTEXT_NONE, - CB_CONTEXT_SIDE_SELECT, CB_CONTEXT_COMMAND, CB_CONTEXT_STRUCTURE_INVENTORY, CB_CONTEXT_BEACON, CB_CONTEXT_UNDER_CONSTRUCTION, CB_CONTEXT_MULTI_SELECT, + CB_CONTEXT_UNK, + CB_CONTEXT_OBSERVER, + CB_CONTEXT_OCL_TIMER, NUM_CB_CONTEXTS, }; @@ -192,7 +195,7 @@ class CommandButton : public Overridable const AudioEventRTS *Get_Unit_Specific_Sound() const { return &m_unitSpecificSound; } void Set_Cameo_Flash_Time(int time) { m_cameoFlashTime = time; } - void Set_Name(Utf8String &name) { m_name = name; } + void Set_Name(const Utf8String &name) { m_name = name; } void Set_Button_Image(Image *image) { m_buttonImage = image; } bool Is_Valid_Object_Target(const Player *player, const Object *obj) const; @@ -205,7 +208,7 @@ class CommandButton : public Overridable void Copy_Images_From(const CommandButton *button, bool set_dirty); void Copy_Button_Text_From(const CommandButton *button, bool conflicting_label, bool set_dirty); void Cache_Button_Image(); - void Set_Next(CommandButton **next); + void Friend_Add_To_List(CommandButton **next); static FieldParse *Get_Field_Parse() { return s_commandButtonFieldParseTable; } static void Parse_Command(INI *ini, void *formal, void *store, const void *user_data); @@ -242,9 +245,13 @@ class ControlBar : public SubsystemInterface public: struct QueueEntry { - int control; - int type; - int production_id; + GameWindow *control; + ProductionEntry::ProductionType type; + union + { + ProductionID production_id; + UpgradeTemplate *upgrade_template; + }; }; struct ContainEntry @@ -253,6 +260,17 @@ class ControlBar : public SubsystemInterface ObjectID id; }; + enum + { + SPECIAL_POWER_SHORTCUT_BUTTON_COUNT = 11, + CONTEXT_PARENT_COUNT = 9, + UNIT_UPGRADE_WINDOW_COUNT = 5, + RANK_1_BUTTON_COUNT = 4, + RANK_3_BUTTON_COUNT = 15, + RANK_8_BUTTON_COUNT = 4, + QUEUE_ENTRY_COUNT = 9, + }; + ControlBar(); virtual ~ControlBar(); virtual void Init() override; @@ -263,7 +281,7 @@ class ControlBar : public SubsystemInterface const CommandButton *Get_Command_Buttons() const { return m_commandButtons; } const ControlBarSchemeManager *Get_Control_Bar_Scheme_Manager() const { return m_controlBarSchemeManager; } const Image *Get_Gen_Arrow_Image() const { return m_genArrowImage; } - const Player *Get_Observer_Player() const { return m_observerPlayer; } + Player *Get_Observer_Player() const { return m_observerPlayer; } bool Is_Observer() const { return m_isObserver; } void Set_Cameo_Flash(bool flash) { m_cameoFlash = flash; } void Set_Gen_Arrow_Image(const Image *image) { m_genArrowImage = image; } @@ -296,7 +314,7 @@ class ControlBar : public SubsystemInterface void Populate_Beacon(Object *beacon); void Populate_Build_Queue(Object *producer); - void Populate_Build_Tooltip_Layout(const CommandButton *, GameWindow *); + void Populate_Build_Tooltip_Layout(const CommandButton *button, GameWindow *window); void Populate_Command(Object *obj); void Populate_Multi_Select(); void Populate_OCL_Timer(Object *obj); @@ -320,7 +338,8 @@ class ControlBar : public SubsystemInterface void Set_Control_Bar_Scheme_By_Name(const Utf8String &name); void Set_Control_Bar_Scheme_By_Player(Player *p); void Set_Control_Bar_Scheme_By_Player_Template(PlayerTemplate *tmplate); - void Set_Control_Command(const Utf8String &button_window_name, GameWindow *parent, const CommandButton *command_button); + // void Set_Control_Command(const Utf8String &button_window_name, GameWindow *parent, const CommandButton + // *command_button); //unused, not implemented void Set_Control_Command(GameWindow *button, const CommandButton *command_button); void Set_Default_Control_Bar_Config(); void Set_Hidden_Control_Bar(); @@ -360,7 +379,7 @@ class ControlBar : public SubsystemInterface const Image *toggle_button_down_on_image, const Image *toggle_button_down_pushed_image, const Image *general_button_enable_image, - const Image *general_button_hightlited_image); + const Image *general_button_hilited_image); void Add_Common_Commands(Drawable *draw, bool first_drawable); void Animate_Special_Power_Shortcut(bool forward); @@ -374,7 +393,7 @@ class ControlBar : public SubsystemInterface CommandButton *New_Command_Button(const Utf8String &name); CommandButton *New_Command_Button_Override(CommandButton *button); CommandSet *New_Command_Set(const Utf8String &name); - CommandSet *New_Command_Set_Override(CommandSet *button); + CommandSet *New_Command_Set_Override(CommandSet *set); void Post_Process_Commands(); void Preload_Assets(TimeOfDayType time_of_day); void Repopulate_Build_Tooltip_Layout(); @@ -391,6 +410,10 @@ class ControlBar : public SubsystemInterface static const Image *Calculate_Veterancy_Overlay_For_Thing(const ThingTemplate *thing); static void Populate_Button_Proc(Object *obj, void *user_data); +#ifdef GAME_DLL + ControlBar *Hook_Ctor() { return new (this) ControlBar; } +#endif + private: WindowVideoManager *m_videoManager; AnimateWindowManager *m_controlBarAnimateWindowManager; @@ -403,7 +426,7 @@ class ControlBar : public SubsystemInterface CommandButton *m_commandButtons; CommandSet *m_commandSets; ControlBarSchemeManager *m_controlBarSchemeManager; - GameWindow *m_contextParent[9]; + GameWindow *m_contextParent[CONTEXT_PARENT_COUNT]; Drawable *m_currentSelectedDrawable; ControlBarContext m_currContext; Drawable *m_rallyPointDrawable; @@ -413,22 +436,22 @@ class ControlBar : public SubsystemInterface unsigned int m_lastRecordedInventoryCount; GameWindow *m_rightHUDWindow; GameWindow *m_rightHUDCameoWindow; - GameWindow *m_unitUpgradeWindows[5]; + GameWindow *m_unitUpgradeWindows[UNIT_UPGRADE_WINDOW_COUNT]; GameWindow *m_unitSelectedWindow; GameWindow *m_popupCommunicator; WindowLayout *m_generalsPointsLayout; - GameWindow *m_rank1Buttons[4]; - void *m_rank3Buttons[15]; - GameWindow *m_rank8Buttons[4]; - GameWindow *m_specialPowerShortcutButtons[11]; - GameWindow *m_specialPowerShortcutButtonParents[11]; - int m_specialPowerShortcutButtonUnk[11]; + GameWindow *m_rank1Buttons[RANK_1_BUTTON_COUNT]; + GameWindow *m_rank3Buttons[RANK_3_BUTTON_COUNT]; + GameWindow *m_rank8Buttons[RANK_8_BUTTON_COUNT]; + GameWindow *m_specialPowerShortcutButtons[SPECIAL_POWER_SHORTCUT_BUTTON_COUNT]; + GameWindow *m_specialPowerShortcutButtonParents[SPECIAL_POWER_SHORTCUT_BUTTON_COUNT]; + int m_specialPowerShortcutButtonUnk[SPECIAL_POWER_SHORTCUT_BUTTON_COUNT]; int m_specialPowerShortcutButtonCount; WindowLayout *m_specialPowerShortcutBarLayout; GameWindow *m_specialPowerShortcutBarParent; GameWindow *m_commandWindows[CommandSet::MAX_COMMAND_BUTTONS]; CommandButton *m_commonCommands[CommandSet::MAX_COMMAND_BUTTONS]; - QueueEntry m_queueData[9]; + QueueEntry m_queueData[QUEUE_ENTRY_COUNT]; bool m_cameoFlash; bool m_unk1; int m_unk2; @@ -462,7 +485,7 @@ class ControlBar : public SubsystemInterface int m_unk11; const Image *m_genArrowImage; const Image *m_generalButtonEnableImage; - const Image *m_generalButtonHightlitedImage; + const Image *m_generalButtonHilitedImage; bool m_starHilight; int m_sciencePurchasePoints; int m_foregroundMarkerPosX; @@ -472,8 +495,10 @@ class ControlBar : public SubsystemInterface bool m_triggerRadarAttackGlow; int m_radarAttackGlowCounter; GameWindow *m_radarAttackGlowWindow; +#ifdef GAME_DEBUG_STRUCTS unsigned int m_uiDirtyFrame; int m_uiDirtyCounter; +#endif static ContainEntry s_containData[CommandSet::MAX_COMMAND_BUTTONS]; static const Image *s_rankEliteIcon; @@ -481,6 +506,10 @@ class ControlBar : public SubsystemInterface static const Image *s_rankVeteranIcon; }; +void Control_Bar_Popup_Description_Update_Func(WindowLayout *layout, void *user_data); +void Hide_Control_Bar(bool hide); +void Show_Control_Bar(bool hide); + #ifdef GAME_DLL extern ControlBar *&g_theControlBar; #else diff --git a/src/game/client/gui/controlbar/controlbarbeacon.cpp b/src/game/client/gui/controlbar/controlbarbeacon.cpp index 39984ad88..454a0d260 100644 --- a/src/game/client/gui/controlbar/controlbarbeacon.cpp +++ b/src/game/client/gui/controlbar/controlbarbeacon.cpp @@ -13,3 +13,5 @@ * LICENSE */ #include "controlbar.h" + +void ControlBar::Update_Context_Beacon() {} diff --git a/src/game/client/gui/controlbar/controlbarcommand.cpp b/src/game/client/gui/controlbar/controlbarcommand.cpp index 39984ad88..3bc5c644b 100644 --- a/src/game/client/gui/controlbar/controlbarcommand.cpp +++ b/src/game/client/gui/controlbar/controlbarcommand.cpp @@ -13,3 +13,121 @@ * LICENSE */ #include "controlbar.h" +#include "gadgetpushbutton.h" +#include "playerlist.h" +#include "veterancygaincreate.h" + +struct PopulateInvButtonData +{ + int curr_index; + int max_index; + GameWindow **controls; + Object *transport; +}; + +void ControlBar::Reset_Contain_Data() +{ + for (int i = 0; i < CommandSet::MAX_COMMAND_BUTTONS; ++i) { + s_containData[i].button = nullptr; + s_containData[i].id = INVALID_OBJECT_ID; + } +} + +void ControlBar::Reset_Build_Queue_Data() +{ + for (int i = 0; i < QUEUE_ENTRY_COUNT; i++) { + m_queueData[i].control = nullptr; + m_queueData[i].type = ProductionEntry::PRODUCTION_INVALID; + m_queueData[i].production_id = INVALID_PRODUCTION_ID; + } +} + +void ControlBar::Populate_Inv_Data_Callback(Object *obj, void *user_data) +{ + PopulateInvButtonData *data = static_cast(user_data); + + if (data->curr_index <= data->max_index) { + GameWindow *control = data->controls[data->curr_index]; + captainslog_dbgassert(control, "Populate_Inv_Data_Callback: Control not found"); + s_containData[data->curr_index].button = control; + s_containData[data->curr_index].id = obj->Get_ID(); + data->curr_index++; + Gadget_Button_Set_Enabled_Image(control, obj->Get_Template()->Get_Button_Image()); + Gadget_Button_Draw_Overlay_Image(control, Calculate_Veterancy_Overlay_For_Object(obj)); + control->Win_Enable(true); + } else { + captainslog_dbgassert(false, + "There is not enough GUI slots to hold the # of items inside a '%s'", + data->transport->Get_Template()->Get_Name().Str()); + } +} + +const Image *ControlBar::Calculate_Veterancy_Overlay_For_Object(const Object *object) +{ + if (object == nullptr) { + return nullptr; + } + + switch (object->Get_Veterancy_Level()) { + case VETERANCY_VETERAN: + return s_rankVeteranIcon; + case VETERANCY_ELITE: + return s_rankEliteIcon; + case VETERANCY_HEROIC: + return s_rankHeroicIcon; + } + + return nullptr; +} + +const Image *ControlBar::Calculate_Veterancy_Overlay_For_Thing(const ThingTemplate *thing) +{ + VeterancyLevel level = VETERANCY_REGULAR; + + if (thing == nullptr) { + return nullptr; + } + + Player *player = g_thePlayerList->Get_Local_Player(); + + if (player == nullptr) { + return nullptr; + } + + const VeterancyGainCreateModuleData *data = nullptr; + Utf8String str; + const ModuleInfo *modules = thing->Get_Body_Modules(); + + for (unsigned int i = 0; i < modules->Get_Count(); i++) { + str = modules->Get_Nth_Name(i); + + if (str == "VeterancyGainCreate") { + data = static_cast(modules->Get_Nth_Data(i)); + + if (data != nullptr) { + if (data->m_scienceRequired == SCIENCE_INVALID + || (player->Has_Science(data->m_scienceRequired) && data->m_startingLevel > level)) { + level = data->m_startingLevel; + } + } + } + } + + switch (level) { + case VETERANCY_VETERAN: + return s_rankVeteranIcon; + case VETERANCY_ELITE: + return s_rankEliteIcon; + case VETERANCY_HEROIC: + return s_rankHeroicIcon; + default: + return nullptr; + } +} + +void ControlBar::Update_Context_Command() +{ +#ifdef GAME_DLL + Call_Method(PICK_ADDRESS(0x005A3B20, 0x008E3643), this); +#endif +} diff --git a/src/game/client/gui/controlbar/controlbarcommandprocessing.cpp b/src/game/client/gui/controlbar/controlbarcommandprocessing.cpp index 39984ad88..59a9f9576 100644 --- a/src/game/client/gui/controlbar/controlbarcommandprocessing.cpp +++ b/src/game/client/gui/controlbar/controlbarcommandprocessing.cpp @@ -12,4 +12,531 @@ * A full copy of the GNU General Public License can be found in * LICENSE */ +#include "audioeventrts.h" +#include "audiomanager.h" +#include "behaviormodule.h" +#include "buildassistant.h" +#include "commandxlat.h" #include "controlbar.h" +#include "drawable.h" +#include "eva.h" +#include "gadgetpushbutton.h" +#include "messagestream.h" +#include "object.h" +#include "player.h" +#include "playerlist.h" +#include "specialpower.h" +#include "upgrade.h" + +struct SelectObjectStruct +{ + const ThingTemplate *thing; + GameMessage *message; +}; + +void Select_Object_Of_Type(Object *obj, void *user_data) +{ + SelectObjectStruct *data = static_cast(user_data); + + if (obj != nullptr) { + if (data != nullptr) { + if (obj->Get_Template()->Is_Equivalent_To(data->thing)) { + data->message->Append_ObjectID_Arg(obj->Get_ID()); + Drawable *drawable = obj->Get_Drawable(); + + if (drawable != nullptr) { + g_theInGameUI->Select_Drawable(drawable); + } + } + } + } +} + +CBCommandStatus ControlBar::Process_Command_UI(GameWindow *control, GadgetGameMessage gadget_message) +{ + CommandButton *button = static_cast(Gadget_Button_Get_Data(control)); + + if (button != nullptr) { + if (m_currContext == CB_CONTEXT_MULTI_SELECT || button->Get_Command() == GUI_COMMAND_PURCHASE_SCIENCE + || button->Get_Command() == GUI_COMMAND_SPECIAL_POWER_FROM_SHORTCUT + || button->Get_Command() == GUI_COMMAND_SPECIAL_POWER_CONSTRUCT_FROM_SHORTCUT + || button->Get_Command() == GUI_COMMAND_SELECT_ALL_UNITS_OF_TYPE + || (m_currentSelectedDrawable != nullptr && m_currentSelectedDrawable->Get_Object() != nullptr)) { + + if (control != nullptr) { + if (control->Win_Get_Input_Func() == Gadget_Push_Button_Input) { + button->Set_Cameo_Flash_Time(0); + g_theControlBar->Set_Cameo_Flash(false); + + if (button->Get_Command() != GUI_COMMAND_EXIT_CONTAINER) { + Gadget_Button_Set_Enabled_Image(control, button->Get_Button_Image()); + } + + Object *obj = nullptr; + + if (m_currContext != CB_CONTEXT_MULTI_SELECT && button->Get_Command() != GUI_COMMAND_PURCHASE_SCIENCE + && button->Get_Command() != GUI_COMMAND_SPECIAL_POWER_FROM_SHORTCUT + && button->Get_Command() != GUI_COMMAND_SPECIAL_POWER_CONSTRUCT_FROM_SHORTCUT + && button->Get_Command() != GUI_COMMAND_SELECT_ALL_UNITS_OF_TYPE) { + obj = m_currentSelectedDrawable->Get_Object(); + } + + if (obj != nullptr && (button->Get_Options() & COMMAND_OPTION_SINGLE_USE_COMMAND) != 0) { + obj->Set_Single_Use_Command(); + } + + g_theInGameUI->Place_Build_Available(nullptr, nullptr); + + Player *player = g_thePlayerList->Get_Local_Player(); + + if (player != nullptr) { + AudioEventRTS sound(*button->Get_Unit_Specific_Sound()); + sound.Set_Player_Index(player->Get_Player_Index()); + g_theAudio->Add_Audio_Event(&sound); + } + + if ((button->Get_Options() + & (COMMAND_OPTION_CONTEXTMODE_COMMAND | COMMAND_OPTION_NEED_TARGET_POS + | COMMAND_OPTION_NEED_TARGET_OBJECT)) + != 0) { + if ((button->Get_Options() & COMMAND_OPTION_USES_MINE_CLEARING_WEAPONSET) != 0) { + g_theMessageStream->Append_Message(GameMessage::MSG_SET_MINE_CLEARING_DETAIL); + } + + g_theInGameUI->Set_GUI_Command(button); + return CBC_COMMAND_USED; + } else { + switch (button->Get_Command()) { + case GUI_COMMAND_DOZER_CONSTRUCT: + if (m_currentSelectedDrawable != nullptr) { + switch (g_theBuildAssistant->Can_Make_Unit(obj, *button->Get_Template())) { + case CAN_MAKE_NOT_ENOUGH_MONEY: + g_theEva->Set_Should_Play(EVA_MESSAGE_INSUFFICIENTFUNDS); + g_theInGameUI->Message("GUI:NotEnoughMoneyToBuild"); + break; + case CAN_MAKE_QUEUE_FULL: + g_theInGameUI->Message("GUI:ProductionQueueFull"); + break; + case CAN_MAKE_PARKING_FULL: + g_theInGameUI->Message("GUI:ParkingPlacesFull"); + break; + case CAN_MAKE_MAXIMUM_NUMBER: + g_theInGameUI->Message("GUI:UnitMaxedOut"); + break; + default: + g_theInGameUI->Place_Build_Available( + *button->Get_Template(), m_currentSelectedDrawable); + break; + } + } + + return CBC_COMMAND_USED; + case GUI_COMMAND_DOZER_CONSTRUCT_CANCEL: + if (obj != nullptr) { + if (obj->Get_Controlling_Player() == g_thePlayerList->Get_Local_Player()) { + g_theMessageStream->Append_Message(GameMessage::MSG_DOZER_CANCEL_CONSTRUCT); + } + } + + return CBC_COMMAND_USED; + case GUI_COMMAND_UNIT_BUILD: { + const ThingTemplate *thing = *button->Get_Template(); + + if (obj != nullptr) { + captainslog_dbgassert(thing != nullptr, + "Undefined BUILD command for object '%s'", + button->Get_Template()->Get_Name().Str()); + CanMakeType type = g_theBuildAssistant->Can_Make_Unit(obj, thing); + + switch (type) { + case CAN_MAKE_NOT_ENOUGH_MONEY: + g_theEva->Set_Should_Play(EVA_MESSAGE_INSUFFICIENTFUNDS); + g_theInGameUI->Message("GUI:NotEnoughMoneyToBuild"); + break; + case CAN_MAKE_QUEUE_FULL: + g_theInGameUI->Message("GUI:ProductionQueueFull"); + break; + case CAN_MAKE_PARKING_FULL: + g_theInGameUI->Message("GUI:ParkingPlacesFull"); + break; + case CAN_MAKE_MAXIMUM_NUMBER: + g_theInGameUI->Message("GUI:UnitMaxedOut"); + break; + default: + if (type == CAN_MAKE_SUCCESS) { + ProductionUpdateInterface *production = + obj->Get_Production_Update_Interface(); + + if (production != nullptr) { + ProductionID id = production->Request_Unique_Unit_ID(); + GameMessage *message = g_theMessageStream->Append_Message( + GameMessage::MSG_QUEUE_UNIT_CREATE); + message->Append_Int_Arg(thing->Get_Template_ID()); + message->Append_Int_Arg(id); + } else { + captainslog_dbgassert(false, + "Cannot create '%s' because the factory object '%s' is not capable " + "of producting units", + thing->Get_Name().Str(), + obj->Get_Template()->Get_Name().Str()); + } + } else { + captainslog_dbgassert(false, + "Cannot create '%s' because the factory object '%s' returns false for " + "Can_Make_Unit", + thing->Get_Name().Str(), + obj->Get_Template()->Get_Name().Str()); + } + + break; + } + } + + return CBC_COMMAND_USED; + } + case GUI_COMMAND_CANCEL_UNIT_BUILD: { + int i; + + for (i = 0; i < QUEUE_ENTRY_COUNT && m_queueData[i].control != control; i++) { + } + + if (i == 9) { + captainslog_dbgassert(false, "Control not found in build queue data"); + } else if (m_queueData[i].type == ProductionEntry::PRODUCTION_UNIT) { + if (obj != nullptr) { + if (obj->Get_Controlling_Player() == g_thePlayerList->Get_Local_Player()) { + GameMessage *message = + g_theMessageStream->Append_Message(GameMessage::MSG_CANCEL_UNIT_CREATE); + message->Append_Int_Arg(m_queueData[i].production_id); + } + } + } + + return CBC_COMMAND_USED; + } + case GUI_COMMAND_PLAYER_UPGRADE: { + const UpgradeTemplate *upgrade = button->Get_Upgrade_Template(); + captainslog_dbgassert( + upgrade != nullptr, "Undefined upgrade '%s' in player upgrade command", "UNKNOWN"); + + if (obj != nullptr) { + if (upgrade != nullptr) { + if (g_theUpgradeCenter->Can_Afford_Upgrade( + g_thePlayerList->Get_Local_Player(), upgrade, true)) { + ProductionUpdateInterface *production; + + if (obj != nullptr) { + production = obj->Get_Production_Update_Interface(); + } else { + production = nullptr; + } + + if (production != nullptr + && production->Can_Queue_Upgrade(upgrade) == CAN_MAKE_QUEUE_FULL) { + g_theInGameUI->Message("GUI:ProductionQueueFull"); + } else { + GameMessage *message = + g_theMessageStream->Append_Message(GameMessage::MSG_QUEUE_UPGRADE); + message->Append_ObjectID_Arg(obj->Get_ID()); + message->Append_Int_Arg(upgrade->Get_Name_Key()); + } + } + } + } + + return CBC_COMMAND_USED; + } + case GUI_COMMAND_OBJECT_UPGRADE: { + const UpgradeTemplate *upgrade = button->Get_Upgrade_Template(); + captainslog_dbgassert( + upgrade != nullptr, "Undefined upgrade '%s' in player upgrade command", "UNKNOWN"); + + if (upgrade != nullptr) { + if (g_theUpgradeCenter->Can_Afford_Upgrade( + g_thePlayerList->Get_Local_Player(), upgrade, true)) { + ProductionUpdateInterface *production; + + if (obj != nullptr) { + production = obj->Get_Production_Update_Interface(); + } else { + production = nullptr; + } + + if (production != nullptr + && production->Can_Queue_Upgrade(upgrade) == CAN_MAKE_QUEUE_FULL) { + g_theInGameUI->Message("GUI:ProductionQueueFull"); + } else { + ObjectID obj_id = INVALID_OBJECT_ID; + + if (obj != nullptr) { + obj_id = obj->Get_ID(); + } + + if (obj == nullptr + || (!obj->Has_Upgrade(upgrade) && obj->Affected_By_Upgrade(upgrade))) { + GameMessage *message = + g_theMessageStream->Append_Message(GameMessage::MSG_QUEUE_UPGRADE); + message->Append_ObjectID_Arg(obj_id); + message->Append_Int_Arg(upgrade->Get_Name_Key()); + } + } + } + } + + return CBC_COMMAND_USED; + } + case GUI_COMMAND_CANCEL_UPGRADE: { + int i; + + for (i = 0; i < QUEUE_ENTRY_COUNT && m_queueData[i].control != control; i++) { + } + + if (i == 9) { + captainslog_dbgassert(false, "Control not found in build queue data"); + } else if (m_queueData[i].type == ProductionEntry::PRODUCTION_UPGRADE) { + UpgradeTemplate *upgrade = m_queueData[i].upgrade_template; + + if (upgrade != nullptr) { + if (obj != nullptr) { + GameMessage *message = + g_theMessageStream->Append_Message(GameMessage::MSG_CANCEL_UPGRADE); + message->Append_Int_Arg(upgrade->Get_Name_Key()); + } + } + } + + return CBC_COMMAND_USED; + } + case GUI_COMMAND_ATTACK_MOVE: + g_theMessageStream->Append_Message(GameMessage::MSG_META_TOGGLE_ATTACKMOVE); + return CBC_COMMAND_USED; + case GUI_COMMAND_GUARD: + case GUI_COMMAND_GUARD_WITHOUT_PURSUIT: + case GUI_COMMAND_GUARD_FLYING_UNITS_ONLY: + case GUI_COMMAND_COMBATDROP: + captainslog_dbgassert(false, "hmm, should never occur"); + return CBC_COMMAND_USED; + case GUI_COMMAND_STOP: + g_theMessageStream->Append_Message(GameMessage::MSG_DO_STOP); + return CBC_COMMAND_USED; + case GUI_COMMAND_WAYPOINTS: + case GUI_COMMAND_BEACON_DELETE: + case GUI_COMMAND_SET_RALLY_POINT: + return CBC_COMMAND_USED; + case GUI_COMMAND_EXIT_CONTAINER: { + ObjectID obj_id; + int i; + + for (i = 0; i < CommandSet::MAX_COMMAND_BUTTONS; i++) { + if (s_containData[i].button == control) { + obj_id = s_containData[i].id; + } + } + + Object *object = g_theGameLogic->Find_Object_By_ID(obj_id); + + if (object != nullptr) { + GameMessage *message = g_theMessageStream->Append_Message(GameMessage::MSG_EXIT); + message->Append_ObjectID_Arg(object->Get_ID()); + } else { + s_containData[i].button = nullptr; + s_containData[i].id = INVALID_OBJECT_ID; + } + return CBC_COMMAND_USED; + } + case GUI_COMMAND_EVACUATE: + g_theInGameUI->Set_GUI_Command(nullptr); + if ((button->Get_Options() & COMMAND_OPTION_NEED_TARGET_POS) == 0) { + Pick_And_Play_Unit_Voice_Response( + g_theInGameUI->Get_All_Selected_Drawables(), GameMessage::MSG_EVACUATE, nullptr); + g_theMessageStream->Append_Message(GameMessage::MSG_EVACUATE); + } + return CBC_COMMAND_USED; + case GUI_COMMAND_EXECUTE_RAILED_TRANSPORT: + g_theMessageStream->Append_Message(GameMessage::MSG_EXECUTE_RAILED_TRANSPORT); + return CBC_COMMAND_USED; + case GUI_COMMAND_SELL: + g_theMessageStream->Append_Message(GameMessage::MSG_SELL); + return CBC_COMMAND_USED; + case GUI_COMMAND_FIRE_WEAPON: { + GameMessage *message = g_theMessageStream->Append_Message(GameMessage::MSG_DO_WEAPON); + message->Append_Int_Arg(button->Get_Weapon_Slot()); + message->Append_Int_Arg(button->Get_Max_Shots_To_Fire()); + return CBC_COMMAND_USED; + } + case GUI_COMMAND_SPECIAL_POWER: { + GameMessage *message = g_theMessageStream->Append_Message(GameMessage::MSG_DO_SPECIAL_POWER); + message->Append_Int_Arg(button->Get_Special_Power()->Get_ID()); + message->Append_Int_Arg(button->Get_Options()); + message->Append_ObjectID_Arg(INVALID_OBJECT_ID); + return CBC_COMMAND_USED; + } + case GUI_COMMAND_PURCHASE_SCIENCE: { + ScienceType science = SCIENCE_INVALID; + Player *local_player = g_thePlayerList->Get_Local_Player(); + + for (unsigned int i = 0; i < button->Get_Sciences()->size(); i++) { + science = (*button->Get_Sciences())[i]; + + if (!local_player->Has_Science(science)) { + if (g_theScienceStore->Player_Has_Prereqs_For_Science(local_player, science)) { + if (g_theScienceStore->Get_Science_Purchase_Cost(science) + <= local_player->Get_Science_Purchase_Points()) { + break; + } + } + } + } + + if (science == SCIENCE_INVALID) { + Switch_To_Context(CB_CONTEXT_NONE, nullptr); + } else { + GameMessage *message = + g_theMessageStream->Append_Message(GameMessage::MSG_PURCHASE_SCIENCE); + message->Append_Int_Arg(science); + Mark_UI_Dirty(); + } + + return CBC_COMMAND_USED; + } + case GUI_COMMAND_HACK_INTERNET: + Pick_And_Play_Unit_Voice_Response( + g_theInGameUI->Get_All_Selected_Drawables(), GameMessage::MSG_INTERNET_HACK, nullptr); + g_theMessageStream->Append_Message(GameMessage::MSG_INTERNET_HACK); + return CBC_COMMAND_USED; + case GUI_COMMAND_TOGGLE_OVERCHARGE: + g_theMessageStream->Append_Message(GameMessage::MSG_TOGGLE_OVERCHARGE); + return CBC_COMMAND_USED; + case GUI_COMMAND_SWITCH_WEAPON: { + GameMessage *message = g_theMessageStream->Append_Message(GameMessage::MSG_SWITCH_WEAPONS); + PickAndPlayInfo info; + WeaponSlotType type = button->Get_Weapon_Slot(); + info.weapon_slot_type = &type; + Pick_And_Play_Unit_Voice_Response( + g_theInGameUI->Get_All_Selected_Drawables(), GameMessage::MSG_SWITCH_WEAPONS, &info); + message->Append_Int_Arg(button->Get_Weapon_Slot()); + return CBC_COMMAND_USED; + } + case GUI_COMMAND_SPECIAL_POWER_FROM_SHORTCUT: { + const SpecialPowerTemplate *power = button->Get_Special_Power(); + Object *object = + g_thePlayerList->Get_Local_Player()->Find_Most_Ready_Shortcut_Special_Power_Of_Type( + power->Get_Type()); + + if (object != nullptr) { + GameMessage *message = + g_theMessageStream->Append_Message(GameMessage::MSG_DO_SPECIAL_POWER); + message->Append_Int_Arg(power->Get_ID()); + message->Append_Int_Arg(button->Get_Options()); + message->Append_ObjectID_Arg(object->Get_ID()); + } + return CBC_COMMAND_USED; + } + case GUI_COMMAND_SPECIAL_POWER_CONSTRUCT: + if (m_currentSelectedDrawable != nullptr) { + switch (g_theBuildAssistant->Can_Make_Unit(obj, *button->Get_Template())) { + case CAN_MAKE_NOT_ENOUGH_MONEY: + g_theEva->Set_Should_Play(EVA_MESSAGE_INSUFFICIENTFUNDS); + g_theInGameUI->Message("GUI:NotEnoughMoneyToBuild"); + break; + case CAN_MAKE_QUEUE_FULL: + g_theInGameUI->Message("GUI:ProductionQueueFull"); + break; + case CAN_MAKE_PARKING_FULL: + g_theInGameUI->Message("GUI:ParkingPlacesFull"); + break; + case CAN_MAKE_MAXIMUM_NUMBER: + g_theInGameUI->Message("GUI:UnitMaxedOut"); + break; + default: + g_theInGameUI->Place_Build_Available( + *button->Get_Template(), m_currentSelectedDrawable); + + ProductionUpdateInterface *production = obj->Get_Production_Update_Interface(); + + if (production != nullptr) { + production->Set_Special_Power_Construction_Command_Button(button); + } + break; + } + } + return CBC_COMMAND_USED; + case GUI_COMMAND_SPECIAL_POWER_CONSTRUCT_FROM_SHORTCUT: { + const SpecialPowerTemplate *power = button->Get_Special_Power(); + Object *object = + g_thePlayerList->Get_Local_Player()->Find_Most_Ready_Shortcut_Special_Power_Of_Type( + power->Get_Type()); + + if (object != nullptr) { + Drawable *drawable = object->Get_Drawable(); + + switch (g_theBuildAssistant->Can_Make_Unit(object, *button->Get_Template())) { + case CAN_MAKE_NOT_ENOUGH_MONEY: + g_theEva->Set_Should_Play(EVA_MESSAGE_INSUFFICIENTFUNDS); + g_theInGameUI->Message("GUI:NotEnoughMoneyToBuild"); + break; + case CAN_MAKE_QUEUE_FULL: + g_theInGameUI->Message("GUI:ProductionQueueFull"); + break; + case CAN_MAKE_PARKING_FULL: + g_theInGameUI->Message("GUI:ParkingPlacesFull"); + break; + case CAN_MAKE_MAXIMUM_NUMBER: + g_theInGameUI->Message("GUI:UnitMaxedOut"); + break; + default: + g_theInGameUI->Place_Build_Available(*button->Get_Template(), drawable); + + ProductionUpdateInterface *production = + object->Get_Production_Update_Interface(); + + if (production != nullptr) { + production->Set_Special_Power_Construction_Command_Button(button); + } + break; + } + } + return CBC_COMMAND_USED; + } + case GUI_COMMAND_SELECT_ALL_UNITS_OF_TYPE: { + Player *local_player = g_thePlayerList->Get_Local_Player(); + + if (local_player != nullptr) { + const ThingTemplate *thing = *button->Get_Template(); + + if (thing != nullptr) { + g_theInGameUI->Deselect_All_Drawables(true); + GameMessage *message = + g_theMessageStream->Append_Message(GameMessage::MSG_CREATE_SELECTED_GROUP); + message->Append_Bool_Arg(true); + SelectObjectStruct select; + select.thing = thing; + select.message = message; + local_player->Iterate_Objects(Select_Object_Of_Type, &select); + } + } + return CBC_COMMAND_USED; + } + default: + captainslog_dbgassert(false, "Unknown command '%d'", button->Get_Command()); + return CBC_COMMAND_NOT_USED; + } + } + } else { + return CBC_COMMAND_NOT_USED; + } + } else { + return CBC_COMMAND_NOT_USED; + } + } else { + if (m_currContext != CB_CONTEXT_NONE) { + Switch_To_Context(CB_CONTEXT_NONE, nullptr); + } + + return CBC_COMMAND_NOT_USED; + } + } else { + captainslog_dbgassert(false, "ControlBar::Process_Command_UI() -- Button activated has no data. Ignoring..."); + return CBC_COMMAND_NOT_USED; + } +} diff --git a/src/game/client/gui/controlbar/controlbarmultiselect.cpp b/src/game/client/gui/controlbar/controlbarmultiselect.cpp index 39984ad88..d5e8f80d9 100644 --- a/src/game/client/gui/controlbar/controlbarmultiselect.cpp +++ b/src/game/client/gui/controlbar/controlbarmultiselect.cpp @@ -13,3 +13,10 @@ * LICENSE */ #include "controlbar.h" + +void ControlBar::Update_Context_Multi_Select() +{ +#ifdef GAME_DLL + Call_Method(PICK_ADDRESS(0x005AB940, 0x008F4155), this); +#endif +} diff --git a/src/game/client/gui/controlbar/controlbarobserver.cpp b/src/game/client/gui/controlbar/controlbarobserver.cpp index 39984ad88..b29960984 100644 --- a/src/game/client/gui/controlbar/controlbarobserver.cpp +++ b/src/game/client/gui/controlbar/controlbarobserver.cpp @@ -13,3 +13,17 @@ * LICENSE */ #include "controlbar.h" + +void ControlBar::Init_Observer_Controls() +{ +#ifdef GAME_DLL + Call_Method(PICK_ADDRESS(0x005A6CB0, 0x008E9B70), this); +#endif +} + +void ControlBar::Populate_Observer_Info_Window() +{ +#ifdef GAME_DLL + Call_Method(PICK_ADDRESS(0x005A7480, 0x008EA4BE), this); +#endif +} diff --git a/src/game/client/gui/controlbar/controlbarocltimer.cpp b/src/game/client/gui/controlbar/controlbarocltimer.cpp index 39984ad88..3ecc34e8f 100644 --- a/src/game/client/gui/controlbar/controlbarocltimer.cpp +++ b/src/game/client/gui/controlbar/controlbarocltimer.cpp @@ -13,3 +13,10 @@ * LICENSE */ #include "controlbar.h" + +void ControlBar::Update_Context_OCL_Timer() +{ +#ifdef GAME_DLL + Call_Method(PICK_ADDRESS(0x005AADE0, 0x008F3148), this); +#endif +} diff --git a/src/game/client/gui/controlbar/controlbarscheme.cpp b/src/game/client/gui/controlbar/controlbarscheme.cpp index b54d36cae..ef08fbc87 100644 --- a/src/game/client/gui/controlbar/controlbarscheme.cpp +++ b/src/game/client/gui/controlbar/controlbarscheme.cpp @@ -13,3 +13,151 @@ * LICENSE */ #include "controlbarscheme.h" + +ControlBarSchemeImage::~ControlBarSchemeImage() +{ + m_image = nullptr; +} + +ControlBarSchemeAnimation::~ControlBarSchemeAnimation() +{ + m_animImage = nullptr; +} + +ControlBarScheme::~ControlBarScheme() +{ + Reset(); +} + +void ControlBarScheme::Reset() +{ + for (int i = 0; i < LAYER_COUNT; i++) { + for (auto it = m_layer[i].begin(); it != m_layer[i].end(); it++) { + if (*it != nullptr) { + delete *it; + } + } + + m_layer[i].clear(); + } + + for (auto it = m_animations.begin(); it != m_animations.end(); it++) { + if (*it != nullptr) { + delete *it; + } + } + + m_animations.clear(); + m_name.Clear(); + m_ScreenCreationRes.x = 0.0f; + m_ScreenCreationRes.y = 0.0f; + m_side.Clear(); + m_buttonQueueImage = nullptr; + m_rightHUDImage = nullptr; + m_optionsButtonEnableImage = nullptr; + m_optionsButtonHilitedImage = nullptr; + m_optionsButtonPushedImage = nullptr; + m_optionsButtonDisabledImage = nullptr; + m_idleWorkerButtonEnableImage = nullptr; + m_idleWorkerButtonHilitedImage = nullptr; + m_idleWorkerButtonPushedImage = nullptr; + m_idleWorkerButtonDisabledImage = nullptr; + m_buddyButtonEnableImage = nullptr; + m_buddyButtonHilitedImage = nullptr; + m_buddyButtonPushedImage = nullptr; + m_buddyButtonDisabledImage = nullptr; + m_beaconButtonEnableImage = nullptr; + m_beaconButtonHilitedImage = nullptr; + m_beaconButtonPushedImage = nullptr; + m_beaconButtonDisabledImage = nullptr; + m_genBarButtonInImage = nullptr; + m_genBarButtonOnImage = nullptr; + m_toggleButtonUpInImage = nullptr; + m_toggleButtonUpOnImage = nullptr; + m_toggleButtonUpPushedImage = nullptr; + m_toggleButtonDownInImage = nullptr; + m_toggleButtonDownOnImage = nullptr; + m_toggleButtonDownPushedImage = nullptr; + m_commandMarkerImage = nullptr; + m_expBarForegroundImage = nullptr; + m_powerPurchaseImage = nullptr; +} + +void ControlBarScheme::Update() +{ + for (auto it = m_animations.begin(); it != m_animations.end(); it++) { + ControlBarSchemeAnimation *anim = *it; + + if (anim == nullptr) { + captainslog_dbgassert(false, "There's no Animation in the ControlBarSchemeAnimationList:m_animations"); + return; + } + + Update_Anim(anim); + } +} + +void Anim_Slide_Right(ControlBarSchemeAnimation *anim) +{ + if (anim->m_animImage != nullptr && anim->m_animDuration != 0) { + unsigned int frame = anim->Get_Current_Frame(); + ICoord2D pos = anim->Get_Start_Pos(); + + if (frame == anim->m_animDuration) { + anim->m_animImage->m_position = pos; + anim->Set_Current_Frame(0); + } else { + if (frame == 0) { + pos = anim->m_animImage->m_position; + anim->Set_Start_Pos(pos); + } + + frame++; + anim->Set_Current_Frame(frame); + anim->m_animImage->m_position.x = frame * (anim->m_finalPos.x - pos.x) / anim->m_animDuration + pos.x; + } + } +} + +void ControlBarScheme::Update_Anim(ControlBarSchemeAnimation *anim) +{ + if (anim->m_animType != ControlBarSchemeAnimation::CB_ANIM_SLIDE_RIGHT) { + captainslog_dbgassert(false, "We tried to animate but not animate function was found %d", anim->m_animType); + } else { + Anim_Slide_Right(anim); + } +} + +ControlBarSchemeManager::ControlBarSchemeManager() : m_currentScheme(nullptr) +{ + m_multiplyer.x = 1.0f; + m_multiplyer.y = 1.0f; +} + +void ControlBarSchemeManager::Init() +{ + INI ini; + ini.Load("Data\\INI\\Default\\ControlBarScheme.ini", INI_LOAD_OVERWRITE, nullptr); + ini.Load("Data\\INI\\ControlBarScheme.ini", INI_LOAD_OVERWRITE, nullptr); + captainslog_dbgassert(m_schemeList.size() != 0, + "There's no ControlBarScheme in the ControlBarSchemeList:m_schemeList that was just read from the INI file"); +} + +ControlBarSchemeManager::~ControlBarSchemeManager() +{ + for (auto it = m_schemeList.begin(); it != m_schemeList.end(); it++) { + if (*it != nullptr) { + delete *it; + } + } + + m_schemeList.clear(); + m_currentScheme = nullptr; +} + +void ControlBarSchemeManager::Update() +{ + if (m_currentScheme != nullptr) { + m_currentScheme->Update(); + } +} diff --git a/src/game/client/gui/controlbar/controlbarscheme.h b/src/game/client/gui/controlbar/controlbarscheme.h index 4f611c083..370c3ade7 100644 --- a/src/game/client/gui/controlbar/controlbarscheme.h +++ b/src/game/client/gui/controlbar/controlbarscheme.h @@ -30,7 +30,6 @@ class ControlBarSchemeImage ControlBarSchemeImage(); ~ControlBarSchemeImage(); -private: Utf8String m_name; ICoord2D m_position; ICoord2D m_size; @@ -49,7 +48,12 @@ class ControlBarSchemeAnimation void Set_Current_Frame(unsigned int frame) { m_currentFrame = frame; } void Set_Start_Pos(ICoord2D pos) { m_startPos = pos; } -private: + enum + { + CB_ANIM_SLIDE_RIGHT, + CB_ANIM_MAX, + }; + Utf8String m_name; int m_animType; ControlBarSchemeImage *m_animImage; @@ -73,6 +77,11 @@ class ControlBarScheme void Update(); void Update_Anim(ControlBarSchemeAnimation *anim); + enum + { + LAYER_COUNT = 6, + }; + private: Utf8String m_name; Coord2D m_ScreenCreationRes; @@ -86,19 +95,19 @@ class ControlBarScheme int m_borderSystemColor; int m_commandBarBorderColor; Image *m_optionsButtonEnableImage; - Image *m_optionsButtonHightlitedImage; + Image *m_optionsButtonHilitedImage; Image *m_optionsButtonPushedImage; Image *m_optionsButtonDisabledImage; Image *m_idleWorkerButtonEnableImage; - Image *m_idleWorkerButtonHightlitedImage; + Image *m_idleWorkerButtonHilitedImage; Image *m_idleWorkerButtonPushedImage; Image *m_idleWorkerButtonDisabledImage; Image *m_buddyButtonEnableImage; - Image *m_buddyButtonHightlitedImage; + Image *m_buddyButtonHilitedImage; Image *m_buddyButtonPushedImage; Image *m_buddyButtonDisabledImage; Image *m_beaconButtonEnableImage; - Image *m_beaconButtonHightlitedImage; + Image *m_beaconButtonHilitedImage; Image *m_beaconButtonPushedImage; Image *m_beaconButtonDisabledImage; Image *m_genBarButtonInImage; @@ -110,14 +119,14 @@ class ControlBarScheme Image *m_toggleButtonDownOnImage; Image *m_toggleButtonDownPushedImage; Image *m_generalButtonEnableImage; - Image *m_generalButtonHightlitedImage; + Image *m_generalButtonHilitedImage; Image *m_generalButtonPushedImage; Image *m_generalButtonDisabledImage; Image *m_uAttackButtonEnableImage; - Image *m_uAttackButtonHightlitedImage; + Image *m_uAttackButtonHilitedImage; Image *m_uAttackButtonPushedImage; Image *m_minMaxButtonEnableImage; - Image *m_minMaxButtonHightlitedImage; + Image *m_minMaxButtonHilitedImage; Image *m_minMaxButtonPushedImage; Image *m_genArrowImage; ICoord2D m_moneyUL; @@ -141,7 +150,7 @@ class ControlBarScheme Image *m_expBarForegroundImage; Image *m_commandMarkerImage; Image *m_powerPurchaseImage; - std::list m_layer[6]; + std::list m_layer[LAYER_COUNT]; std::list m_animations; }; diff --git a/src/game/client/gui/controlbar/controlbarstructureinventory.cpp b/src/game/client/gui/controlbar/controlbarstructureinventory.cpp index 39984ad88..d19b88588 100644 --- a/src/game/client/gui/controlbar/controlbarstructureinventory.cpp +++ b/src/game/client/gui/controlbar/controlbarstructureinventory.cpp @@ -13,3 +13,105 @@ * LICENSE */ #include "controlbar.h" +#include "gadgetpushbutton.h" +#include "hotkey.h" +#include "object.h" +#include "player.h" +#include "playerlist.h" +#include "thingtemplate.h" + +struct PopulateButtonInfo +{ + Object *source; + int button_index; + ControlBar *self; + GameWindow **inventory_buttons; +}; + +void ControlBar::Populate_Button_Proc(Object *obj, void *user_data) +{ + PopulateButtonInfo *data = static_cast(user_data); + captainslog_dbgassert(data->button_index < 10, + "Too many objects inside '%s' for the inventory buttons to hold", + data->source->Get_Template()->Get_Name().Str()); + s_containData[data->button_index].button = data->inventory_buttons[data->button_index]; + s_containData[data->button_index].id = obj->Get_ID(); + Gadget_Button_Set_Enabled_Image(data->inventory_buttons[data->button_index], obj->Get_Template()->Get_Button_Image()); + Gadget_Button_Draw_Overlay_Image( + data->inventory_buttons[data->button_index], Calculate_Veterancy_Overlay_For_Object(obj)); + data->inventory_buttons[data->button_index]->Win_Enable(true); + data->button_index++; +} + +void ControlBar::Update_Context_Structure_Inventory() +{ + Object *object = m_currentSelectedDrawable->Get_Object(); + + if (object->Is_Locally_Controlled() + || g_thePlayerList->Get_Local_Player()->Get_Relationship(object->Get_Team()) == NEUTRAL) { + ContainModuleInterface *contain = object->Get_Contain(); + captainslog_dbgassert(contain != nullptr, "No contain module defined for object in the inventory bar"); + + if (contain != nullptr && m_lastRecordedInventoryCount != contain->Get_Contain_Count()) { + Populate_Structure_Inventory(object); + } + } else { + Drawable *drawable = object->Get_Drawable(); + + if (drawable != nullptr) { + g_theInGameUI->Deselect_Drawable(drawable); + } + } +} + +void ControlBar::Populate_Structure_Inventory(Object *building) +{ + Reset_Contain_Data(); + + if (g_theHotKeyManager != nullptr) { + g_theHotKeyManager->Reset(); + } + + for (int i = 0; i < CommandSet::MAX_COMMAND_BUTTONS; i++) { + if (m_commandWindows[i] != nullptr) { + m_commandWindows[i]->Win_Hide(true); + } + } + + ContainModuleInterface *contain = building->Get_Contain(); + captainslog_dbgassert(contain != nullptr, "Object in structure inventory does not contain a Contain Module"); + + if (contain != nullptr) { + Set_Control_Command(m_commandWindows[11], Find_Command_Button("Command_Evacuate")); + Set_Control_Command(m_commandWindows[10], Find_Command_Button("Command_Stop")); + const CommandButton *exit = Find_Command_Button("Command_StructureExit"); + + for (int i = 0; i < 10; i++) { + m_commandWindows[i]->Win_Hide(false); + m_commandWindows[i]->Win_Enable(false); + m_commandWindows[i]->Win_Set_Status(WIN_STATUS_ALWAYS_COLOR); + m_commandWindows[i]->Win_Clear_Status(WIN_STATUS_NOT_READY); + Set_Control_Command(m_commandWindows[i], exit); + Gadget_Button_Draw_Overlay_Image(m_commandWindows[i], nullptr); + + if (i + 1 > contain->Get_Contain_Max()) { + m_commandWindows[i]->Win_Hide(true); + } + } + + m_commandWindows[11]->Win_Hide(false); + m_commandWindows[10]->Win_Hide(false); + + if (contain->Get_Contain_Count()) { + m_commandWindows[11]->Win_Enable(true); + m_commandWindows[10]->Win_Enable(true); + } + + PopulateButtonInfo info; + info.source = building; + info.button_index = 0; + info.self = this; + info.inventory_buttons = m_commandWindows; + contain->Iterate_Contained(Populate_Button_Proc, &info, false); + } +} diff --git a/src/game/client/gui/controlbar/controlbarunderconstruction.cpp b/src/game/client/gui/controlbar/controlbarunderconstruction.cpp index 39984ad88..e57927604 100644 --- a/src/game/client/gui/controlbar/controlbarunderconstruction.cpp +++ b/src/game/client/gui/controlbar/controlbarunderconstruction.cpp @@ -13,3 +13,30 @@ * LICENSE */ #include "controlbar.h" +#include "gadgetstatictext.h" +#include "gametext.h" +#include "gamewindowmanager.h" + +void ControlBar::Update_Context_Under_Construction() +{ + Object *object = m_currentSelectedDrawable->Get_Object(); + + if (object->Get_Status_Bits().Test(OBJECT_STATUS_UNDER_CONSTRUCTION)) { + if (object->Get_Construction_Percent() != m_displayedConstructPercent) { + Update_Construction_Text_Display(object); + } + } else { + Evaluate_Context_UI(); + } +} + +void ControlBar::Update_Construction_Text_Display(Object *obj) +{ + Utf16String text; + static NameKeyType desc_id = g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:UnderConstructionDesc"); + GameWindow *window = g_theWindowManager->Win_Get_Window_From_Id(nullptr, desc_id); + captainslog_dbgassert(window != nullptr, "Under construction window not found"); + text.Format(g_theGameText->Fetch("CONTROLBAR:UnderConstructionDesc"), obj->Get_Construction_Percent()); + Gadget_Static_Text_Set_Text(window, text); + m_displayedConstructPercent = obj->Get_Construction_Percent(); +} diff --git a/src/game/client/gui/disconnectmenu/disconnectmenu.cpp b/src/game/client/gui/disconnectmenu/disconnectmenu.cpp new file mode 100644 index 000000000..0f512dd0f --- /dev/null +++ b/src/game/client/gui/disconnectmenu/disconnectmenu.cpp @@ -0,0 +1,19 @@ +/** + * @file + * + * @author Jonathan Wilson + * + * @brief Disconnect Menu + * + * @copyright Thyme is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version + * 2 of the License, or (at your option) any later version. + * A full copy of the GNU General Public License can be found in + * LICENSE + */ +#include "disconnectmenu.h" + +#ifndef GAME_DLL +DisconnectMenu *g_theDisconnectMenu; +#endif diff --git a/src/game/client/gui/disconnectmenu/disconnectmenu.h b/src/game/client/gui/disconnectmenu/disconnectmenu.h new file mode 100644 index 000000000..01929e5f7 --- /dev/null +++ b/src/game/client/gui/disconnectmenu/disconnectmenu.h @@ -0,0 +1,42 @@ +/** + * @file + * + * @author Jonathan Wilson + * + * @brief Disconnect Menu + * + * @copyright Thyme is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version + * 2 of the License, or (at your option) any later version. + * A full copy of the GNU General Public License can be found in + * LICENSE + */ +#pragma once +#include "always.h" + +class DisconnectManager; + +enum DisconnectMenuStateType +{ + DISCONNECTMENUSTATETYPE_SCREENON, + DISCONNECTMENUSTATETYPE_SCREENOFF, +}; + +class DisconnectMenu +{ +public: + virtual ~DisconnectMenu(); + + bool Is_Screen_Visible() const { return m_menuState == DISCONNECTMENUSTATETYPE_SCREENON; } + +private: + DisconnectManager *m_disconnectManager; + DisconnectMenuStateType m_menuState; +}; + +#ifdef GAME_DLL +extern DisconnectMenu *&g_theDisconnectMenu; +#else +extern DisconnectMenu *g_theDisconnectMenu; +#endif diff --git a/src/game/client/gui/gadget/gadgetpushbutton.cpp b/src/game/client/gui/gadget/gadgetpushbutton.cpp index f4a833f59..17fe2f840 100644 --- a/src/game/client/gui/gadget/gadgetpushbutton.cpp +++ b/src/game/client/gui/gadget/gadgetpushbutton.cpp @@ -44,3 +44,47 @@ WindowMsgHandledType Gadget_Push_Button_System( return MSG_IGNORED; #endif } + +void *Gadget_Button_Get_Data(GameWindow *push_button) +{ +#ifdef GAME_DLL + return Call_Function(PICK_ADDRESS(0x005AC4D0, 0x008F5209), push_button); +#else + return nullptr; +#endif +} + +void Gadget_Button_Enable_Check_Like(GameWindow *push_button, bool is_enabled, bool is_checked) +{ +#ifdef GAME_DLL + Call_Function(PICK_ADDRESS(0x005AC300, 0x008F4F1C), push_button, is_enabled, is_checked); +#endif +} + +void Gadget_Button_Set_Data(GameWindow *push_button, void *data) +{ +#ifdef GAME_DLL + Call_Function(PICK_ADDRESS(0x005AC4A0, 0x008F51CB), push_button, data); +#endif +} + +void Gadget_Button_Set_Alt_Sound(GameWindow *push_button, Utf8String alt_sound) +{ +#ifdef GAME_DLL + Call_Function(PICK_ADDRESS(0x005AC4F0, 0x008F5236), push_button, alt_sound); +#endif +} + +void Gadget_Button_Set_Border(GameWindow *push_button, int color, bool draw_border) +{ +#ifdef GAME_DLL + Call_Function(PICK_ADDRESS(0x005AC3F0, 0x008F50AC), push_button, color, draw_border); +#endif +} + +void Gadget_Button_Draw_Overlay_Image(GameWindow *push_button, const Image *image) +{ +#ifdef GAME_DLL + Call_Function(PICK_ADDRESS(0x005AC470, 0x008F518D), push_button, image); +#endif +} diff --git a/src/game/client/gui/gadget/gadgetpushbutton.h b/src/game/client/gui/gadget/gadgetpushbutton.h index bb9de2296..98a8b9bd3 100644 --- a/src/game/client/gui/gadget/gadgetpushbutton.h +++ b/src/game/client/gui/gadget/gadgetpushbutton.h @@ -164,4 +164,4 @@ void Gadget_Button_Draw_Inverse_Clock(GameWindow *push_button, int percent, int void Gadget_Button_Draw_Overlay_Image(GameWindow *push_button, const Image *image); void Gadget_Button_Set_Data(GameWindow *push_button, void *data); void *Gadget_Button_Get_Data(GameWindow *push_button); -void Gaget_Button_Set_Alt_Sound(GameWindow *push_button, Utf8String alt_sound); +void Gadget_Button_Set_Alt_Sound(GameWindow *push_button, Utf8String alt_sound); diff --git a/src/game/client/gui/gamewindow.h b/src/game/client/gui/gamewindow.h index 51c5fa92c..b87cea27e 100644 --- a/src/game/client/gui/gamewindow.h +++ b/src/game/client/gui/gamewindow.h @@ -154,7 +154,7 @@ enum GadgetGameMessage GGM_LEFT_DRAG = 0x4000, GGM_SET_LABEL, GGM_GET_LABEL, - GGM_FOCUS_CHANG, + GGM_FOCUS_CHANGE, GGM_RESIZED, GGM_CLOSE, GBM_MOUSE_ENTERING, diff --git a/src/game/client/gui/guicallbacks/controlbarcallback.cpp b/src/game/client/gui/guicallbacks/controlbarcallback.cpp new file mode 100644 index 000000000..a9b242708 --- /dev/null +++ b/src/game/client/gui/guicallbacks/controlbarcallback.cpp @@ -0,0 +1,29 @@ +/** + * @file + * + * @author Jonathan Wilson + * + * @brief Control Bar + * + * @copyright Thyme is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version + * 2 of the License, or (at your option) any later version. + * A full copy of the GNU General Public License can be found in + * LICENSE + */ +#include "controlbar.h" + +void Hide_Control_Bar(bool hide) +{ +#ifdef GAME_DLL + Call_Function(PICK_ADDRESS(0x0048A3E0, 0x009DF7F2), hide); +#endif +} + +void Show_Control_Bar(bool show) +{ +#ifdef GAME_DLL + Call_Function(PICK_ADDRESS(0x0048A250, 0x009DF683), show); +#endif +} diff --git a/src/game/client/gui/guicallbacks/controlbarpopupdescription.cpp b/src/game/client/gui/guicallbacks/controlbarpopupdescription.cpp new file mode 100644 index 000000000..5448510cd --- /dev/null +++ b/src/game/client/gui/guicallbacks/controlbarpopupdescription.cpp @@ -0,0 +1,561 @@ +/** + * @file + * + * @author Jonathan Wilson + * + * @brief Control Bar + * + * @copyright Thyme is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version + * 2 of the License, or (at your option) any later version. + * A full copy of the GNU General Public License can be found in + * LICENSE + */ +#include "animatewindowmanager.h" +#include "buildassistant.h" +#include "controlbar.h" +#include "disconnectmenu.h" +#include "displaystringmanager.h" +#include "drawable.h" +#include "gadgetpushbutton.h" +#include "gadgetstatictext.h" +#include "gametext.h" +#include "gamewindowmanager.h" +#include "globaldata.h" +#include "ingameui.h" +#include "object.h" +#include "overchargebehavior.h" +#include "player.h" +#include "playerlist.h" +#include "productionprerequisite.h" +#include "scriptengine.h" +#include "thingtemplate.h" +#include "upgrade.h" +#include "windowlayout.h" + +AnimateWindowManager *g_theAnimateWindowManager = nullptr; +GameWindow *g_prevWindow = nullptr; +bool g_useAnimation = false; + +void Control_Bar_Popup_Description_Update_Func(WindowLayout *layout, void *user_data) +{ + if (g_theScriptEngine->Is_End_Game_Timer_Running()) { + g_theControlBar->Hide_Build_Tooltip_Layout(); + } + + if (g_theAnimateWindowManager != nullptr && !g_theControlBar->Get_Build_Tooltip_Layout_Visible() + && !g_theAnimateWindowManager->Is_Reversed()) { + g_theAnimateWindowManager->Reverse_Animate_Window(); + } else if (!g_theControlBar->Get_Build_Tooltip_Layout_Visible() + && (!g_theWriteableGlobalData->m_animateWindows || !g_useAnimation)) { + g_theControlBar->Delete_Build_Tooltip_Layout(); + } + + if (g_useAnimation) { + if (g_theAnimateWindowManager != nullptr) { + if (g_theWriteableGlobalData->m_animateWindows) { + bool finished = g_theAnimateWindowManager->Is_Finished(); + g_theAnimateWindowManager->Update(); + + if (g_theAnimateWindowManager != nullptr) { + if (g_theAnimateWindowManager->Is_Finished() && !finished && g_theAnimateWindowManager->Is_Reversed()) { + if (g_theAnimateWindowManager != nullptr) { + delete g_theAnimateWindowManager; + } + + g_theAnimateWindowManager = nullptr; + g_theControlBar->Delete_Build_Tooltip_Layout(); + } + } + } + } + } +} + +void ControlBar::Show_Build_Tooltip_Layout(GameWindow *window) +{ + static bool is_initialized = false; + static unsigned int begin_wait_time = 0; + + if (g_theInGameUI->Are_Tooltips_Disabled() || g_theScriptEngine->Is_End_Game_Timer_Running()) { + return; + } + + bool show = false; + + if (g_prevWindow == window) { + m_buildTooltipLayoutVisible = true; + + if (!is_initialized) { + if (window->Get_Tooltip_Delay() + begin_wait_time < rts::Get_Time()) { + show = true; + } + } + + if (!show) { + return; + } + } else if (!m_controlBarPopupDescriptionLayout->Is_Hidden()) { + if (g_useAnimation && g_theWriteableGlobalData->m_animateWindows && !g_theAnimateWindowManager->Is_Reversed()) { + g_theAnimateWindowManager->Reverse_Animate_Window(); + } else if (!g_useAnimation || !g_theWriteableGlobalData->m_animateWindows + || !g_theAnimateWindowManager->Is_Reversed()) { + m_controlBarPopupDescriptionLayout->Hide(true); + g_prevWindow = nullptr; + } + + return; + } + + if (!show) { + g_prevWindow = window; + begin_wait_time = rts::Get_Time(); + is_initialized = false; + return; + } + + is_initialized = true; + + if (window != nullptr) { + if ((window->Win_Get_Style() & GWS_PUSH_BUTTON) != 0) { + CommandButton *button = static_cast(Gadget_Button_Get_Data(window)); + + if (button == nullptr || g_theGameLogic->Is_In_Replay_Game() || g_theInGameUI->Is_Quit_Menu_Visible() + || (g_theDisconnectMenu != nullptr && g_theDisconnectMenu->Is_Screen_Visible())) { + return; + } + + m_buildTooltipLayoutVisible = true; + Populate_Build_Tooltip_Layout(button, nullptr); + } else { + if ((window->Win_Get_Style() & GWS_USER_WINDOW) == 0 && (window->Win_Get_Style() & GWS_STATIC_TEXT) == 0) { + return; + } + + Populate_Build_Tooltip_Layout(nullptr, window); + } + + m_controlBarPopupDescriptionLayout->Hide(false); + + if (g_useAnimation && g_theWriteableGlobalData->m_animateWindows) { + g_theAnimateWindowManager = new AnimateWindowManager(); + g_theAnimateWindowManager->Reset(); + g_theAnimateWindowManager->Register_Game_Window( + m_controlBarPopupDescriptionLayout->Get_Window_List(), WIN_ANIMATION_SLIDE_RIGHT_FAST, true, 200, 0); + } + } +} + +void ControlBar::Repopulate_Build_Tooltip_Layout() +{ + if (g_prevWindow != nullptr && m_controlBarPopupDescriptionLayout != nullptr + && (g_prevWindow->Win_Get_Style() & GWS_PUSH_BUTTON) != 0) { + CommandButton *button = static_cast(Gadget_Button_Get_Data(g_prevWindow)); + Populate_Build_Tooltip_Layout(button, nullptr); + } +} + +void ControlBar::Populate_Build_Tooltip_Layout(const CommandButton *button, GameWindow *window) +{ + if (m_controlBarPopupDescriptionLayout == nullptr) { + return; + } + + Player *player = g_thePlayerList->Get_Local_Player(); + Utf16String name_str; + Utf16String cost_str; + Utf16String description_string; + Utf16String temp_string1(Utf16String::s_emptyString); + Utf16String temp_string2; + + bool skip_append_comma = true; + bool skip_cost = false; + unsigned int cost = 0; + + if (button != nullptr) { + const ThingTemplate *thing = *button->Get_Template(); + const UpgradeTemplate *upgrade = button->Get_Upgrade_Template(); + ScienceType science = SCIENCE_INVALID; + + if (button->Get_Command() != GUI_COMMAND_PLAYER_UPGRADE && button->Get_Command() != GUI_COMMAND_OBJECT_UPGRADE) { + if (button->Get_Sciences()->size() > 1) { + for (unsigned int i = 0; i < button->Get_Sciences()->size(); i++) { + unsigned int index = i; + science = (*button->Get_Sciences())[index]; + + if (button->Get_Command() != GUI_COMMAND_PURCHASE_SCIENCE) { + if (!player->Has_Science(science) && i > 0) { + index = i - 1; + science = (*button->Get_Sciences())[index]; + } + + skip_cost = true; + break; + } + + if (!player->Has_Science(science)) { + break; + } + } + } else if (button->Get_Sciences()->size() == 1) { + science = (*button->Get_Sciences())[0]; + + if (button->Get_Command() != GUI_COMMAND_PURCHASE_SCIENCE) { + skip_cost = true; + } + } + } + + if (button->Get_Descript_Label().Is_Not_Empty()) { + description_string = g_theGameText->Fetch(button->Get_Descript_Label()); + Drawable *drawable = g_theInGameUI->Get_First_Selected_Drawable(); + Object *object = drawable ? drawable->Get_Object() : nullptr; + + if (object != nullptr) { + if (button->Get_Command() == GUI_COMMAND_TOGGLE_OVERCHARGE) { + for (BehaviorModule **module = object->Get_All_Modules(); *module != nullptr; module++) { + OverchargeBehaviorInterface *overcharge = (*module)->Get_Overcharge_Behavior_Interface(); + + if (overcharge != nullptr) { + description_string.Concat(U_CHAR("\n")); + + if (overcharge->Is_Overcharge_Active()) { + description_string.Concat(g_theGameText->Fetch("TOOLTIP:TooltipNukeReactorOverChargeIsOn")); + } else { + description_string.Concat(g_theGameText->Fetch("TOOLTIP:TooltipNukeReactorOverChargeIsOff")); + } + } + } + } else if (thing != nullptr) { + CanMakeType type = g_theBuildAssistant->Can_Make_Unit(object, *button->Get_Template()); + + switch (type) { + case CAN_MAKE_NOT_ENOUGH_MONEY: + description_string.Concat(U_CHAR("\n\n")); + description_string.Concat(g_theGameText->Fetch("TOOLTIP:TooltipNotEnoughMoneyToBuild")); + break; + case CAN_MAKE_QUEUE_FULL: + description_string.Concat(U_CHAR("\n\n")); + description_string.Concat(g_theGameText->Fetch("TOOLTIP:TooltipCannotPurchaseBecauseQueueFull")); + break; + case CAN_MAKE_PARKING_FULL: + description_string.Concat(U_CHAR("\n\n")); + description_string.Concat( + g_theGameText->Fetch("TOOLTIP:TooltipCannotBuildUnitBecauseParkingFull")); + break; + case CAN_MAKE_MAXIMUM_NUMBER: + description_string.Concat(U_CHAR("\n\n")); + + if (thing->Is_KindOf(KINDOF_STRUCTURE)) { + description_string.Concat( + g_theGameText->Fetch("TOOLTIP:TooltipCannotBuildBuildingBecauseMaximumNumber")); + } else { + description_string.Concat( + g_theGameText->Fetch("TOOLTIP:TooltipCannotBuildUnitBecauseMaximumNumber")); + } + break; + default: + break; + } + } else if (upgrade != nullptr && !player->Has_Upgrade_In_Production(upgrade) + && (button->Get_Command() == GUI_COMMAND_PLAYER_UPGRADE + || button->Get_Command() == GUI_COMMAND_OBJECT_UPGRADE)) { + ProductionUpdateInterface *production = object->Get_Production_Update_Interface(); + + if (production != nullptr && production->Get_Production_Count() == 9) { + description_string.Concat(U_CHAR("\n\n")); + description_string.Concat(g_theGameText->Fetch("TOOLTIP:TooltipCannotPurchaseBecauseQueueFull")); + } else { + if (!g_theUpgradeCenter->Can_Afford_Upgrade(g_thePlayerList->Get_Local_Player(), upgrade, false)) { + description_string.Concat(g_theGameText->Fetch("TOOLTIP:TooltipNotEnoughMoneyToBuild")); + } + } + } + } + } + + name_str = g_theGameText->Fetch(button->Get_Text_Label().Str()); + + if (thing == nullptr || button->Get_Command() == GUI_COMMAND_PURCHASE_SCIENCE) { + if (upgrade != nullptr) { + bool has_upgrade = player->Has_Upgrade_Complete(upgrade); + bool is_not_affected_by_upgrade = false; + bool is_missing_science = false; + bool is_player_upgrade = button->Get_Command() == GUI_COMMAND_PLAYER_UPGRADE; + bool is_object_upgrade = button->Get_Command() == GUI_COMMAND_OBJECT_UPGRADE; + + if (!has_upgrade) { + const Drawable *drawable = g_theInGameUI->Get_First_Selected_Drawable(); + + if (drawable != nullptr) { + const Object *object = drawable->Get_Object(); + + if (object != nullptr) { + has_upgrade = object->Has_Upgrade(upgrade); + + if (is_object_upgrade) { + is_not_affected_by_upgrade = !object->Affected_By_Upgrade(upgrade); + } + } + } + } + + if (!is_not_affected_by_upgrade || has_upgrade) { + if (has_upgrade && (is_player_upgrade || is_object_upgrade)) { + if (button->Get_Purchased_Label().Is_Not_Empty()) { + description_string = g_theGameText->Fetch(button->Get_Purchased_Label()); + + } else { + description_string = g_theGameText->Fetch("TOOLTIP:AlreadyUpgradedDefault"); + } + } else if (!has_upgrade) { + for (unsigned int i = 0; i < button->Get_Sciences()->size(); i++) { + science = (*button->Get_Sciences())[i]; + + if (!player->Has_Science(science)) { + is_missing_science = true; + break; + } + } + + cost = upgrade->Calc_Cost_To_Build(player); + + if (cost != 0) { + cost_str.Format(g_theGameText->Fetch("TOOLTIP:Cost"), cost); + } + + if (is_missing_science) { + if (!description_string.Is_Empty()) { + description_string.Concat(U_CHAR("\n")); + } + + temp_string1.Format(g_theGameText->Fetch("CONTROLBAR:Requirements").Str(), + g_theGameText->Fetch("CONTROLBAR:GeneralsPromotion").Str()); + description_string.Concat(temp_string1); + } + } + } else { + if (button->Get_Conflicting_Label().Is_Not_Empty()) { + description_string = g_theGameText->Fetch(button->Get_Conflicting_Label()); + } else { + description_string = g_theGameText->Fetch("TOOLTIP:HasConflictingUpgradeDefault"); + } + } + } else if (science != SCIENCE_INVALID && !skip_cost) { + g_theScienceStore->Get_Name_And_Description(science, name_str, description_string); + cost = g_theScienceStore->Get_Science_Purchase_Cost(science); + + if (cost != 0) { + cost_str.Format(g_theGameText->Fetch("TOOLTIP:ScienceCost"), cost); + } + + if (thing != nullptr) { + for (int j = 0; j < thing->Get_Prereq_Count(); j++) { + const ProductionPrerequisite *prerequisite = thing->Get_Nth_Prereq(j); + temp_string2 = prerequisite->Get_Requires_List(player); + + if (temp_string2 != Utf16String::s_emptyString) { + if (skip_append_comma) { + skip_append_comma = false; + } else { + temp_string1.Concat(U_CHAR(", ")); + } + } + + temp_string1.Concat(temp_string2); + } + + if (!temp_string1.Is_Empty()) { + temp_string1.Format(g_theGameText->Fetch("CONTROLBAR:Requirements"), temp_string1.Str()); + + if (!description_string.Is_Empty()) { + description_string.Concat(U_CHAR("\n")); + } + + description_string.Concat(temp_string1); + } + } + } + } else { + cost = thing->Calc_Cost_To_Build(player); + + if (cost != 0) { + cost_str.Format(g_theGameText->Fetch("TOOLTIP:Cost"), cost); + } + + for (int j = 0; j < thing->Get_Prereq_Count(); j++) { + const ProductionPrerequisite *prerequisite = thing->Get_Nth_Prereq(j); + temp_string2 = prerequisite->Get_Requires_List(player); + + if (temp_string2 != Utf16String::s_emptyString) { + if (skip_append_comma) { + skip_append_comma = false; + } else { + temp_string1.Concat(U_CHAR(", ")); + } + } + + temp_string1.Concat(temp_string2); + } + + if (!temp_string1.Is_Empty()) { + temp_string1.Format(g_theGameText->Fetch("CONTROLBAR:Requirements"), temp_string1.Str()); + + if (!description_string.Is_Empty()) { + description_string.Concat(U_CHAR("\n")); + } + + description_string.Concat(temp_string1); + } + } + } else if (window != nullptr) { + if (window + == g_theWindowManager->Win_Get_Window_From_Id(m_controlBarPopupDescriptionLayout->Get_Window_List(), + g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:MoneyDisplay"))) { + name_str = g_theGameText->Fetch("CONTROLBAR:Money"); + description_string = g_theGameText->Fetch("CONTROLBAR:MoneyDescription"); + } else if (window + == g_theWindowManager->Win_Get_Window_From_Id(m_controlBarPopupDescriptionLayout->Get_Window_List(), + g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:PowerWindow"))) { + name_str = g_theGameText->Fetch("CONTROLBAR:Power"); + description_string = g_theGameText->Fetch("CONTROLBAR:PowerDescription"); + + player = nullptr; + + if (g_theControlBar->Is_Observer()) { + player = g_theControlBar->Get_Observer_Player(); + } else { + player = g_thePlayerList->Get_Local_Player(); + } + + if (player != nullptr && player->Get_Energy() != nullptr) { + const Energy *energy = player->Get_Energy(); + description_string.Format(description_string, energy->Get_Production(), energy->Get_Consumption()); + } else { + description_string.Format(description_string, 0, 0); + } + } else { + if (window + != g_theWindowManager->Win_Get_Window_From_Id(m_controlBarPopupDescriptionLayout->Get_Window_List(), + g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:GeneralsExp"))) { + captainslog_dbgassert(false, + "ControlBar::Populate_Build_Tooltip_Layout We attempted to call the popup tooltip on a game window " + "that has yet to be hand coded in as this fuction was/is designed for only buttons but has been " + "hacked to work with GameWindows."); + return; + } + + name_str = g_theGameText->Fetch("CONTROLBAR:GeneralsExp"); + description_string = g_theGameText->Fetch("CONTROLBAR:GeneralsExpDescription"); + } + } + + GameWindow *win = g_theWindowManager->Win_Get_Window_From_Id(m_controlBarPopupDescriptionLayout->Get_Window_List(), + g_theNameKeyGenerator->Name_To_Key("ControlBarPopupDescription.wnd:StaticTextName")); + + if (win != nullptr) { + Gadget_Static_Text_Set_Text(win, name_str); + } + + win = g_theWindowManager->Win_Get_Window_From_Id(m_controlBarPopupDescriptionLayout->Get_Window_List(), + g_theNameKeyGenerator->Name_To_Key("ControlBarPopupDescription.wnd:StaticTextCost")); + + if (win != nullptr) { + if (cost != 0) { + win->Win_Hide(false); + Gadget_Static_Text_Set_Text(win, cost_str); + } else { + win->Win_Hide(true); + } + } + + win = g_theWindowManager->Win_Get_Window_From_Id(m_controlBarPopupDescriptionLayout->Get_Window_List(), + g_theNameKeyGenerator->Name_To_Key("ControlBarPopupDescription.wnd:StaticTextDescription")); + + if (win != nullptr) { + static NameKeyType win_name_key = g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:BackgroundMarker"); + DisplayString *display_string = g_theDisplayStringManager->New_Display_String(); + + int width; + int height; + win->Win_Get_Size(&width, &height); + display_string->Set_Font(win->Win_Get_Font()); + display_string->Set_Word_Wrap(width - 10); + display_string->Set_Text(description_string); + + int text_w; + int text_h; + display_string->Get_Size(&text_w, &text_h); + g_theDisplayStringManager->Free_Display_String(display_string); + display_string = nullptr; + int add_text_h = text_h - height; + + GameWindow *win_list = m_controlBarPopupDescriptionLayout->Get_Window_List(); + + if (win_list == nullptr) { + return; + } + + win_list->Win_Get_Size(&width, &height); + + if (add_text_h + height < 102) { + add_text_h = 102 - height; + } + + win_list->Win_Set_Size(width, add_text_h + height); + + int x_pos; + int y_pos; + win_list->Win_Get_Position(&x_pos, &y_pos); + GameWindow *background_win = g_theWindowManager->Win_Get_Window_From_Id(nullptr, win_name_key); + + if (background_win == nullptr) { + return; + } + + static ICoord2D base_pos; + static ICoord2D last_offset; + g_theControlBar->Get_Background_Marker_Pos(&base_pos.x, &base_pos.y); + + int screen_x; + int screen_y; + background_win->Win_Get_Screen_Position(&screen_x, &screen_y); + + ICoord2D c; + c.x = screen_x - base_pos.x; + c.y = screen_y - base_pos.y; + + win_list->Win_Set_Position(x_pos, screen_y - base_pos.y - last_offset.y + y_pos - add_text_h); + last_offset = c; + win->Win_Get_Size(&width, &height); + win->Win_Set_Size(width, add_text_h + height); + Gadget_Static_Text_Set_Text(win, description_string); + } + + m_controlBarPopupDescriptionLayout->Hide(false); +} + +void ControlBar::Hide_Build_Tooltip_Layout() +{ + if (g_theAnimateWindowManager == nullptr || !g_theAnimateWindowManager->Is_Reversed()) { + if (g_useAnimation && g_theAnimateWindowManager != nullptr && g_theWriteableGlobalData->m_animateWindows) { + g_theAnimateWindowManager->Reverse_Animate_Window(); + } else { + Delete_Build_Tooltip_Layout(); + } + } +} + +void ControlBar::Delete_Build_Tooltip_Layout() +{ + m_buildTooltipLayoutVisible = false; + g_prevWindow = nullptr; + m_controlBarPopupDescriptionLayout->Hide(true); + + if (g_theAnimateWindowManager != nullptr) { + delete g_theAnimateWindowManager; + } + + g_theAnimateWindowManager = nullptr; +} diff --git a/src/game/client/messagestream/commandxlat.cpp b/src/game/client/messagestream/commandxlat.cpp new file mode 100644 index 000000000..b2ec4151e --- /dev/null +++ b/src/game/client/messagestream/commandxlat.cpp @@ -0,0 +1,24 @@ +/** + * @file + * + * @author Jonathan Wilson + * + * @brief Command Translate + * + * @copyright Thyme is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version + * 2 of the License, or (at your option) any later version. + * A full copy of the GNU General Public License can be found in + * LICENSE + */ +#include "commandxlat.h" + +void Pick_And_Play_Unit_Voice_Response( + const std::list *list, GameMessage::MessageType type, PickAndPlayInfo *info) +{ +#ifdef GAME_DLL + Call_Function *, GameMessage::MessageType, PickAndPlayInfo *>( + PICK_ADDRESS(0x005E92B0, 0x007E8AE3), list, type, info); +#endif +} diff --git a/src/game/client/messagestream/commandxlat.h b/src/game/client/messagestream/commandxlat.h new file mode 100644 index 000000000..cbced45b5 --- /dev/null +++ b/src/game/client/messagestream/commandxlat.h @@ -0,0 +1,32 @@ +/** + * @file + * + * @author Jonathan Wilson + * + * @brief Command Translate + * + * @copyright Thyme is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version + * 2 of the License, or (at your option) any later version. + * A full copy of the GNU General Public License can be found in + * LICENSE + */ +#pragma once +#include "always.h" +#include "drawable.h" +#include "messagestream.h" + +struct PickAndPlayInfo +{ + bool is_airborne; + Drawable *drawable; + WeaponSlotType *weapon_slot_type; + SpecialPowerType special_power_type; + PickAndPlayInfo() : is_airborne(false), drawable(nullptr), weapon_slot_type(nullptr), special_power_type(SPECIAL_INVALID) + { + } +}; + +void Pick_And_Play_Unit_Voice_Response( + const std::list *list, GameMessage::MessageType type, PickAndPlayInfo *info); diff --git a/src/game/client/messagestream/hotkey.cpp b/src/game/client/messagestream/hotkey.cpp index 526ac4b18..316dca4ff 100644 --- a/src/game/client/messagestream/hotkey.cpp +++ b/src/game/client/messagestream/hotkey.cpp @@ -13,6 +13,7 @@ * LICENSE */ #include "hotkey.h" +#include "gametext.h" #include "gamewindow.h" #include "unicodestring.h" @@ -20,6 +21,11 @@ HotKeyManager *g_theHotKeyManager; #endif +Utf8String HotKeyManager::Search_Hot_Key(const Utf8String &str) +{ + return Search_Hot_Key(g_theGameText->Fetch(str)); +} + Utf8String HotKeyManager::Search_Hot_Key(const Utf16String &key) { if (!key.Is_Empty()) { @@ -50,8 +56,8 @@ void HotKeyManager::Add_Hot_Key(GameWindow *window, const Utf8String &key) window->Win_Get_Instance_Data()->m_decoratedNameString.Str()); } else { HotKey hotkey; - hotkey.m_key = key; + hotkey.m_key.Set(key_lower); hotkey.m_window = window; - m_hotKeys[key] = hotkey; + m_hotKeys[key_lower] = hotkey; } } diff --git a/src/game/client/messagestream/hotkey.h b/src/game/client/messagestream/hotkey.h index bba73ac77..ed34ddb79 100644 --- a/src/game/client/messagestream/hotkey.h +++ b/src/game/client/messagestream/hotkey.h @@ -25,8 +25,8 @@ class HotKey HotKey() : m_window(nullptr) {} private: - Utf8String m_key; GameWindow *m_window; + Utf8String m_key; friend class HotKeyManager; }; @@ -38,6 +38,7 @@ class HotKeyManager : public SubsystemInterface virtual void Init() override; virtual void Reset() override; virtual void Update() override; + Utf8String Search_Hot_Key(const Utf8String &str); Utf8String Search_Hot_Key(const Utf16String &str); void Add_Hot_Key(GameWindow *window, const Utf8String &key); diff --git a/src/game/common/gameengine.cpp b/src/game/common/gameengine.cpp index 727de9fd0..c10e1f1d2 100644 --- a/src/game/common/gameengine.cpp +++ b/src/game/common/gameengine.cpp @@ -89,20 +89,6 @@ GameEngine *g_theGameEngine = nullptr; #endif -void Hide_Control_Bar(bool hide) -{ -#ifdef GAME_DLL - Call_Function(PICK_ADDRESS(0x0048A3E0, 0x009DF7F2), hide); -#endif -} - -void Show_Control_Bar(bool show) -{ -#ifdef GAME_DLL - Call_Function(PICK_ADDRESS(0x0048A250, 0x009DF683), show); -#endif -} - GameEngine::GameEngine() : m_maxFPS(0), m_isQuitting(false), m_isActive(false) { #ifdef PLATFORM_WINDOWS diff --git a/src/game/common/ini/ini.cpp b/src/game/common/ini/ini.cpp index 478587107..b632838f6 100644 --- a/src/game/common/ini/ini.cpp +++ b/src/game/common/ini/ini.cpp @@ -20,6 +20,7 @@ #include "challengegenerals.h" #include "color.h" #include "colorspace.h" +#include "controlbar.h" #include "coord.h" #include "file.h" #include "filesystem.h" @@ -84,9 +85,9 @@ const BlockParse TheTypeTable[] = { {"Bridge", &TerrainRoadCollection::Parse_Terrain_Bridge_Definition}, {"Campaign", HOOK_BLOCK(0x00517490) /*&INI::parseCampaignDefinition*/}, {"ChallengeGenerals", ChallengeGenerals::Parse_Challenge_Mode_Definition}, - {"CommandButton", HOOK_BLOCK(0x00516CE0) /*&INI::parseCommandButtonDefinition*/}, + {"CommandButton", &ControlBar::Parse_Command_Button_Definition}, {"CommandMap", HOOK_BLOCK(0x00498480) /*&INI::parseMetaMapDefinition*/}, - {"CommandSet", HOOK_BLOCK(0x00516CD0) /*&INI::parseCommandSetDefinition*/}, + {"CommandSet", &ControlBar::Parse_Command_Set_Definition}, {"ControlBarScheme", HOOK_BLOCK(0x00516BA0) /*&INI::parseControlBarSchemeDefinition*/}, {"ControlBarResizer", &INI::Parse_Control_Bar_Resizer_Definition}, {"CrateData", HOOK_BLOCK(0x00516B90) /*&INI::parseCrateTemplateDefinition*/}, @@ -1129,7 +1130,7 @@ void INI::Parse_Upgrade_Template(INI *ini, void *formal, void *store, const void captainslog_relassert(g_theUpgradeCenter != nullptr, CODE_01, "TheUpgradeCenter not inited yet"); const UpgradeTemplate **tmplate = static_cast(store); const UpgradeTemplate *upgrade_template = g_theUpgradeCenter->Find_Upgrade(name); - captainslog_dbgassert(upgrade_template != nullptr, "Upgrade %s not found!", name); + captainslog_dbgassert(upgrade_template != nullptr || strcasecmp(name, "None") == 0, "Upgrade %s not found!", name); *tmplate = upgrade_template; } @@ -1139,7 +1140,7 @@ void INI::Parse_Special_Power_Template(INI *ini, void *formal, void *store, cons captainslog_relassert(g_theSpecialPowerStore != nullptr, CODE_01, "TheSpecialPowerStore not inited yet"); const SpecialPowerTemplate **tmplate = static_cast(store); const SpecialPowerTemplate *special_power_template = g_theSpecialPowerStore->Find_Special_Power_Template(name); - captainslog_dbgassert(special_power_template != nullptr && strcasecmp(name, "None") == 0, + captainslog_dbgassert(special_power_template != nullptr || strcasecmp(name, "None") == 0, "[LINE: %d in '%s'] Specialpower %s not found!", ini->Get_Line_Number(), ini->Get_Filename().Str(), diff --git a/src/game/common/rts/productionprerequisite.cpp b/src/game/common/rts/productionprerequisite.cpp index 4f0eab7a6..09c06d126 100644 --- a/src/game/common/rts/productionprerequisite.cpp +++ b/src/game/common/rts/productionprerequisite.cpp @@ -128,14 +128,14 @@ Utf16String ProductionPrerequisite::Get_Requires_List(const Player *player) cons for (int i = 0; i < num; i++) { if (counts[i] == 0) { if (required[i]) { - str2 = m_prereqUnit[i - 1].unit->Get_Name(); + str2 = m_prereqUnit[i - 1].unit->Get_Display_Name(); str2.Concat(U_CHAR(' ')); str2.Concat(g_theGameText->Fetch("CONTROLBAR:OrRequirement")); str2.Concat(U_CHAR(' ')); str.Concat(str2); } - str2 = m_prereqUnit[i].unit->Get_Name(); + str2 = m_prereqUnit[i].unit->Get_Display_Name(); if (newline) { newline = false; diff --git a/src/game/common/system/buildassistant.cpp b/src/game/common/system/buildassistant.cpp index b86ad3c4f..2d4e77d4d 100644 --- a/src/game/common/system/buildassistant.cpp +++ b/src/game/common/system/buildassistant.cpp @@ -176,7 +176,7 @@ CanMakeType BuildAssistant::Can_Make_Unit(Object *constructor_object, const Thin return Call_Method( PICK_ADDRESS(0x004B53E0, 0x009FAC20), this, constructor_object, what); #else - return CAN_MAKE_UNK; + return CAN_MAKE_SUCCESS; #endif } diff --git a/src/game/common/system/buildassistant.h b/src/game/common/system/buildassistant.h index ff0f34520..deefc5032 100644 --- a/src/game/common/system/buildassistant.h +++ b/src/game/common/system/buildassistant.h @@ -25,8 +25,13 @@ class Player; enum CanMakeType { - CAN_MAKE_UNK, - CAN_MAKE_UNK2 = 4, + CAN_MAKE_SUCCESS, + CAN_MAKE_IMPOSSIBLE, + CAN_MAKE_NOT_ENOUGH_MONEY, + CAN_MAKE_NOT_ENABLED, + CAN_MAKE_QUEUE_FULL, + CAN_MAKE_PARKING_FULL, + CAN_MAKE_MAXIMUM_NUMBER, }; class BuildAssistant : public SubsystemInterface diff --git a/src/game/logic/ai/aigroup.cpp b/src/game/logic/ai/aigroup.cpp index 7468e6631..0894a685f 100644 --- a/src/game/logic/ai/aigroup.cpp +++ b/src/game/logic/ai/aigroup.cpp @@ -2399,7 +2399,7 @@ void AIGroup::Queue_Upgrade(UpgradeTemplate *upgrade) ProductionUpdateInterface *production = member_obj->Get_Production_Update_Interface(); if (production != nullptr) { - if (production->Can_Queue_Upgrade(upgrade) != CAN_MAKE_UNK2) { + if (production->Can_Queue_Upgrade(upgrade) != CAN_MAKE_QUEUE_FULL) { production->Queue_Upgrade(upgrade); } } diff --git a/src/game/logic/object/behavior/behaviormodule.h b/src/game/logic/object/behavior/behaviormodule.h index 8eeb8ffe4..227ba7b36 100644 --- a/src/game/logic/object/behavior/behaviormodule.h +++ b/src/game/logic/object/behavior/behaviormodule.h @@ -95,13 +95,13 @@ class ProductionEntry : public MemoryPoolObject virtual ~ProductionEntry() override; ProductionID Get_Production_ID() const { return m_productionID; } - const ThingTemplate *Get_Production_Object() const { return m_objectToProduce; } + const UpgradeTemplate *Get_Production_Object() const { return m_objectToProduce; } int Get_Type() const { return m_type; } float Get_Percent_Complete() const { return m_percentComplete; } private: int m_type; - ThingTemplate *m_objectToProduce; + UpgradeTemplate *m_objectToProduce; ProductionID m_productionID; float m_percentComplete; int m_framesUnderConstruction; diff --git a/src/game/logic/object/create/createmodule.cpp b/src/game/logic/object/create/createmodule.cpp new file mode 100644 index 000000000..a70a458a2 --- /dev/null +++ b/src/game/logic/object/create/createmodule.cpp @@ -0,0 +1,15 @@ +/** + * @file + * + * @author Jonathan Wilson + * + * @brief Create + * + * @copyright Thyme is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version + * 2 of the License, or (at your option) any later version. + * A full copy of the GNU General Public License can be found in + * LICENSE + */ +#include "createmodule.h" diff --git a/src/game/logic/object/create/createmodule.h b/src/game/logic/object/create/createmodule.h new file mode 100644 index 000000000..1038f52dd --- /dev/null +++ b/src/game/logic/object/create/createmodule.h @@ -0,0 +1,23 @@ +/** + * @file + * + * @author Jonathan Wilson + * + * @brief Create + * + * @copyright Thyme is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version + * 2 of the License, or (at your option) any later version. + * A full copy of the GNU General Public License can be found in + * LICENSE + */ +#pragma once +#include "always.h" +#include "behaviormodule.h" + +class CreateModuleData : public BehaviorModuleData +{ +public: + virtual ~CreateModuleData() override; +}; diff --git a/src/game/logic/object/create/veterancygaincreate.cpp b/src/game/logic/object/create/veterancygaincreate.cpp new file mode 100644 index 000000000..9df9424ee --- /dev/null +++ b/src/game/logic/object/create/veterancygaincreate.cpp @@ -0,0 +1,15 @@ +/** + * @file + * + * @author Jonathan Wilson + * + * @brief Veterancy Gain Create + * + * @copyright Thyme is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version + * 2 of the License, or (at your option) any later version. + * A full copy of the GNU General Public License can be found in + * LICENSE + */ +#include "veterancygaincreate.h" diff --git a/src/game/logic/object/create/veterancygaincreate.h b/src/game/logic/object/create/veterancygaincreate.h new file mode 100644 index 000000000..bca19b837 --- /dev/null +++ b/src/game/logic/object/create/veterancygaincreate.h @@ -0,0 +1,28 @@ +/** + * @file + * + * @author Jonathan Wilson + * + * @brief Veterancy Gain Create + * + * @copyright Thyme is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version + * 2 of the License, or (at your option) any later version. + * A full copy of the GNU General Public License can be found in + * LICENSE + */ +#pragma once +#include "always.h" +#include "createmodule.h" + +class VeterancyGainCreateModuleData : public CreateModuleData +{ +public: + virtual ~VeterancyGainCreateModuleData() override; + +private: + VeterancyLevel m_startingLevel; + ScienceType m_scienceRequired; + friend class ControlBar; +}; diff --git a/src/game/logic/system/gamelogic.cpp b/src/game/logic/system/gamelogic.cpp index 5418c99d4..725b89235 100644 --- a/src/game/logic/system/gamelogic.cpp +++ b/src/game/logic/system/gamelogic.cpp @@ -74,9 +74,6 @@ GameLogic *g_theGameLogic; #endif -void Hide_Control_Bar(bool hide); -void Show_Control_Bar(bool hide); - GameLogic::GameLogic() : m_width(0.0f), m_height(0.0f), diff --git a/src/game/logic/system/gamelogicdispatch.cpp b/src/game/logic/system/gamelogicdispatch.cpp index 220d2c27a..19503d4cf 100644 --- a/src/game/logic/system/gamelogicdispatch.cpp +++ b/src/game/logic/system/gamelogicdispatch.cpp @@ -12,6 +12,7 @@ * A full copy of the GNU General Public License can be found in * LICENSE */ +#include "controlbar.h" #include "gameengine.h" #include "gamelogic.h" #include "gamemessage.h" @@ -28,8 +29,6 @@ #include "hooker.h" #endif -void Hide_Control_Bar(bool hide); - void Fixup_Score_Screen_Movie_Window() { #ifdef GAME_DLL diff --git a/src/hooker/setupglobals_zh.cpp b/src/hooker/setupglobals_zh.cpp index b2032b220..dc675580f 100644 --- a/src/hooker/setupglobals_zh.cpp +++ b/src/hooker/setupglobals_zh.cpp @@ -832,3 +832,7 @@ HeaderTemplateManager *&g_theHeaderTemplateManager = // hotkey.cpp class HotKeyManager; HotKeyManager *&g_theHotKeyManager = Make_Global(PICK_ADDRESS(0x00A2C678, 0x04CA8B00)); + +// disconnectmenu.cpp +class DisconnectMenu; +DisconnectMenu *&g_theDisconnectMenu = Make_Global(PICK_ADDRESS(0x00A31DA0, 0x04CAD314)); diff --git a/src/hooker/setuphooks_zh.cpp b/src/hooker/setuphooks_zh.cpp index e2171a7fc..d12bf0634 100644 --- a/src/hooker/setuphooks_zh.cpp +++ b/src/hooker/setuphooks_zh.cpp @@ -43,6 +43,8 @@ #include "commandline.h" #include "commandlist.h" #include "compressionmanager.h" +#include "controlbar.h" +#include "controlbarscheme.h" #include "copyprotect.h" #include "datachunk.h" #include "ddsfile.h" @@ -3502,4 +3504,63 @@ void Setup_Hooks() // windowvideomanager.h Hook_Any(0x005A9D00, WindowVideoManager::Hook_Ctor); Hook_Any(0x005AA400, WindowVideoManager::Load_Movie); + + // controlbar.h + Hook_Any(0x0045CB00, CommandSet::Get_Command_Button); + Hook_Method(0x0045C3B0, + static_cast(&CommandButton::Is_Valid_Object_Target)); + Hook_Method(0x0045C430, + static_cast(&CommandButton::Is_Valid_Object_Target)); + Hook_Any(0x0045C4A0, CommandButton::Is_Valid_To_Use_On); + Hook_Any(0x0045C5F0, CommandButton::Is_Ready); + Hook_Method(0x0045C660, + static_cast( + &CommandButton::Is_Valid_Object_Target)); + Hook_Any(0x0045C6E0, CommandButton::Is_Context_Command); + Hook_Any(0x0045C6F0, CommandButton::Copy_Images_From); + Hook_Any(0x0045C720, CommandButton::Copy_Button_Text_From); + Hook_Any(0x0045CBF0, ControlBar::Hook_Ctor); + Hook_Any(0x00460A80, ControlBar::Update_Command_Bar_Border_Colors); + Hook_Any(0x0045D010, ControlBar::Init); + Hook_Any(0x00461620, ControlBar::Get_Background_Marker_Pos); + Hook_Any(0x0045FD00, ControlBar::Set_Control_Command); + Hook_Any(0x0045E2A0, ControlBar::Reset); + Hook_Any(0x0045E4C0, ControlBar::Update); + Hook_Any(0x0045EAE0, ControlBar::Get_Star_Image); + Hook_Any(0x0045FEF0, ControlBar::Set_Portrait_By_Object); + Hook_Any(0x00462960, ControlBar::Hide_Special_Power_Shortcut); + Hook_Any(0x0045B3F0, ControlBar::Mark_UI_Dirty); + Hook_Any(0x00460AB0, ControlBar::Hide_Communicator); + Hook_Any(0x0045F0A0, ControlBar::Find_Non_Const_Command_Button); + Hook_Any(0x0045F650, ControlBar::Find_Non_Const_Command_Set); + Hook_Any(0x0045F770, ControlBar::Find_Command_Set); + Hook_Any(0x0045F6D0, ControlBar::Find_Command_Button); + Hook_Any(0x0045F130, ControlBar::New_Command_Button); + Hook_Any(0x0045F250, ControlBar::New_Command_Button_Override); + + Hook_Any(0x005A3750, ControlBar::Reset_Contain_Data); + Hook_Any(0x005A3770, ControlBar::Reset_Build_Queue_Data); + Hook_Any(0x005A3020, ControlBar::Populate_Inv_Data_Callback); + Hook_Any(0x005A4060, ControlBar::Calculate_Veterancy_Overlay_For_Object); + Hook_Any(0x005A3DD0, ControlBar::Calculate_Veterancy_Overlay_For_Thing); + + Hook_Any(0x005AC680, ControlBar::Process_Command_UI); + + Hook_Any(0x005AB280, ControlBar::Populate_Button_Proc); + Hook_Any(0x005AB640, ControlBar::Update_Context_Structure_Inventory); + Hook_Any(0x005AB320, ControlBar::Populate_Structure_Inventory); + + Hook_Any(0x005AB080, ControlBar::Update_Context_Under_Construction); + Hook_Any(0x005AAE70, ControlBar::Update_Construction_Text_Display); + + Hook_Any(0x005A7870, Control_Bar_Popup_Description_Update_Func); + Hook_Any(0x005A79F0, ControlBar::Show_Build_Tooltip_Layout); + Hook_Any(0x005A7C60, ControlBar::Repopulate_Build_Tooltip_Layout); + Hook_Any(0x005A7CA0, ControlBar::Populate_Build_Tooltip_Layout); + Hook_Any(0x005A8FD0, ControlBar::Delete_Build_Tooltip_Layout); + + // controlbarscheme.h + Hook_Any(0x005A49F0, ControlBarScheme::Reset); + Hook_Any(0x005A6570, ControlBarSchemeManager::Init); + Hook_Any(0x005A6620, ControlBarSchemeManager::Update); }