diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8b24e53d6..71916135c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -10,6 +10,7 @@ set(GAMEENGINE_INCLUDES game/client/gui/disconnectmenu game/client/gui/gadget game/client/gui/guicallbacks + game/client/gui/guicallbacks/menus game/client/gui/shell game/client/input game/client/messagestream @@ -54,6 +55,7 @@ set(GAMEENGINE_INCLUDES platform/w3dengine/client/drawable/draw platform/w3dengine/client/gui platform/w3dengine/client/gui/gadget + platform/w3dengine/client/gui/guicallbacks platform/w3dengine/client/shadow platform/w3dengine/client/water platform/w3dengine/common @@ -129,6 +131,11 @@ set(GAMEENGINE_SRC game/client/gui/gamewindowtransitionsstyles.cpp game/client/gui/guicallbacks/controlbarcallback.cpp game/client/gui/guicallbacks/controlbarpopupdescription.cpp + game/client/gui/guicallbacks/diplomacy.cpp + game/client/gui/guicallbacks/generalsexppoints.cpp + game/client/gui/guicallbacks/ingamechat.cpp + game/client/gui/guicallbacks/menus/quitmenu.cpp + game/client/gui/guicallbacks/skirmishgameoptionsmenu.cpp game/client/gui/headertemplate.cpp game/client/gui/imemanager.cpp game/client/gui/imemanagerinterface.cpp @@ -332,6 +339,7 @@ set(GAMEENGINE_SRC game/logic/object/update/autodepositupdate.cpp game/logic/object/update/battleplanupdate.cpp game/logic/object/update/laserupdate.cpp + game/logic/object/update/oclupdate.cpp game/logic/object/update/physicsupdate.cpp game/logic/object/update/projectilestreamupdate.cpp game/logic/object/update/specialabilityupdate.cpp @@ -415,6 +423,7 @@ set(GAMEENGINE_SRC platform/w3dengine/client/gui/gadget/w3dtabcontrol.cpp platform/w3dengine/client/gui/gadget/w3dtextentry.cpp platform/w3dengine/client/gui/gadget/w3dverticalslider.cpp + platform/w3dengine/client/gui/guicallbacks/w3dcontrolbar.cpp platform/w3dengine/client/gui/w3dgamefont.cpp platform/w3dengine/client/gui/w3dgamewindow.cpp platform/w3dengine/client/gui/w3dgamewindowmanager.cpp diff --git a/src/game/client/gui/controlbar/controlbar.cpp b/src/game/client/gui/controlbar/controlbar.cpp index 2fb10be77..12a2eef94 100644 --- a/src/game/client/gui/controlbar/controlbar.cpp +++ b/src/game/client/gui/controlbar/controlbar.cpp @@ -23,17 +23,21 @@ #include "drawable.h" #include "gadgetprogressbar.h" #include "gadgetpushbutton.h" +#include "gadgetstatictext.h" #include "gameclient.h" #include "gamelogic.h" +#include "gametext.h" #include "gamewindowmanager.h" #include "gamewindowtransitions.h" #include "hotkey.h" #include "image.h" +#include "ingamechat.h" #include "multiplayersettings.h" #include "object.h" #include "player.h" #include "playerlist.h" #include "playertemplate.h" +#include "rebuildholebehavior.h" #include "recorder.h" #include "scriptengine.h" #include "specialpower.h" @@ -1837,51 +1841,1142 @@ void ControlBar::Trigger_Radar_Attack_Glow() } } +void ControlBar::Toggle_Purchase_Science() +{ + if (m_contextParent[1]->Win_Is_Hidden()) { + Show_Purchase_Science(); + } else { + Hide_Purchase_Science(); + } +} + +void ControlBar::Hide_Purchase_Science() +{ + if (m_contextParent[1] != nullptr) { + if (!m_contextParent[1]->Win_Is_Hidden()) { + m_contextParent[1]->Win_Hide(true); + } + } +} + +void ControlBar::Show_Special_Power_Shortcut() +{ + if (!g_theScriptEngine->Is_End_Game_Timer_Running() && m_specialPowerShortcutBarParent != nullptr + && g_thePlayerList != nullptr && g_thePlayerList->Get_Local_Player() != nullptr) { + bool missing = true; + + for (int i = 0; i < m_specialPowerShortcutButtonCount; i++) { + if (m_specialPowerShortcutButtons[i]->Win_Get_User_Data()) { + missing = false; + break; + } + } + + if (!missing) { + if (g_thePlayerList->Get_Local_Player()->Has_Any_Shortcut_Special_Power() || Has_Any_Shortcut_Selection()) { + m_specialPowerShortcutBarParent->Win_Hide(false); + Populate_Special_Power_Shortcut(g_thePlayerList->Get_Local_Player()); + } + } + } +} + +void ControlBar::Show_Purchase_Science() +{ + if (!g_theScriptEngine->Is_End_Game_Timer_Running()) { + Populate_Purchase_Science(g_thePlayerList->Get_Local_Player()); + m_starHilight = false; + + if (m_contextParent[1]->Win_Is_Hidden()) { + m_contextParent[1]->Win_Hide(false); + + if (g_theWriteableGlobalData->m_animateWindows) { + g_theTransitionHandler->Set_Group("GenExpFade", false); + } + } + } +} + +void ControlBar::Populate_Purchase_Science(Player *player) +{ + if (g_theScriptEngine->Is_End_Game_Timer_Running()) { + return; + } + + if (player == nullptr) { + return; + } + + if (player->Get_Player_Template() == nullptr) { + return; + } + + if (player->Get_Player_Template()->Get_Purchase_Command_Set_Rank_One().Is_Empty()) { + return; + } + + if (player->Get_Player_Template()->Get_Purchase_Command_Set_Rank_Three().Is_Empty()) { + return; + } + + if (player->Get_Player_Template()->Get_Purchase_Command_Set_Rank_Eight().Is_Empty()) { + return; + } + + const CommandSet *command_set_one = + g_theControlBar->Find_Command_Set(player->Get_Player_Template()->Get_Purchase_Command_Set_Rank_One()); + const CommandSet *command_set_three = + g_theControlBar->Find_Command_Set(player->Get_Player_Template()->Get_Purchase_Command_Set_Rank_Three()); + const CommandSet *command_set_eight = + g_theControlBar->Find_Command_Set(player->Get_Player_Template()->Get_Purchase_Command_Set_Rank_Eight()); + + for (int i = 0; i < RANK_1_BUTTON_COUNT; i++) { + m_rank1Buttons[i]->Win_Hide(true); + } + + for (int i = 0; i < RANK_3_BUTTON_COUNT; i++) { + m_rank3Buttons[i]->Win_Hide(true); + } + + for (int i = 0; i < RANK_8_BUTTON_COUNT; i++) { + m_rank8Buttons[i]->Win_Hide(true); + } + + if (command_set_one == nullptr || command_set_three == nullptr || command_set_eight == nullptr) { + return; + } + + for (int i = 0; i < RANK_1_BUTTON_COUNT; i++) { + const CommandButton *command_button = command_set_one->Get_Command_Button(i); + + if (command_button == nullptr || (command_button->Get_Options() & COMMAND_OPTION_SCRIPT_ONLY) != 0) { + m_rank1Buttons[i]->Win_Hide(true); + continue; + } + + m_rank1Buttons[i]->Win_Hide(false); + m_rank1Buttons[i]->Win_Enable(false); + Set_Control_Command(m_rank1Buttons[i], command_button); + + if (!command_button->Get_Sciences()->empty()) { + ScienceType science = (*command_button->Get_Sciences())[0]; + + if (player->Is_Science_Disabled(science)) { + m_rank1Buttons[i]->Win_Enable(false); + continue; + } + + if (player->Is_Science_Hidden(science)) { + m_rank1Buttons[i]->Win_Hide(true); + continue; + } + + if (!player->Has_Science(science)) { + if (g_theScienceStore->Player_Has_Prereqs_For_Science(player, science)) { + if (g_theScienceStore->Get_Science_Purchase_Cost(science) <= player->Get_Science_Purchase_Points()) { + m_rank1Buttons[i]->Win_Enable(true); + } + } + } + + if (player->Has_Science(science)) { + m_rank1Buttons[i]->Win_Set_Status(WIN_STATUS_ALWAYS_COLOR); + } else { + m_rank1Buttons[i]->Win_Clear_Status(WIN_STATUS_ALWAYS_COLOR); + } + + if (!g_theScienceStore->Player_Has_Root_Prereqs_For_Science(player, science)) { + m_rank1Buttons[i]->Win_Hide(true); + } + } + } + + for (int i = 0; i < RANK_3_BUTTON_COUNT; i++) { + const CommandButton *command_button = command_set_three->Get_Command_Button(i); + + if (command_button == nullptr || (command_button->Get_Options() & COMMAND_OPTION_SCRIPT_ONLY) != 0) { + m_rank3Buttons[i]->Win_Hide(true); + continue; + } + + m_rank3Buttons[i]->Win_Hide(false); + m_rank3Buttons[i]->Win_Enable(false); + Set_Control_Command(m_rank3Buttons[i], command_button); + + if (!command_button->Get_Sciences()->empty()) { + ScienceType science = (*command_button->Get_Sciences())[0]; + + if (player->Is_Science_Disabled(science)) { + m_rank3Buttons[i]->Win_Enable(false); + continue; + } + + if (player->Is_Science_Hidden(science)) { + m_rank3Buttons[i]->Win_Hide(true); + continue; + } + + if (!player->Has_Science(science)) { + if (g_theScienceStore->Player_Has_Prereqs_For_Science(player, science)) { + if (g_theScienceStore->Get_Science_Purchase_Cost(science) <= player->Get_Science_Purchase_Points()) { + m_rank3Buttons[i]->Win_Enable(true); + } + } + } + + if (player->Has_Science(science)) { + m_rank3Buttons[i]->Win_Set_Status(WIN_STATUS_ALWAYS_COLOR); + } else { + m_rank3Buttons[i]->Win_Clear_Status(WIN_STATUS_ALWAYS_COLOR); + } + + if (!g_theScienceStore->Player_Has_Root_Prereqs_For_Science(player, science)) { + m_rank3Buttons[i]->Win_Hide(true); + } + } + } + + for (int i = 0; i < RANK_8_BUTTON_COUNT; i++) { + const CommandButton *command_button = command_set_eight->Get_Command_Button(i); + + if (command_button == nullptr || (command_button->Get_Options() & COMMAND_OPTION_SCRIPT_ONLY) != 0) { + m_rank8Buttons[i]->Win_Hide(true); + continue; + } + + m_rank8Buttons[i]->Win_Hide(false); + m_rank8Buttons[i]->Win_Enable(false); + Set_Control_Command(m_rank8Buttons[i], command_button); + + if (!command_button->Get_Sciences()->empty()) { + ScienceType science = (*command_button->Get_Sciences())[0]; + + if (player->Is_Science_Disabled(science)) { + m_rank8Buttons[i]->Win_Enable(false); + continue; + } + + if (player->Is_Science_Hidden(science)) { + m_rank8Buttons[i]->Win_Hide(true); + continue; + } + + if (!player->Has_Science(science)) { + if (g_theScienceStore->Player_Has_Prereqs_For_Science(player, science)) { + if (g_theScienceStore->Get_Science_Purchase_Cost(science) <= player->Get_Science_Purchase_Points()) { + m_rank8Buttons[i]->Win_Enable(true); + } + } + } + + if (player->Has_Science(science)) { + m_rank8Buttons[i]->Win_Set_Status(WIN_STATUS_ALWAYS_COLOR); + } else { + m_rank8Buttons[i]->Win_Clear_Status(WIN_STATUS_ALWAYS_COLOR); + } + + if (!g_theScienceStore->Player_Has_Root_Prereqs_For_Science(player, science)) { + m_rank8Buttons[i]->Win_Hide(true); + } + } + } + + Utf16String points; + + GameWindow *window = g_theWindowManager->Win_Get_Window_From_Id( + m_contextParent[1], g_theNameKeyGenerator->Name_To_Key("GeneralsExpPoints.wnd:StaticTextRankPointsAvailable")); + + if (window != nullptr) { + points.Format(U_CHAR("%d"), player->Get_Science_Purchase_Points()); + Gadget_Static_Text_Set_Text(window, points); + } + + 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())); + } + + window = g_theWindowManager->Win_Get_Window_From_Id( + m_contextParent[1], g_theNameKeyGenerator->Name_To_Key("GeneralsExpPoints.wnd:StaticTextTitle")); + + if (window != nullptr) { + Utf8String text; + text.Format("SCIENCE:Rank%d", player->Get_Rank_Level()); + Gadget_Static_Text_Set_Text(window, g_theGameText->Fetch(text)); + } + + Update_Context_Purchase_Science(); +} + +void ControlBar::Animate_Special_Power_Shortcut(bool forward) +{ + if (m_specialPowerShortcutBarParent != nullptr && m_specialPowerShortcutAnimateWindowManager != nullptr + && m_specialPowerShortcutButtonCount != 0) { + bool notfound = true; + + for (int i = 0; i < m_specialPowerShortcutButtonCount; i++) { + if (m_specialPowerShortcutButtons[i]->Win_Get_User_Data() != nullptr) { + notfound = false; + break; + } + } + + if (!notfound) { + if (forward) { + m_specialPowerShortcutAnimateWindowManager->Reset(); + m_specialPowerShortcutAnimateWindowManager->Register_Game_Window( + m_specialPowerShortcutBarParent, WIN_ANIMATION_SLIDE_RIGHT, true, 500, 0); + } else { + m_specialPowerShortcutAnimateWindowManager->Reverse_Animate_Window(); + } + } + } +} + +CBCommandStatus ControlBar::Process_Context_Sensitive_Button_Click(GameWindow *button, GadgetGameMessage gadget_message) +{ + return Process_Command_UI(button, gadget_message); +} + +bool ControlBar::Has_Any_Shortcut_Selection() +{ + for (int i = 0; i < m_specialPowerShortcutButtonCount; i++) { + if (m_specialPowerShortcutButtons[i] != nullptr) { + CommandButton *button = static_cast(Gadget_Button_Get_Data(m_specialPowerShortcutButtons[i])); + + if (button != nullptr) { + if (button->Get_Command() == GUI_COMMAND_SELECT_ALL_UNITS_OF_TYPE) { + return true; + } + } + } + } + + return false; +} + void ControlBar::Set_Control_Bar_Scheme_By_Player(Player *p) { -#ifdef GAME_DLL - Call_Method(PICK_ADDRESS(0x00460340, 0x0072F421), this, p); -#endif + if (m_controlBarSchemeManager != nullptr) { + m_controlBarSchemeManager->Set_Control_Bar_Scheme_By_Player(p); + } + + static const NameKeyType buttonPlaceBeaconID = g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:ButtonPlaceBeacon"); + static const NameKeyType buttonIdleWorkerID = g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:ButtonIdleWorker"); + static const NameKeyType buttonGeneralID = g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:ButtonGeneral"); + GameWindow *place_beacon = g_theWindowManager->Win_Get_Window_From_Id(nullptr, buttonPlaceBeaconID); + GameWindow *idle_worker = g_theWindowManager->Win_Get_Window_From_Id(nullptr, buttonIdleWorkerID); + GameWindow *general = g_theWindowManager->Win_Get_Window_From_Id(nullptr, buttonGeneralID); + + if (p->Is_Player_Active()) { + Switch_To_Context(CB_CONTEXT_NONE, nullptr); + m_isObserver = false; + + if (place_beacon != nullptr) { + if ((g_theGameLogic->Get_Game_Mode() == GAME_LAN || g_theGameLogic->Get_Game_Mode() == GAME_INTERNET) + && g_theGameInfo->Is_Multi_Player()) { + place_beacon->Win_Hide(false); + } else { + place_beacon->Win_Hide(true); + } + } + + if (idle_worker != nullptr) { + idle_worker->Win_Hide(false); + } + + if (general != nullptr) { + general->Win_Hide(false); + general->Win_Enable(true); + } + } else { + m_isObserver = true; + Switch_To_Context(CB_CONTEXT_OBSERVER, nullptr); + captainslog_debug("We're loading the Observer Command Bar"); + + if (place_beacon != nullptr) { + place_beacon->Win_Hide(true); + } + + if (idle_worker != nullptr) { + idle_worker->Win_Hide(true); + } + + if (general != nullptr) { + general->Win_Enable(false); + } + } + + Switch_Control_Bar_Stage(CONTROL_BAR_STAGE_DEFAULT); } void ControlBar::Set_Control_Bar_Scheme_By_Player_Template(PlayerTemplate *tmplate) { -#ifdef GAME_DLL - Call_Method(PICK_ADDRESS(0x004606B0, 0x0072F642), this, tmplate); -#endif + if (m_controlBarSchemeManager != nullptr) { + m_controlBarSchemeManager->Set_Control_Bar_Scheme_By_Player_Template(tmplate, false); + } + + static const NameKeyType buttonPlaceBeaconID = g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:ButtonPlaceBeacon"); + static const NameKeyType buttonIdleWorkerID = g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:ButtonIdleWorker"); + static const NameKeyType buttonGeneralID = g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:ButtonGeneral"); + GameWindow *place_beacon = g_theWindowManager->Win_Get_Window_From_Id(nullptr, buttonPlaceBeaconID); + GameWindow *idle_worker = g_theWindowManager->Win_Get_Window_From_Id(nullptr, buttonIdleWorkerID); + GameWindow *general = g_theWindowManager->Win_Get_Window_From_Id(nullptr, buttonGeneralID); + + if (tmplate == g_thePlayerTemplateStore->Find_Player_Template(g_theNameKeyGenerator->Name_To_Key("FactionObserver"))) { + m_isObserver = true; + Switch_To_Context(CB_CONTEXT_OBSERVER, nullptr); + captainslog_debug("We're loading the Observer Command Bar"); + + if (place_beacon != nullptr) { + place_beacon->Win_Hide(true); + } + + if (idle_worker != nullptr) { + idle_worker->Win_Hide(true); + } + + if (general != nullptr) { + general->Win_Enable(false); + } + } else { + Switch_To_Context(CB_CONTEXT_NONE, nullptr); + m_isObserver = false; + + if (place_beacon != nullptr) { + if ((g_theGameLogic->Get_Game_Mode() == GAME_LAN || g_theGameLogic->Get_Game_Mode() == GAME_INTERNET) + && g_theGameInfo->Is_Multi_Player()) { + place_beacon->Win_Hide(false); + } else { + place_beacon->Win_Hide(true); + } + } + + if (idle_worker != nullptr) { + idle_worker->Win_Hide(false); + } + + if (general != nullptr) { + general->Win_Hide(false); + general->Win_Enable(true); + } + } + + Switch_Control_Bar_Stage(CONTROL_BAR_STAGE_DEFAULT); + Hide_Purchase_Science(); } void ControlBar::Init_Special_Power_Shortcut_Bar(Player *player) { -#ifdef GAME_DLL - Call_Method(PICK_ADDRESS(0x00461680, 0x0073027A), this, player); -#endif + for (int i = 0; i < SPECIAL_POWER_SHORTCUT_BUTTON_COUNT; i++) { + m_specialPowerShortcutButtonParents[i] = nullptr; + m_specialPowerShortcutButtons[i] = nullptr; + } + + if (m_specialPowerShortcutBarLayout != nullptr) { + m_specialPowerShortcutBarLayout->Destroy_Windows(); + m_specialPowerShortcutBarLayout->Delete_Instance(); + m_specialPowerShortcutBarLayout = nullptr; + } + + m_specialPowerShortcutBarParent = nullptr; + m_specialPowerShortcutButtonCount = 0; + const PlayerTemplate *tmplate = player->Get_Player_Template(); + + if (player != nullptr) { + if (tmplate != nullptr) { + if (player->Is_Local_Player()) { + if (tmplate->Get_Special_Power_Shortcut_Button_Count() != 0) { + if (!tmplate->Get_Special_Power_Shortcut_Win_Name().Is_Empty() && player->Is_Player_Active()) { + m_specialPowerShortcutButtonCount = tmplate->Get_Special_Power_Shortcut_Button_Count(); + Utf8String win_name; + Utf8String str1; + Utf8String str2; + Utf8String str3; + win_name = tmplate->Get_Special_Power_Shortcut_Win_Name(); + m_specialPowerShortcutBarLayout = g_theWindowManager->Win_Create_Layout(win_name); + m_specialPowerShortcutBarLayout->Hide(true); + str1 = win_name; + str1.Concat(":GenPowersShortcutBarParent"); + m_specialPowerShortcutBarParent = g_theWindowManager->Win_Get_Window_From_Id( + nullptr, g_theNameKeyGenerator->Name_To_Key(str1.Str())); + str1 = win_name; + str1.Concat(":ButtonCommand%d"); + str3 = win_name; + str3.Concat(":ButtonParent%d"); + + if (tmplate->Get_Special_Power_Shortcut_Button_Count() >= SPECIAL_POWER_SHORTCUT_BUTTON_COUNT) { + m_specialPowerShortcutButtonCount = SPECIAL_POWER_SHORTCUT_BUTTON_COUNT; + } else { + m_specialPowerShortcutButtonCount = tmplate->Get_Special_Power_Shortcut_Button_Count(); + } + + for (int i = 0; i < SPECIAL_POWER_SHORTCUT_BUTTON_COUNT; i++) { + str2.Format(str1, i + 1); + m_specialPowerShortcutButtons[i] = g_theWindowManager->Win_Get_Window_From_Id( + m_specialPowerShortcutBarParent, g_theNameKeyGenerator->Name_To_Key(str2.Str())); + m_specialPowerShortcutButtons[i]->Win_Set_Status(WIN_STATUS_USE_OVERLAY_STATES); + m_specialPowerShortcutButtons[i]->Win_Set_Status(WIN_STATUS_UNK); + str2.Format(str3, i + 1); + m_specialPowerShortcutButtonParents[i] = g_theWindowManager->Win_Get_Window_From_Id( + m_specialPowerShortcutBarParent, g_theNameKeyGenerator->Name_To_Key(str2.Str())); + } + } + } + } + } + } } void ControlBar::Switch_To_Context(ControlBarContext context, Drawable *draw) { -#ifdef GAME_DLL - Call_Method(PICK_ADDRESS(0x0045F8C0, 0x0072E3D0), this, context, draw); -#endif + Set_Portrait_By_Object(nullptr); + Object *obj; + + if (draw != nullptr) { + obj = draw->Get_Object(); + } else { + obj = nullptr; + } + + Set_Portrait_By_Object(obj); + + if (g_theHotKeyManager != nullptr) { + g_theHotKeyManager->Reset(); + } + + g_theInGameUI->Set_Radius_Cursor_None(); + m_currentSelectedDrawable = draw; + + if (!Is_In_Game_Chat_Active() && g_theGameLogic != nullptr && !g_theGameLogic->Is_In_Shell_Game()) { + g_theWindowManager->Win_Set_Focus(nullptr); + } + + switch (context) { + case CB_CONTEXT_NONE: + m_contextParent[2]->Win_Hide(true); + m_contextParent[3]->Win_Hide(true); + m_contextParent[4]->Win_Hide(true); + m_contextParent[5]->Win_Hide(true); + m_contextParent[8]->Win_Hide(true); + m_contextParent[6]->Win_Hide(true); + m_contextParent[7]->Win_Hide(true); + + for (int i = 0; i < CommandSet::MAX_COMMAND_BUTTONS; i++) { + if (m_commandWindows[i]) { + m_commandWindows[i]->Win_Clear_Status(WIN_STATUS_FLASHING); + } + } + + if (draw != nullptr) { + draw->Get_Template(); + Object *object = draw->Get_Object(); + + if (object != nullptr) { + if (object->Is_KindOf(KINDOF_REBUILD_HOLE)) { + RebuildHoleBehaviorInterface *interface = + RebuildHoleBehavior::Get_Rebuild_Hole_Behavior_Interface_From_Object(object); + + if (interface != nullptr) { + interface->Get_Rebuild_Template(); + } + } + } + + Set_Portrait_By_Object(object); + } + + Show_Rally_Point(nullptr); + break; + case CB_CONTEXT_COMMAND: + m_contextParent[2]->Win_Hide(false); + m_contextParent[3]->Win_Hide(true); + m_contextParent[4]->Win_Hide(true); + m_contextParent[5]->Win_Hide(true); + m_contextParent[8]->Win_Hide(true); + m_contextParent[6]->Win_Hide(true); + m_contextParent[7]->Win_Hide(true); + Populate_Command(draw->Get_Object()); + + if (obj != nullptr) { + ProductionUpdateInterface *update = obj->Get_Production_Update_Interface(); + + if (update != nullptr && update->First_Production() != nullptr) { + m_contextParent[3]->Win_Hide(false); + Populate_Build_Queue(obj); + Set_Portrait_By_Object(nullptr); + } else { + Set_Portrait_By_Object(obj); + } + } + break; + case CB_CONTEXT_STRUCTURE_INVENTORY: + m_contextParent[2]->Win_Hide(false); + m_contextParent[3]->Win_Hide(true); + m_contextParent[4]->Win_Hide(true); + m_contextParent[5]->Win_Hide(true); + m_contextParent[8]->Win_Hide(true); + m_contextParent[6]->Win_Hide(true); + m_contextParent[7]->Win_Hide(true); + Populate_Structure_Inventory(draw->Get_Object()); + break; + case CB_CONTEXT_BEACON: + m_contextParent[2]->Win_Hide(true); + m_contextParent[3]->Win_Hide(true); + m_contextParent[4]->Win_Hide(false); + m_contextParent[5]->Win_Hide(true); + m_contextParent[8]->Win_Hide(true); + m_contextParent[6]->Win_Hide(true); + m_contextParent[7]->Win_Hide(true); + Populate_Beacon(draw->Get_Object()); + break; + case CB_CONTEXT_UNDER_CONSTRUCTION: + m_contextParent[2]->Win_Hide(true); + m_contextParent[3]->Win_Hide(true); + m_contextParent[4]->Win_Hide(true); + m_contextParent[5]->Win_Hide(false); + m_contextParent[8]->Win_Hide(true); + m_contextParent[6]->Win_Hide(true); + m_contextParent[7]->Win_Hide(true); + Populate_Under_Construction(draw->Get_Object()); + break; + case CB_CONTEXT_MULTI_SELECT: + m_contextParent[2]->Win_Hide(false); + m_contextParent[3]->Win_Hide(true); + m_contextParent[4]->Win_Hide(true); + m_contextParent[5]->Win_Hide(true); + m_contextParent[8]->Win_Hide(true); + m_contextParent[6]->Win_Hide(true); + m_contextParent[7]->Win_Hide(true); + Populate_Multi_Select(); + break; + case CB_CONTEXT_OBSERVER: + m_contextParent[2]->Win_Hide(true); + m_contextParent[3]->Win_Hide(true); + m_contextParent[4]->Win_Hide(true); + m_contextParent[5]->Win_Hide(true); + m_contextParent[8]->Win_Hide(true); + m_contextParent[6]->Win_Hide(true); + m_contextParent[7]->Win_Hide(false); + Populate_Observer_List(); + break; + case CB_CONTEXT_OCL_TIMER: + m_contextParent[2]->Win_Hide(true); + m_contextParent[3]->Win_Hide(true); + m_contextParent[4]->Win_Hide(true); + m_contextParent[5]->Win_Hide(true); + m_contextParent[8]->Win_Hide(false); + m_contextParent[6]->Win_Hide(true); + m_contextParent[7]->Win_Hide(true); + Populate_OCL_Timer(draw->Get_Object()); + break; + default: + captainslog_dbgassert(false, "ControlBar::Switch_To_Context, unknown context '%d'", context); + break; + } + + m_currContext = context; } void ControlBar::Evaluate_Context_UI() { -#ifdef GAME_DLL - Call_Method(PICK_ADDRESS(0x0045EC00, 0x0072D9A7), this); -#endif + m_UIDirty = false; + + if (!m_contextParent[1]->Win_Is_Hidden()) { + Show_Purchase_Science(); + } + + Switch_To_Context(CB_CONTEXT_NONE, nullptr); + + if (g_theInGameUI->Get_Select_Count() != 0) { + const std::list *drawables = g_theInGameUI->Get_All_Selected_Drawables(); + + if (!drawables->empty()) { + if (g_theInGameUI->Are_Selected_Objects_Controllable()) { + goto l1; + } + + Drawable *draw = drawables->front(); + + if (draw != nullptr) { + Object *object = draw->Get_Object(); + + if (object != nullptr) { + if (object->Get_Controlling_Player() == nullptr) { + goto l2; + } + + if (object->Get_Controlling_Player()->Get_Player_Template() == nullptr) { + goto l2; + } + + if (object->Get_Controlling_Player()->Get_Player_Template()->Get_Beacon_Name().Compare( + object->Get_Template()->Get_Name()) + == 0) { + Switch_To_Context(CB_CONTEXT_BEACON, draw); + } else { + l2: + Switch_To_Context(CB_CONTEXT_NONE, draw); + } + + ContainModuleInterface *contain = object->Get_Contain(); + + if (contain != nullptr) { + if (contain->Get_Contain_Max() > 0) { + const Player *player = + contain->Get_Apparent_Controlling_Player(g_thePlayerList->Get_Local_Player()); + + if (player == nullptr) { + player = object->Get_Controlling_Player(); + } + + Player *local_player = g_thePlayerList->Get_Local_Player(); + + if (local_player != nullptr) { + if (player != nullptr) { + if (contain->Is_Garrisonable() + && local_player->Get_Relationship(player->Get_Default_Team()) == NEUTRAL) { + l1: + Drawable *drawable = nullptr; + bool b = false; + + if (g_theInGameUI->Get_Select_Count() <= 1) { + drawable = drawables->front(); + } else { + drawable = g_theGameClient->Find_Drawable_By_ID( + g_theInGameUI->Get_Solo_Nexus_Selected_Drawable_ID()); + b = drawable == 0; + } + + if (b) { + Switch_To_Context(CB_CONTEXT_MULTI_SELECT, nullptr); + } else if (drawable != nullptr) { + Object *obj = drawable->Get_Object(); + + if (obj != nullptr) { + if (!obj->Get_Status_Bits().Test(OBJECT_STATUS_SOLD)) { + static const NameKeyType key_OCLUpdate = + g_theNameKeyGenerator->Name_To_Key("OCLUpdate"); + UpdateModule *update = obj->Find_Update_Module(key_OCLUpdate); + bool under_construction = false; + + if (obj->Get_Status_Bits().Test(OBJECT_STATUS_UNDER_CONSTRUCTION)) { + Switch_To_Context(CB_CONTEXT_UNDER_CONSTRUCTION, drawable); + under_construction = true; + } + + if (!under_construction) { + ContainModuleInterface *contain_module = obj->Get_Contain(); + + if (contain_module != nullptr && contain_module->Is_Garrisonable() + && obj->Get_Command_Set_String().Is_Empty()) { + if (obj->Is_Locally_Controlled() + || g_thePlayerList->Get_Local_Player()->Get_Relationship( + obj->Get_Team()) + == NEUTRAL) { + Switch_To_Context(CB_CONTEXT_STRUCTURE_INVENTORY, drawable); + } + } else if (update != nullptr) { + Switch_To_Context(CB_CONTEXT_OCL_TIMER, drawable); + } else { + if (obj->Get_Command_Set_String().Is_Empty()) { + if (obj->Get_Controlling_Player() + ->Get_Player_Template() + ->Get_Beacon_Name() + .Compare(obj->Get_Template()->Get_Name()) + == 0) { + Switch_To_Context(CB_CONTEXT_BEACON, drawable); + } else { + Switch_To_Context(CB_CONTEXT_NONE, drawable); + } + } else { + Switch_To_Context(CB_CONTEXT_COMMAND, drawable); + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } } void ControlBar::Update_Special_Power_Shortcut() { -#ifdef GAME_DLL - Call_Method(PICK_ADDRESS(0x00462230, 0x00731139), this); -#endif + if (m_specialPowerShortcutBarParent != nullptr && g_thePlayerList != nullptr && g_thePlayerList->Get_Local_Player()) { + bool has_shortcut = + Has_Any_Shortcut_Selection() || g_thePlayerList->Get_Local_Player()->Has_Any_Shortcut_Special_Power(); + + if (has_shortcut && m_specialPowerShortcutBarParent->Win_Is_Hidden() && m_contextParent[0] != nullptr + && !m_contextParent[0]->Win_Is_Hidden()) { + Show_Special_Power_Shortcut(); + Animate_Special_Power_Shortcut(true); + } else if (!has_shortcut && !m_specialPowerShortcutBarParent->Win_Is_Hidden() + && m_specialPowerShortcutAnimateWindowManager->Is_Finished()) { + Animate_Special_Power_Shortcut(false); + } + + if (!m_specialPowerShortcutBarParent->Win_Is_Hidden()) { + if (g_thePlayerList->Get_Local_Player()->Is_Player_Active()) { + if (m_contextParent[0] != nullptr && !m_contextParent[0]->Win_Is_Hidden() + && m_specialPowerShortcutBarParent->Win_Is_Hidden()) { + Show_Special_Power_Shortcut(); + } + + for (int i = 0; i < m_specialPowerShortcutButtonCount; i++) { + GameWindow *win = m_specialPowerShortcutButtons[i]; + + if (!win->Win_Is_Hidden()) { + CommandButton *button = static_cast(Gadget_Button_Get_Data(win)); + + if (button != nullptr) { + win->Win_Clear_Status(WIN_STATUS_NOT_READY); + win->Win_Clear_Status(WIN_STATUS_ALWAYS_COLOR); + CommandAvailability availability = COMMAND_AVAILABILITY_DISABLED; + Object *obj = nullptr; + + if (button->Get_Special_Power() != nullptr) { + obj = g_thePlayerList->Get_Local_Player()->Find_Most_Ready_Shortcut_Special_Power_Of_Type( + button->Get_Special_Power()->Get_Type()); + availability = Get_Command_Availability(button, obj, win, nullptr, false); + } else if (button->Get_Command() != GUI_COMMAND_SELECT_ALL_UNITS_OF_TYPE) { + availability = COMMAND_AVAILABILITY_HIDDEN; + Object *existing_object = + g_thePlayerList->Get_Local_Player()->Find_Any_Existing_Object_With_Thing_Template( + button->Get_Template()); + + if (existing_object != nullptr) { + availability = COMMAND_AVAILABILITY_ENABLED; + unsigned int percent; + existing_object = g_thePlayerList->Get_Local_Player() + ->Find_Most_Ready_Shortcut_Special_Power_For_Thing( + button->Get_Template(), percent); + + if (existing_object != nullptr) { + const CommandSet *set = Find_Command_Set(existing_object->Get_Command_Set_String()); + + if (set != nullptr) { + for (int j = 0; j < CommandSet::MAX_COMMAND_BUTTONS; j++) { + const CommandButton *command_button = set->Get_Command_Button(j); + GameWindow *window = m_commandWindows[j]; + + if (command_button != nullptr + && button->Get_Command() == GUI_COMMAND_SPECIAL_POWER) { + availability = Get_Command_Availability( + command_button, existing_object, window, win, false); + break; + } + } + } + } + } + } + + switch (availability) { + case COMMAND_AVAILABILITY_DISABLED: + win->Win_Enable(false); + break; + case COMMAND_AVAILABILITY_HIDDEN: + win->Win_Hide(true); + break; + case COMMAND_AVAILABILITY_NOT_READY: + win->Win_Enable(false); + win->Win_Set_Status(WIN_STATUS_NOT_READY); + break; + case COMMAND_AVAILABILITY_DISABLED_PERMANENTLY: + win->Win_Enable(false); + win->Win_Set_Status(WIN_STATUS_ALWAYS_COLOR); + break; + default: + win->Win_Enable(true); + break; + } + } + } + } + } else { + Hide_Special_Power_Shortcut(); + } + } + } } void ControlBar::Populate_Special_Power_Shortcut(Player *player) { -#ifdef GAME_DLL - Call_Method(PICK_ADDRESS(0x00461B10, 0x0073067E), this, player); -#endif + if (player == nullptr || player->Get_Player_Template() == nullptr || !player->Is_Local_Player() + || m_specialPowerShortcutButtonCount == 0) { + return; + } + + for (int i = 0; i < SPECIAL_POWER_SHORTCUT_BUTTON_COUNT; i++) { + if (m_specialPowerShortcutButtons[i] != nullptr) { + m_specialPowerShortcutButtons[i]->Win_Hide(true); + } + + if (m_specialPowerShortcutButtonParents[i] != nullptr) { + m_specialPowerShortcutButtonParents[i]->Win_Hide(true); + } + } + + if (player->Get_Player_Template()->Get_Special_Power_Shortcut_Command_Set().Is_Empty()) { + return; + } + + const CommandSet *set = + g_theControlBar->Find_Command_Set(player->Get_Player_Template()->Get_Special_Power_Shortcut_Command_Set()); + + if (set == nullptr) { + return; + } + + int count = 0; + + for (int i = 0; i < m_specialPowerShortcutButtonCount; i++) { + const CommandButton *button = set->Get_Command_Button(i); + + if (button != nullptr) { + const UpgradeTemplate *upgrade; + if ((button->Get_Options() & COMMAND_OPTION_NEED_UPGRADE) == 0 || (upgrade = button->Get_Upgrade_Template()) == 0 + || g_thePlayerList->Get_Local_Player()->Has_Upgrade_Complete(upgrade->Get_Upgrade_Mask())) { + if ((button->Get_Options() & COMMAND_OPTION_NEED_SPECIAL_POWER_SCIENCE) != 0) { + const SpecialPowerTemplate *power = button->Get_Special_Power(); + + if (power != nullptr) { + if (!g_thePlayerList->Get_Local_Player()->Find_Most_Ready_Shortcut_Special_Power_Of_Type( + power->Get_Type())) { + continue; + } + + if (power->Get_Required_Science() == SCIENCE_INVALID) { + goto l1; + } + + if (!player->Has_Science(power->Get_Required_Science())) { + continue; + } + + int type = -1; + + for (unsigned int j = 0; j < button->Get_Sciences()->size(); type = j++) { + if (!player->Has_Science((*button->Get_Sciences())[i])) { + break; + } + } + + if (type == -1) { + goto l1; + } + + ScienceType science = (*button->Get_Sciences())[type]; + + if (player->Get_Player_Template() != nullptr) { + if (!player->Get_Player_Template()->Get_Purchase_Command_Set_Rank_One().Is_Empty()) { + if (!player->Get_Player_Template()->Get_Purchase_Command_Set_Rank_Three().Is_Empty()) { + if (!player->Get_Player_Template()->Get_Purchase_Command_Set_Rank_Eight().Is_Empty()) { + const CommandSet *command_set_one = g_theControlBar->Find_Command_Set( + player->Get_Player_Template()->Get_Purchase_Command_Set_Rank_One()); + const CommandSet *command_set_three = g_theControlBar->Find_Command_Set( + player->Get_Player_Template()->Get_Purchase_Command_Set_Rank_One()); + const CommandSet *command_set_eight = g_theControlBar->Find_Command_Set( + player->Get_Player_Template()->Get_Purchase_Command_Set_Rank_One()); + + if (command_set_one != nullptr) { + if (command_set_three != nullptr && command_set_eight != nullptr) { + bool b = false; + + for (int k = 0; !b && k < RANK_1_BUTTON_COUNT; k++) { + const CommandButton *command = command_set_one->Get_Command_Button(k); + + if (command != nullptr + && command->Get_Command() == GUI_COMMAND_PURCHASE_SCIENCE) { + if (command->Get_Sciences()->empty()) { + captainslog_dbgassert(false, + "Commandbutton %s is a purchase science button without any " + "science! Please add it.", + command->Get_Name()); + } else { + if ((*button->Get_Sciences())[0] == science) { + button->Copy_Images_From(command, true); + button->Copy_Button_Text_From(command, true, true); + b = true; + break; + } + } + } + } + + for (int k = 0; !b && k < RANK_3_BUTTON_COUNT; k++) { + const CommandButton *command = command_set_three->Get_Command_Button(k); + + if (command != nullptr + && command->Get_Command() == GUI_COMMAND_PURCHASE_SCIENCE) { + if (command->Get_Sciences()->empty()) { + captainslog_dbgassert(false, + "Commandbutton %s is a purchase science button without any " + "science! Please add it.", + command->Get_Name()); + } else { + if ((*button->Get_Sciences())[0] == science) { + button->Copy_Images_From(command, true); + button->Copy_Button_Text_From(command, true, true); + b = true; + break; + } + } + } + } + + for (int k = 0; !b && k < RANK_8_BUTTON_COUNT; k++) { + const CommandButton *command = command_set_eight->Get_Command_Button(k); + + if (command != nullptr + && command->Get_Command() == GUI_COMMAND_PURCHASE_SCIENCE) { + if (command->Get_Sciences()->empty()) { + captainslog_dbgassert(false, + "Commandbutton %s is a purchase science button without any " + "science! Please add it.", + command->Get_Name()); + } else { + if ((*button->Get_Sciences())[0] == science) { + button->Copy_Images_From(command, true); + button->Copy_Button_Text_From(command, true, true); + b = true; + break; + } + } + } + } + + l1: + m_specialPowerShortcutButtons[count]->Win_Hide(false); + m_specialPowerShortcutButtonParents[count]->Win_Hide(false); + m_specialPowerShortcutButtons[count]->Win_Enable(true); + m_specialPowerShortcutButtonParents[count]->Win_Enable(true); + Set_Control_Command(m_specialPowerShortcutButtons[count], button); + Gadget_Button_Set_Alt_Sound( + m_specialPowerShortcutButtons[count], "GUIGenShortcutClick"); + count++; + continue; + } + } + } + } + } + } + } else { + captainslog_dbgassert(false, + "CommandButton %s needs a SpecialPower entry, but it's either incorrect or missing.", + button->Get_Name()); + } + } else { + if (button->Get_Command() != GUI_COMMAND_SELECT_ALL_UNITS_OF_TYPE) { + goto l1; + } + + if (g_thePlayerList->Get_Local_Player()->Find_Any_Existing_Object_With_Thing_Template( + button->Get_Template())) { + goto l1; + } + } + } + } + } + + if (m_contextParent[0] != nullptr && !m_contextParent[0]->Win_Is_Hidden() + && m_specialPowerShortcutBarParent->Win_Is_Hidden()) { + Show_Special_Power_Shortcut(); + Animate_Special_Power_Shortcut(true); + } + + Update_Special_Power_Shortcut(); +} + +void ControlBar::Set_Portrait_By_Image(const Image *image) +{ + if (image != nullptr) { + m_unitSelectedWindow->Win_Hide(false); + m_rightHUDCameoWindow->Win_Set_Enabled_Image(0, image); + 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++) { + m_unitUpgradeWindows[i]->Win_Hide(true); + } + } else { + m_rightHUDWindow->Win_Set_Status(WIN_STATUS_IMAGE); + m_rightHUDCameoWindow->Win_Clear_Status(WIN_STATUS_IMAGE); + m_unitSelectedWindow->Win_Hide(true); + + for (int i = 0; i < UNIT_UPGRADE_WINDOW_COUNT; i++) { + m_unitUpgradeWindows[i]->Win_Hide(true); + } + } +} + +void ControlBar::Set_Control_Command( + const Utf8String &button_window_name, GameWindow *parent, const CommandButton *command_button) +{ + GameWindow *window = + g_theWindowManager->Win_Get_Window_From_Id(parent, g_theNameKeyGenerator->Name_To_Key(button_window_name.Str())); + + if (window != nullptr) { + Set_Control_Command(window, command_button); + } else { + captainslog_dbgassert(false, "setControlCommand: Unable to find window '%s'", button_window_name.Str()); + } +} + +void ControlBar::Set_Squished_Control_Bar_Config() +{ + if (m_controlBarConfig != CONTROL_BAR_STAGE_SQUISHED) { + m_controlBarConfig = CONTROL_BAR_STAGE_SQUISHED; + m_contextParent[0]->Win_Set_Position(m_parentXPosition, m_parentYPosition); + Repopulate_Build_Tooltip_Layout(); + g_theTacticalView->Set_Height(g_theDisplay->Get_Height()); + m_controlBarSchemeManager->Set_Control_Bar_Scheme_By_Player_Template( + g_thePlayerList->Get_Local_Player()->Get_Player_Template(), true); + } +} + +void ControlBar::Draw_Special_Power_Shortcut_Multiplier_Text() +{ + for (int i = 0; i < m_specialPowerShortcutButtonCount; i++) { + GameWindow *window = m_specialPowerShortcutButtons[i]; + + if (!window->Win_Is_Hidden()) { + CommandButton *button = static_cast(Gadget_Button_Get_Data(window)); + + if (button != nullptr) { + for (int j = 0; j < SPECIAL_POWER_SHORTCUT_BUTTON_COUNT; j++) { + const SpecialPowerTemplate *power = button->Get_Special_Power(); + int count = 0; + + if (power != nullptr) { + count = g_thePlayerList->Get_Local_Player()->Count_Ready_Shortcut_Special_Powers_Of_Type( + power->Get_Type()); + } + + if (count <= 1) { + Utf16String str; + Gadget_Button_Set_Text(window, str); + } else { + Utf16String str; + str.Format(U_CHAR("%d"), count); + Gadget_Button_Set_Text(window, str); + } + } + } + } + } } diff --git a/src/game/client/gui/controlbar/controlbar.h b/src/game/client/gui/controlbar/controlbar.h index d1910eac8..0e39c9183 100644 --- a/src/game/client/gui/controlbar/controlbar.h +++ b/src/game/client/gui/controlbar/controlbar.h @@ -43,7 +43,7 @@ enum ControlBarContext enum ControlBarStages { CONTROL_BAR_STAGE_DEFAULT, - CONTROL_BAR_STAGE_UNK, + CONTROL_BAR_STAGE_SQUISHED, CONTROL_BAR_STAGE_LOW, CONTROL_BAR_STAGE_HIDDEN, CONTROL_BAR_STAGE_MAX, @@ -291,6 +291,7 @@ class ControlBar : public SubsystemInterface ControlBarSchemeManager *Get_Control_Bar_Scheme_Manager() const { return m_controlBarSchemeManager; } const Image *Get_Gen_Arrow_Image() const { return m_genArrowImage; } Player *Get_Observer_Player() const { return m_observerPlayer; } + int Get_Command_Bar_Border_Color() const { return m_CommandBarBorderColor; } 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; } @@ -347,8 +348,7 @@ 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); //unused, not implemented + void Set_Control_Command(const Utf8String &button_window_name, GameWindow *parent, const CommandButton *command_button); void Set_Control_Command(GameWindow *button, const CommandButton *command_button); void Set_Default_Control_Bar_Config(); void Set_Hidden_Control_Bar(); @@ -514,13 +514,23 @@ class ControlBar : public SubsystemInterface static const Image *s_rankEliteIcon; static const Image *s_rankHeroicIcon; static const Image *s_rankVeteranIcon; + friend void Hide_Control_Bar(bool immediate); + friend void Show_Control_Bar(bool immediate); + friend void Toggle_Control_Bar(bool immediate); }; void Control_Bar_Popup_Description_Update_Func(WindowLayout *layout, void *user_data); WindowMsgHandledType Beacon_Window_Input( GameWindow *text_entry, unsigned int message, unsigned int data_1, unsigned int data_2); -void Hide_Control_Bar(bool hide); -void Show_Control_Bar(bool hide); +void Hide_Control_Bar(bool immediate); +void Show_Control_Bar(bool immediate); +void Toggle_Control_Bar(bool immediate); +WindowMsgHandledType Control_Bar_Observer_System( + GameWindow *window, unsigned int message, unsigned int data_1, unsigned int data_2); +WindowMsgHandledType Left_HUD_Input(GameWindow *window, unsigned int message, unsigned int data_1, unsigned int data_2); +WindowMsgHandledType Control_Bar_Input(GameWindow *window, unsigned int message, unsigned int data_1, unsigned int data_2); +WindowMsgHandledType Control_Bar_System(GameWindow *window, unsigned int message, unsigned int data_1, unsigned int data_2); +void Toggle_Control_Bar(bool immediate); #ifdef GAME_DLL extern ControlBar *&g_theControlBar; diff --git a/src/game/client/gui/controlbar/controlbarobserver.cpp b/src/game/client/gui/controlbar/controlbarobserver.cpp index b29960984..076193741 100644 --- a/src/game/client/gui/controlbar/controlbarobserver.cpp +++ b/src/game/client/gui/controlbar/controlbarobserver.cpp @@ -12,18 +12,223 @@ * A full copy of the GNU General Public License can be found in * LICENSE */ +#include "colorspace.h" #include "controlbar.h" +#include "gadgetpushbutton.h" +#include "gadgetstatictext.h" +#include "gametext.h" +#include "gamewindow.h" +#include "gamewindowmanager.h" +#include "playerlist.h" +#include "playertemplate.h" +#include "recorder.h" + +enum +{ + OBSERVER_BUTTON_COUNT = 8 +}; + +static NameKeyType s_buttonPlayerID[OBSERVER_BUTTON_COUNT]; +static NameKeyType s_staticTextPlayerID[OBSERVER_BUTTON_COUNT]; +static GameWindow *s_observerPlayerInfoWindow; +static GameWindow *s_observerPlayerListWindow; +static GameWindow *s_buttonPlayer[OBSERVER_BUTTON_COUNT]; +static GameWindow *s_staticTextPlayer[OBSERVER_BUTTON_COUNT]; +static NameKeyType s_buttonCancelID; +static GameWindow *s_winFlag; +static GameWindow *s_winGeneralPortrait; +static GameWindow *s_staticTextNumberOfUnits; +static GameWindow *s_staticTextNumberOfBuildings; +static GameWindow *s_staticTextNumberOfUnitsKilled; +static GameWindow *s_staticTextNumberOfUnitsLost; +static GameWindow *s_staticTextPlayerName; void ControlBar::Init_Observer_Controls() { -#ifdef GAME_DLL - Call_Method(PICK_ADDRESS(0x005A6CB0, 0x008E9B70), this); -#endif + s_observerPlayerInfoWindow = g_theWindowManager->Win_Get_Window_From_Id( + nullptr, g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:ObserverPlayerInfoWindow")); + s_observerPlayerListWindow = g_theWindowManager->Win_Get_Window_From_Id( + nullptr, g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:ObserverPlayerListWindow")); + + for (int i = 0; i < OBSERVER_BUTTON_COUNT; i++) { + Utf8String str; + str.Format("ControlBar.wnd:ButtonPlayer%d", i); + s_buttonPlayerID[i] = g_theNameKeyGenerator->Name_To_Key(str.Str()); + s_buttonPlayer[i] = g_theWindowManager->Win_Get_Window_From_Id(s_observerPlayerListWindow, s_buttonPlayerID[i]); + + str.Format("ControlBar.wnd:StaticTextPlayer%d", i); + s_staticTextPlayerID[i] = g_theNameKeyGenerator->Name_To_Key(str.Str()); + s_staticTextPlayer[i] = + g_theWindowManager->Win_Get_Window_From_Id(s_observerPlayerListWindow, s_staticTextPlayerID[i]); + } + + s_staticTextNumberOfUnits = g_theWindowManager->Win_Get_Window_From_Id( + nullptr, g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:StaticTextNumberOfUnits")); + s_staticTextNumberOfBuildings = g_theWindowManager->Win_Get_Window_From_Id( + nullptr, g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:StaticTextNumberOfBuildings")); + s_staticTextNumberOfUnitsKilled = g_theWindowManager->Win_Get_Window_From_Id( + nullptr, g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:StaticTextNumberOfUnitsKilled")); + s_staticTextNumberOfUnitsLost = g_theWindowManager->Win_Get_Window_From_Id( + nullptr, g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:StaticTextNumberOfUnitsLost")); + s_staticTextPlayerName = g_theWindowManager->Win_Get_Window_From_Id( + nullptr, g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:StaticTextPlayerName")); + s_winFlag = + g_theWindowManager->Win_Get_Window_From_Id(nullptr, g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:WinFlag")); + s_winGeneralPortrait = g_theWindowManager->Win_Get_Window_From_Id( + nullptr, g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:WinGeneralPortrait")); + s_buttonCancelID = g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:ButtonCancel"); +} + +WindowMsgHandledType Control_Bar_Observer_System( + GameWindow *window, unsigned int message, unsigned int data_1, unsigned int data_2) +{ + if (message > GBM_MOUSE_LEAVING) { + if (message > GBM_SELECTED_RIGHT) { + return MSG_IGNORED; + } + + int id = reinterpret_cast(data_1)->Win_Get_Window_Id(); + + if (id == s_buttonCancelID) { + g_theControlBar->Set_Observer_Player(nullptr); + s_observerPlayerInfoWindow->Win_Hide(true); + s_observerPlayerListWindow->Win_Hide(false); + g_theControlBar->Populate_Observer_List(); + } + + for (int i = 0; i < OBSERVER_BUTTON_COUNT; i++) { + if (id == s_buttonPlayerID[i]) { + s_observerPlayerInfoWindow->Win_Hide(false); + s_observerPlayerListWindow->Win_Hide(true); + g_theControlBar->Set_Observer_Player(reinterpret_cast(Gadget_Button_Get_Data(s_buttonPlayer[i]))); + + if (g_theControlBar->Get_Observer_Player() != nullptr) { + g_theControlBar->Populate_Observer_Info_Window(); + } + + return MSG_HANDLED; + } + } + } else if (message < GBM_MOUSE_ENTERING && message != GWM_CREATE) { + return MSG_IGNORED; + } + + return MSG_HANDLED; +} + +void ControlBar::Populate_Observer_List() +{ + int button_count = 0; + + if (g_theRecorder->Is_Multiplayer()) { + for (int i = 0; i < OBSERVER_BUTTON_COUNT; i++) { + Utf8String str; + str.Format("player%d", i); + Player *player = g_thePlayerList->Find_Player_With_NameKey(g_theNameKeyGenerator->Name_To_Key(str.Str())); + + if (player != nullptr && !player->Is_Player_Observer()) { + captainslog_dbgassert(button_count < OBSERVER_BUTTON_COUNT, + "ControlBar::Populate_Observer_List trying to populate more buttons then we have"); + Gadget_Button_Set_Data(s_buttonPlayer[button_count], reinterpret_cast(player)); + Gadget_Button_Set_Enabled_Image( + s_buttonPlayer[button_count], player->Get_Player_Template()->Get_Enabled_Image()); + s_buttonPlayer[button_count]->Win_Set_Tooltip(player->Get_Player_Display_Name()); + s_buttonPlayer[button_count]->Win_Hide(false); + s_buttonPlayer[button_count]->Win_Set_Status(WIN_STATUS_USE_OVERLAY_STATES); + const GameSlot *slot = g_theGameInfo->Get_Const_Slot(button_count); + s_staticTextPlayer[button_count]->Win_Set_Enabled_Text_Colors(player->Get_Color(), Make_Color(0, 0, 0, 255)); + s_staticTextPlayer[button_count]->Win_Hide(false); + Utf8String str2; + str2.Format("Team:%d", slot->Get_Team_Number() + 1); + + if (slot->Is_AI() && slot->Get_Team_Number() == -1) { + str2 = "Team:AI"; + } + + Utf16String str3; + str3.Format(g_theGameText->Fetch("CONTROLBAR:ObsPlayerLabel"), + player->Get_Player_Display_Name().Str(), + g_theGameText->Fetch(str2).Str()); + Gadget_Static_Text_Set_Text(s_staticTextPlayer[button_count], str3); + button_count++; + } + } + + while (button_count < 8) { + s_buttonPlayer[button_count]->Win_Hide(true); + s_staticTextPlayer[button_count]->Win_Hide(true); + button_count++; + } + } else { + for (int i = 0; i < MAX_PLAYER_COUNT; i++) { + Player *player = g_thePlayerList->Get_Nth_Player(i); + + if (player != nullptr && !player->Is_Player_Observer() && player->Get_Player_Type() == Player::PLAYER_HUMAN) { + Gadget_Button_Set_Data(s_buttonPlayer[button_count], reinterpret_cast(player)); + Gadget_Button_Set_Enabled_Image( + s_buttonPlayer[button_count], player->Get_Player_Template()->Get_Enabled_Image()); + s_buttonPlayer[button_count]->Win_Set_Tooltip(player->Get_Player_Display_Name()); + s_buttonPlayer[button_count]->Win_Hide(false); + s_buttonPlayer[button_count]->Win_Set_Status(WIN_STATUS_USE_OVERLAY_STATES); + s_staticTextPlayer[button_count]->Win_Set_Enabled_Text_Colors(player->Get_Color(), Make_Color(0, 0, 0, 255)); + s_staticTextPlayer[button_count]->Win_Hide(false); + Gadget_Static_Text_Set_Text(s_staticTextPlayer[button_count], player->Get_Player_Display_Name()); + button_count++; + break; + } + } + + while (button_count < 8) { + s_buttonPlayer[button_count]->Win_Hide(true); + s_staticTextPlayer[button_count]->Win_Hide(true); + button_count++; + } + } } void ControlBar::Populate_Observer_Info_Window() { -#ifdef GAME_DLL - Call_Method(PICK_ADDRESS(0x005A7480, 0x008EA4BE), this); -#endif + if (!s_observerPlayerInfoWindow->Win_Is_Hidden()) { + if (m_observerPlayer != nullptr) { + Utf16String str; + BitFlags must_be_set; + BitFlags must_be_clear; + must_be_set.Set(KINDOF_SCORE, true); + must_be_clear.Set(KINDOF_STRUCTURE, true); + str.Format(U_CHAR("%d"), m_observerPlayer->Count_Objects(must_be_set, must_be_clear)); + Gadget_Static_Text_Set_Text(s_staticTextNumberOfUnits, str); + + int count = 0; + must_be_set.Clear(); + must_be_set.Set(KINDOF_SCORE, true); + must_be_set.Set(KINDOF_STRUCTURE, true); + must_be_clear.Clear(); + count = m_observerPlayer->Count_Objects(must_be_set, must_be_clear); + + must_be_set.Clear(); + must_be_set.Set(KINDOF_SCORE_CREATE, true); + must_be_set.Set(KINDOF_STRUCTURE, true); + count += m_observerPlayer->Count_Objects(must_be_set, must_be_clear); + + must_be_set.Clear(); + must_be_set.Set(KINDOF_SCORE_DESTROY, true); + must_be_set.Set(KINDOF_STRUCTURE, true); + count += m_observerPlayer->Count_Objects(must_be_set, must_be_clear); + + str.Format(U_CHAR("%d"), count); + Gadget_Static_Text_Set_Text(s_staticTextNumberOfBuildings, str); + str.Format(U_CHAR("%d"), m_observerPlayer->Get_Score_Keeper()->Get_Total_Units_Destroyed()); + Gadget_Static_Text_Set_Text(s_staticTextNumberOfUnitsKilled, str); + str.Format(U_CHAR("%d"), m_observerPlayer->Get_Score_Keeper()->Get_Total_Units_Lost()); + Gadget_Static_Text_Set_Text(s_staticTextNumberOfUnitsLost, str); + Gadget_Static_Text_Set_Text(s_staticTextPlayerName, m_observerPlayer->Get_Player_Display_Name()); + s_staticTextPlayerName->Win_Set_Enabled_Text_Colors(m_observerPlayer->Get_Color(), Make_Color(0, 0, 0, 255)); + s_winFlag->Win_Set_Enabled_Image(0, m_observerPlayer->Get_Player_Template()->Get_Flag_Watermark_Image()); + s_winGeneralPortrait->Win_Hide(false); + } else { + s_observerPlayerInfoWindow->Win_Hide(true); + s_observerPlayerListWindow->Win_Hide(false); + Populate_Observer_List(); + } + } } diff --git a/src/game/client/gui/controlbar/controlbarocltimer.cpp b/src/game/client/gui/controlbar/controlbarocltimer.cpp index 3ecc34e8f..9598cf9b7 100644 --- a/src/game/client/gui/controlbar/controlbarocltimer.cpp +++ b/src/game/client/gui/controlbar/controlbarocltimer.cpp @@ -13,10 +13,72 @@ * LICENSE */ #include "controlbar.h" +#include "gadgetprogressbar.h" +#include "gadgetstatictext.h" +#include "gametext.h" +#include "gamewindow.h" +#include "gamewindowmanager.h" +#include "oclupdate.h" void ControlBar::Update_Context_OCL_Timer() { -#ifdef GAME_DLL - Call_Method(PICK_ADDRESS(0x005AADE0, 0x008F3148), this); -#endif + Object *object = m_currentSelectedDrawable->Get_Object(); + static const NameKeyType key_OCLUpdate = g_theNameKeyGenerator->Name_To_Key("OCLUpdate"); + OCLUpdate *ocl = static_cast(object->Find_Update_Module(key_OCLUpdate)); + unsigned int remaining_frames = ocl->Get_Remaining_Frames() / 30; + float countdown = ocl->Get_Countdown_Percent(); + + if (m_oclTimerFrame != remaining_frames) { + Update_OCL_Timer_Text_Display(remaining_frames, countdown); + } +} + +void ControlBar::Populate_OCL_Timer(Object *obj) +{ + if (obj != nullptr) { + GameWindow *button = g_theWindowManager->Win_Get_Window_From_Id( + m_contextParent[8], g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:OCLTimerSellButton")); + + if (obj->Is_KindOf(KINDOF_TECH_BUILDING)) { + if (obj->Is_KindOf(KINDOF_TECH_BUILDING) && obj->Is_KindOf(KINDOF_AUTO_RALLYPOINT)) { + const CommandButton *command = Find_Command_Button("Command_SetRallyPoint"); + Set_Control_Command(button, command); + button->Win_Set_Status(WIN_STATUS_USE_OVERLAY_STATES); + ExitInterface *exit = obj->Get_Object_Exit_Interface(); + + if (exit != nullptr) { + Show_Rally_Point(exit->Get_Rally_Point()); + } + } else { + button->Win_Hide(true); + } + } else { + const CommandButton *command = Find_Command_Button("Command_Sell"); + Set_Control_Command(button, command); + button->Win_Set_Status(WIN_STATUS_USE_OVERLAY_STATES); + } + + Update_Context_OCL_Timer(); + Set_Portrait_By_Object(obj); + } +} + +void ControlBar::Update_OCL_Timer_Text_Display(unsigned int remaining_frames, float progress) +{ + Utf16String str; + static const NameKeyType descID = g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:OCLTimerStaticText"); + GameWindow *desc = g_theWindowManager->Win_Get_Window_From_Id(nullptr, descID); + static const NameKeyType barID = g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:OCLTimerProgressBar"); + GameWindow *bar = g_theWindowManager->Win_Get_Window_From_Id(nullptr, barID); + captainslog_dbgassert(desc != nullptr, "Under construction window not found"); + + if ((remaining_frames % 60) >= 10) { + str.Format(g_theGameText->Fetch("CONTROLBAR:OCLTimerDesc"), remaining_frames / 60, remaining_frames % 60); + } else { + str.Format(g_theGameText->Fetch("CONTROLBAR:OCLTimerDescWithPadding"), remaining_frames / 60, remaining_frames % 60); + } + + Gadget_Static_Text_Set_Text(desc, str); + Gadget_Progress_Bar_Set_Progress(bar, progress * 100.0f); + m_oclTimerFrame = remaining_frames; } diff --git a/src/game/client/gui/gadget/gadgettextentry.h b/src/game/client/gui/gadget/gadgettextentry.h index d46ac58da..1baeedaea 100644 --- a/src/game/client/gui/gadget/gadgettextentry.h +++ b/src/game/client/gui/gadget/gadgettextentry.h @@ -139,4 +139,21 @@ WindowMsgHandledType Gadget_Text_Entry_System( GameWindow *text_entry, unsigned int message, unsigned int data_1, unsigned int data_2); void Gadget_Text_Entry_Set_Font(GameWindow *text_entry, GameFont *font); -Utf16String Gadget_Text_Entry_Get_Text(GameWindow *text_entry); + +static Utf16String Gadget_Text_Entry_Get_Text(GameWindow *text_entry) +{ + if (text_entry != nullptr) { + if ((text_entry->Win_Get_Style() & GWS_ENTRY_FIELD) != 0) { + Utf16String str; +#ifdef GAME_DLL // temporary since we can't change the definition of Win_Send_System_Msg at this point and we can't cast a + // pointer to an unsigned int on 64 bit + g_theWindowManager->Win_Send_System_Msg(text_entry, GEM_GET_TEXT, 0, reinterpret_cast(&str)); +#endif + return str; + } else { + return Utf16String::s_emptyString; + } + } else { + return Utf16String::s_emptyString; + } +} diff --git a/src/game/client/gui/gamewindow.h b/src/game/client/gui/gamewindow.h index b87cea27e..909714941 100644 --- a/src/game/client/gui/gamewindow.h +++ b/src/game/client/gui/gamewindow.h @@ -68,6 +68,7 @@ enum WinStatus WIN_STATUS_FLASHING = 1 << 23, WIN_STATUS_ALWAYS_COLOR = 1 << 24, WIN_STATUS_ON_MOUSE_DOWN = 1 << 25, + WIN_STATUS_UNK = 1 << 26, }; enum GameWindowStyle diff --git a/src/game/client/gui/guicallbacks/controlbarcallback.cpp b/src/game/client/gui/guicallbacks/controlbarcallback.cpp index a9b242708..a04bcf2b3 100644 --- a/src/game/client/gui/guicallbacks/controlbarcallback.cpp +++ b/src/game/client/gui/guicallbacks/controlbarcallback.cpp @@ -12,18 +12,360 @@ * A full copy of the GNU General Public License can be found in * LICENSE */ +#include "animatewindowmanager.h" +#include "commandxlat.h" #include "controlbar.h" +#include "diplomacy.h" +#include "display.h" +#include "gadgettextentry.h" +#include "gameclient.h" +#include "globaldata.h" +#include "languagefilter.h" +#include "mouse.h" +#include "player.h" +#include "playerlist.h" +#include "quitmenu.h" +#include "radar.h" +#include "scriptengine.h" +#include "view.h" -void Hide_Control_Bar(bool hide) +void Hide_Control_Bar(bool immediate) { -#ifdef GAME_DLL - Call_Function(PICK_ADDRESS(0x0048A3E0, 0x009DF7F2), hide); -#endif + Hide_Replay_Controls(); + + if (g_theControlBar != nullptr) { + g_theControlBar->Hide_Special_Power_Shortcut(); + } + + if (g_theWindowManager != nullptr) { + GameWindow *window = g_theWindowManager->Win_Get_Window_From_Id( + nullptr, g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:ControlBarParent")); + + if (window != nullptr) { + g_theTacticalView->Set_Height(g_theDisplay->Get_Height()); + } + + if (immediate) { + window->Win_Hide(true); + + if (g_theControlBar != nullptr) { + g_theControlBar->Hide_Special_Power_Shortcut(); + } + } else { + g_theControlBar->m_controlBarAnimateWindowManager->Reverse_Animate_Window(); + g_theControlBar->Animate_Special_Power_Shortcut(false); + } + + if (g_theControlBar != nullptr) { + g_theControlBar->Hide_Purchase_Science(); + } + } +} + +void Show_Control_Bar(bool immediate) +{ + Show_Replay_Controls(); + + if (g_theControlBar != nullptr) { + g_theControlBar->Show_Special_Power_Shortcut(); + } + + if (g_theWindowManager != nullptr) { + GameWindow *window = g_theWindowManager->Win_Get_Window_From_Id( + nullptr, g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:ControlBarParent")); + + if (window != nullptr) { + g_theControlBar->Switch_Control_Bar_Stage(CONTROL_BAR_STAGE_DEFAULT); + g_theTacticalView->Set_Height(g_theDisplay->Get_Height() * 0.8f); + + if (g_theControlBar->m_controlBarAnimateWindowManager != nullptr && immediate) { + g_theControlBar->m_controlBarAnimateWindowManager->Reset(); + g_theControlBar->m_controlBarAnimateWindowManager->Register_Game_Window( + window, WIN_ANIMATION_SLIDE_BOTTOM, true, 500, 0); + g_theControlBar->Animate_Special_Power_Shortcut(true); + } + + window->Win_Hide(false); + } + } + + if (g_theControlBar != nullptr) { + g_theControlBar->Mark_UI_Dirty(); + } +} + +WindowMsgHandledType Left_HUD_Input(GameWindow *window, unsigned int message, unsigned int data_1, unsigned int data_2) +{ + Player *player = g_thePlayerList->Get_Local_Player(); + + if (!g_theRadar->Is_Radar_Forced() && (g_theRadar->Is_Radar_Hidden() || !player->Has_Radar())) { + return MSG_HANDLED; + } + + if (g_theMouse->Get_Mouse_Status()->middle_state == 1) { + return MSG_IGNORED; + } + + switch (message) { + case GWM_NONE: + case GWM_MOUSE_ENTERING: + case GWM_MOUSE_LEAVING: { + bool needs_target = false; + const CommandButton *command = g_theInGameUI->Get_GUI_Command(); + + if (command != nullptr + && (command->Get_Command() == GUI_COMMAND_SPECIAL_POWER + || command->Get_Command() == GUI_COMMAND_SPECIAL_POWER_FROM_SHORTCUT) + && (command->Get_Options() & COMMAND_OPTION_NEED_TARGET_POS) != 0) { + needs_target = true; + } + + if (!needs_target) { + const std::list *drawables = g_theInGameUI->Get_All_Selected_Drawables(); + MouseCursor cursor = CURSOR_ARROW; + + if (!drawables->empty() && message != GWM_MOUSE_LEAVING) { + if (command != nullptr && command->Get_Command() == GUI_COMMAND_ATTACK_MOVE) { + cursor = CURSOR_ATTACK_MOVE; + } else { + cursor = CURSOR_MOVE; + } + } + + g_theMouse->Set_Cursor(cursor); + } + + return MSG_HANDLED; + } + case GWM_LEFT_DOWN: + case GWM_RIGHT_DOWN: { + int width; + int height; + int screen_x; + int screen_y; + window->Win_Get_Size(&width, &height); + window->Win_Get_Screen_Position(&screen_x, &screen_y); + ICoord2D pixel; + pixel.x = (data_1 & 0xffff) - screen_x; + pixel.y = ((data_1 >> 16) & 0xffff) - screen_y; + ICoord2D radar; + Coord3D world; + + if ((!g_theRadar->Is_Radar_Hidden() || g_theRadar->Is_Radar_Forced()) + && g_theRadar->Local_Pixel_To_Radar(&pixel, &radar) && g_theRadar->Radar_To_World(&radar, &world)) { + if (g_theInGameUI->Get_All_Selected_Drawables()->empty() + || (!g_theWriteableGlobalData->m_alternateMouseEnabled && message == GWM_RIGHT_DOWN) + || (g_theWriteableGlobalData->m_alternateMouseEnabled && message == GWM_LEFT_DOWN)) { + g_theTacticalView->Look_At(&world); + } else { + const CommandButton *command = g_theInGameUI->Get_GUI_Command(); + + if (command != nullptr + && (command->Get_Command() == GUI_COMMAND_SPECIAL_POWER + || command->Get_Command() == GUI_COMMAND_SPECIAL_POWER_FROM_SHORTCUT) + && (command->Get_Options() & COMMAND_OPTION_NEED_TARGET_POS) != 0) { + g_theGameClient->Evaluate_Context_Command(nullptr, &world, CommandTranslator::DO_COMMAND); + } else if (command != nullptr && command->Get_Command() == GUI_COMMAND_ATTACK_MOVE) { + GameMessage *msg = g_theMessageStream->Append_Message(GameMessage::MSG_DO_ATTACKMOVETO); + msg->Append_Location_Arg(world); + Pick_And_Play_Unit_Voice_Response( + g_theInGameUI->Get_All_Selected_Drawables(), GameMessage::MSG_DO_ATTACKMOVETO, nullptr); + } else { + GameMessage *msg = g_theMessageStream->Append_Message(GameMessage::MSG_DO_MOVETO); + msg->Append_Location_Arg(world); + Pick_And_Play_Unit_Voice_Response( + g_theInGameUI->Get_All_Selected_Drawables(), GameMessage::MSG_DO_MOVETO, nullptr); + } + } + } + + g_theInGameUI->Clear_Attack_Move_To_Mode(); + return MSG_HANDLED; + } + case GWM_LEFT_UP: + case GWM_RIGHT_UP: { + g_theInGameUI->Clear_Attack_Move_To_Mode(); + return MSG_HANDLED; + } + case GWM_MOUSE_POS: { + int screen_x; + int screen_y; + window->Win_Get_Screen_Position(&screen_x, &screen_y); + ICoord2D pixel; + pixel.x = (data_1 & 0xffff) - screen_x; + pixel.y = ((data_1 >> 16) & 0xffff) - screen_y; + ICoord2D radar; + + if ((!g_theRadar->Is_Radar_Hidden() || g_theRadar->Is_Radar_Forced()) + && g_theRadar->Local_Pixel_To_Radar(&pixel, &radar)) { + const CommandButton *command = g_theInGameUI->Get_GUI_Command(); + + if (command != nullptr + && (command->Get_Command() == GUI_COMMAND_SPECIAL_POWER + || command->Get_Command() == GUI_COMMAND_SPECIAL_POWER_FROM_SHORTCUT) + && (command->Get_Options() & COMMAND_OPTION_NEED_TARGET_POS) != 0) { + MouseCursor index = g_theMouse->Get_Cursor_Index(command->Get_Cursor_Name()); + + if (index == CURSOR_INVALID) { + g_theMouse->Set_Cursor(CURSOR_TARGET); + } else { + g_theMouse->Set_Cursor(index); + } + } else { + const std::list *drawables = g_theInGameUI->Get_All_Selected_Drawables(); + MouseCursor cursor = CURSOR_ARROW; + + if (!drawables->empty() && message != GWM_MOUSE_LEAVING) { + if (command != nullptr && command->Get_Command() == GUI_COMMAND_ATTACK_MOVE) { + cursor = CURSOR_ATTACK_MOVE; + } else { + cursor = CURSOR_MOVE; + } + } + + g_theMouse->Set_Cursor(cursor); + } + } + + g_theInGameUI->Clear_Attack_Move_To_Mode(); + return MSG_HANDLED; + } + default: { + return MSG_IGNORED; + } + } +} + +WindowMsgHandledType Control_Bar_Input(GameWindow *window, unsigned int message, unsigned int data_1, unsigned int data_2) +{ + return MSG_IGNORED; +} + +WindowMsgHandledType Control_Bar_System(GameWindow *window, unsigned int message, unsigned int data_1, unsigned int data_2) +{ + GameWindow *window2 = reinterpret_cast(data_1); + static NameKeyType buttonCommunicator; + + if (g_theScriptEngine != nullptr && g_theScriptEngine->Is_End_Game_Timer_Running()) { + return MSG_IGNORED; + } + + if (message > GBM_SELECTED_RIGHT) { + if (message == GEM_EDIT_DONE) { + int id = window2->Win_Get_Window_Id(); + static const NameKeyType textID = g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:EditBeaconText"); + + if (id == textID && g_theInGameUI->Get_Select_Count() == 1) { + GameMessage *msg = g_theMessageStream->Append_Message(GameMessage::MSG_SET_BEACON_TEXT); + Utf16String text = Gadget_Text_Entry_Get_Text(window2); + g_theLanguageFilter->Filter_Line(text); + const unichar_t *str = text.Str(); + + while (str != nullptr && *str != '\0') { + msg->Append_Wide_Char_Arg(*str); + str++; + } + + msg->Append_Wide_Char_Arg('\0'); + } + + return MSG_HANDLED; + } + + return MSG_IGNORED; + } + + if (message >= GBM_SELECTED) { + static const NameKeyType beaconPlacementButtonID = + g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:ButtonPlaceBeacon"); + static const NameKeyType beaconDeleteButtonID = + g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:ButtonDeleteBeacon"); + static const NameKeyType beaconClearTextButtonID = + g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:ButtonClearBeaconText"); + static const NameKeyType beaconGeneralButtonID = g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:ButtonGeneral"); + static const NameKeyType buttonLargeID = g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:ButtonLarge"); + static const NameKeyType buttonOptions = g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:ButtonOptions"); + static const NameKeyType buttonIdleWorker = g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:ButtonIdleWorker"); + int id = window2->Win_Get_Window_Id(); + + if (id == buttonCommunicator) { + Toggle_Diplomacy(false); + } else if (id == beaconPlacementButtonID && g_theGameLogic->Is_In_Multiplayer_Game() + && g_thePlayerList->Get_Local_Player()->Is_Player_Active()) { + g_theInGameUI->Set_GUI_Command(g_theControlBar->Find_Command_Button("Command_PlaceBeacon")); + } else if (id == beaconDeleteButtonID && g_theGameLogic->Is_In_Multiplayer_Game()) { + g_theMessageStream->Append_Message(GameMessage::MSG_REMOVE_BEACON); + } else if (id == beaconClearTextButtonID && g_theGameLogic->Is_In_Multiplayer_Game()) { + static const NameKeyType textID = g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:EditBeaconText"); + GameWindow *text_window = g_theWindowManager->Win_Get_Window_From_Id(nullptr, textID); + + if (text_window != nullptr) { + Gadget_Text_Entry_Set_Text(text_window, Utf16String::s_emptyString); + } + } else if (id == beaconGeneralButtonID) { + Hide_Quit_Menu(); + g_theControlBar->Toggle_Purchase_Science(); + } else if (id == buttonLargeID) { + g_theControlBar->Toggle_Control_Bar_Stage(); + } else if (id == buttonOptions) { + Toggle_Quit_Menu(); + } else if (id == buttonIdleWorker) { + Hide_Quit_Menu(); + g_theInGameUI->Select_Next_Idle_Worker(); + } else { + g_theControlBar->Process_Context_Sensitive_Button_Click(window2, static_cast(message)); + } + + return MSG_HANDLED; + } + + if (message == GWM_CREATE) { + buttonCommunicator = g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:PopupCommunicator"); + return MSG_HANDLED; + } + + if (message <= GGM_CLOSE) { + return MSG_IGNORED; + } + + g_theControlBar->Process_Context_Sensitive_Button_Transition(window2, static_cast(message)); + return MSG_HANDLED; } -void Show_Control_Bar(bool show) +void Toggle_Control_Bar(bool immediate) { -#ifdef GAME_DLL - Call_Function(PICK_ADDRESS(0x0048A250, 0x009DF683), show); -#endif + Toggle_Replay_Controls(); + + if (g_theWindowManager != nullptr) { + 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()) { + if (g_theControlBar != nullptr) { + g_theControlBar->Show_Special_Power_Shortcut(); + } + + g_theTacticalView->Set_Height(g_theDisplay->Get_Height() * 0.8f); + window->Win_Hide(!window->Win_Is_Hidden()); + g_theControlBar->Switch_Control_Bar_Stage(CONTROL_BAR_STAGE_DEFAULT); + + if (g_theControlBar->m_controlBarAnimateWindowManager != nullptr) { + if (!immediate) { + g_theControlBar->m_controlBarAnimateWindowManager->Reset(); + g_theControlBar->m_controlBarAnimateWindowManager->Register_Game_Window( + window, WIN_ANIMATION_SLIDE_BOTTOM, true, 500, 0); + g_theControlBar->Animate_Special_Power_Shortcut(true); + } + } + } else { + if (g_theControlBar != nullptr) { + g_theControlBar->Hide_Special_Power_Shortcut(); + } + + g_theTacticalView->Set_Height(g_theDisplay->Get_Height()); + window->Win_Hide(!window->Win_Is_Hidden()); + } + } + } } diff --git a/src/game/client/gui/guicallbacks/diplomacy.cpp b/src/game/client/gui/guicallbacks/diplomacy.cpp new file mode 100644 index 000000000..272373485 --- /dev/null +++ b/src/game/client/gui/guicallbacks/diplomacy.cpp @@ -0,0 +1,26 @@ +/** + * @file + * + * @author Jonathan Wilson + * + * @brief Diplomacy + * + * @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 "diplomacy.h" + +#ifdef GAME_DLL +#include "hooker.h" +#endif + +void Toggle_Diplomacy(bool immediate) +{ +#ifdef GAME_DLL + Call_Function(PICK_ADDRESS(0x005EEF60, 0x00A11E14), immediate); +#endif +} diff --git a/src/game/client/gui/guicallbacks/diplomacy.h b/src/game/client/gui/guicallbacks/diplomacy.h new file mode 100644 index 000000000..5ec22fb19 --- /dev/null +++ b/src/game/client/gui/guicallbacks/diplomacy.h @@ -0,0 +1,18 @@ +/** + * @file + * + * @author Jonathan Wilson + * + * @brief Diplomacy + * + * @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" + +void Toggle_Diplomacy(bool immediate); diff --git a/src/game/client/gui/guicallbacks/generalsexppoints.cpp b/src/game/client/gui/guicallbacks/generalsexppoints.cpp new file mode 100644 index 000000000..1a8da3020 --- /dev/null +++ b/src/game/client/gui/guicallbacks/generalsexppoints.cpp @@ -0,0 +1,70 @@ +/** + * @file + * + * @author Jonathan Wilson + * + * @brief Generals Exp Points + * + * @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 "generalsexppoints.h" +#include "controlbar.h" +#include "ingameui.h" +#include "keyboard.h" + +WindowMsgHandledType Generals_Exp_Points_Input( + GameWindow *window, unsigned int message, unsigned int data_1, unsigned int data_2) +{ + if (message == GWM_MOUSE_ENTERING) { + if (g_theInGameUI != nullptr) { + g_theInGameUI->Place_Build_Available(nullptr, nullptr); + } + + return MSG_HANDLED; + } + + if (message != GWM_CHAR) { + return MSG_HANDLED; + } + + if (data_1 == Keyboard::KEY_ESCAPE) { + g_theControlBar->Hide_Purchase_Science(); + } + + return MSG_HANDLED; +} + +WindowMsgHandledType Generals_Exp_Points_System( + GameWindow *window, unsigned int message, unsigned int data_1, unsigned int data_2) +{ + if (message == GWM_INPUT_FOCUS) { + if (data_1 == 1) { + *reinterpret_cast(data_2) = false; + } + + return MSG_HANDLED; + } else { + if (message != GGM_FOCUS_CHANGE) { + if (message != GBM_SELECTED) { + return MSG_IGNORED; + } + + int id = reinterpret_cast(data_1)->Win_Get_Window_Id(); + static const NameKeyType buttonExitID = g_theNameKeyGenerator->Name_To_Key("GeneralsExpPoints.wnd:ButtonExit"); + + if (id == buttonExitID) { + g_theControlBar->Hide_Purchase_Science(); + } else { + g_theControlBar->Process_Context_Sensitive_Button_Click( + reinterpret_cast(data_1), static_cast(message)); + } + } + + return MSG_HANDLED; + } +} diff --git a/src/game/client/gui/guicallbacks/generalsexppoints.h b/src/game/client/gui/guicallbacks/generalsexppoints.h new file mode 100644 index 000000000..7fb77122f --- /dev/null +++ b/src/game/client/gui/guicallbacks/generalsexppoints.h @@ -0,0 +1,22 @@ +/** + * @file + * + * @author Jonathan Wilson + * + * @brief Generals Exp Points + * + * @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 "gamewindow.h" + +WindowMsgHandledType Generals_Exp_Points_Input( + GameWindow *window, unsigned int message, unsigned int data_1, unsigned int data_2); +WindowMsgHandledType Generals_Exp_Points_System( + GameWindow *window, unsigned int message, unsigned int data_1, unsigned int data_2); diff --git a/src/game/client/gui/guicallbacks/ingamechat.cpp b/src/game/client/gui/guicallbacks/ingamechat.cpp new file mode 100644 index 000000000..f5f76f6c3 --- /dev/null +++ b/src/game/client/gui/guicallbacks/ingamechat.cpp @@ -0,0 +1,28 @@ +/** + * @file + * + * @author Jonathan Wilson + * + * @brief In Game Chat + * + * @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 "ingamechat.h" + +#ifdef GAME_DLL +#include "hooker.h" +#endif + +bool Is_In_Game_Chat_Active() +{ +#ifdef GAME_DLL + return Call_Function(PICK_ADDRESS(0x005AE1A0, 0x008F7E4F)); +#else + return false; +#endif +} diff --git a/src/game/client/gui/guicallbacks/ingamechat.h b/src/game/client/gui/guicallbacks/ingamechat.h new file mode 100644 index 000000000..ef838acfc --- /dev/null +++ b/src/game/client/gui/guicallbacks/ingamechat.h @@ -0,0 +1,18 @@ +/** + * @file + * + * @author Jonathan Wilson + * + * @brief In Game Chat + * + * @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" + +bool Is_In_Game_Chat_Active(); diff --git a/src/game/client/gui/guicallbacks/menus/quitmenu.cpp b/src/game/client/gui/guicallbacks/menus/quitmenu.cpp new file mode 100644 index 000000000..1b9a520d1 --- /dev/null +++ b/src/game/client/gui/guicallbacks/menus/quitmenu.cpp @@ -0,0 +1,33 @@ +/** + * @file + * + * @author Jonathan Wilson + * + * @brief Quit 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 "quitmenu.h" + +#ifdef GAME_DLL +#include "hooker.h" +#endif + +void Hide_Quit_Menu() +{ +#ifdef GAME_DLL + Call_Function(PICK_ADDRESS(0x005C9B20, 0x00A0F692)); +#endif +} + +void Toggle_Quit_Menu() +{ +#ifdef GAME_DLL + Call_Function(PICK_ADDRESS(0x005C9C20, 0x00A0F784)); +#endif +} diff --git a/src/game/client/gui/guicallbacks/menus/quitmenu.h b/src/game/client/gui/guicallbacks/menus/quitmenu.h new file mode 100644 index 000000000..affe8b0ce --- /dev/null +++ b/src/game/client/gui/guicallbacks/menus/quitmenu.h @@ -0,0 +1,19 @@ +/** + * @file + * + * @author Jonathan Wilson + * + * @brief Quit 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" + +void Hide_Quit_Menu(); +void Toggle_Quit_Menu(); diff --git a/src/game/client/gui/guicallbacks/skirmishgameoptionsmenu.cpp b/src/game/client/gui/guicallbacks/skirmishgameoptionsmenu.cpp new file mode 100644 index 000000000..2e1b6e02d --- /dev/null +++ b/src/game/client/gui/guicallbacks/skirmishgameoptionsmenu.cpp @@ -0,0 +1,111 @@ +/** + * @file + * + * @author Jonathan Wilson + * + * @brief Skirmish Game Options 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 "skirmishgameoptionsmenu.h" +#include "gametext.h" +#include "image.h" +#include "mouse.h" + +TechAndSupplyImages g_theSupplyAndTechImageLocations; + +void Position_Additional_Images(MapMetaData *map, GameWindow *window, bool reset) +{ + g_theSupplyAndTechImageLocations.m_supplyPositions.clear(); + g_theSupplyAndTechImageLocations.m_techPositions.clear(); + + if (map != nullptr && window != nullptr && !window->Win_Is_Hidden()) { + static MapMetaData *prevMMD; + + if (reset) { + prevMMD = nullptr; + } + + if (map != prevMMD) { + int width; + int height; + int screen_x; + int screen_y; + window->Win_Get_Size(&width, &height); + window->Win_Get_Screen_Position(&screen_x, &screen_y); + ICoord2D ul; + ICoord2D lr; + Find_Draw_Positions(0, 0, width, height, map->m_extent, &ul, &lr); + int x = lr.x - ul.x; + int y = lr.y - ul.y; + + for (auto it = map->m_supplyPositions.begin(); it != map->m_supplyPositions.end(); it++) { + ICoord2D pos; + float f1 = (it->x - map->m_extent.lo.x) / (map->m_extent.hi.x - map->m_extent.lo.x); + pos.x = (x * f1 - 7.0f + ul.x); + f1 = (it->y - map->m_extent.lo.y) / (map->m_extent.hi.y - map->m_extent.lo.y); + pos.y = ((1.0f - f1) * y - 7.0f + ul.y); + g_theSupplyAndTechImageLocations.m_supplyPositions.push_front(pos); + } + + for (auto it = map->m_techPositions.begin(); it != map->m_techPositions.end(); it++) { + ICoord2D pos; + float f1 = (it->x - map->m_extent.lo.x) / (map->m_extent.hi.x - map->m_extent.lo.x); + pos.x = (x * f1 - 7.0f + ul.x); + f1 = (it->y - map->m_extent.lo.y) / (map->m_extent.hi.y - map->m_extent.lo.y); + pos.y = ((1.0f - f1) * y - 7.0f + ul.y); + g_theSupplyAndTechImageLocations.m_supplyPositions.push_front(pos); + } + } + } +} + +void Map_Selector_Tooltip(GameWindow *window, WinInstanceData *instance, unsigned int mouse) +{ + int mouse_x = (mouse & 0xffff); + int mouse_y = ((mouse >> 16) & 0xffff); + int screen_x; + int screen_y; + window->Win_Get_Screen_Position(&screen_x, &screen_y); + Image *tech_building = g_theMappedImageCollection->Find_Image_By_Name("TecBuilding"); + Image *cash = g_theMappedImageCollection->Find_Image_By_Name("Cash"); + + if (tech_building != nullptr) { + for (auto it = g_theSupplyAndTechImageLocations.m_techPositions.begin(); + it != g_theSupplyAndTechImageLocations.m_techPositions.end(); + it++) { + if (mouse_x > it->x + screen_x) { + if (mouse_x < screen_x + it->x + 15) { + if (mouse_y > it->y + screen_y) { + if (mouse_y < screen_y + it->y + 15) { + g_theMouse->Set_Cursor_Tooltip(g_theGameText->Fetch("TOOLTIP:TechBuilding"), -1, nullptr, 1.0f); + return; + } + } + } + } + } + } + + if (cash != nullptr) { + for (auto it = g_theSupplyAndTechImageLocations.m_supplyPositions.begin(); + it != g_theSupplyAndTechImageLocations.m_supplyPositions.end(); + it++) { + if (mouse_x > it->x + screen_x) { + if (mouse_x < screen_x + it->x + 15) { + if (mouse_y > it->y + screen_y) { + if (mouse_y < screen_y + it->y + 15) { + g_theMouse->Set_Cursor_Tooltip(g_theGameText->Fetch("TOOLTIP:SupplyDock"), -1, nullptr, 1.0f); + return; + } + } + } + } + } + } +} diff --git a/src/game/client/gui/guicallbacks/skirmishgameoptionsmenu.h b/src/game/client/gui/guicallbacks/skirmishgameoptionsmenu.h new file mode 100644 index 000000000..f8429498a --- /dev/null +++ b/src/game/client/gui/guicallbacks/skirmishgameoptionsmenu.h @@ -0,0 +1,32 @@ +/** + * @file + * + * @author Jonathan Wilson + * + * @brief Skirmish Game Options 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" +#include "coord.h" +#include "gamewindow.h" +#include "maputil.h" +#include + +class TechAndSupplyImages +{ +public: + std::list m_techPositions; + std::list m_supplyPositions; +}; + +void Position_Additional_Images(MapMetaData *map, GameWindow *window, bool reset); +void Map_Selector_Tooltip(GameWindow *window, WinInstanceData *instance, unsigned int mouse); + +extern TechAndSupplyImages g_theSupplyAndTechImageLocations; diff --git a/src/game/client/ingameui.cpp b/src/game/client/ingameui.cpp index dc0a13e9e..a5b4d0824 100644 --- a/src/game/client/ingameui.cpp +++ b/src/game/client/ingameui.cpp @@ -20,6 +20,27 @@ InGameUI *g_theInGameUI; #endif +void Hide_Replay_Controls() +{ +#ifdef GAME_DLL + Call_Function(PICK_ADDRESS(0x00506FD0, 0x00506FD0)); +#endif +} + +void Show_Replay_Controls() +{ +#ifdef GAME_DLL + Call_Function(PICK_ADDRESS(0x00506FB0, 0x00506FB0)); +#endif +} + +void Toggle_Replay_Controls() +{ +#ifdef GAME_DLL + Call_Function(PICK_ADDRESS(0x00807954, 0x00506FF0)); +#endif +} + void InGameUI::Add_World_Animation( Anim2DTemplate *anim, const Coord3D *pos, WorldAnimationOptions options, float time, float z_rise) { diff --git a/src/game/client/ingameui.h b/src/game/client/ingameui.h index b46ac0b3d..d3faedea6 100644 --- a/src/game/client/ingameui.h +++ b/src/game/client/ingameui.h @@ -363,6 +363,10 @@ class InGameUI : public SubsystemInterface, public SnapShot DrawableID m_soloNexusSelectedDrawableID; }; +void Hide_Replay_Controls(); +void Show_Replay_Controls(); +void Toggle_Replay_Controls(); + #ifdef GAME_DLL extern InGameUI *&g_theInGameUI; #else diff --git a/src/game/client/input/mouse.h b/src/game/client/input/mouse.h index a11786a4d..10ca60c0d 100644 --- a/src/game/client/input/mouse.h +++ b/src/game/client/input/mouse.h @@ -175,12 +175,12 @@ class Mouse : public SubsystemInterface void Draw_Cursor_Text() const; void Set_Cursor_Tooltip(Utf16String tooltip, int delay, const RGBColor *color, float scale); void Draw_Tooltip(); + MouseCursor Get_Cursor_Index(const Utf8String &name); protected: void Update_Mouse_Data(); void Process_Mouse_Event(int event_num); void Move_Mouse(int x, int y, int absolute); // TODO Should be bool absolute, fix after verifying correctness. - MouseCursor Get_Cursor_Index(const Utf8String &name); void Set_Mouse_Text(const MouseCursor cursor); void Set_Mouse_Text(const Utf16String text, const RGBAColorInt *color, const RGBAColorInt *drop_color); diff --git a/src/game/client/maputil.cpp b/src/game/client/maputil.cpp index 5fb872bc4..a5d50df31 100644 --- a/src/game/client/maputil.cpp +++ b/src/game/client/maputil.cpp @@ -85,3 +85,30 @@ MapMetaData *MapCache::Find_Map(Utf8String map_name) return &it->second; } } + +void Find_Draw_Positions(int start_x, int start_y, int width, int height, Region3D extent, ICoord2D *ul, ICoord2D *lr) +{ + float f1 = extent.Width() / (width * 1.0f); + float f2 = extent.Height() / (height * 1.0f); + + if (f1 < f2) { + float f3 = extent.Width() / f2; + float f4 = extent.Height() / f2; + ul->x = 0; + ul->y = (width - f3) / 2.0f; + lr->x = width - ul->x; + lr->y = f4; + } else { + float f3 = extent.Width() / f1; + float f4 = extent.Height() / f1; + ul->x = 0; + ul->y = (height - f4) / 2.0f; + lr->x = f2; + lr->y = height - ul->y; + } + + ul->x += start_x; + ul->y += start_y; + lr->x += start_x; + lr->y += start_y; +} diff --git a/src/game/client/maputil.h b/src/game/client/maputil.h index ced94b7aa..61174dc0f 100644 --- a/src/game/client/maputil.h +++ b/src/game/client/maputil.h @@ -80,6 +80,8 @@ class MapCache : public std::map std::set m_unk; }; +void Find_Draw_Positions(int start_x, int start_y, int width, int height, Region3D extent, ICoord2D *ul, ICoord2D *lr); + #ifdef GAME_DLL extern WaypointMap *&g_waypoints; extern MapCache *&g_theMapCache; diff --git a/src/game/common/rts/playertemplate.cpp b/src/game/common/rts/playertemplate.cpp index 228aa9522..65ca78827 100644 --- a/src/game/common/rts/playertemplate.cpp +++ b/src/game/common/rts/playertemplate.cpp @@ -34,27 +34,27 @@ PlayerTemplate::PlayerTemplate() : { } -Image *PlayerTemplate::Get_Head_Watermark_Image() +const Image *PlayerTemplate::Get_Head_Watermark_Image() const { return g_theMappedImageCollection->Find_Image_By_Name(m_headWaterMark); } -Image *PlayerTemplate::Get_Flag_Watermark_Image() +const Image *PlayerTemplate::Get_Flag_Watermark_Image() const { return g_theMappedImageCollection->Find_Image_By_Name(m_flagWaterMark); } -Image *PlayerTemplate::Get_Side_Icon_Image() +const Image *PlayerTemplate::Get_Side_Icon_Image() const { return g_theMappedImageCollection->Find_Image_By_Name(m_sideIconImage); } -Image *PlayerTemplate::Get_General_Image() +const Image *PlayerTemplate::Get_General_Image() const { return g_theMappedImageCollection->Find_Image_By_Name(m_generalImage); } -Image *PlayerTemplate::Get_Enabled_Image() +const Image *PlayerTemplate::Get_Enabled_Image() const { return g_theMappedImageCollection->Find_Image_By_Name(m_enabledImage); } diff --git a/src/game/common/rts/playertemplate.h b/src/game/common/rts/playertemplate.h index a41950780..ff65dd917 100644 --- a/src/game/common/rts/playertemplate.h +++ b/src/game/common/rts/playertemplate.h @@ -44,11 +44,11 @@ class PlayerTemplate PlayerTemplate(); ~PlayerTemplate() {} - Image *Get_Head_Watermark_Image(); - Image *Get_Flag_Watermark_Image(); - Image *Get_Side_Icon_Image(); - Image *Get_General_Image(); - Image *Get_Enabled_Image(); + const Image *Get_Head_Watermark_Image() const; + const Image *Get_Flag_Watermark_Image() const; + const Image *Get_Side_Icon_Image() const; + const Image *Get_General_Image() const; + const Image *Get_Enabled_Image() const; Utf8String Get_Starting_Unit(int unit) const; Utf8String Get_Name() const { return g_theNameKeyGenerator->Key_To_Name(m_nameKey); } diff --git a/src/game/common/system/gamememory.cpp b/src/game/common/system/gamememory.cpp index f7d1861b2..343422370 100644 --- a/src/game/common/system/gamememory.cpp +++ b/src/game/common/system/gamememory.cpp @@ -22,6 +22,11 @@ #include "mempoolfact.h" #include "rawalloc.h" +#pragma warning(push) +#pragma warning(disable : 4073) // warning C4073: initializers put in library initialization area +#pragma init_seg(lib) // Forces objects and variables in this file to initialize before other stuff. +#pragma warning(pop) + #ifndef GAME_DLL bool g_thePreMainInitFlag = false; bool g_theMainInitFlag = false; diff --git a/src/game/logic/object/update/oclupdate.cpp b/src/game/logic/object/update/oclupdate.cpp new file mode 100644 index 000000000..c20f80766 --- /dev/null +++ b/src/game/logic/object/update/oclupdate.cpp @@ -0,0 +1,28 @@ +/** + * @file + * + * @author Jonathan Wilson + * + * @brief OCL Update + * + * @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 "oclupdate.h" +#include "gamelogic.h" + +float OCLUpdate::Get_Countdown_Percent() const +{ + return 1.0f + - (float)(m_creationTimerEndFrame - g_theGameLogic->Get_Frame()) + / (float)(m_creationTimerEndFrame - m_creationTimerStarttFrame); +} + +unsigned int OCLUpdate::Get_Remaining_Frames() const +{ + return m_creationTimerEndFrame - g_theGameLogic->Get_Frame(); +} diff --git a/src/game/logic/object/update/oclupdate.h b/src/game/logic/object/update/oclupdate.h new file mode 100644 index 000000000..0c3b2866c --- /dev/null +++ b/src/game/logic/object/update/oclupdate.h @@ -0,0 +1,42 @@ +/** + * @file + * + * @author Jonathan Wilson + * + * @brief OCL Update + * + * @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 "updatemodule.h" + +class OCLUpdate : public UpdateModule +{ + IMPLEMENT_POOL(OCLUpdate) + +public: + virtual ~OCLUpdate() override; + virtual NameKeyType Get_Module_Name_Key() const override; + + virtual void CRC_Snapshot(Xfer *xfer) override; + virtual void Xfer_Snapshot(Xfer *xfer) override; + virtual void Load_Post_Process() override; + + virtual UpdateSleepTime Update() override; + virtual DisabledBitFlags Get_Disabled_Types_To_Process() const override; + + float Get_Countdown_Percent() const; + unsigned int Get_Remaining_Frames() const; + +private: + unsigned int m_creationTimerEndFrame; + unsigned int m_creationTimerStarttFrame; + bool m_isAIControlled; + int m_color; +}; diff --git a/src/hooker/setuphooks_zh.cpp b/src/hooker/setuphooks_zh.cpp index deb929f61..c74baa8f5 100644 --- a/src/hooker/setuphooks_zh.cpp +++ b/src/hooker/setuphooks_zh.cpp @@ -83,6 +83,7 @@ #include "gamestate.h" #include "gametext.h" #include "gamewindowtransitions.h" +#include "generalsexppoints.h" #include "geometry.h" #include "globaldata.h" #include "hanimmgr.h" @@ -99,6 +100,7 @@ #include "locomotor.h" #include "main.h" #include "mapobject.h" +#include "maputil.h" #include "matpass.h" #include "memdynalloc.h" #include "mesh.h" @@ -155,6 +157,7 @@ #include "shadermanager.h" #include "sidesinfo.h" #include "sideslist.h" +#include "skirmishgameoptionsmenu.h" #include "smudge.h" #include "sortingrenderer.h" #include "specialpower.h" @@ -189,6 +192,7 @@ #include "w3dbibbuffer.h" #include "w3dbridgebuffer.h" #include "w3dbuffermanager.h" +#include "w3dcontrolbar.h" #include "w3ddebugdisplay.h" #include "w3ddisplay.h" #include "w3dfilesystem.h" @@ -3523,7 +3527,8 @@ void Setup_Hooks() 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_Method(0x0045FD00, + static_cast(&ControlBar::Set_Control_Command)); Hook_Any(0x0045E2A0, ControlBar::Reset); Hook_Any(0x0045E4C0, ControlBar::Update); Hook_Any(0x0045EAE0, ControlBar::Get_Star_Image); @@ -3593,9 +3598,61 @@ void Setup_Hooks() Hook_Any(0x005AB940, ControlBar::Update_Context_Multi_Select); Hook_Any(0x005AAF60, ControlBar::Populate_Under_Construction); + Hook_Any(0x00460B70, ControlBar::Toggle_Purchase_Science); + Hook_Any(0x00460B50, ControlBar::Hide_Purchase_Science); + Hook_Any(0x00462860, ControlBar::Show_Special_Power_Shortcut); + Hook_Any(0x00460AD0, ControlBar::Show_Purchase_Science); + Hook_Any(0x0045B400, ControlBar::Populate_Purchase_Science); + Hook_Any(0x004627D0, ControlBar::Animate_Special_Power_Shortcut); + Hook_Any(0x0045F880, ControlBar::Process_Context_Sensitive_Button_Click); + Hook_Any(0x005A6970, ControlBar::Set_Control_Bar_Scheme_By_Player); + Hook_Any(0x005A6710, ControlBar::Set_Control_Bar_Scheme_By_Player_Template); + Hook_Any(0x00461680, ControlBar::Init_Special_Power_Shortcut_Bar); + Hook_Any(0x0045F8C0, ControlBar::Switch_To_Context); + Hook_Any(0x0045EC00, ControlBar::Evaluate_Context_UI); + Hook_Any(0x00462230, ControlBar::Update_Special_Power_Shortcut); + Hook_Any(0x00461B10, ControlBar::Populate_Special_Power_Shortcut); + Hook_Any(0x00462670, ControlBar::Draw_Special_Power_Shortcut_Multiplier_Text); + Hook_Any(0x005A6CB0, ControlBar::Init_Observer_Controls); + Hook_Any(0x005A6F60, Control_Bar_Observer_System); + Hook_Any(0x005A7050, ControlBar::Populate_Observer_List); + Hook_Any(0x005A7480, ControlBar::Populate_Observer_Info_Window); + Hook_Any(0x005AADE0, ControlBar::Update_Context_OCL_Timer); + Hook_Any(0x005AAB80, ControlBar::Populate_OCL_Timer); + Hook_Any(0x005AAA10, ControlBar::Update_OCL_Timer_Text_Display); + Hook_Any(0x0048A3E0, Hide_Control_Bar); + Hook_Any(0x0048A250, Show_Control_Bar); + Hook_Any(0x00489930, Left_HUD_Input); + Hook_Any(0x00489D00, Control_Bar_System); + Hook_Any(0x0048A540, Toggle_Control_Bar); + // controlbarscheme.h Hook_Any(0x005A66B0, ControlBarSchemeManager::Draw_Foreground); Hook_Any(0x005A66E0, ControlBarSchemeManager::Draw_Background); Hook_Any(0x005A6710, ControlBarSchemeManager::Set_Control_Bar_Scheme_By_Player_Template); Hook_Any(0x005A6970, ControlBarSchemeManager::Set_Control_Bar_Scheme_By_Player); + + // generalsexppoints.h + Hook_Any(0x006D62E0, Generals_Exp_Points_Input); + Hook_Any(0x006D6330, Generals_Exp_Points_System); + + // skirmishgameoptionsmenu.h + Hook_Any(0x005F22A0, Position_Additional_Images); + Hook_Any(0x005F1DB0, Map_Selector_Tooltip); + + // maputil.h + Hook_Any(0x00483510, Find_Draw_Positions); + + // w3dcontrolbar.h + Hook_Any(0x007C8860, W3D_Cameo_Movie_Draw); + Hook_Any(0x007C88D0, W3D_Left_HUD_Draw); + Hook_Any(0x007C89C0, W3D_Right_HUD_Draw); + Hook_Any(0x007C89E0, W3D_Power_Draw); + Hook_Any(0x007C8EA0, W3D_Command_Bar_Grid_Draw); + Hook_Any(0x007C9010, W3D_Command_Bar_Gen_Exp_Draw); + Hook_Any(0x007C9450, W3D_Command_Bar_Top_Draw); + Hook_Any(0x007C94A0, W3D_Command_Bar_Background_Draw); + Hook_Any(0x007C95F0, W3D_Command_Bar_Foreground_Draw); + Hook_Any(0x007C9740, W3D_Draw_Map_Preview); + Hook_Any(0x007CA250, W3D_Command_Bar_Help_Popup_Draw); } diff --git a/src/platform/w3dengine/client/gui/guicallbacks/w3dcontrolbar.cpp b/src/platform/w3dengine/client/gui/guicallbacks/w3dcontrolbar.cpp new file mode 100644 index 000000000..585ee50d8 --- /dev/null +++ b/src/platform/w3dengine/client/gui/guicallbacks/w3dcontrolbar.cpp @@ -0,0 +1,565 @@ +/** + * @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 "w3dcontrolbar.h" +#include "controlbar.h" +#include "controlbarscheme.h" +#include "display.h" +#include "gamewindowmanager.h" +#include "globaldata.h" +#include "ingameui.h" +#include "maputil.h" +#include "player.h" +#include "playerlist.h" +#include "radar.h" +#include "skirmishgameoptionsmenu.h" +#include "w3dgamewindow.h" + +void W3D_Cameo_Movie_Draw(GameWindow *window, WinInstanceData *instance) +{ + VideoBuffer *buffer = g_theInGameUI->Cameo_Video_Buffer(); + + if (buffer != nullptr) { + int screen_x; + int screen_y; + int width; + int height; + window->Win_Get_Screen_Position(&screen_x, &screen_y); + window->Win_Get_Size(&width, &height); + g_theDisplay->Draw_VideoBuffer(buffer, screen_x, screen_y, screen_x + width, screen_y + height); + } +} + +void W3D_Left_HUD_Draw(GameWindow *window, WinInstanceData *instance) +{ + Player *player = g_thePlayerList->Get_Local_Player(); + VideoBuffer *buffer = g_theInGameUI->Video_Buffer(); + + if (buffer != nullptr) { + int screen_x; + int screen_y; + int width; + int height; + window->Win_Get_Screen_Position(&screen_x, &screen_y); + window->Win_Get_Size(&width, &height); + g_theDisplay->Draw_VideoBuffer(buffer, screen_x, screen_y, screen_x + width, screen_y + height); + } else if (g_theRadar->Is_Radar_Forced() || (!g_theRadar->Is_Radar_Hidden() && player->Has_Radar())) { + int screen_x; + int screen_y; + int width; + int height; + window->Win_Get_Screen_Position(&screen_x, &screen_y); + window->Win_Get_Size(&width, &height); + g_theRadar->Draw(screen_x + 1, screen_y + 1, width - 2, height - 2); + } +} + +void W3D_Right_HUD_Draw(GameWindow *window, WinInstanceData *instance) +{ + if ((window->Win_Get_Status() & WIN_STATUS_IMAGE) != 0) { + W3D_Game_Win_Default_Draw(window, instance); + } +} + +float Log_N(float f1, float f2) +{ + return log10(f1) / log10(f2); +} + +void W3D_Power_Draw(GameWindow *window, WinInstanceData *instance) +{ + static const Image *centerBarYellow = g_theMappedImageCollection->Find_Image_By_Name("PowerPointY"); + static const Image *centerBarRed = g_theMappedImageCollection->Find_Image_By_Name("PowerPointR"); + static const Image *centerBarGreen = g_theMappedImageCollection->Find_Image_By_Name("PowerPointG"); + static const Image *slider = g_theMappedImageCollection->Find_Image_By_Name("PowerBarSlider"); + Player *player; + + if (g_theControlBar->Is_Observer()) { + player = g_theControlBar->Get_Observer_Player(); + } else { + player = g_thePlayerList->Get_Local_Player(); + } + + if (player != nullptr) { + if (g_theWriteableGlobalData != nullptr) { + Energy *energy = player->Get_Energy(); + + if (energy != nullptr) { + int consumption = energy->Get_Consumption(); + int production = energy->Get_Production(); + int screen_x; + int screen_y; + int width; + int height; + window->Win_Get_Screen_Position(&screen_x, &screen_y); + window->Win_Get_Size(&width, &height); + static float pixelsPerInterval = width / g_theWriteableGlobalData->m_powerBarIntervals; + const Image *bar; + + if (consumption <= energy->Get_Production() - g_theWriteableGlobalData->m_powerBarYellowRange + || consumption > energy->Get_Production()) { + bar = centerBarRed; + + if (consumption < production) { + bar = centerBarGreen; + } + } else { + bar = centerBarYellow; + } + + if (slider != nullptr && bar != nullptr) { + int log = Log_N(production, g_theWriteableGlobalData->m_powerBarBase) + * (width / g_theWriteableGlobalData->m_powerBarIntervals); + + if (log >= width) { + log = width; + } + + if (log > 0) { + int image_width = bar->Get_Image_Width(); + int start_x = screen_x; + int end_y = screen_y + height; + int count = log / image_width; + + if (count > 0) { + do { + g_theWindowManager->Win_Draw_Image( + bar, start_x, screen_y, image_width + start_x, end_y, 0xFFFFFFFF); + image_width = bar->Get_Image_Width(); + start_x += image_width; + count--; + } while (count != 0); + } + + IRegion2D clip_region; + clip_region.hi.x = width + screen_x; + clip_region.hi.y = screen_y + height; + clip_region.lo.x = start_x; + clip_region.lo.y = screen_y; + log = width + screen_x - start_x; + + if (log > 0) { + g_theDisplay->Set_Clip_Region(&clip_region); + g_theWindowManager->Win_Draw_Image( + bar, start_x, screen_y, start_x + bar->Get_Image_Width(), end_y, 0xFFFFFFFF); + g_theDisplay->Enable_Clipping(false); + } + } + + float f; + + if (consumption == 1) { + f = 1.5f; + } else { + f = consumption; + } + + int log2 = Log_N(f, g_theWriteableGlobalData->m_powerBarBase) + * (width / g_theWriteableGlobalData->m_powerBarIntervals); + + if (log > 0 || log2 > 0) { + int image_width = slider->Get_Image_Width(); + int start_x; + int end_x; + + if (log2 < width) { + start_x = log2 + screen_x - image_width / 2; + end_x = log2 + screen_x + image_width / 2; + } else { + start_x = width + screen_x - image_width; + end_x = screen_x + width; + } + + if (start_x <= screen_x) { + start_x = screen_x; + end_x = image_width + screen_x; + } + + g_theWindowManager->Win_Draw_Image(slider, + start_x, + screen_y + height - slider->Get_Image_Height(), + end_x, + height + screen_y, + 0xFFFFFFFF); + } + } + } + } + } +} + +void W3D_Command_Bar_Grid_Draw(GameWindow *window, WinInstanceData *instance) +{ + if ((window->Win_Get_Status() & WIN_STATUS_IMAGE) == 0) { + int screen_x; + int screen_y; + int width; + int height; + window->Win_Get_Screen_Position(&screen_x, &screen_y); + window->Win_Get_Size(&width, &height); + int color = g_theControlBar->Get_Command_Bar_Border_Color(); + window->Win_Set_Enabled_Border_Color(0, color); + int i = height * 0.33f + screen_y; + g_theDisplay->Draw_Line(screen_x, i, screen_x + width, i, 1.0f, color); + i = height * 0.66f + screen_y; + g_theDisplay->Draw_Line(screen_x, i, screen_x + width, i, 1.0f, color); + i = width * 0.33f + screen_x; + g_theDisplay->Draw_Line(i, screen_y, i, screen_y + height, 1.0f, color); + i = width * 0.66f + screen_x; + g_theDisplay->Draw_Line(i, screen_y, i, screen_y + height, 1.0f, color); + } else { + W3D_Game_Win_Default_Draw(window, instance); + } +} + +void W3D_Command_Bar_Gen_Exp_Draw(GameWindow *window, WinInstanceData *instance) +{ + Player *player = g_thePlayerList->Get_Local_Player(); + + if (player->Is_Player_Active()) { + static const Image *endBar = g_theMappedImageCollection->Find_Image_By_Name("GenExpBarTop1"); + static const Image *beginBar = g_theMappedImageCollection->Find_Image_By_Name("GenExpBarBottom1"); + static const Image *centerBar = g_theMappedImageCollection->Find_Image_By_Name("GenExpBar1"); + int i1 = 100 * (player->Get_Current_Skill_Points() - player->Get_Rank_Progress()) + / (player->Get_Skill_Points_Needed_For_Next_Rank() - player->Get_Rank_Progress()); + int i2 = i1; + + if (i1 > 0) { + if (i1 > 100) { + i2 = 100; + } + + int screen_x; + int screen_y; + int width; + int height; + window->Win_Get_Screen_Position(&screen_x, &screen_y); + window->Win_Get_Size(&width, &height); + + if (endBar != nullptr && beginBar != nullptr && centerBar != nullptr) { + int begin_bar_height = beginBar->Get_Image_Height(); + int i3 = i2 * height; + int end_bar_height = endBar->Get_Image_Height(); + int end_x = screen_x + width; + int start_y = screen_y + height - begin_bar_height; + int i4 = i3 / 100; + int i5 = screen_y + height - end_bar_height - i3 / 100; + + if (start_y - i5 > 0) { + int center_bar_height = centerBar->Get_Image_Height(); + + if ((start_y - i5) / center_bar_height > 0) { + int count = (start_y - i5) / center_bar_height; + + do { + g_theWindowManager->Win_Draw_Image( + centerBar, screen_x, i5, end_x, i5 + center_bar_height, 0xFFFFFFFF); + center_bar_height = centerBar->Get_Image_Height(); + i5 += center_bar_height; + count--; + } while (count != 0); + } + + IRegion2D clip_region; + clip_region.lo.x = screen_x; + clip_region.lo.y = i5; + clip_region.hi.x = end_x; + clip_region.hi.y = start_y; + + if (start_y - i5 > 0) { + g_theDisplay->Set_Clip_Region(&clip_region); + g_theWindowManager->Win_Draw_Image( + centerBar, screen_x, i5, end_x, i5 + centerBar->Get_Image_Height(), 0xFFFFFFFF); + g_theDisplay->Enable_Clipping(false); + } + + g_theWindowManager->Win_Draw_Image( + beginBar, screen_x, start_y, screen_x + width, screen_y + height, 0xFFFFFFFF); + g_theWindowManager->Win_Draw_Image(endBar, + screen_x, + screen_y + height - i4, + screen_x + width, + screen_y + height - end_bar_height - i4, + 0xFFFFFFFF); + } else { + g_theWindowManager->Win_Draw_Image(beginBar, screen_x, start_y, end_x, screen_y + height, 0xFFFFFFFF); + g_theWindowManager->Win_Draw_Image(endBar, + screen_x, + screen_y + height - end_bar_height - begin_bar_height, + width + screen_x, + screen_y + height - begin_bar_height, + 0xFFFFFFFF); + } + } + } + } +} + +void W3D_Command_Bar_Top_Draw(GameWindow *window, WinInstanceData *instance) +{ + GameWindow *win = g_theWindowManager->Win_Get_Window_From_Id( + nullptr, g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:ButtonGeneral")); + + if (win != nullptr) { + if (!win->Win_Is_Hidden()) { + g_thePlayerList->Get_Local_Player()->Is_Player_Active(); + } + } +} + +void W3D_Command_Bar_Background_Draw(GameWindow *window, WinInstanceData *instance) +{ + ControlBarSchemeManager *manager = g_theControlBar->Get_Control_Bar_Scheme_Manager(); + + if (manager != nullptr) { + static const NameKeyType winNamekey = g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:BackgroundMarker"); + GameWindow *win = g_theWindowManager->Win_Get_Window_From_Id(nullptr, winNamekey); + + if (win != nullptr) { + static ICoord2D basePos; + g_theControlBar->Get_Background_Marker_Pos(&basePos.x, &basePos.y); + int screen_x; + int screen_y; + win->Win_Get_Screen_Position(&screen_x, &screen_y); + ICoord2D offset; + offset.y = screen_y - basePos.y; + offset.x = screen_x - basePos.x; + manager->Draw_Background(offset); + } + } +} + +void W3D_Command_Bar_Foreground_Draw(GameWindow *window, WinInstanceData *instance) +{ + ControlBarSchemeManager *manager = g_theControlBar->Get_Control_Bar_Scheme_Manager(); + + if (manager != nullptr) { + static const NameKeyType winNamekey = g_theNameKeyGenerator->Name_To_Key("ControlBar.wnd:BackgroundMarker"); + GameWindow *win = g_theWindowManager->Win_Get_Window_From_Id(nullptr, winNamekey); + + if (win != nullptr) { + static ICoord2D basePos; + g_theControlBar->Get_Foreground_Marker_Pos(&basePos.x, &basePos.y); + int screen_x; + int screen_y; + win->Win_Get_Screen_Position(&screen_x, &screen_y); + ICoord2D offset; + offset.y = screen_y - basePos.y; + offset.x = screen_x - basePos.x; + manager->Draw_Foreground(offset); + } + } +} + +void Draw_Skinny_Border(int x, int y, int width, int height) +{ + int i1 = x + width; + int i2 = y + height; + int i3 = y + height - 5; + int i4 = x + width - 10; + Image *frame_t = g_theMappedImageCollection->Find_Image_By_Name("FrameT"); + Image *frame_b = g_theMappedImageCollection->Find_Image_By_Name("FrameB"); + int i; + + for (i = x + 3; i <= i4; i += 5) { + g_theDisplay->Draw_Image(frame_t, i, y - 2, i + 5, y + 3, 0xFFFFFFFF, Display::DRAWIMAGE_ADDITIVE); + g_theDisplay->Draw_Image(frame_b, i, i3, i + 5, i3 + 5, 0xFFFFFFFF, Display::DRAWIMAGE_ADDITIVE); + } + + int i5 = i1 - 5; + + if (i1 - 5 - i >= 2) { + g_theDisplay->Draw_Image(frame_t, i, y - 2, i + 2, y + 3, 0xFFFFFFFF, Display::DRAWIMAGE_ADDITIVE); + g_theDisplay->Draw_Image(frame_b, i, i3, i + 2, i3 + 5, 0xFFFFFFFF, Display::DRAWIMAGE_ADDITIVE); + i += 2; + } + + if (i < i5) { + int i6 = i - (2 - ((i5 - i + 1) & 0xFFFFFFFE)); + g_theDisplay->Draw_Image(frame_t, i6, y - 2, i6 + 2, y + 3, 0xFFFFFFFF, Display::DRAWIMAGE_ADDITIVE); + g_theDisplay->Draw_Image(frame_b, i6, i3, i6 + 2, i3 + 5, 0xFFFFFFFF, Display::DRAWIMAGE_ADDITIVE); + } + + Image *frame_l = g_theMappedImageCollection->Find_Image_By_Name("FrameL"); + Image *frame_r = g_theMappedImageCollection->Find_Image_By_Name("FrameR"); + int i7 = x - 2; + int j; + + for (j = y + 3; j <= i2 - 10; j += 5) { + g_theDisplay->Draw_Image(frame_l, x - 2, j, i7 + 5, j + 5, 0xFFFFFFFF, Display::DRAWIMAGE_ADDITIVE); + g_theDisplay->Draw_Image(frame_r, i1 - 5, j, i1, j + 5, 0xFFFFFFFF, Display::DRAWIMAGE_ADDITIVE); + } + + int i8 = i2 - 5; + + if (i2 - 5 - j >= 2) { + g_theDisplay->Draw_Image(frame_l, x - 2, j, i7 + 5, j + 2, 0xFFFFFFFF, Display::DRAWIMAGE_ADDITIVE); + g_theDisplay->Draw_Image(frame_r, i1 - 5, j, i1, j + 2, 0xFFFFFFFF, Display::DRAWIMAGE_ADDITIVE); + j += 2; + } + + if (j < i8) { + int i9 = j - (2 - ((i8 - j + 1) & 0xFFFFFFFE)); + g_theDisplay->Draw_Image(frame_l, x - 2, i9, i7 + 5, i9 + 2, 0xFFFFFFFF, Display::DRAWIMAGE_ADDITIVE); + g_theDisplay->Draw_Image(frame_r, i1 - 5, i9, i1, i9 + 2, 0xFFFFFFFF, Display::DRAWIMAGE_ADDITIVE); + } + + Image *frame_corner_ul = g_theMappedImageCollection->Find_Image_By_Name("FrameCornerUL"); + g_theDisplay->Draw_Image(frame_corner_ul, x - 2, y - 2, x - 2 + 5, y - 2 + 5, 0xFFFFFFFF, Display::DRAWIMAGE_ADDITIVE); + Image *frame_corner_ur = g_theMappedImageCollection->Find_Image_By_Name("FrameCornerUR"); + g_theDisplay->Draw_Image(frame_corner_ur, i1 - 5, y - 2, i1, y - 2 + 5, 0xFFFFFFFF, Display::DRAWIMAGE_ADDITIVE); + Image *frame_corner_ll = g_theMappedImageCollection->Find_Image_By_Name("FrameCornerLL"); + g_theDisplay->Draw_Image(frame_corner_ll, x - 2, i2 - 5, x - 2 + 5, i2, 0xFFFFFFFF, Display::DRAWIMAGE_ADDITIVE); + Image *frame_corner_lr = g_theMappedImageCollection->Find_Image_By_Name("FrameCornerLR"); + g_theDisplay->Draw_Image(frame_corner_lr, i1 - 5, i2 - 5, i1, i2, 0xFFFFFFFF, Display::DRAWIMAGE_ADDITIVE); +} + +void W3D_Draw_Map_Preview(GameWindow *window, WinInstanceData *instance) +{ + MapMetaData *data = static_cast(window->Win_Get_User_Data()); + int screen_x; + int screen_y; + int width; + int height; + window->Win_Get_Screen_Position(&screen_x, &screen_y); + window->Win_Get_Size(&width, &height); + + if (data != nullptr) { + ICoord2D ul; + ICoord2D lr; + Find_Draw_Positions(screen_x, screen_y, width, height, data->m_extent, &ul, &lr); + + if ((data->m_extent.hi.y - data->m_extent.lo.y) / height > (data->m_extent.hi.x - data->m_extent.lo.x) / width) { + g_theDisplay->Draw_Fill_Rect(screen_x, screen_y, ul.x - screen_x - 1, height, 0xFF000000); + g_theDisplay->Draw_Fill_Rect(lr.x + 1, screen_y, width - lr.x + screen_x - 1, height, 0xFF000000); + g_theDisplay->Draw_Line(ul.x, screen_y, ul.x, screen_y + height, 1.0f, 0xFF323232); + g_theDisplay->Draw_Line(lr.x + 1, screen_y, lr.x + 1, screen_y + height, 1.0f, 0xFF323232); + } else { + g_theDisplay->Draw_Fill_Rect(screen_x, screen_y, width, ul.y - screen_y - 1, 0xFF000000); + g_theDisplay->Draw_Fill_Rect(screen_x, lr.y + 1, width, screen_y + height - lr.y - 1, 0xFF000000); + g_theDisplay->Draw_Line(screen_x, ul.y, screen_x + width, ul.y, 1.0f, 0xFF323232); + g_theDisplay->Draw_Line(screen_x, lr.y + 1, screen_x + width, lr.y + 1, 1.0f, 0xFF323232); + } + + if ((window->Win_Get_Status() & WIN_STATUS_IMAGE) != 0 + && window->Win_Get_Instance_Data()->m_enabledDrawData[0].image != nullptr) { + g_theDisplay->Draw_Image(window->Win_Get_Instance_Data()->m_enabledDrawData[0].image, + ul.x, + ul.y, + lr.x, + lr.y, + 0xFFFFFFFF, + Display::DRAWIMAGE_ADDITIVE); + } else { + g_theDisplay->Draw_Fill_Rect(ul.x, ul.y, lr.x - ul.x, lr.y - ul.y, 0xFF323232); + } + + Image *tech_building = g_theMappedImageCollection->Find_Image_By_Name("TecBuilding"); + + for (auto it = g_theSupplyAndTechImageLocations.m_techPositions.begin(); + it != g_theSupplyAndTechImageLocations.m_techPositions.end(); + it++) { + g_theDisplay->Draw_Image(tech_building, + screen_x + it->x, + screen_y + it->y, + screen_x + it->x + 15, + screen_y + it->y + 15, + 0xFFFFFFFF, + Display::DRAWIMAGE_ADDITIVE); + } + + Image *cash = g_theMappedImageCollection->Find_Image_By_Name("Cash"); + + for (auto it = g_theSupplyAndTechImageLocations.m_supplyPositions.begin(); + it != g_theSupplyAndTechImageLocations.m_supplyPositions.end(); + it++) { + g_theDisplay->Draw_Image(cash, + screen_x + it->x, + screen_y + it->y, + screen_x + it->x + 15, + screen_y + it->y + 15, + 0xFFFFFFFF, + Display::DRAWIMAGE_ADDITIVE); + } + + Draw_Skinny_Border(screen_x - 1, screen_y - 1, width + 2, height + 2); + } else { + W3D_Game_Win_Default_Draw(window, instance); + Draw_Skinny_Border(screen_x - 1, screen_y - 1, width + 2, height + 2); + } +} + +void W3D_Command_Bar_Help_Popup_Draw(GameWindow *window, WinInstanceData *instance) +{ + static const Image *endBar = g_theMappedImageCollection->Find_Image_By_Name("Helpbox-top"); + static const Image *beginBar = g_theMappedImageCollection->Find_Image_By_Name("Helpbox-bottom"); + static const Image *centerBar = g_theMappedImageCollection->Find_Image_By_Name("Helpbox-middle"); + int screen_x; + int screen_y; + int width; + int height; + window->Win_Get_Screen_Position(&screen_x, &screen_y); + window->Win_Get_Size(&width, &height); + + if (endBar != nullptr && beginBar != nullptr && centerBar != nullptr) { + int begin_bar_height = beginBar->Get_Image_Height(); + int end_bar_height = endBar->Get_Image_Height(); + int i1 = height - end_bar_height - begin_bar_height; + + if (i1 > 0) { + int center_bar_height = centerBar->Get_Image_Height(); + int i2 = screen_y + end_bar_height; + int i3 = screen_x + width; + int i4 = i1 / center_bar_height; + if (i4 > 0) { + int i5 = i4; + do { + g_theWindowManager->Win_Draw_Image(centerBar, screen_x, i2, i3, i2 + center_bar_height, 0xFFFFFFFF); + center_bar_height = centerBar->Get_Image_Height(); + i2 += center_bar_height; + i5--; + } while (i5 != 0); + } + + IRegion2D clip_region; + clip_region.lo.x = screen_x; + clip_region.hi.x = screen_x + width; + clip_region.hi.y = screen_y + height - begin_bar_height; + clip_region.lo.y = i2; + + if (screen_y + height - i2 - begin_bar_height > 0) { + g_theDisplay->Set_Clip_Region(&clip_region); + g_theWindowManager->Win_Draw_Image( + centerBar, screen_x, i2, i3, i2 + centerBar->Get_Image_Height(), 0xFFFFFFFF); + g_theDisplay->Enable_Clipping(false); + } + + g_theWindowManager->Win_Draw_Image( + beginBar, screen_x, screen_y + height - begin_bar_height, screen_x + width, height + screen_y, 0xFFFFFFFF); + g_theWindowManager->Win_Draw_Image( + endBar, screen_x, screen_y, screen_x + width, screen_y + end_bar_height, 0xFFFFFFFF); + } else { + g_theWindowManager->Win_Draw_Image( + beginBar, screen_x, screen_y + height - begin_bar_height, screen_x + width, screen_y + height, 0xFFFFFFFF); + g_theWindowManager->Win_Draw_Image(endBar, + screen_x, + screen_y + height - end_bar_height - begin_bar_height, + width + screen_x, + screen_y + height - begin_bar_height, + 0xFFFFFFFF); + } + } +} + +void W3D_No_Draw(GameWindow *window, WinInstanceData *instance) {} diff --git a/src/platform/w3dengine/client/gui/guicallbacks/w3dcontrolbar.h b/src/platform/w3dengine/client/gui/guicallbacks/w3dcontrolbar.h new file mode 100644 index 000000000..1fcc53f44 --- /dev/null +++ b/src/platform/w3dengine/client/gui/guicallbacks/w3dcontrolbar.h @@ -0,0 +1,30 @@ +/** + * @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 + */ +#pragma once +#include "always.h" +#include "gamewindow.h" + +void W3D_Cameo_Movie_Draw(GameWindow *window, WinInstanceData *instance); +void W3D_Left_HUD_Draw(GameWindow *window, WinInstanceData *instance); +void W3D_Right_HUD_Draw(GameWindow *window, WinInstanceData *instance); +void W3D_Power_Draw(GameWindow *window, WinInstanceData *instance); +void W3D_Command_Bar_Grid_Draw(GameWindow *window, WinInstanceData *instance); +void W3D_Command_Bar_Gen_Exp_Draw(GameWindow *window, WinInstanceData *instance); +void W3D_Command_Bar_Top_Draw(GameWindow *window, WinInstanceData *instance); +void W3D_Command_Bar_Background_Draw(GameWindow *window, WinInstanceData *instance); +void W3D_Command_Bar_Foreground_Draw(GameWindow *window, WinInstanceData *instance); +void W3D_Draw_Map_Preview(GameWindow *window, WinInstanceData *instance); +void W3D_Command_Bar_Help_Popup_Draw(GameWindow *window, WinInstanceData *instance); +void W3D_No_Draw(GameWindow *window, WinInstanceData *instance);