From 32dab094d9dbfa608186731625ff0272b6fe29a6 Mon Sep 17 00:00:00 2001
From: CrimRecya <335958461@qq.com>
Date: Sun, 15 Sep 2024 20:38:04 +0800
Subject: [PATCH 01/12] Core
---
CREDITS.md | 2 +
Phobos.vcxproj | 4 +
docs/User-Interface.md | 29 +-
docs/Whats-New.md | 1 +
src/Commands/Commands.cpp | 10 +
src/Commands/SWShortcuts.cpp | 1 +
src/Commands/SWShortcuts.h | 94 ++++++
src/Ext/House/Body.cpp | 2 +
src/Ext/House/Body.h | 5 +
src/Ext/Rules/Body.cpp | 3 +
src/Ext/Rules/Body.h | 3 +
src/Ext/SWType/Body.cpp | 31 ++
src/Ext/SWType/Body.h | 31 ++
src/Ext/Side/Body.cpp | 6 +
src/Ext/Side/Body.h | 3 +
src/Misc/PhobosToolTip.cpp | 21 ++
src/Misc/TacticalButtons.cpp | 617 +++++++++++++++++++++++++++++++++++
src/Misc/TacticalButtons.h | 48 +++
18 files changed, 910 insertions(+), 1 deletion(-)
create mode 100644 src/Commands/SWShortcuts.cpp
create mode 100644 src/Commands/SWShortcuts.h
create mode 100644 src/Misc/TacticalButtons.cpp
create mode 100644 src/Misc/TacticalButtons.h
diff --git a/CREDITS.md b/CREDITS.md
index 5fa07e8307..eba5d58fdb 100644
--- a/CREDITS.md
+++ b/CREDITS.md
@@ -353,6 +353,8 @@ This page lists all the individual contributions to the project by their author.
- Re-enable the Veinhole Monster and Weeds from TS
- Recreate the weed-charging of SWs like the TS Chemical Missile
- Allow to change the speed of gas particles
+- **CrimRecya**
+ - Exclusive Sidebar for Superweapons
- **Ollerus**
- Build limit group enhancement
- Customizable rocker amplitude
diff --git a/Phobos.vcxproj b/Phobos.vcxproj
index da0fa52603..fd2780e176 100644
--- a/Phobos.vcxproj
+++ b/Phobos.vcxproj
@@ -179,6 +179,8 @@
+
+
@@ -272,6 +274,8 @@
+
+
diff --git a/docs/User-Interface.md b/docs/User-Interface.md
index 6a900a6545..79ba95c6a2 100644
--- a/docs/User-Interface.md
+++ b/docs/User-Interface.md
@@ -45,7 +45,7 @@ IngameScore.LoseTheme= ; Soundtrack theme ID
- Default `Offset.ShieldDelta` for `InfoType=Shield` is `0,-10`, `0,0` for others.
- Default `Shape.Spacing` for buildings is `4,-2`, `4,0` for others.
- `ValueScaleDivisor` can be used to adjust scale of displayed values. Both the current & maximum value will be divided by the integer number given, if higher than 1.
-
+
In `rulesmd.ini`:
```ini
[DigitalDisplayTypes]
@@ -344,6 +344,33 @@ In `rulesmd.ini`:
MissingCameo=XXICON.SHP ; filename - including the .shp/.pcx extension
```
+### Exclusive sidebar for superweapons
+
+- Now, you can display a sidebar exclusive to superweapons through a series of settings. At the same time, you can specify the shortcuts for these buttons in the shortcut key settings. Note that this feature does not support superweapons with `SW.UseAITargeting=true`.
+ - `SWSidebarBackground` controls whether to draw the background shape of the exclusive sidebar.
+ - `SWSidebarBackground.TopPCX`, `SWSidebarBackground.CenterPCX` and `SWSidebarBackground.BottomPCX` controlled the materials that were combined to create the entire exclusive sidebar background shape. Their required sizes are respectively `80 * 20`, `80 * 50` and `80 * 20`. In `SWSidebarBackground.CenterPCX`, the position of the superweapon's `SidebarPCX` is 5 pixels away from the left contour of this background, 15 pixels away from the right contour, and 1 pixel away from both the upper and lower contours.
+ - `SW.InScreen.Show` controls whether the superweapon should be displayed first in the exclusive sidebar. If the exclusive sidebar is full (up to 9 are displayed), the overflowing superweapon's cameo will be added back to the original sidebar. If there is an empty space in the exclusive sidebar afterwards, it will no longer return to the exclusive sidebar, unless the permission to use the superweapon is regained (lost and gained again). Therefore, it is not recommended to place all superweapons in the exclusive sidebar.
+ - `SW.InScreen.PriorityHouses` controls if the superweapon is displayed first in the exclusive sidebar, players belonging to these houses will have priority in placing the superweapon cameo in the exclusive sidebar.
+ - `SW.InScreen.RequiredHouses` controls if the superweapon is displayed first in the exclusive sidebar, players must belong to these houses in order to have superweapon a real chance of being displayed in the exclusive sidebar. The default is empty, which means this condition will always be met.
+ - `SW.InScreen.QuickFire` controls whether the superweapon which is displayed in the exclusive sidebar will forcibly launch to the center position of the current screen without all Ares conditions check except charging and funds.
+
+In `rulesmd.ini`:
+```ini
+[AudioVisual]
+SWSidebarBackground=true ; boolean
+
+[SOMESIDE] ; Side
+SWSidebarBackground.TopPCX= ; filename - including the .pcx extension
+SWSidebarBackground.CenterPCX= ; filename - including the .pcx extension
+SWSidebarBackground.BottomPCX= ; filename - including the .pcx extension
+
+[SOMESW] ; SuperWeapon
+SW.InScreen.Show=false ; boolean
+SW.InScreen.PriorityHouses= ; list of house types
+SW.InScreen.RequiredHouses= ; list of house types
+SW.InScreen.QuickFire=false ; boolean
+```
+
### Harvester counter

diff --git a/docs/Whats-New.md b/docs/Whats-New.md
index 9b82ece325..d0c22aa573 100644
--- a/docs/Whats-New.md
+++ b/docs/Whats-New.md
@@ -450,6 +450,7 @@ New:
- Forbidding parallel AI queues for specific TechnoTypes (by Starkku)
- Nonprovocative Warheads (by Starkku)
- Option to restore `PowerSurplus` setting for AI (by Starkku)
+- Exclusive Sidebar for Superweapons (by CrimRecya)
- `FireOnce` infantry sequence reset toggle (by Starkku)
Vanilla fixes:
diff --git a/src/Commands/Commands.cpp b/src/Commands/Commands.cpp
index 712a596467..3069c3ea32 100644
--- a/src/Commands/Commands.cpp
+++ b/src/Commands/Commands.cpp
@@ -10,6 +10,7 @@
#include "ToggleDigitalDisplay.h"
#include "ToggleDesignatorRange.h"
#include "SaveVariablesToFile.h"
+#include "SWShortcuts.h"
DEFINE_HOOK(0x533066, CommandClassCallback_Register, 0x6)
{
@@ -19,6 +20,15 @@ DEFINE_HOOK(0x533066, CommandClassCallback_Register, 0x6)
MakeCommand();
MakeCommand();
MakeCommand();
+ MakeCommand>();
+ MakeCommand>();
+ MakeCommand>();
+ MakeCommand>();
+ MakeCommand>();
+ MakeCommand>();
+ MakeCommand>();
+ MakeCommand>();
+ MakeCommand>();
if (Phobos::Config::DevelopmentCommands)
{
diff --git a/src/Commands/SWShortcuts.cpp b/src/Commands/SWShortcuts.cpp
new file mode 100644
index 0000000000..e0dc8de25e
--- /dev/null
+++ b/src/Commands/SWShortcuts.cpp
@@ -0,0 +1 @@
+#include "SWShortcuts.h"
diff --git a/src/Commands/SWShortcuts.h b/src/Commands/SWShortcuts.h
new file mode 100644
index 0000000000..046befe9ff
--- /dev/null
+++ b/src/Commands/SWShortcuts.h
@@ -0,0 +1,94 @@
+#pragma once
+
+#include "Commands.h"
+
+#include
+#include
+
+// Super Weapon Sidebar Keyboard shortcut command class
+template
+class SWShortcutsCommandClass : public CommandClass
+{
+public:
+ // CommandClass
+ virtual const char* GetName() const override;
+ virtual const wchar_t* GetUIName() const override;
+ virtual const wchar_t* GetUICategory() const override;
+ virtual const wchar_t* GetUIDescription() const override;
+ virtual void Execute(WWKey eInput) const override;
+};
+
+template
+inline const char* SWShortcutsCommandClass::GetName() const
+{
+ class to_string_t
+ {
+ public:
+ char buffer[27];
+
+ public:
+ constexpr to_string_t() noexcept
+ : buffer { "SW Sidebar Shortcuts Num 0" }
+ {
+ buffer[25] = KeyIndex + '0';
+ }
+
+ constexpr operator char* () noexcept { return buffer; }
+ };
+ static to_string_t name;
+ return name;
+}
+
+template
+inline const wchar_t* SWShortcutsCommandClass::GetUIName() const
+{
+ class to_string_t
+ {
+ public:
+ wchar_t buffer[18];
+
+ public:
+ constexpr to_string_t() noexcept
+ : buffer { L"Quick Select SW 0" }
+ {
+ buffer[16] = KeyIndex + '0';
+ }
+
+ constexpr operator wchar_t* () noexcept { return buffer; }
+ };
+ static to_string_t name;
+ return StringTable::TryFetchString("TXT_SW_XX_FORWARD", name);
+}
+
+template
+inline const wchar_t* SWShortcutsCommandClass::GetUICategory() const
+{
+ return CATEGORY_CONTROL;
+}
+
+template
+inline const wchar_t* SWShortcutsCommandClass::GetUIDescription() const
+{
+ class to_string_t
+ {
+ public:
+ wchar_t buffer[31];
+
+ public:
+ constexpr to_string_t() noexcept
+ : buffer { L"Select No.0 SW in left sidebar" }
+ {
+ buffer[10] = KeyIndex + '0';
+ }
+
+ constexpr operator wchar_t* () noexcept { return buffer; }
+ };
+ static to_string_t name;
+ return StringTable::TryFetchString("TXT_SW_XX_FORWARD_DESC", name);
+}
+
+template
+inline void SWShortcutsCommandClass::Execute(WWKey eInput) const
+{
+ TacticalButtonClass::TriggerButtonForSW(KeyIndex);
+}
diff --git a/src/Ext/House/Body.cpp b/src/Ext/House/Body.cpp
index 67cf9d0c54..6e0cd938bc 100644
--- a/src/Ext/House/Body.cpp
+++ b/src/Ext/House/Body.cpp
@@ -636,6 +636,8 @@ void HouseExt::ExtData::Serialize(T& Stm)
.Process(this->Factory_VehicleType)
.Process(this->Factory_NavyType)
.Process(this->Factory_AircraftType)
+ .Process(this->SuperWeaponButtonData)
+ .Process(this->SuperWeaponButtonCount)
.Process(this->AISuperWeaponDelayTimer)
.Process(this->RepairBaseNodes)
.Process(this->RestrictedFactoryPlants)
diff --git a/src/Ext/House/Body.h b/src/Ext/House/Body.h
index a872b10457..f9148f5d8c 100644
--- a/src/Ext/House/Body.h
+++ b/src/Ext/House/Body.h
@@ -35,6 +35,9 @@ class HouseExt
BuildingClass* Factory_NavyType;
BuildingClass* Factory_AircraftType;
+ int SuperWeaponButtonData[9];
+ int SuperWeaponButtonCount;
+
CDTimerClass AISuperWeaponDelayTimer;
//Read from INI
@@ -65,6 +68,8 @@ class HouseExt
, Factory_VehicleType { nullptr }
, Factory_NavyType { nullptr }
, Factory_AircraftType { nullptr }
+ , SuperWeaponButtonData { -1, -1, -1, -1, -1, -1, -1, -1, -1 }
+ , SuperWeaponButtonCount { 0 }
, AISuperWeaponDelayTimer {}
, RepairBaseNodes { false,false,false }
, RestrictedFactoryPlants {}
diff --git a/src/Ext/Rules/Body.cpp b/src/Ext/Rules/Body.cpp
index 336cae4272..a347f8257d 100644
--- a/src/Ext/Rules/Body.cpp
+++ b/src/Ext/Rules/Body.cpp
@@ -185,6 +185,8 @@ void RulesExt::ExtData::LoadBeforeTypeData(RulesClass* pThis, CCINIClass* pINI)
this->Vehicles_DefaultDigitalDisplayTypes.Read(exINI, GameStrings::AudioVisual, "Vehicles.DefaultDigitalDisplayTypes");
this->Aircraft_DefaultDigitalDisplayTypes.Read(exINI, GameStrings::AudioVisual, "Aircraft.DefaultDigitalDisplayTypes");
+ this->SWSidebarBackground.Read(exINI, GameStrings::AudioVisual, "SWSidebarBackground");
+
this->VoxelLightSource.Read(exINI, GameStrings::AudioVisual, "VoxelLightSource");
// this->VoxelShadowLightSource.Read(exINI, GameStrings::AudioVisual, "VoxelShadowLightSource");
@@ -360,6 +362,7 @@ void RulesExt::ExtData::Serialize(T& Stm)
.Process(this->ShowDesignatorRange)
.Process(this->DropPodTrailer)
.Process(this->PodImage)
+ .Process(this->SWSidebarBackground)
.Process(this->VoxelLightSource)
// .Process(this->VoxelShadowLightSource)
.Process(this->UseFixedVoxelLighting)
diff --git a/src/Ext/Rules/Body.h b/src/Ext/Rules/Body.h
index b6dc6a00ac..a647b48885 100644
--- a/src/Ext/Rules/Body.h
+++ b/src/Ext/Rules/Body.h
@@ -147,6 +147,8 @@ class RulesExt
Valueable Promote_VeteranAnimation;
Valueable Promote_EliteAnimation;
+ Valueable SWSidebarBackground;
+
Nullable> VoxelLightSource;
// Nullable> VoxelShadowLightSource;
Valueable UseFixedVoxelLighting;
@@ -256,6 +258,7 @@ class RulesExt
, ShowDesignatorRange { true }
, DropPodTrailer { }
, PodImage { }
+ , SWSidebarBackground { true }
, VoxelLightSource { }
// , VoxelShadowLightSource { }
, UseFixedVoxelLighting { false }
diff --git a/src/Ext/SWType/Body.cpp b/src/Ext/SWType/Body.cpp
index 93ebecc40f..f150ac8b4a 100644
--- a/src/Ext/SWType/Body.cpp
+++ b/src/Ext/SWType/Body.cpp
@@ -23,7 +23,18 @@ void SWTypeExt::ExtData::Serialize(T& Stm)
.Process(this->SW_AuxBuildings)
.Process(this->SW_NegBuildings)
.Process(this->SW_InitialReady)
+ .Process(this->SW_AutoFire)
+ .Process(this->SW_ManualFire)
+ .Process(this->SW_Unstoppable)
.Process(this->SW_PostDependent)
+ .Process(this->EVA_Impatient)
+ .Process(this->EVA_InsufficientFunds)
+ .Process(this->EVA_SelectTarget)
+ .Process(this->Message_InsufficientFunds)
+ .Process(this->Message_ColorScheme)
+ .Process(this->Message_FirerColor)
+ .Process(this->SidebarPCX)
+ .Process(this->SW_UseAITargeting)
.Process(this->UIDescription)
.Process(this->CameoPriority)
.Process(this->LimboDelivery_Types)
@@ -47,6 +58,10 @@ void SWTypeExt::ExtData::Serialize(T& Stm)
.Process(this->ShowTimer_Priority)
.Process(this->Convert_Pairs)
.Process(this->ShowDesignatorRange)
+ .Process(this->SW_InScreen_Show)
+ .Process(this->SW_InScreen_PriorityHouses)
+ .Process(this->SW_InScreen_RequiredHouses)
+ .Process(this->SW_InScreen_QuickFire)
.Process(this->UseWeeds)
.Process(this->UseWeeds_Amount)
.Process(this->UseWeeds_StorageTimer)
@@ -79,7 +94,18 @@ void SWTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI)
this->SW_AuxBuildings.Read(exINI, pSection, "SW.AuxBuildings");
this->SW_NegBuildings.Read(exINI, pSection, "SW.NegBuildings");
this->SW_InitialReady.Read(exINI, pSection, "SW.InitialReady");
+ this->SW_AutoFire.Read(exINI, pSection, "SW.AutoFire");
+ this->SW_ManualFire.Read(exINI, pSection, "SW.ManualFire");
+ this->SW_Unstoppable.Read(exINI, pSection, "SW.Unstoppable");
this->SW_PostDependent.Read(exINI, pSection, "SW.PostDependent");
+ this->EVA_Impatient.Read(exINI, pSection, "EVA.Impatient");
+ this->EVA_InsufficientFunds.Read(exINI, pSection, "EVA.InsufficientFunds");
+ this->EVA_SelectTarget.Read(exINI, pSection, "EVA.SelectTarget");
+ this->Message_InsufficientFunds.Read(exINI, pSection, "Message.InsufficientFunds");
+ this->Message_ColorScheme.Read(exINI, pSection, "Message.ColorScheme");
+ this->Message_FirerColor.Read(exINI, pSection, "Message.FirerColor");
+ this->SidebarPCX.Read(pINI, pSection, "SidebarPCX");
+ this->SW_UseAITargeting.Read(exINI, pSection, "SW.UseAITargeting");
this->UIDescription.Read(exINI, pSection, "UIDescription");
this->CameoPriority.Read(exINI, pSection, "CameoPriority");
@@ -160,6 +186,11 @@ void SWTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI)
this->ShowDesignatorRange.Read(exINI, pSection, "ShowDesignatorRange");
+ this->SW_InScreen_Show.Read(exINI, pSection, "SW.InScreen.Show");
+ this->SW_InScreen_PriorityHouses = pINI->ReadHouseTypesList(pSection, "SW.InScreen.PriorityHouses", this->SW_InScreen_PriorityHouses);
+ this->SW_InScreen_RequiredHouses = pINI->ReadHouseTypesList(pSection, "SW.InScreen.RequiredHouses", this->SW_InScreen_RequiredHouses);
+ this->SW_InScreen_QuickFire.Read(exINI, pSection, "SW.InScreen.QuickFire");
+
this->UseWeeds.Read(exINI, pSection, "UseWeeds");
this->UseWeeds_Amount.Read(exINI, pSection, "UseWeeds.Amount");
this->UseWeeds_StorageTimer.Read(exINI, pSection, "UseWeeds.StorageTimer");
diff --git a/src/Ext/SWType/Body.h b/src/Ext/SWType/Body.h
index 82bd9ad3f4..6b94e3fd77 100644
--- a/src/Ext/SWType/Body.h
+++ b/src/Ext/SWType/Body.h
@@ -35,7 +35,19 @@ class SWTypeExt
ValueableVector SW_AuxBuildings;
ValueableVector SW_NegBuildings;
Valueable SW_InitialReady;
+ Valueable SW_AutoFire;
+ Valueable SW_ManualFire;
+ Valueable SW_Unstoppable;
ValueableIdx SW_PostDependent;
+ ValueableIdx EVA_Impatient;
+ ValueableIdx EVA_InsufficientFunds;
+ ValueableIdx EVA_SelectTarget;
+ Valueable Message_InsufficientFunds;
+ Valueable Message_ColorScheme;
+ Valueable Message_FirerColor;
+ PhobosPCXFile SidebarPCX;
+
+ Valueable SW_UseAITargeting;
Valueable UIDescription;
Valueable CameoPriority;
@@ -65,6 +77,11 @@ class SWTypeExt
std::vector Convert_Pairs;
+ Valueable SW_InScreen_Show;
+ DWORD SW_InScreen_PriorityHouses;
+ DWORD SW_InScreen_RequiredHouses;
+ Valueable SW_InScreen_QuickFire;
+
Valueable UseWeeds;
Valueable UseWeeds_Amount;
Valueable UseWeeds_StorageTimer;
@@ -83,7 +100,17 @@ class SWTypeExt
, SW_AuxBuildings {}
, SW_NegBuildings {}
, SW_InitialReady { false }
+ , SW_AutoFire { false }
+ , SW_ManualFire { true }
+ , SW_Unstoppable { false }
, SW_PostDependent {}
+ , EVA_Impatient { -1 }
+ , EVA_InsufficientFunds { -1 }
+ , EVA_SelectTarget { -1 }
+ , Message_InsufficientFunds {}
+ , Message_ColorScheme { -1 }
+ , Message_FirerColor { false }
+ , SW_UseAITargeting { false }
, UIDescription {}
, CameoPriority { 0 }
, LimboDelivery_Types {}
@@ -107,6 +134,10 @@ class SWTypeExt
, ShowTimer_Priority { 0 }
, Convert_Pairs {}
, ShowDesignatorRange { true }
+ , SW_InScreen_Show { false }
+ , SW_InScreen_PriorityHouses { 0u }
+ , SW_InScreen_RequiredHouses { 0xFFFFFFFFu }
+ , SW_InScreen_QuickFire { false }
, UseWeeds { false }
, UseWeeds_Amount { RulesClass::Instance->WeedCapacity }
, UseWeeds_StorageTimer { false }
diff --git a/src/Ext/Side/Body.cpp b/src/Ext/Side/Body.cpp
index 961a834701..fc41f25222 100644
--- a/src/Ext/Side/Body.cpp
+++ b/src/Ext/Side/Body.cpp
@@ -41,6 +41,9 @@ void SideExt::ExtData::LoadFromINIFile(CCINIClass* pINI)
this->ToolTip_Background_Opacity.Read(exINI, pSection, "ToolTip.Background.Opacity");
this->ToolTip_Background_BlurSize.Read(exINI, pSection, "ToolTip.Background.BlurSize");
this->BriefingTheme = pINI->ReadTheme(pSection, "BriefingTheme", this->BriefingTheme);
+ this->SWSidebarBackground_TopPCX.Read(pINI, pSection, "SWSidebarBackground.TopPCX");
+ this->SWSidebarBackground_CenterPCX.Read(pINI, pSection, "SWSidebarBackground.CenterPCX");
+ this->SWSidebarBackground_BottomPCX.Read(pINI, pSection, "SWSidebarBackground.BottomPCX");
}
// =============================
@@ -70,6 +73,9 @@ void SideExt::ExtData::Serialize(T& Stm)
.Process(this->IngameScore_WinTheme)
.Process(this->IngameScore_LoseTheme)
.Process(this->BriefingTheme)
+ .Process(this->SWSidebarBackground_TopPCX)
+ .Process(this->SWSidebarBackground_CenterPCX)
+ .Process(this->SWSidebarBackground_BottomPCX)
;
}
diff --git a/src/Ext/Side/Body.h b/src/Ext/Side/Body.h
index 88e694aa0c..3c1504ef56 100644
--- a/src/Ext/Side/Body.h
+++ b/src/Ext/Side/Body.h
@@ -36,6 +36,9 @@ class SideExt
Nullable ToolTip_Background_Opacity;
Nullable ToolTip_Background_BlurSize;
Valueable BriefingTheme;
+ PhobosPCXFile SWSidebarBackground_TopPCX;
+ PhobosPCXFile SWSidebarBackground_CenterPCX;
+ PhobosPCXFile SWSidebarBackground_BottomPCX;
ExtData(SideClass* OwnerObject) : Extension(OwnerObject)
, ArrayIndex { -1 }
diff --git a/src/Misc/PhobosToolTip.cpp b/src/Misc/PhobosToolTip.cpp
index 7e25ed9e9f..19083664f5 100644
--- a/src/Misc/PhobosToolTip.cpp
+++ b/src/Misc/PhobosToolTip.cpp
@@ -1,6 +1,7 @@
#include
#include "PhobosToolTip.h"
+#include "TacticalButtons.h"
#include
#include
@@ -199,6 +200,26 @@ DEFINE_HOOK(0x6A9316, SidebarClass_StripClass_HelpText, 0x6)
return 0x6A93DE;
}
+DEFINE_HOOK(0x4AE511, DisplayClass_GetToolTip_SkipTacticalTip, 0x5)
+{
+ enum { UseButtonTip = 0x4AE5F8, SkipGameCode = 0x4AE69B };
+
+ const int buttonIndex = TacticalButtonClass::Instance.GetButtonIndex();
+
+ if (buttonIndex < 0)
+ return 0;
+
+ if (!buttonIndex)
+ return SkipGameCode;
+
+ if (buttonIndex <= 8)
+ R->EAX(PhobosToolTip::Instance.GetBuffer());
+ else
+ R->EAX(0);
+
+ return UseButtonTip;
+}
+
// TODO: reimplement CCToolTip::Draw2 completely
DEFINE_HOOK(0x478EE1, CCToolTip_Draw2_SetBuffer, 0x6)
diff --git a/src/Misc/TacticalButtons.cpp b/src/Misc/TacticalButtons.cpp
new file mode 100644
index 0000000000..863c09eb2f
--- /dev/null
+++ b/src/Misc/TacticalButtons.cpp
@@ -0,0 +1,617 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "PhobosToolTip.h"
+#include "TacticalButtons.h"
+
+TacticalButtonClass TacticalButtonClass::Instance;
+
+// Functions
+
+// Private functions
+int TacticalButtonClass::CheckMouseOverButtons(const Point2D* pMousePosition)
+{
+ if (pMousePosition->X < 65 && pMousePosition->X >= 5) // Button index 1-9 : Super weapons buttons
+ {
+ const int currentCounts = HouseExt::ExtMap.Find(HouseClass::CurrentPlayer)->SuperWeaponButtonCount;
+ const int height = DSurface::Composite->GetHeight();
+ int checkHight = (height - 32 - 48 * currentCounts - 2 * (currentCounts - 1)) / 2;
+
+ for (int i = 0; i < currentCounts; ++i)
+ {
+ if (pMousePosition->Y < checkHight)
+ break;
+
+ checkHight += 48;
+
+ if (pMousePosition->Y < checkHight)
+ return i + 1;
+
+ checkHight += 2;
+ }
+ }
+
+ // TODO New buttons (Start from index = 10)
+
+ if (CheckMouseOverBackground(pMousePosition))
+ return 0; // Button index 0 : Background
+
+ return -1;
+}
+
+bool TacticalButtonClass::CheckMouseOverBackground(const Point2D* pMousePosition)
+{
+ if (RulesExt::Global()->SWSidebarBackground && pMousePosition->X < 80 && pMousePosition->X >= 0)
+ {
+ const int currentCounts = HouseExt::ExtMap.Find(HouseClass::CurrentPlayer)->SuperWeaponButtonCount;
+ const int height = DSurface::Composite->GetHeight();
+ const int checkHight = (height - 32 - 48 * currentCounts - 2 * (currentCounts - 1)) / 2 - 21;
+
+ if (pMousePosition->Y >= checkHight && pMousePosition->Y < (checkHight + currentCounts * 50 + 40))
+ return true;
+ }
+
+ // TODO New button backgrounds
+
+ return false;
+}
+
+// Inline functions
+inline bool TacticalButtonClass::MouseOverButtons()
+{
+ return this->ButtonIndex > 0;
+}
+
+inline bool TacticalButtonClass::MouseOverTactical()
+{
+ return this->ButtonIndex < 0;
+}
+
+// Cite functions
+int TacticalButtonClass::GetButtonIndex()
+{
+ return this->ButtonIndex;
+}
+
+// General functions
+void TacticalButtonClass::SetMouseButtonIndex(const Point2D* pMousePosition)
+{
+ if (this->LastPosition == *pMousePosition)
+ return;
+
+ this->LastPosition = *pMousePosition;
+ this->ButtonIndex = CheckMouseOverButtons(pMousePosition);
+
+ // SW ToolTip
+ if (this->ButtonIndex > 0)
+ {
+ HouseClass* const pHouse = HouseClass::CurrentPlayer;
+ const int index = HouseExt::ExtMap.Find(pHouse)->SuperWeaponButtonData[this->ButtonIndex - 1];
+ SuperClass* const pSuper = pHouse->Supers.Items[index];
+
+ if (pSuper != this->pRecordSuper)
+ {
+ PhobosToolTip::Instance.HelpText(pSuper);
+ this->pRecordSuper = pSuper;
+ }
+ }
+ else if (this->pRecordSuper)
+ {
+ this->pRecordSuper = nullptr;
+ }
+}
+
+void TacticalButtonClass::PressDesignatedButton(int triggerIndex)
+{
+ const int buttonIndex = this->ButtonIndex;
+
+ if (!buttonIndex) // In buttons background
+ return;
+
+ if (buttonIndex <= 9) // Button index 1-9 : Super weapons buttons
+ {
+ if (!triggerIndex)
+ TriggerButtonForSW(buttonIndex);
+ else if (triggerIndex == 2)
+ DisplayClass::Instance->CurrentSWTypeIndex = -1;
+ }
+/* else if (?) // TODO New buttons (Start from index = 10)
+ {
+ ;
+ }*/
+}
+
+// SW buttons functions
+void TacticalButtonClass::DrawButtonForSW()
+{
+ HouseClass* const pHouse = HouseClass::CurrentPlayer;
+ HouseExt::ExtData* const pHouseExt = HouseExt::ExtMap.Find(pHouse);
+ SideExt::ExtData* const pSideExt = SideExt::ExtMap.Find(SideClass::Array->GetItem(pHouse->SideIndex));
+ const int currentCounts = pHouseExt->SuperWeaponButtonCount;
+ const bool drawSWSidebarBackground = RulesExt::Global()->SWSidebarBackground;
+
+ if (!currentCounts)
+ return;
+
+ auto& data = pHouseExt->SuperWeaponButtonData;
+ const int height = DSurface::Composite->GetHeight();
+ const int color = Drawing::RGB_To_Int(Drawing::TooltipColor);
+
+ Point2D position { 5, (height - 32 - 48 * currentCounts - 2 * (currentCounts - 1)) / 2 };
+ RectangleStruct rect { 0, 0, 65, position.Y + 48 };
+ int recordHeight = -1;
+
+ // Draw top background (80 * 20)
+ Point2D backPosition { 0, position.Y - 21 };
+
+ if (drawSWSidebarBackground)
+ {
+ if (BSurface* const CameoPCX = pSideExt->SWSidebarBackground_TopPCX.GetSurface())
+ {
+ RectangleStruct drawRect { backPosition.X, backPosition.Y, 60, 48 };
+ PCX::Instance->BlitToSurface(&drawRect, DSurface::Composite, CameoPCX);
+ }
+ else
+ {
+ RectangleStruct backRect { 0, backPosition.Y, 80, 20};
+ DSurface::Composite->FillRect(&backRect, COLOR_BLACK);
+ }
+ }
+
+ // Draw each buttons
+ for (int i = 0; i < currentCounts; position.Y += 50, rect.Height += 50) // Button index 1-9
+ {
+ // Draw center background (80 * 50)
+ if (drawSWSidebarBackground)
+ {
+ backPosition.Y = position.Y - 1;
+
+ if (BSurface* const CameoPCX = pSideExt->SWSidebarBackground_CenterPCX.GetSurface())
+ {
+ RectangleStruct drawRect { backPosition.X, backPosition.Y, 60, 48 };
+ PCX::Instance->BlitToSurface(&drawRect, DSurface::Composite, CameoPCX);
+ }
+ else
+ {
+ RectangleStruct backRect { 0, backPosition.Y, 80, 50};
+ DSurface::Composite->FillRect(&backRect, COLOR_BLACK);
+ }
+ }
+
+ // Get SW data
+ SuperClass* const pSuper = pHouse->Supers.Items[data[i]];
+ SuperWeaponTypeClass* const pSWType = pSuper->Type;
+ SWTypeExt::ExtData* const pTypeExt = SWTypeExt::ExtMap.Find(pSWType);
+
+ // Draw cameo
+ BSurface* const CameoPCX = pTypeExt->SidebarPCX.GetSurface();
+
+ if (CAN_USE_ARES && AresHelper::CanUseAres && CameoPCX)
+ {
+ RectangleStruct drawRect { position.X, position.Y, 60, 48 };
+ PCX::Instance->BlitToSurface(&drawRect, DSurface::Composite, CameoPCX);
+ }
+ else if (SHPStruct* const pSHP = pSWType->SidebarImage)
+ {
+ DSurface::Composite->DrawSHP(FileSystem::CAMEO_PAL, pSHP, 0, &position, &rect,
+ BlitterFlags::bf_400, 0, 0, ZGradient::Ground, 1000, 0, 0, 0, 0, 0);
+ }
+
+ // Flash cameo
+ const int delay = pSWType->FlashSidebarTabFrames;
+
+ if (delay > 0 && !pSuper->IsSuspended && (pSuper->IsReady || (pSWType->UseChargeDrain && pSuper->ChargeDrainState != ChargeDrainState::Charging))
+ && ((Unsorted::CurrentFrame - pSuper->ReadyFrame) % (delay << 1)) > delay)
+ {
+ DSurface::Composite->DrawSHP(FileSystem::SIDEBAR_PAL, Make_Global(0xB07BC0), 0, &position, &rect,
+ BlitterFlags(0x406), 0, 0, ZGradient::Ground, 1000, 0, 0, 0, 0, 0);
+ }
+
+ // SW charge progress
+ if (pSuper->ShouldDrawProgress())
+ {
+ const int frame = pSuper->AnimStage() + 1;
+
+ DSurface::Composite->DrawSHP(FileSystem::SIDEBAR_PAL, Make_Global(0xB0B484), frame, &position, &rect,
+ BlitterFlags(0x404), 0, 0, ZGradient::Ground, 1000, 0, 0, 0, 0, 0);
+ }
+
+ // SW status
+ if (const wchar_t* pName = pSuper->NameReadiness())
+ {
+ Point2D textLocation { 35, position.Y + 1 };
+ const TextPrintType printType = TextPrintType::Center | TextPrintType::FullShadow | TextPrintType::Point8;
+ RectangleStruct textRect = Drawing::GetTextDimensions(pName, textLocation, static_cast(printType), 2, 1);
+
+ // Text black background
+ reinterpret_cast(0x621B80)(&textRect, DSurface::Composite, 0, 0xAFu);
+ DSurface::Composite->DrawTextA(pName, &rect, &textLocation, static_cast(color), COLOR_BLACK, printType);
+ }
+
+ if (++i == Instance.ButtonIndex)
+ recordHeight = position.Y;
+ }
+
+ // Draw bottom background (80 * 20)
+ if (drawSWSidebarBackground)
+ {
+ backPosition.Y = position.Y - 1;
+
+ if (BSurface* const CameoPCX = pSideExt->SWSidebarBackground_BottomPCX.GetSurface())
+ {
+ RectangleStruct drawRect { backPosition.X, backPosition.Y, 60, 48 };
+ PCX::Instance->BlitToSurface(&drawRect, DSurface::Composite, CameoPCX);
+ }
+ else
+ {
+ RectangleStruct backRect { 0, backPosition.Y, 80, 20};
+ DSurface::Composite->FillRect(&backRect, COLOR_BLACK);
+ }
+ }
+
+ // Draw mouse hover rectangle
+ if (!ScenarioClass::Instance->UserInputLocked && recordHeight >= 0)
+ {
+ position.Y = recordHeight;
+ rect.Height = recordHeight + 48;
+
+ RectangleStruct drawRect { 5, position.Y, 60, 48 };
+ DSurface::Composite->DrawRectEx(&rect, &drawRect, color);
+ }
+}
+
+void TacticalButtonClass::RecheckButtonForSW()
+{
+ Instance.LastPosition = Point2D::Empty;
+ HouseClass* const pHouse = HouseClass::CurrentPlayer;
+ HouseExt::ExtData* const pHouseExt = HouseExt::ExtMap.Find(pHouse);
+ auto& data = pHouseExt->SuperWeaponButtonData;
+
+ for (int i = 0; i < pHouseExt->SuperWeaponButtonCount; ++i)
+ {
+ if (data[i] >= pHouse->Supers.Count || !pHouse->Supers.Items[data[i]]->IsPresent)
+ {
+ const int counts = pHouseExt->SuperWeaponButtonCount - 1;
+
+ for (int j = i; j < counts; ++j)
+ {
+ data[j] = data[j + 1];
+ }
+
+ data[--pHouseExt->SuperWeaponButtonCount] = -1;
+ }
+ }
+}
+
+bool TacticalButtonClass::InsertButtonForSW(int& superIndex)
+{
+ SuperWeaponTypeClass* const pType = SuperWeaponTypeClass::Array->Items[superIndex];
+ SWTypeExt::ExtData* const pTypeExt = SWTypeExt::ExtMap.Find(pType);
+ bool overflow = true;
+
+ if (pTypeExt->SW_InScreen_Show && !pTypeExt->SW_UseAITargeting)
+ {
+ HouseClass* const pHouse = HouseClass::CurrentPlayer;
+ HouseExt::ExtData* const pHouseExt = HouseExt::ExtMap.Find(pHouse);
+ const unsigned int ownerBits = 1u << pHouse->Type->ArrayIndex;
+
+ if (pTypeExt->SW_InScreen_RequiredHouses & ownerBits)
+ {
+ auto& data = pHouseExt->SuperWeaponButtonData;
+ bool move = false;
+
+ for (int i = 0; i < 9; ++i) // 9 buttons at max
+ {
+ if (move)
+ {
+ if (data[i] != -1)
+ {
+ int buffer = data[i];
+ data[i] = superIndex;
+ superIndex = buffer;
+ }
+ else
+ {
+ data[i] = superIndex;
+ overflow = false;
+ ++pHouseExt->SuperWeaponButtonCount;
+ break;
+ }
+ }
+ else if (data[i] != -1)
+ {
+ if (MoveButtonForSW(SuperWeaponTypeClass::Array->Items[data[i]], pType, pTypeExt, ownerBits))
+ {
+ move = true;
+ int buffer = data[i];
+ data[i] = superIndex;
+ superIndex = buffer;
+ }
+ }
+ else
+ {
+ data[i] = superIndex;
+ overflow = false;
+ ++pHouseExt->SuperWeaponButtonCount;
+ break;
+ }
+ }
+ }
+ }
+
+ return overflow;
+}
+
+bool TacticalButtonClass::MoveButtonForSW(SuperWeaponTypeClass* pDataType, SuperWeaponTypeClass* pAddType, SWTypeExt::ExtData* pAddTypeExt, unsigned int ownerBits)
+{
+ SWTypeExt::ExtData* const pDataTypeExt = SWTypeExt::ExtMap.Find(pDataType);
+
+ if ((pDataTypeExt->SW_InScreen_PriorityHouses & ownerBits) && !(pAddTypeExt->SW_InScreen_PriorityHouses & ownerBits))
+ return false;
+ else if (!(pDataTypeExt->SW_InScreen_PriorityHouses & ownerBits) && (pAddTypeExt->SW_InScreen_PriorityHouses & ownerBits))
+ return true;
+ else if (pDataTypeExt->CameoPriority > pAddTypeExt->CameoPriority)
+ return false;
+ else if (pDataTypeExt->CameoPriority < pAddTypeExt->CameoPriority)
+ return true;
+ else if (pDataType->RechargeTime < pAddType->RechargeTime)
+ return false;
+ else if (pDataType->RechargeTime > pAddType->RechargeTime)
+ return true;
+
+ return wcscmp(pDataType->UIName, pAddType->UIName) > 0;
+}
+
+void TacticalButtonClass::TriggerButtonForSW(int buttonIndex)
+{
+ if (ScenarioClass::Instance->UserInputLocked)
+ return;
+
+ HouseClass* const pHouse = HouseClass::CurrentPlayer;
+ const int index = HouseExt::ExtMap.Find(pHouse)->SuperWeaponButtonData[buttonIndex - 1];
+
+ if (index < 0) // Keyboard shortcuts may be invalid
+ return;
+
+ SuperClass* const pSuper = pHouse->Supers.Items[index];
+ SuperWeaponTypeClass* const pType = pSuper->Type;
+ SWTypeExt::ExtData* const pTypeExt = SWTypeExt::ExtMap.Find(pType);
+
+ if (CAN_USE_ARES && AresHelper::CanUseAres)
+ {
+ const bool autoFire = !pTypeExt->SW_ManualFire && pTypeExt->SW_AutoFire;
+
+ if (!pSuper->CanFire() && !autoFire)
+ {
+ VoxClass::PlayIndex(pTypeExt->EVA_Impatient);
+ return;
+ }
+
+ if (!pHouse->CanTransactMoney(pTypeExt->Money_Amount))
+ {
+ if (pTypeExt->EVA_InsufficientFunds != -1)
+ VoxClass::PlayIndex(pTypeExt->EVA_InsufficientFunds);
+ else
+ VoxClass::Play(&Make_Global(0x819044)); // 0x819044 -> EVA_InsufficientFunds
+
+ const CSFText csf = pTypeExt->Message_InsufficientFunds;
+
+ if (!csf.empty())
+ {
+ int color = ColorScheme::FindIndex("Gold");
+
+ if (pTypeExt->Message_FirerColor)
+ {
+ if (pHouse)
+ color = pHouse->ColorSchemeIndex;
+ }
+ else
+ {
+ if (pTypeExt->Message_ColorScheme > -1)
+ color = pTypeExt->Message_ColorScheme;
+ else if (pHouse)
+ color = pHouse->ColorSchemeIndex;
+ }
+
+ MessageListClass::Instance->PrintMessage(csf, RulesClass::Instance->MessageDelay, color);
+ }
+
+ return;
+ }
+
+ const bool unstoppable = pType->UseChargeDrain && pSuper->ChargeDrainState == ChargeDrainState::Draining
+ && pTypeExt->SW_Unstoppable;
+
+ if (autoFire || unstoppable)
+ return;
+ }
+ else if (!pSuper->CanFire())
+ {
+ return;
+ }
+
+ // Use SW.InScreen.QuickFire here, to some extent to replace SW.UseAITargeting
+ // Inevitably ignore various conditions such as range, sight, indicators .etc
+ // No check for SW.UseAITargeting, too complicated for me. - CrimRecya
+ if (pType->Action == Action::None)
+ {
+ EventClass event
+ (
+ pHouse->ArrayIndex,
+ EventType::SpecialPlace,
+ pType->ArrayIndex,
+ CellStruct::Empty
+ );
+ EventClass::AddEvent(event);
+ }
+ else if (pTypeExt->SW_InScreen_QuickFire)
+ {
+ EventClass event
+ (
+ pHouse->ArrayIndex,
+ EventType::SpecialPlace,
+ pType->ArrayIndex,
+ CellClass::Coord2Cell(TacticalClass::Instance->ClientToCoords(Point2D{ (DSurface::Composite->Width >> 1), (DSurface::Composite->Height >> 1) }))
+ );
+ EventClass::AddEvent(event);
+ }
+ else
+ {
+ MouseClass* const pMouse = MouseClass::Instance;
+ pMouse->CurrentBuilding = nullptr;
+ pMouse->CurrentBuildingType = nullptr;
+ pMouse->unknown_11AC = 0xFFFFFFFF;
+ pMouse->SetActiveFoundation(nullptr);
+ pMouse->SetRepairMode(0);
+ pMouse->SetSellMode(0);
+ pMouse->PowerToggleMode = false;
+ pMouse->PlanningMode = false;
+ pMouse->PlaceBeaconMode = false;
+ pMouse->CurrentSWTypeIndex = index;
+ pMouse->UnselectAll();
+
+ if (CAN_USE_ARES && AresHelper::CanUseAres && pTypeExt->EVA_SelectTarget != -1)
+ VoxClass::PlayIndex(pTypeExt->EVA_SelectTarget);
+ else
+ VoxClass::Play(&Make_Global(0x83FB78)); // 0x83FB78 -> EVA_SelectTarget
+ }
+}
+
+// Hooks
+
+// Mouse trigger hooks
+DEFINE_HOOK(0x6931A5, ScrollClass_WindowsProcedure_PressLeftMouseButton, 0x6)
+{
+ enum { SkipGameCode = 0x6931B4 };
+
+ TacticalButtonClass* const pButtons = &TacticalButtonClass::Instance;
+
+ if (!pButtons->MouseOverTactical())
+ {
+ pButtons->PressedInButtonsLayer = true;
+ pButtons->PressDesignatedButton(0);
+
+ R->Stack(STACK_OFFSET(0x28, 0x8), 0);
+ R->EAX(Action::None);
+ return SkipGameCode;
+ }
+
+ return 0;
+}
+
+DEFINE_HOOK(0x693268, ScrollClass_WindowsProcedure_ReleaseLeftMouseButton, 0x5)
+{
+ enum { SkipGameCode = 0x693276 };
+
+ TacticalButtonClass* const pButtons = &TacticalButtonClass::Instance;
+
+ if (pButtons->PressedInButtonsLayer)
+ {
+ pButtons->PressedInButtonsLayer = false;
+ pButtons->PressDesignatedButton(1);
+
+ R->Stack(STACK_OFFSET(0x28, 0x8), 0);
+ R->EAX(Action::None);
+ return SkipGameCode;
+ }
+
+ return 0;
+}
+
+DEFINE_HOOK(0x69330E, ScrollClass_WindowsProcedure_PressRightMouseButton, 0x6)
+{
+ enum { SkipGameCode = 0x69334A };
+
+ TacticalButtonClass* const pButtons = &TacticalButtonClass::Instance;
+
+ if (!pButtons->MouseOverTactical())
+ {
+ pButtons->PressedInButtonsLayer = true;
+ pButtons->PressDesignatedButton(2);
+
+ return SkipGameCode;
+ }
+
+ return 0;
+}
+
+DEFINE_HOOK(0x693397, ScrollClass_WindowsProcedure_ReleaseRightMouseButton, 0x6)
+{
+ enum { SkipGameCode = 0x6933CB };
+
+ TacticalButtonClass* const pButtons = &TacticalButtonClass::Instance;
+
+ if (pButtons->PressedInButtonsLayer)
+ {
+ pButtons->PressedInButtonsLayer = false;
+ pButtons->PressDesignatedButton(3);
+
+ return SkipGameCode;
+ }
+
+ return 0;
+}
+
+// Mouse suspend hooks
+DEFINE_HOOK(0x692F85, ScrollClass_MouseUpdate_SkipMouseLongPress, 0x7)
+{
+ enum { CheckMousePress = 0x692F8E, CheckMouseNoPress = 0x692FDC, SkipGameCode = 0x692FAE };
+
+ GET(ScrollClass*, pThis, EBX);
+
+ if (pThis->unknown_byte_554A) // 555A: AnyMouseButtonDown
+ return !TacticalButtonClass::Instance.PressedInButtonsLayer ? CheckMousePress : SkipGameCode;
+
+ return CheckMouseNoPress;
+}
+
+DEFINE_HOOK(0x69300B, ScrollClass_MouseUpdate_SkipMouseActionUpdate, 0x6)
+{
+ enum { SkipGameCode = 0x69301A };
+
+ const Point2D mousePosition = WWMouseClass::Instance->XY1;
+ TacticalButtonClass* const pButtons = &TacticalButtonClass::Instance;
+ pButtons->SetMouseButtonIndex(&mousePosition);
+
+ if (pButtons->MouseOverTactical())
+ return 0;
+
+ R->Stack(STACK_OFFSET(0x30, -0x24), 0);
+ R->EAX(Action::None);
+ return SkipGameCode;
+}
+
+// Buttons display hooks
+DEFINE_HOOK(0x6D4941, TacticalClass_Render_DrawButtonCameo, 0x6)
+{
+ // TODO New buttons (The later draw, the higher layer)
+
+ TacticalButtonClass::DrawButtonForSW();
+ return 0;
+}
+
+// SW buttons hooks
+DEFINE_HOOK(0x4F9283, HouseClass_Update_RecheckTechTree, 0x5)
+{
+ TacticalButtonClass::RecheckButtonForSW();
+ return 0;
+}
+
+DEFINE_HOOK(0x6A6314, SidebarClass_AddCameo_SupportSWButtons, 0x8)
+{
+ enum { SkipGameCode = 0x6A65F5 };
+
+ GET_STACK(const AbstractType, absType, STACK_OFFSET(0x14, 0x4));
+ REF_STACK(int, index, STACK_OFFSET(0x14, 0x8));
+
+ return (absType != AbstractType::Special || SuperWeaponTypeClass::Array->Count <= index || TacticalButtonClass::InsertButtonForSW(index)) ? 0 : SkipGameCode;
+}
diff --git a/src/Misc/TacticalButtons.h b/src/Misc/TacticalButtons.h
new file mode 100644
index 0000000000..dc628c9542
--- /dev/null
+++ b/src/Misc/TacticalButtons.h
@@ -0,0 +1,48 @@
+#include
+#include
+
+// Test function for extra pressable buttons above tactical map
+
+// Note:
+// If some of the functions are intended for some multiplayer gamemodes,
+// I think they should be triggered through the EventClass. But in fact,
+// there are too few existing events can be used that I don't know what
+// universal functionality can be achieved. - CrimRecya
+
+// It would be great if it could be modularized
+// TODO TacticalButtonClass::TacticalButtonGroup::TacticalButton
+
+class TacticalButtonClass
+{
+public:
+ static TacticalButtonClass Instance;
+
+private:
+ static int CheckMouseOverButtons(const Point2D* pMousePosition);
+ static bool CheckMouseOverBackground(const Point2D* pMousePosition);
+
+public:
+ inline bool MouseOverButtons();
+ inline bool MouseOverTactical();
+
+ int GetButtonIndex();
+ void SetMouseButtonIndex(const Point2D* pMousePosition);
+ void PressDesignatedButton(int triggerIndex);
+
+ // Button index 1-9 : Super weapons buttons
+ static void DrawButtonForSW();
+ static void RecheckButtonForSW();
+ static bool InsertButtonForSW(int& superIndex);
+ static bool MoveButtonForSW(SuperWeaponTypeClass* pDataType, SuperWeaponTypeClass* pAddType, SWTypeExt::ExtData* pAddTypeExt, unsigned int ownerBits);
+ static void TriggerButtonForSW(int buttonIndex);
+
+public:
+ bool PressedInButtonsLayer { false }; // Check press
+
+private:
+ int ButtonIndex { -1 }; // -1 -> above no buttons, 0 -> above buttons background, POSITIVE -> above button who have this index
+ Point2D LastPosition { Point2D::Empty }; // Check moving
+
+ // Button index 1-9 : Super weapons buttons
+ SuperClass* pRecordSuper = nullptr; // Cannot be used, only for comparison purposes
+};
From 1d5ee3f1f7c5edccc24ea20ed070adcda7f4333a Mon Sep 17 00:00:00 2001
From: CrimRecya <335958461@qq.com>
Date: Wed, 18 Sep 2024 16:38:21 +0800
Subject: [PATCH 02/12] Adapt to Ares' features
---
docs/User-Interface.md | 10 +-
src/Commands/SWShortcuts.h | 113 +++++++----
src/Ext/House/Body.cpp | 2 -
src/Ext/House/Body.h | 5 -
src/Ext/SWType/Body.cpp | 26 +--
src/Ext/SWType/Body.h | 27 +--
src/Misc/TacticalButtons.cpp | 378 ++++++++++++++++++-----------------
src/Misc/TacticalButtons.h | 58 +++---
8 files changed, 314 insertions(+), 305 deletions(-)
diff --git a/docs/User-Interface.md b/docs/User-Interface.md
index 79ba95c6a2..6ede2fbba5 100644
--- a/docs/User-Interface.md
+++ b/docs/User-Interface.md
@@ -346,13 +346,14 @@ MissingCameo=XXICON.SHP ; filename - including the .shp/.pcx extension
### Exclusive sidebar for superweapons
-- Now, you can display a sidebar exclusive to superweapons through a series of settings. At the same time, you can specify the shortcuts for these buttons in the shortcut key settings. Note that this feature does not support superweapons with `SW.UseAITargeting=true`.
+- Now, you can display a sidebar exclusive to superweapons through a series of settings. At the same time, you can specify the shortcuts for these buttons in the shortcut key settings.
- `SWSidebarBackground` controls whether to draw the background shape of the exclusive sidebar.
- `SWSidebarBackground.TopPCX`, `SWSidebarBackground.CenterPCX` and `SWSidebarBackground.BottomPCX` controlled the materials that were combined to create the entire exclusive sidebar background shape. Their required sizes are respectively `80 * 20`, `80 * 50` and `80 * 20`. In `SWSidebarBackground.CenterPCX`, the position of the superweapon's `SidebarPCX` is 5 pixels away from the left contour of this background, 15 pixels away from the right contour, and 1 pixel away from both the upper and lower contours.
- - `SW.InScreen.Show` controls whether the superweapon should be displayed first in the exclusive sidebar. If the exclusive sidebar is full (up to 9 are displayed), the overflowing superweapon's cameo will be added back to the original sidebar. If there is an empty space in the exclusive sidebar afterwards, it will no longer return to the exclusive sidebar, unless the permission to use the superweapon is regained (lost and gained again). Therefore, it is not recommended to place all superweapons in the exclusive sidebar.
+ - `SW.InScreen.Show` controls whether the superweapon should be displayed first in the exclusive sidebar. If the exclusive sidebar is full (up to 10 are displayed), the overflowing superweapon's cameo will be added back to the original sidebar. If there is an empty space in the exclusive sidebar afterwards, it will no longer return to the exclusive sidebar, unless the permission to use the superweapon is regained (lost and gained again). Therefore, it is not recommended to place all superweapons in the exclusive sidebar.
- `SW.InScreen.PriorityHouses` controls if the superweapon is displayed first in the exclusive sidebar, players belonging to these houses will have priority in placing the superweapon cameo in the exclusive sidebar.
- `SW.InScreen.RequiredHouses` controls if the superweapon is displayed first in the exclusive sidebar, players must belong to these houses in order to have superweapon a real chance of being displayed in the exclusive sidebar. The default is empty, which means this condition will always be met.
- - `SW.InScreen.QuickFire` controls whether the superweapon which is displayed in the exclusive sidebar will forcibly launch to the center position of the current screen without all Ares conditions check except charging and funds.
+ - `SW.QuickFireAtMouse` controls whether the superweapon which is command by keyboards will forcibly launch to the mouse position without all Ares conditions check except charging and funds. If the mouse is not in the tactical map now, the superweapon will launch like `SW.QuickFireInScreen=true` do.
+ - `SW.QuickFireInScreen` controls whether the superweapon will forcibly launch to the center position of the current screen without all Ares conditions check except charging and funds.
In `rulesmd.ini`:
```ini
@@ -368,7 +369,8 @@ SWSidebarBackground.BottomPCX= ; filename - including the .pcx extension
SW.InScreen.Show=false ; boolean
SW.InScreen.PriorityHouses= ; list of house types
SW.InScreen.RequiredHouses= ; list of house types
-SW.InScreen.QuickFire=false ; boolean
+SW.QuickFireAtMouse=false ; boolean
+SW.QuickFireInScreen=false ; boolean
```
### Harvester counter
diff --git a/src/Commands/SWShortcuts.h b/src/Commands/SWShortcuts.h
index 046befe9ff..7bb7f37ee1 100644
--- a/src/Commands/SWShortcuts.h
+++ b/src/Commands/SWShortcuts.h
@@ -21,43 +21,53 @@ class SWShortcutsCommandClass : public CommandClass
template
inline const char* SWShortcutsCommandClass::GetName() const
{
- class to_string_t
+ if (KeyIndex > 0)
{
- public:
- char buffer[27];
-
- public:
- constexpr to_string_t() noexcept
- : buffer { "SW Sidebar Shortcuts Num 0" }
+ class to_string_t
{
- buffer[25] = KeyIndex + '0';
- }
+ public:
+ char buffer[29];
+
+ public:
+ constexpr to_string_t() noexcept
+ : buffer { "" }
+ {
+ sprintf_s(buffer, "SW Sidebar Shortcuts Num %2d", KeyIndex);
+ }
+
+ constexpr operator char* () noexcept { return buffer; }
+ };
+ static to_string_t name;
+ return name;
+ }
- constexpr operator char* () noexcept { return buffer; }
- };
- static to_string_t name;
- return name;
+ return "SW Sidebar Display";
}
template
inline const wchar_t* SWShortcutsCommandClass::GetUIName() const
{
- class to_string_t
+ if (KeyIndex > 0)
{
- public:
- wchar_t buffer[18];
-
- public:
- constexpr to_string_t() noexcept
- : buffer { L"Quick Select SW 0" }
+ class to_string_t
{
- buffer[16] = KeyIndex + '0';
- }
+ public:
+ wchar_t buffer[20];
+
+ public:
+ constexpr to_string_t() noexcept
+ : buffer { L"" }
+ {
+ swprintf_s(buffer, L"Quick Select SW %2d", KeyIndex);
+ }
+
+ constexpr operator wchar_t* () noexcept { return buffer; }
+ };
+ static to_string_t name;
+ return StringTable::TryFetchString("TXT_SW_XX_FORWARD", name);
+ }
- constexpr operator wchar_t* () noexcept { return buffer; }
- };
- static to_string_t name;
- return StringTable::TryFetchString("TXT_SW_XX_FORWARD", name);
+ return GeneralUtils::LoadStringUnlessMissing("TXT_SW_XX_FORWARD", L"SW sidebar display");
}
template
@@ -69,26 +79,49 @@ inline const wchar_t* SWShortcutsCommandClass::GetUICategory() const
template
inline const wchar_t* SWShortcutsCommandClass::GetUIDescription() const
{
- class to_string_t
+ if (KeyIndex > 0)
{
- public:
- wchar_t buffer[31];
-
- public:
- constexpr to_string_t() noexcept
- : buffer { L"Select No.0 SW in left sidebar" }
+ class to_string_t
{
- buffer[10] = KeyIndex + '0';
- }
+ public:
+ wchar_t buffer[34];
+
+ public:
+ constexpr to_string_t() noexcept
+ : buffer { L"" }
+ {
+ swprintf_s(buffer, L"Select No.%02d SW in left sidebar", KeyIndex);
+ }
+
+ constexpr operator wchar_t* () noexcept { return buffer; }
+ };
+ static to_string_t name;
+ return StringTable::TryFetchString("TXT_SW_XX_FORWARD_DESC", name);
+ }
- constexpr operator wchar_t* () noexcept { return buffer; }
- };
- static to_string_t name;
- return StringTable::TryFetchString("TXT_SW_XX_FORWARD_DESC", name);
+ return GeneralUtils::LoadStringUnlessMissing("TXT_SW_XX_FORWARD_DESC", L"Switch between visible/invisible modes for exclusive SW sidebar");
}
template
inline void SWShortcutsCommandClass::Execute(WWKey eInput) const
{
- TacticalButtonClass::TriggerButtonForSW(KeyIndex);
+ if (KeyIndex > 0)
+ {
+ TacticalButtonClass::Instance.KeyboardCall = true;
+ TacticalButtonClass::Instance.TriggerButtonForSW(KeyIndex);
+ return;
+ }
+
+ TacticalButtonClass::Instance.SuperVisible = !TacticalButtonClass::Instance.SuperVisible;
+ TacticalButtonClass::Instance.RecheckButtonIndex();
+
+ MessageListClass::Instance->PrintMessage
+ (
+ (TacticalButtonClass::Instance.SuperVisible ?
+ GeneralUtils::LoadStringUnlessMissing("MSG:SWSidebarVisible", L"Set exclusive SW sidebar visible.") :
+ GeneralUtils::LoadStringUnlessMissing("MSG:SWSidebarInvisible", L"Set exclusive SW sidebar invisible.")),
+ RulesClass::Instance->MessageDelay,
+ HouseClass::CurrentPlayer->ColorSchemeIndex,
+ true
+ );
}
diff --git a/src/Ext/House/Body.cpp b/src/Ext/House/Body.cpp
index 6e0cd938bc..67cf9d0c54 100644
--- a/src/Ext/House/Body.cpp
+++ b/src/Ext/House/Body.cpp
@@ -636,8 +636,6 @@ void HouseExt::ExtData::Serialize(T& Stm)
.Process(this->Factory_VehicleType)
.Process(this->Factory_NavyType)
.Process(this->Factory_AircraftType)
- .Process(this->SuperWeaponButtonData)
- .Process(this->SuperWeaponButtonCount)
.Process(this->AISuperWeaponDelayTimer)
.Process(this->RepairBaseNodes)
.Process(this->RestrictedFactoryPlants)
diff --git a/src/Ext/House/Body.h b/src/Ext/House/Body.h
index f9148f5d8c..a872b10457 100644
--- a/src/Ext/House/Body.h
+++ b/src/Ext/House/Body.h
@@ -35,9 +35,6 @@ class HouseExt
BuildingClass* Factory_NavyType;
BuildingClass* Factory_AircraftType;
- int SuperWeaponButtonData[9];
- int SuperWeaponButtonCount;
-
CDTimerClass AISuperWeaponDelayTimer;
//Read from INI
@@ -68,8 +65,6 @@ class HouseExt
, Factory_VehicleType { nullptr }
, Factory_NavyType { nullptr }
, Factory_AircraftType { nullptr }
- , SuperWeaponButtonData { -1, -1, -1, -1, -1, -1, -1, -1, -1 }
- , SuperWeaponButtonCount { 0 }
, AISuperWeaponDelayTimer {}
, RepairBaseNodes { false,false,false }
, RestrictedFactoryPlants {}
diff --git a/src/Ext/SWType/Body.cpp b/src/Ext/SWType/Body.cpp
index f150ac8b4a..adf5875d3b 100644
--- a/src/Ext/SWType/Body.cpp
+++ b/src/Ext/SWType/Body.cpp
@@ -23,18 +23,8 @@ void SWTypeExt::ExtData::Serialize(T& Stm)
.Process(this->SW_AuxBuildings)
.Process(this->SW_NegBuildings)
.Process(this->SW_InitialReady)
- .Process(this->SW_AutoFire)
- .Process(this->SW_ManualFire)
- .Process(this->SW_Unstoppable)
.Process(this->SW_PostDependent)
- .Process(this->EVA_Impatient)
- .Process(this->EVA_InsufficientFunds)
- .Process(this->EVA_SelectTarget)
- .Process(this->Message_InsufficientFunds)
- .Process(this->Message_ColorScheme)
- .Process(this->Message_FirerColor)
.Process(this->SidebarPCX)
- .Process(this->SW_UseAITargeting)
.Process(this->UIDescription)
.Process(this->CameoPriority)
.Process(this->LimboDelivery_Types)
@@ -58,10 +48,11 @@ void SWTypeExt::ExtData::Serialize(T& Stm)
.Process(this->ShowTimer_Priority)
.Process(this->Convert_Pairs)
.Process(this->ShowDesignatorRange)
+ .Process(this->SW_QuickFireAtMouse)
+ .Process(this->SW_QuickFireInScreen)
.Process(this->SW_InScreen_Show)
.Process(this->SW_InScreen_PriorityHouses)
.Process(this->SW_InScreen_RequiredHouses)
- .Process(this->SW_InScreen_QuickFire)
.Process(this->UseWeeds)
.Process(this->UseWeeds_Amount)
.Process(this->UseWeeds_StorageTimer)
@@ -94,18 +85,8 @@ void SWTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI)
this->SW_AuxBuildings.Read(exINI, pSection, "SW.AuxBuildings");
this->SW_NegBuildings.Read(exINI, pSection, "SW.NegBuildings");
this->SW_InitialReady.Read(exINI, pSection, "SW.InitialReady");
- this->SW_AutoFire.Read(exINI, pSection, "SW.AutoFire");
- this->SW_ManualFire.Read(exINI, pSection, "SW.ManualFire");
- this->SW_Unstoppable.Read(exINI, pSection, "SW.Unstoppable");
this->SW_PostDependent.Read(exINI, pSection, "SW.PostDependent");
- this->EVA_Impatient.Read(exINI, pSection, "EVA.Impatient");
- this->EVA_InsufficientFunds.Read(exINI, pSection, "EVA.InsufficientFunds");
- this->EVA_SelectTarget.Read(exINI, pSection, "EVA.SelectTarget");
- this->Message_InsufficientFunds.Read(exINI, pSection, "Message.InsufficientFunds");
- this->Message_ColorScheme.Read(exINI, pSection, "Message.ColorScheme");
- this->Message_FirerColor.Read(exINI, pSection, "Message.FirerColor");
this->SidebarPCX.Read(pINI, pSection, "SidebarPCX");
- this->SW_UseAITargeting.Read(exINI, pSection, "SW.UseAITargeting");
this->UIDescription.Read(exINI, pSection, "UIDescription");
this->CameoPriority.Read(exINI, pSection, "CameoPriority");
@@ -186,10 +167,11 @@ void SWTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI)
this->ShowDesignatorRange.Read(exINI, pSection, "ShowDesignatorRange");
+ this->SW_QuickFireAtMouse.Read(exINI, pSection, "SW.QuickFireAtMouse");
+ this->SW_QuickFireInScreen.Read(exINI, pSection, "SW.QuickFireInScreen");
this->SW_InScreen_Show.Read(exINI, pSection, "SW.InScreen.Show");
this->SW_InScreen_PriorityHouses = pINI->ReadHouseTypesList(pSection, "SW.InScreen.PriorityHouses", this->SW_InScreen_PriorityHouses);
this->SW_InScreen_RequiredHouses = pINI->ReadHouseTypesList(pSection, "SW.InScreen.RequiredHouses", this->SW_InScreen_RequiredHouses);
- this->SW_InScreen_QuickFire.Read(exINI, pSection, "SW.InScreen.QuickFire");
this->UseWeeds.Read(exINI, pSection, "UseWeeds");
this->UseWeeds_Amount.Read(exINI, pSection, "UseWeeds.Amount");
diff --git a/src/Ext/SWType/Body.h b/src/Ext/SWType/Body.h
index 6b94e3fd77..82bb80549b 100644
--- a/src/Ext/SWType/Body.h
+++ b/src/Ext/SWType/Body.h
@@ -35,20 +35,9 @@ class SWTypeExt
ValueableVector SW_AuxBuildings;
ValueableVector SW_NegBuildings;
Valueable SW_InitialReady;
- Valueable SW_AutoFire;
- Valueable SW_ManualFire;
- Valueable SW_Unstoppable;
ValueableIdx SW_PostDependent;
- ValueableIdx EVA_Impatient;
- ValueableIdx EVA_InsufficientFunds;
- ValueableIdx EVA_SelectTarget;
- Valueable Message_InsufficientFunds;
- Valueable Message_ColorScheme;
- Valueable Message_FirerColor;
PhobosPCXFile SidebarPCX;
- Valueable SW_UseAITargeting;
-
Valueable UIDescription;
Valueable CameoPriority;
ValueableVector LimboDelivery_Types;
@@ -77,10 +66,11 @@ class SWTypeExt
std::vector Convert_Pairs;
+ Valueable SW_QuickFireAtMouse;
+ Valueable SW_QuickFireInScreen;
Valueable SW_InScreen_Show;
DWORD SW_InScreen_PriorityHouses;
DWORD SW_InScreen_RequiredHouses;
- Valueable SW_InScreen_QuickFire;
Valueable UseWeeds;
Valueable UseWeeds_Amount;
@@ -100,17 +90,7 @@ class SWTypeExt
, SW_AuxBuildings {}
, SW_NegBuildings {}
, SW_InitialReady { false }
- , SW_AutoFire { false }
- , SW_ManualFire { true }
- , SW_Unstoppable { false }
, SW_PostDependent {}
- , EVA_Impatient { -1 }
- , EVA_InsufficientFunds { -1 }
- , EVA_SelectTarget { -1 }
- , Message_InsufficientFunds {}
- , Message_ColorScheme { -1 }
- , Message_FirerColor { false }
- , SW_UseAITargeting { false }
, UIDescription {}
, CameoPriority { 0 }
, LimboDelivery_Types {}
@@ -134,10 +114,11 @@ class SWTypeExt
, ShowTimer_Priority { 0 }
, Convert_Pairs {}
, ShowDesignatorRange { true }
+ , SW_QuickFireAtMouse { false }
+ , SW_QuickFireInScreen { false }
, SW_InScreen_Show { false }
, SW_InScreen_PriorityHouses { 0u }
, SW_InScreen_RequiredHouses { 0xFFFFFFFFu }
- , SW_InScreen_QuickFire { false }
, UseWeeds { false }
, UseWeeds_Amount { RulesClass::Instance->WeedCapacity }
, UseWeeds_StorageTimer { false }
diff --git a/src/Misc/TacticalButtons.cpp b/src/Misc/TacticalButtons.cpp
index 863c09eb2f..4cfe7feb03 100644
--- a/src/Misc/TacticalButtons.cpp
+++ b/src/Misc/TacticalButtons.cpp
@@ -20,9 +20,9 @@ TacticalButtonClass TacticalButtonClass::Instance;
// Private functions
int TacticalButtonClass::CheckMouseOverButtons(const Point2D* pMousePosition)
{
- if (pMousePosition->X < 65 && pMousePosition->X >= 5) // Button index 1-9 : Super weapons buttons
+ if (this->SuperVisible && pMousePosition->X < 65 && pMousePosition->X >= 5) // Button index 1-10 : Super weapons buttons
{
- const int currentCounts = HouseExt::ExtMap.Find(HouseClass::CurrentPlayer)->SuperWeaponButtonCount;
+ const int currentCounts = this->SWButtonData.size();
const int height = DSurface::Composite->GetHeight();
int checkHight = (height - 32 - 48 * currentCounts - 2 * (currentCounts - 1)) / 2;
@@ -40,7 +40,7 @@ int TacticalButtonClass::CheckMouseOverButtons(const Point2D* pMousePosition)
}
}
- // TODO New buttons (Start from index = 10)
+ // TODO New buttons (Start from index = 11)
if (CheckMouseOverBackground(pMousePosition))
return 0; // Button index 0 : Background
@@ -50,14 +50,19 @@ int TacticalButtonClass::CheckMouseOverButtons(const Point2D* pMousePosition)
bool TacticalButtonClass::CheckMouseOverBackground(const Point2D* pMousePosition)
{
- if (RulesExt::Global()->SWSidebarBackground && pMousePosition->X < 80 && pMousePosition->X >= 0)
+ if (RulesExt::Global()->SWSidebarBackground && this->SuperVisible)
{
- const int currentCounts = HouseExt::ExtMap.Find(HouseClass::CurrentPlayer)->SuperWeaponButtonCount;
- const int height = DSurface::Composite->GetHeight();
- const int checkHight = (height - 32 - 48 * currentCounts - 2 * (currentCounts - 1)) / 2 - 21;
+ if (const int currentCounts = this->SWButtonData.size())
+ {
+ if (pMousePosition->X < 80 && pMousePosition->X >= 0)
+ {
+ const int height = DSurface::Composite->GetHeight();
+ const int checkHight = (height - 32 - 48 * currentCounts - 2 * (currentCounts - 1)) / 2 - 21;
- if (pMousePosition->Y >= checkHight && pMousePosition->Y < (checkHight + currentCounts * 50 + 40))
- return true;
+ if (pMousePosition->Y >= checkHight && pMousePosition->Y < (checkHight + currentCounts * 50 + 40))
+ return true;
+ }
+ }
}
// TODO New button backgrounds
@@ -66,12 +71,12 @@ bool TacticalButtonClass::CheckMouseOverBackground(const Point2D* pMousePosition
}
// Inline functions
-inline bool TacticalButtonClass::MouseOverButtons()
+inline bool TacticalButtonClass::MouseIsOverButtons()
{
return this->ButtonIndex > 0;
}
-inline bool TacticalButtonClass::MouseOverTactical()
+inline bool TacticalButtonClass::MouseIsOverTactical()
{
return this->ButtonIndex < 0;
}
@@ -82,6 +87,11 @@ int TacticalButtonClass::GetButtonIndex()
return this->ButtonIndex;
}
+void TacticalButtonClass::RecheckButtonIndex()
+{
+ this->LastPosition = Point2D { -1, -1 };
+}
+
// General functions
void TacticalButtonClass::SetMouseButtonIndex(const Point2D* pMousePosition)
{
@@ -95,18 +105,18 @@ void TacticalButtonClass::SetMouseButtonIndex(const Point2D* pMousePosition)
if (this->ButtonIndex > 0)
{
HouseClass* const pHouse = HouseClass::CurrentPlayer;
- const int index = HouseExt::ExtMap.Find(pHouse)->SuperWeaponButtonData[this->ButtonIndex - 1];
+ const int index = Instance.SWButtonData[this->ButtonIndex - 1];
SuperClass* const pSuper = pHouse->Supers.Items[index];
- if (pSuper != this->pRecordSuper)
+ if (pSuper != this->RecordSuper)
{
PhobosToolTip::Instance.HelpText(pSuper);
- this->pRecordSuper = pSuper;
+ this->RecordSuper = pSuper;
}
}
- else if (this->pRecordSuper)
+ else if (this->RecordSuper)
{
- this->pRecordSuper = nullptr;
+ this->RecordSuper = nullptr;
}
}
@@ -114,17 +124,17 @@ void TacticalButtonClass::PressDesignatedButton(int triggerIndex)
{
const int buttonIndex = this->ButtonIndex;
- if (!buttonIndex) // In buttons background
+ if (buttonIndex <= 0) // In buttons background
return;
- if (buttonIndex <= 9) // Button index 1-9 : Super weapons buttons
+ if (buttonIndex <= 10) // Button index 1-10 : Super weapons buttons
{
if (!triggerIndex)
TriggerButtonForSW(buttonIndex);
else if (triggerIndex == 2)
DisplayClass::Instance->CurrentSWTypeIndex = -1;
}
-/* else if (?) // TODO New buttons (Start from index = 10)
+/* else if (?) // TODO New buttons (Start from index = 11)
{
;
}*/
@@ -133,16 +143,19 @@ void TacticalButtonClass::PressDesignatedButton(int triggerIndex)
// SW buttons functions
void TacticalButtonClass::DrawButtonForSW()
{
- HouseClass* const pHouse = HouseClass::CurrentPlayer;
- HouseExt::ExtData* const pHouseExt = HouseExt::ExtMap.Find(pHouse);
- SideExt::ExtData* const pSideExt = SideExt::ExtMap.Find(SideClass::Array->GetItem(pHouse->SideIndex));
- const int currentCounts = pHouseExt->SuperWeaponButtonCount;
- const bool drawSWSidebarBackground = RulesExt::Global()->SWSidebarBackground;
+ if (!this->SuperVisible)
+ return;
+
+ const int currentCounts = this->SWButtonData.size();
if (!currentCounts)
return;
- auto& data = pHouseExt->SuperWeaponButtonData;
+ HouseClass* const pHouse = HouseClass::CurrentPlayer;
+ SideExt::ExtData* const pSideExt = SideExt::ExtMap.Find(SideClass::Array->GetItem(pHouse->SideIndex));
+ const bool drawSWSidebarBackground = RulesExt::Global()->SWSidebarBackground && pSideExt;
+
+ auto& data = this->SWButtonData;
const int height = DSurface::Composite->GetHeight();
const int color = Drawing::RGB_To_Int(Drawing::TooltipColor);
@@ -168,7 +181,7 @@ void TacticalButtonClass::DrawButtonForSW()
}
// Draw each buttons
- for (int i = 0; i < currentCounts; position.Y += 50, rect.Height += 50) // Button index 1-9
+ for (int i = 0; i < currentCounts; position.Y += 50, rect.Height += 50) // Button index 1-10
{
// Draw center background (80 * 50)
if (drawSWSidebarBackground)
@@ -190,20 +203,22 @@ void TacticalButtonClass::DrawButtonForSW()
// Get SW data
SuperClass* const pSuper = pHouse->Supers.Items[data[i]];
SuperWeaponTypeClass* const pSWType = pSuper->Type;
- SWTypeExt::ExtData* const pTypeExt = SWTypeExt::ExtMap.Find(pSWType);
// Draw cameo
- BSurface* const CameoPCX = pTypeExt->SidebarPCX.GetSurface();
-
- if (CAN_USE_ARES && AresHelper::CanUseAres && CameoPCX)
+ if (SWTypeExt::ExtData* const pTypeExt = SWTypeExt::ExtMap.Find(pSWType))
{
- RectangleStruct drawRect { position.X, position.Y, 60, 48 };
- PCX::Instance->BlitToSurface(&drawRect, DSurface::Composite, CameoPCX);
- }
- else if (SHPStruct* const pSHP = pSWType->SidebarImage)
- {
- DSurface::Composite->DrawSHP(FileSystem::CAMEO_PAL, pSHP, 0, &position, &rect,
- BlitterFlags::bf_400, 0, 0, ZGradient::Ground, 1000, 0, 0, 0, 0, 0);
+ BSurface* const CameoPCX = pTypeExt->SidebarPCX.GetSurface();
+
+ if (CAN_USE_ARES && AresHelper::CanUseAres && CameoPCX)
+ {
+ RectangleStruct drawRect { position.X, position.Y, 60, 48 };
+ PCX::Instance->BlitToSurface(&drawRect, DSurface::Composite, CameoPCX);
+ }
+ else if (SHPStruct* const pSHP = pSWType->SidebarImage)
+ {
+ DSurface::Composite->DrawSHP(FileSystem::CAMEO_PAL, pSHP, 0, &position, &rect,
+ BlitterFlags::bf_400, 0, 0, ZGradient::Ground, 1000, 0, 0, 0, 0, 0);
+ }
}
// Flash cameo
@@ -237,7 +252,7 @@ void TacticalButtonClass::DrawButtonForSW()
DSurface::Composite->DrawTextA(pName, &rect, &textLocation, static_cast(color), COLOR_BLACK, printType);
}
- if (++i == Instance.ButtonIndex)
+ if (++i == this->ButtonIndex)
recordHeight = position.Y;
}
@@ -271,24 +286,18 @@ void TacticalButtonClass::DrawButtonForSW()
void TacticalButtonClass::RecheckButtonForSW()
{
- Instance.LastPosition = Point2D::Empty;
+ RecheckButtonIndex();
HouseClass* const pHouse = HouseClass::CurrentPlayer;
- HouseExt::ExtData* const pHouseExt = HouseExt::ExtMap.Find(pHouse);
- auto& data = pHouseExt->SuperWeaponButtonData;
+ auto& data = this->SWButtonData;
- for (int i = 0; i < pHouseExt->SuperWeaponButtonCount; ++i)
+ for (auto it = data.begin(); it != data.end();)
{
- if (data[i] >= pHouse->Supers.Count || !pHouse->Supers.Items[data[i]]->IsPresent)
- {
- const int counts = pHouseExt->SuperWeaponButtonCount - 1;
-
- for (int j = i; j < counts; ++j)
- {
- data[j] = data[j + 1];
- }
+ const int superIndex = *it;
- data[--pHouseExt->SuperWeaponButtonCount] = -1;
- }
+ if (superIndex >= pHouse->Supers.Count || !pHouse->Supers.Items[superIndex]->IsPresent)
+ it = data.erase(it);
+ else
+ ++it;
}
}
@@ -298,22 +307,21 @@ bool TacticalButtonClass::InsertButtonForSW(int& superIndex)
SWTypeExt::ExtData* const pTypeExt = SWTypeExt::ExtMap.Find(pType);
bool overflow = true;
- if (pTypeExt->SW_InScreen_Show && !pTypeExt->SW_UseAITargeting)
+ if (pTypeExt && pTypeExt->SW_InScreen_Show)
{
- HouseClass* const pHouse = HouseClass::CurrentPlayer;
- HouseExt::ExtData* const pHouseExt = HouseExt::ExtMap.Find(pHouse);
- const unsigned int ownerBits = 1u << pHouse->Type->ArrayIndex;
+ const unsigned int ownerBits = 1u << HouseClass::CurrentPlayer->Type->ArrayIndex;
if (pTypeExt->SW_InScreen_RequiredHouses & ownerBits)
{
- auto& data = pHouseExt->SuperWeaponButtonData;
+ const int currentCounts = this->SWButtonData.size();
+ auto& data = this->SWButtonData;
bool move = false;
- for (int i = 0; i < 9; ++i) // 9 buttons at max
+ for (int i = 0; i < 10; ++i) // 10 buttons at max
{
if (move)
{
- if (data[i] != -1)
+ if (i < currentCounts)
{
int buffer = data[i];
data[i] = superIndex;
@@ -321,15 +329,14 @@ bool TacticalButtonClass::InsertButtonForSW(int& superIndex)
}
else
{
- data[i] = superIndex;
+ data.push_back(superIndex);
overflow = false;
- ++pHouseExt->SuperWeaponButtonCount;
break;
}
}
- else if (data[i] != -1)
+ else if (i < currentCounts)
{
- if (MoveButtonForSW(SuperWeaponTypeClass::Array->Items[data[i]], pType, pTypeExt, ownerBits))
+ if (SortButtonForSW(SuperWeaponTypeClass::Array->Items[data[i]], pType, pTypeExt, ownerBits))
{
move = true;
int buffer = data[i];
@@ -339,9 +346,8 @@ bool TacticalButtonClass::InsertButtonForSW(int& superIndex)
}
else
{
- data[i] = superIndex;
+ data.push_back(superIndex);
overflow = false;
- ++pHouseExt->SuperWeaponButtonCount;
break;
}
}
@@ -351,21 +357,29 @@ bool TacticalButtonClass::InsertButtonForSW(int& superIndex)
return overflow;
}
-bool TacticalButtonClass::MoveButtonForSW(SuperWeaponTypeClass* pDataType, SuperWeaponTypeClass* pAddType, SWTypeExt::ExtData* pAddTypeExt, unsigned int ownerBits)
+bool TacticalButtonClass::SortButtonForSW(SuperWeaponTypeClass* pDataType, SuperWeaponTypeClass* pAddType, SWTypeExt::ExtData* pAddTypeExt, unsigned int ownerBits)
{
SWTypeExt::ExtData* const pDataTypeExt = SWTypeExt::ExtMap.Find(pDataType);
- if ((pDataTypeExt->SW_InScreen_PriorityHouses & ownerBits) && !(pAddTypeExt->SW_InScreen_PriorityHouses & ownerBits))
- return false;
- else if (!(pDataTypeExt->SW_InScreen_PriorityHouses & ownerBits) && (pAddTypeExt->SW_InScreen_PriorityHouses & ownerBits))
- return true;
- else if (pDataTypeExt->CameoPriority > pAddTypeExt->CameoPriority)
- return false;
- else if (pDataTypeExt->CameoPriority < pAddTypeExt->CameoPriority)
- return true;
- else if (pDataType->RechargeTime < pAddType->RechargeTime)
+ if (pDataTypeExt && pAddTypeExt)
+ {
+ if ((pDataTypeExt->SW_InScreen_PriorityHouses & ownerBits) && !(pAddTypeExt->SW_InScreen_PriorityHouses & ownerBits))
+ return false;
+
+ if (!(pDataTypeExt->SW_InScreen_PriorityHouses & ownerBits) && (pAddTypeExt->SW_InScreen_PriorityHouses & ownerBits))
+ return true;
+
+ if (pDataTypeExt->CameoPriority > pAddTypeExt->CameoPriority)
+ return false;
+
+ if (pDataTypeExt->CameoPriority < pAddTypeExt->CameoPriority)
+ return true;
+ }
+
+ if (pDataType->RechargeTime < pAddType->RechargeTime)
return false;
- else if (pDataType->RechargeTime > pAddType->RechargeTime)
+
+ if (pDataType->RechargeTime > pAddType->RechargeTime)
return true;
return wcscmp(pDataType->UIName, pAddType->UIName) > 0;
@@ -373,117 +387,24 @@ bool TacticalButtonClass::MoveButtonForSW(SuperWeaponTypeClass* pDataType, Super
void TacticalButtonClass::TriggerButtonForSW(int buttonIndex)
{
- if (ScenarioClass::Instance->UserInputLocked)
+ if (ScenarioClass::Instance->UserInputLocked || !this->SuperVisible)
return;
- HouseClass* const pHouse = HouseClass::CurrentPlayer;
- const int index = HouseExt::ExtMap.Find(pHouse)->SuperWeaponButtonData[buttonIndex - 1];
+ const int superIndex = this->SWButtonData[buttonIndex - 1];
- if (index < 0) // Keyboard shortcuts may be invalid
+ if (superIndex < 0)
return;
- SuperClass* const pSuper = pHouse->Supers.Items[index];
- SuperWeaponTypeClass* const pType = pSuper->Type;
- SWTypeExt::ExtData* const pTypeExt = SWTypeExt::ExtMap.Find(pType);
-
- if (CAN_USE_ARES && AresHelper::CanUseAres)
- {
- const bool autoFire = !pTypeExt->SW_ManualFire && pTypeExt->SW_AutoFire;
-
- if (!pSuper->CanFire() && !autoFire)
- {
- VoxClass::PlayIndex(pTypeExt->EVA_Impatient);
- return;
- }
-
- if (!pHouse->CanTransactMoney(pTypeExt->Money_Amount))
- {
- if (pTypeExt->EVA_InsufficientFunds != -1)
- VoxClass::PlayIndex(pTypeExt->EVA_InsufficientFunds);
- else
- VoxClass::Play(&Make_Global(0x819044)); // 0x819044 -> EVA_InsufficientFunds
-
- const CSFText csf = pTypeExt->Message_InsufficientFunds;
-
- if (!csf.empty())
- {
- int color = ColorScheme::FindIndex("Gold");
-
- if (pTypeExt->Message_FirerColor)
- {
- if (pHouse)
- color = pHouse->ColorSchemeIndex;
- }
- else
- {
- if (pTypeExt->Message_ColorScheme > -1)
- color = pTypeExt->Message_ColorScheme;
- else if (pHouse)
- color = pHouse->ColorSchemeIndex;
- }
+ SidebarClass* const pSidebar = SidebarClass::Instance;
+ this->DummyAction = true;
- MessageListClass::Instance->PrintMessage(csf, RulesClass::Instance->MessageDelay, color);
- }
-
- return;
- }
+ DummySelectClass pButton;
+ pButton.LinkTo = &pSidebar->Tabs[pSidebar->ActiveTabIndex];
+ pButton.unknown_int_30 = 0x7FFFFFFF;
+ pButton.SWIndex = superIndex;
- const bool unstoppable = pType->UseChargeDrain && pSuper->ChargeDrainState == ChargeDrainState::Draining
- && pTypeExt->SW_Unstoppable;
-
- if (autoFire || unstoppable)
- return;
- }
- else if (!pSuper->CanFire())
- {
- return;
- }
-
- // Use SW.InScreen.QuickFire here, to some extent to replace SW.UseAITargeting
- // Inevitably ignore various conditions such as range, sight, indicators .etc
- // No check for SW.UseAITargeting, too complicated for me. - CrimRecya
- if (pType->Action == Action::None)
- {
- EventClass event
- (
- pHouse->ArrayIndex,
- EventType::SpecialPlace,
- pType->ArrayIndex,
- CellStruct::Empty
- );
- EventClass::AddEvent(event);
- }
- else if (pTypeExt->SW_InScreen_QuickFire)
- {
- EventClass event
- (
- pHouse->ArrayIndex,
- EventType::SpecialPlace,
- pType->ArrayIndex,
- CellClass::Coord2Cell(TacticalClass::Instance->ClientToCoords(Point2D{ (DSurface::Composite->Width >> 1), (DSurface::Composite->Height >> 1) }))
- );
- EventClass::AddEvent(event);
- }
- else
- {
- MouseClass* const pMouse = MouseClass::Instance;
- pMouse->CurrentBuilding = nullptr;
- pMouse->CurrentBuildingType = nullptr;
- pMouse->unknown_11AC = 0xFFFFFFFF;
- pMouse->SetActiveFoundation(nullptr);
- pMouse->SetRepairMode(0);
- pMouse->SetSellMode(0);
- pMouse->PowerToggleMode = false;
- pMouse->PlanningMode = false;
- pMouse->PlaceBeaconMode = false;
- pMouse->CurrentSWTypeIndex = index;
- pMouse->UnselectAll();
-
- if (CAN_USE_ARES && AresHelper::CanUseAres && pTypeExt->EVA_SelectTarget != -1)
- VoxClass::PlayIndex(pTypeExt->EVA_SelectTarget);
- else
- VoxClass::Play(&Make_Global(0x83FB78)); // 0x83FB78 -> EVA_SelectTarget
- }
+ DWORD KeyNum = 0;
+ reinterpret_cast(0x6AAD00)(&pButton, GadgetFlag::LeftPress, &KeyNum, KeyModifier::None); // SelectClass_Action
}
// Hooks
@@ -495,7 +416,7 @@ DEFINE_HOOK(0x6931A5, ScrollClass_WindowsProcedure_PressLeftMouseButton, 0x6)
TacticalButtonClass* const pButtons = &TacticalButtonClass::Instance;
- if (!pButtons->MouseOverTactical())
+ if (!pButtons->MouseIsOverTactical())
{
pButtons->PressedInButtonsLayer = true;
pButtons->PressDesignatedButton(0);
@@ -533,7 +454,7 @@ DEFINE_HOOK(0x69330E, ScrollClass_WindowsProcedure_PressRightMouseButton, 0x6)
TacticalButtonClass* const pButtons = &TacticalButtonClass::Instance;
- if (!pButtons->MouseOverTactical())
+ if (!pButtons->MouseIsOverTactical())
{
pButtons->PressedInButtonsLayer = true;
pButtons->PressDesignatedButton(2);
@@ -582,7 +503,7 @@ DEFINE_HOOK(0x69300B, ScrollClass_MouseUpdate_SkipMouseActionUpdate, 0x6)
TacticalButtonClass* const pButtons = &TacticalButtonClass::Instance;
pButtons->SetMouseButtonIndex(&mousePosition);
- if (pButtons->MouseOverTactical())
+ if (pButtons->MouseIsOverTactical())
return 0;
R->Stack(STACK_OFFSET(0x30, -0x24), 0);
@@ -595,14 +516,14 @@ DEFINE_HOOK(0x6D4941, TacticalClass_Render_DrawButtonCameo, 0x6)
{
// TODO New buttons (The later draw, the higher layer)
- TacticalButtonClass::DrawButtonForSW();
+ TacticalButtonClass::Instance.DrawButtonForSW();
return 0;
}
// SW buttons hooks
DEFINE_HOOK(0x4F9283, HouseClass_Update_RecheckTechTree, 0x5)
{
- TacticalButtonClass::RecheckButtonForSW();
+ TacticalButtonClass::Instance.RecheckButtonForSW();
return 0;
}
@@ -613,5 +534,90 @@ DEFINE_HOOK(0x6A6314, SidebarClass_AddCameo_SupportSWButtons, 0x8)
GET_STACK(const AbstractType, absType, STACK_OFFSET(0x14, 0x4));
REF_STACK(int, index, STACK_OFFSET(0x14, 0x8));
- return (absType != AbstractType::Special || SuperWeaponTypeClass::Array->Count <= index || TacticalButtonClass::InsertButtonForSW(index)) ? 0 : SkipGameCode;
+ return (absType != AbstractType::Special || SuperWeaponTypeClass::Array->Count <= index || TacticalButtonClass::Instance.InsertButtonForSW(index)) ? 0 : SkipGameCode;
+}
+
+DEFINE_HOOK(0x6AAF46, SelectClass_Action_ButtonClick1, 0x6)
+{
+ enum { SkipGameCode = 0x6AB95A };
+
+ GET(const int, index, ESI);
+
+ SuperWeaponTypeClass* const pType = SuperWeaponTypeClass::Array->Items[index];
+ SWTypeExt::ExtData* const pTypeExt = SWTypeExt::ExtMap.Find(pType);
+ TacticalButtonClass* const pButtons = &TacticalButtonClass::Instance;
+ bool keyboardCall = false;
+
+ if (pButtons->KeyboardCall)
+ {
+ pButtons->KeyboardCall = false;
+ keyboardCall = true;
+ }
+
+ if (pTypeExt)
+ {
+ if (pTypeExt->SW_QuickFireAtMouse && keyboardCall)
+ {
+ const CoordStruct mouseCoords = TacticalClass::Instance->ClientToCoords(WWMouseClass::Instance->XY1);
+
+ if (mouseCoords != CoordStruct::Empty)
+ {
+ EventClass event
+ (
+ HouseClass::CurrentPlayer->ArrayIndex,
+ EventType::SpecialPlace,
+ pType->ArrayIndex,
+ CellClass::Coord2Cell(mouseCoords)
+ );
+ EventClass::AddEvent(event);
+
+ return SkipGameCode;
+ }
+ }
+ else if (!pTypeExt->SW_QuickFireInScreen)
+ {
+ return 0;
+ }
+
+ EventClass event
+ (
+ HouseClass::CurrentPlayer->ArrayIndex,
+ EventType::SpecialPlace,
+ pType->ArrayIndex,
+ CellClass::Coord2Cell(TacticalClass::Instance->ClientToCoords(Point2D{ (DSurface::Composite->Width >> 1), (DSurface::Composite->Height >> 1) }))
+ );
+ EventClass::AddEvent(event);
+
+ return SkipGameCode;
+ }
+
+ return 0;
+}
+
+DEFINE_HOOK_AGAIN(0x6AAD2F, SelectClass_Action_ButtonClick2, 0x7)
+DEFINE_HOOK(0x6AB94F, SelectClass_Action_ButtonClick2, 0xB)
+{
+ enum { SkipGameCode = 0x6AAE7C };
+
+ if (!TacticalButtonClass::Instance.DummyAction)
+ return 0;
+
+ GET(TacticalButtonClass::DummySelectClass* const , pThis, EDI);
+
+ R->Stack(STACK_OFFSET(0xAC, -0x98), pThis->SWIndex);
+ return SkipGameCode;
+}
+
+DEFINE_HOOK(0x6AB961, SelectClass_Action_ButtonClick3, 0x7)
+{
+ enum { SkipGameCode = 0x6AB975 };
+
+ TacticalButtonClass* const pButtons = &TacticalButtonClass::Instance;
+
+ if (!pButtons->DummyAction)
+ return 0;
+
+ pButtons->DummyAction = false;
+
+ return SkipGameCode;
}
diff --git a/src/Misc/TacticalButtons.h b/src/Misc/TacticalButtons.h
index dc628c9542..aece63c50c 100644
--- a/src/Misc/TacticalButtons.h
+++ b/src/Misc/TacticalButtons.h
@@ -1,16 +1,6 @@
#include
#include
-
-// Test function for extra pressable buttons above tactical map
-
-// Note:
-// If some of the functions are intended for some multiplayer gamemodes,
-// I think they should be triggered through the EventClass. But in fact,
-// there are too few existing events can be used that I don't know what
-// universal functionality can be achieved. - CrimRecya
-
-// It would be great if it could be modularized
-// TODO TacticalButtonClass::TacticalButtonGroup::TacticalButton
+#include
class TacticalButtonClass
{
@@ -18,31 +8,53 @@ class TacticalButtonClass
static TacticalButtonClass Instance;
private:
- static int CheckMouseOverButtons(const Point2D* pMousePosition);
- static bool CheckMouseOverBackground(const Point2D* pMousePosition);
+ int CheckMouseOverButtons(const Point2D* pMousePosition);
+ bool CheckMouseOverBackground(const Point2D* pMousePosition);
public:
- inline bool MouseOverButtons();
- inline bool MouseOverTactical();
+ inline bool MouseIsOverButtons();
+ inline bool MouseIsOverTactical();
int GetButtonIndex();
+ void RecheckButtonIndex();
void SetMouseButtonIndex(const Point2D* pMousePosition);
void PressDesignatedButton(int triggerIndex);
- // Button index 1-9 : Super weapons buttons
- static void DrawButtonForSW();
- static void RecheckButtonForSW();
- static bool InsertButtonForSW(int& superIndex);
- static bool MoveButtonForSW(SuperWeaponTypeClass* pDataType, SuperWeaponTypeClass* pAddType, SWTypeExt::ExtData* pAddTypeExt, unsigned int ownerBits);
- static void TriggerButtonForSW(int buttonIndex);
+ // Button index 1-10 : Super weapons buttons
+ void DrawButtonForSW();
+ void RecheckButtonForSW();
+ bool InsertButtonForSW(int& superIndex);
+ bool SortButtonForSW(SuperWeaponTypeClass* pDataType, SuperWeaponTypeClass* pAddType, SWTypeExt::ExtData* pAddTypeExt, unsigned int ownerBits);
+ void TriggerButtonForSW(int buttonIndex);
+
+ struct DummySelectClass
+ {
+ char _[0x2C] {}; // : ControlClass
+ StripClass *LinkTo { nullptr };
+ int unknown_int_30 { 0 };
+ bool MouseEntered { false };
+ int SWIndex { -1 }; // New
+ };
+
+ // TODO New buttons (Start from index = 11)
public:
bool PressedInButtonsLayer { false }; // Check press
+ // Button index 1-10 : Super weapons buttons
+ bool DummyAction { false };
+ bool KeyboardCall { false };
+ bool SuperVisible { true };
+
+ // TODO New buttons (Start from index = 11)
+
private:
int ButtonIndex { -1 }; // -1 -> above no buttons, 0 -> above buttons background, POSITIVE -> above button who have this index
Point2D LastPosition { Point2D::Empty }; // Check moving
- // Button index 1-9 : Super weapons buttons
- SuperClass* pRecordSuper = nullptr; // Cannot be used, only for comparison purposes
+ // Button index 1-10 : Super weapons buttons
+ std::vector SWButtonData;
+ SuperClass* RecordSuper { nullptr }; // Cannot be used, only for comparison purposes
+
+ // TODO New buttons (Start from index = 11)
};
From b315341a2ba6ecb5905997ce2527ce8471883b93 Mon Sep 17 00:00:00 2001
From: CrimRecya <335958461@qq.com>
Date: Thu, 19 Sep 2024 19:48:13 +0800
Subject: [PATCH 03/12] Switch button
---
docs/User-Interface.md | 3 +
src/Commands/SWShortcuts.h | 17 +-
src/Ext/Side/Body.cpp | 4 +
src/Ext/Side/Body.h | 2 +
src/Misc/PhobosToolTip.cpp | 2 +-
src/Misc/TacticalButtons.cpp | 348 ++++++++++++++++++++++-------------
src/Misc/TacticalButtons.h | 34 ++--
7 files changed, 257 insertions(+), 153 deletions(-)
diff --git a/docs/User-Interface.md b/docs/User-Interface.md
index 6ede2fbba5..dd09844e22 100644
--- a/docs/User-Interface.md
+++ b/docs/User-Interface.md
@@ -348,6 +348,7 @@ MissingCameo=XXICON.SHP ; filename - including the .shp/.pcx extension
- Now, you can display a sidebar exclusive to superweapons through a series of settings. At the same time, you can specify the shortcuts for these buttons in the shortcut key settings.
- `SWSidebarBackground` controls whether to draw the background shape of the exclusive sidebar.
+ - `SWSidebarBackground.OnPCX` and `SWSidebarBackground.OffPCX` controlled the shapes of this exclusive sidebar's switch displaying, respectively used in non-hidden and hidden. Required sizes are all `10 * 50`.
- `SWSidebarBackground.TopPCX`, `SWSidebarBackground.CenterPCX` and `SWSidebarBackground.BottomPCX` controlled the materials that were combined to create the entire exclusive sidebar background shape. Their required sizes are respectively `80 * 20`, `80 * 50` and `80 * 20`. In `SWSidebarBackground.CenterPCX`, the position of the superweapon's `SidebarPCX` is 5 pixels away from the left contour of this background, 15 pixels away from the right contour, and 1 pixel away from both the upper and lower contours.
- `SW.InScreen.Show` controls whether the superweapon should be displayed first in the exclusive sidebar. If the exclusive sidebar is full (up to 10 are displayed), the overflowing superweapon's cameo will be added back to the original sidebar. If there is an empty space in the exclusive sidebar afterwards, it will no longer return to the exclusive sidebar, unless the permission to use the superweapon is regained (lost and gained again). Therefore, it is not recommended to place all superweapons in the exclusive sidebar.
- `SW.InScreen.PriorityHouses` controls if the superweapon is displayed first in the exclusive sidebar, players belonging to these houses will have priority in placing the superweapon cameo in the exclusive sidebar.
@@ -361,6 +362,8 @@ In `rulesmd.ini`:
SWSidebarBackground=true ; boolean
[SOMESIDE] ; Side
+SWSidebarBackground.OnPCX= ; filename - including the .pcx extension
+SWSidebarBackground.OffPCX= ; filename - including the .pcx extension
SWSidebarBackground.TopPCX= ; filename - including the .pcx extension
SWSidebarBackground.CenterPCX= ; filename - including the .pcx extension
SWSidebarBackground.BottomPCX= ; filename - including the .pcx extension
diff --git a/src/Commands/SWShortcuts.h b/src/Commands/SWShortcuts.h
index 7bb7f37ee1..595b4a8be0 100644
--- a/src/Commands/SWShortcuts.h
+++ b/src/Commands/SWShortcuts.h
@@ -107,21 +107,10 @@ inline void SWShortcutsCommandClass::Execute(WWKey eInput) const
{
if (KeyIndex > 0)
{
- TacticalButtonClass::Instance.KeyboardCall = true;
- TacticalButtonClass::Instance.TriggerButtonForSW(KeyIndex);
+ TacticalButtonsClass::Instance.KeyboardCall = true;
+ TacticalButtonsClass::Instance.SWSidebarTrigger(KeyIndex);
return;
}
- TacticalButtonClass::Instance.SuperVisible = !TacticalButtonClass::Instance.SuperVisible;
- TacticalButtonClass::Instance.RecheckButtonIndex();
-
- MessageListClass::Instance->PrintMessage
- (
- (TacticalButtonClass::Instance.SuperVisible ?
- GeneralUtils::LoadStringUnlessMissing("MSG:SWSidebarVisible", L"Set exclusive SW sidebar visible.") :
- GeneralUtils::LoadStringUnlessMissing("MSG:SWSidebarInvisible", L"Set exclusive SW sidebar invisible.")),
- RulesClass::Instance->MessageDelay,
- HouseClass::CurrentPlayer->ColorSchemeIndex,
- true
- );
+ TacticalButtonsClass::Instance.SWSidebarSwitch();
}
diff --git a/src/Ext/Side/Body.cpp b/src/Ext/Side/Body.cpp
index fc41f25222..a93ee4e221 100644
--- a/src/Ext/Side/Body.cpp
+++ b/src/Ext/Side/Body.cpp
@@ -41,6 +41,8 @@ void SideExt::ExtData::LoadFromINIFile(CCINIClass* pINI)
this->ToolTip_Background_Opacity.Read(exINI, pSection, "ToolTip.Background.Opacity");
this->ToolTip_Background_BlurSize.Read(exINI, pSection, "ToolTip.Background.BlurSize");
this->BriefingTheme = pINI->ReadTheme(pSection, "BriefingTheme", this->BriefingTheme);
+ this->SWSidebarBackground_OnPCX.Read(pINI, pSection, "SWSidebarBackground.OnPCX");
+ this->SWSidebarBackground_OffPCX.Read(pINI, pSection, "SWSidebarBackground.OffPCX");
this->SWSidebarBackground_TopPCX.Read(pINI, pSection, "SWSidebarBackground.TopPCX");
this->SWSidebarBackground_CenterPCX.Read(pINI, pSection, "SWSidebarBackground.CenterPCX");
this->SWSidebarBackground_BottomPCX.Read(pINI, pSection, "SWSidebarBackground.BottomPCX");
@@ -73,6 +75,8 @@ void SideExt::ExtData::Serialize(T& Stm)
.Process(this->IngameScore_WinTheme)
.Process(this->IngameScore_LoseTheme)
.Process(this->BriefingTheme)
+ .Process(this->SWSidebarBackground_OnPCX)
+ .Process(this->SWSidebarBackground_OffPCX)
.Process(this->SWSidebarBackground_TopPCX)
.Process(this->SWSidebarBackground_CenterPCX)
.Process(this->SWSidebarBackground_BottomPCX)
diff --git a/src/Ext/Side/Body.h b/src/Ext/Side/Body.h
index 3c1504ef56..d14c8591f1 100644
--- a/src/Ext/Side/Body.h
+++ b/src/Ext/Side/Body.h
@@ -36,6 +36,8 @@ class SideExt
Nullable ToolTip_Background_Opacity;
Nullable ToolTip_Background_BlurSize;
Valueable BriefingTheme;
+ PhobosPCXFile SWSidebarBackground_OnPCX;
+ PhobosPCXFile SWSidebarBackground_OffPCX;
PhobosPCXFile SWSidebarBackground_TopPCX;
PhobosPCXFile SWSidebarBackground_CenterPCX;
PhobosPCXFile SWSidebarBackground_BottomPCX;
diff --git a/src/Misc/PhobosToolTip.cpp b/src/Misc/PhobosToolTip.cpp
index 19083664f5..7786a2058d 100644
--- a/src/Misc/PhobosToolTip.cpp
+++ b/src/Misc/PhobosToolTip.cpp
@@ -204,7 +204,7 @@ DEFINE_HOOK(0x4AE511, DisplayClass_GetToolTip_SkipTacticalTip, 0x5)
{
enum { UseButtonTip = 0x4AE5F8, SkipGameCode = 0x4AE69B };
- const int buttonIndex = TacticalButtonClass::Instance.GetButtonIndex();
+ const int buttonIndex = TacticalButtonsClass::Instance.GetButtonIndex();
if (buttonIndex < 0)
return 0;
diff --git a/src/Misc/TacticalButtons.cpp b/src/Misc/TacticalButtons.cpp
index 4cfe7feb03..6c4a1bc0f0 100644
--- a/src/Misc/TacticalButtons.cpp
+++ b/src/Misc/TacticalButtons.cpp
@@ -9,46 +9,61 @@
#include
#include
#include
+#include
#include "PhobosToolTip.h"
#include "TacticalButtons.h"
-TacticalButtonClass TacticalButtonClass::Instance;
+TacticalButtonsClass TacticalButtonsClass::Instance;
// Functions
// Private functions
-int TacticalButtonClass::CheckMouseOverButtons(const Point2D* pMousePosition)
+int TacticalButtonsClass::CheckMouseOverButtons(const Point2D* pMousePosition)
{
- if (this->SuperVisible && pMousePosition->X < 65 && pMousePosition->X >= 5) // Button index 1-10 : Super weapons buttons
+ if (const int currentCounts = this->SWButtonData.size())
{
- const int currentCounts = this->SWButtonData.size();
- const int height = DSurface::Composite->GetHeight();
- int checkHight = (height - 32 - 48 * currentCounts - 2 * (currentCounts - 1)) / 2;
+ const int height = DSurface::Composite->GetHeight() - 32;
- for (int i = 0; i < currentCounts; ++i)
+ if (this->SuperVisible && pMousePosition->X < 65 && pMousePosition->X >= 5) // Button index 1-10 : Super weapons buttons
{
- if (pMousePosition->Y < checkHight)
- break;
+ int checkHight = (height - 48 * currentCounts - 2 * (currentCounts - 1)) / 2;
- checkHight += 48;
+ for (int i = 0; i < currentCounts; ++i)
+ {
+ if (pMousePosition->Y < checkHight)
+ break;
+
+ checkHight += 48;
+
+ if (pMousePosition->Y < checkHight)
+ return i + 1;
+
+ checkHight += 2;
+ }
+ }
- if (pMousePosition->Y < checkHight)
- return i + 1;
+ if (RulesExt::Global()->SWSidebarBackground) // Button index 11 : SW sidebar switch
+ {
+ if (this->SuperVisible ? (pMousePosition->X < 90 && pMousePosition->X >= 80) : (pMousePosition->X < 10 && pMousePosition->X >= 0))
+ {
+ const int checkHight = height / 2;
- checkHight += 2;
+ if (pMousePosition->Y < checkHight + 25 && pMousePosition->Y >= checkHight - 25)
+ return 11;
+ }
}
}
- // TODO New buttons (Start from index = 11)
+ // TODO New buttons (Start from index = 12)
- if (CheckMouseOverBackground(pMousePosition))
+ if (this->CheckMouseOverBackground(pMousePosition))
return 0; // Button index 0 : Background
return -1;
}
-bool TacticalButtonClass::CheckMouseOverBackground(const Point2D* pMousePosition)
+bool TacticalButtonsClass::CheckMouseOverBackground(const Point2D* pMousePosition)
{
if (RulesExt::Global()->SWSidebarBackground && this->SuperVisible)
{
@@ -56,8 +71,8 @@ bool TacticalButtonClass::CheckMouseOverBackground(const Point2D* pMousePosition
{
if (pMousePosition->X < 80 && pMousePosition->X >= 0)
{
- const int height = DSurface::Composite->GetHeight();
- const int checkHight = (height - 32 - 48 * currentCounts - 2 * (currentCounts - 1)) / 2 - 21;
+ const int height = DSurface::Composite->GetHeight() - 32;
+ const int checkHight = (height - 48 * currentCounts - 2 * (currentCounts - 1)) / 2 - 21;
if (pMousePosition->Y >= checkHight && pMousePosition->Y < (checkHight + currentCounts * 50 + 40))
return true;
@@ -71,81 +86,97 @@ bool TacticalButtonClass::CheckMouseOverBackground(const Point2D* pMousePosition
}
// Inline functions
-inline bool TacticalButtonClass::MouseIsOverButtons()
+inline bool TacticalButtonsClass::MouseIsOverButtons()
{
return this->ButtonIndex > 0;
}
-inline bool TacticalButtonClass::MouseIsOverTactical()
+inline bool TacticalButtonsClass::MouseIsOverTactical()
{
return this->ButtonIndex < 0;
}
// Cite functions
-int TacticalButtonClass::GetButtonIndex()
+int TacticalButtonsClass::GetButtonIndex()
{
return this->ButtonIndex;
}
-void TacticalButtonClass::RecheckButtonIndex()
+void TacticalButtonsClass::RecheckButtonIndex()
{
this->LastPosition = Point2D { -1, -1 };
+ this->ButtonIndex = -1;
}
// General functions
-void TacticalButtonClass::SetMouseButtonIndex(const Point2D* pMousePosition)
+void TacticalButtonsClass::SetMouseButtonIndex(const Point2D* pMousePosition)
{
if (this->LastPosition == *pMousePosition)
return;
this->LastPosition = *pMousePosition;
- this->ButtonIndex = CheckMouseOverButtons(pMousePosition);
+ this->ButtonIndex = this->CheckMouseOverButtons(pMousePosition);
// SW ToolTip
- if (this->ButtonIndex > 0)
+ CCToolTip* const toolTips = CCToolTip::Instance;
+
+ if (this->MouseIsOverButtons() && this->IndexInSWButtons()) // Button index 1-10 : Super weapons buttons
{
- HouseClass* const pHouse = HouseClass::CurrentPlayer;
- const int index = Instance.SWButtonData[this->ButtonIndex - 1];
- SuperClass* const pSuper = pHouse->Supers.Items[index];
+ SuperClass* const pSuper = HouseClass::CurrentPlayer->Supers.Items[Instance.SWButtonData[this->ButtonIndex - 1]];
- if (pSuper != this->RecordSuper)
+ if (pSuper && pSuper != this->RecordSuper)
{
PhobosToolTip::Instance.HelpText(pSuper);
this->RecordSuper = pSuper;
+
+ if (toolTips->ToolTipDelay)
+ toolTips->LastToolTipDelay = toolTips->ToolTipDelay;
+
+ toolTips->ToolTipDelay = 0;
}
}
else if (this->RecordSuper)
{
this->RecordSuper = nullptr;
+ toolTips->ToolTipDelay = toolTips->LastToolTipDelay;
}
}
-void TacticalButtonClass::PressDesignatedButton(int triggerIndex)
+void TacticalButtonsClass::PressDesignatedButton(int triggerIndex)
{
- const int buttonIndex = this->ButtonIndex;
-
- if (buttonIndex <= 0) // In buttons background
+ if (!this->MouseIsOverButtons()) // In buttons background
return;
- if (buttonIndex <= 10) // Button index 1-10 : Super weapons buttons
+ if (this->IndexInSWButtons()) // Button index 1-10 : Super weapons buttons
{
if (!triggerIndex)
- TriggerButtonForSW(buttonIndex);
+ this->SWSidebarTrigger(this->ButtonIndex);
else if (triggerIndex == 2)
DisplayClass::Instance->CurrentSWTypeIndex = -1;
+
+ CCToolTip* const toolTips = CCToolTip::Instance;
+ this->RecordSuper = nullptr;
+ toolTips->ToolTipDelay = toolTips->LastToolTipDelay;
}
-/* else if (?) // TODO New buttons (Start from index = 11)
+ else if (this->IndexIsSWSwitch())
+ {
+ if (!triggerIndex)
+ this->SWSidebarSwitch();
+ }
+/* else if (?) // TODO New buttons (Start from index = 12)
{
;
}*/
}
// SW buttons functions
-void TacticalButtonClass::DrawButtonForSW()
+inline bool TacticalButtonsClass::IndexInSWButtons()
{
- if (!this->SuperVisible)
- return;
+ return this->ButtonIndex <= 10;
+}
+void TacticalButtonsClass::SWSidebarDraw()
+{
const int currentCounts = this->SWButtonData.size();
if (!currentCounts)
@@ -154,12 +185,51 @@ void TacticalButtonClass::DrawButtonForSW()
HouseClass* const pHouse = HouseClass::CurrentPlayer;
SideExt::ExtData* const pSideExt = SideExt::ExtMap.Find(SideClass::Array->GetItem(pHouse->SideIndex));
const bool drawSWSidebarBackground = RulesExt::Global()->SWSidebarBackground && pSideExt;
-
- auto& data = this->SWButtonData;
- const int height = DSurface::Composite->GetHeight();
+ const int height = DSurface::Composite->GetHeight() - 32;
const int color = Drawing::RGB_To_Int(Drawing::TooltipColor);
- Point2D position { 5, (height - 32 - 48 * currentCounts - 2 * (currentCounts - 1)) / 2 };
+ // Draw switch
+ if (this->SuperVisible)
+ {
+ if (drawSWSidebarBackground)
+ {
+ RectangleStruct drawRect { 80, (height / 2 - 25), 10, 50 };
+
+ if (BSurface* const CameoPCX = pSideExt->SWSidebarBackground_OnPCX.GetSurface())
+ PCX::Instance->BlitToSurface(&drawRect, DSurface::Composite, CameoPCX);
+ else
+ DSurface::Composite->FillRect(&drawRect, COLOR_BLUE);
+
+ if (this->IndexIsSWSwitch())
+ {
+ RectangleStruct rect { 0, 0, 90, drawRect.Y + 50 };
+ DSurface::Composite->DrawRectEx(&rect, &drawRect, color);
+ }
+ }
+ }
+ else
+ {
+ if (drawSWSidebarBackground)
+ {
+ RectangleStruct drawRect { 0, (height / 2 - 25), 10, 50 };
+
+ if (BSurface* const CameoPCX = pSideExt->SWSidebarBackground_OffPCX.GetSurface())
+ PCX::Instance->BlitToSurface(&drawRect, DSurface::Composite, CameoPCX);
+ else
+ DSurface::Composite->FillRect(&drawRect, COLOR_BLUE);
+
+ if (this->IndexIsSWSwitch())
+ {
+ RectangleStruct rect { 0, 0, 10, drawRect.Y + 50 };
+ DSurface::Composite->DrawRectEx(&rect, &drawRect, color);
+ }
+ }
+
+ return;
+ }
+
+ auto& data = this->SWButtonData;
+ Point2D position { 5, (height - 48 * currentCounts - 2 * (currentCounts - 1)) / 2 };
RectangleStruct rect { 0, 0, 65, position.Y + 48 };
int recordHeight = -1;
@@ -284,9 +354,8 @@ void TacticalButtonClass::DrawButtonForSW()
}
}
-void TacticalButtonClass::RecheckButtonForSW()
+void TacticalButtonsClass::SWSidebarRecheck()
{
- RecheckButtonIndex();
HouseClass* const pHouse = HouseClass::CurrentPlayer;
auto& data = this->SWButtonData;
@@ -295,13 +364,18 @@ void TacticalButtonClass::RecheckButtonForSW()
const int superIndex = *it;
if (superIndex >= pHouse->Supers.Count || !pHouse->Supers.Items[superIndex]->IsPresent)
+ {
it = data.erase(it);
+ this->RecheckButtonIndex();
+ }
else
+ {
++it;
+ }
}
}
-bool TacticalButtonClass::InsertButtonForSW(int& superIndex)
+bool TacticalButtonsClass::SWSidebarAdd(int& superIndex)
{
SuperWeaponTypeClass* const pType = SuperWeaponTypeClass::Array->Items[superIndex];
SWTypeExt::ExtData* const pTypeExt = SWTypeExt::ExtMap.Find(pType);
@@ -336,7 +410,7 @@ bool TacticalButtonClass::InsertButtonForSW(int& superIndex)
}
else if (i < currentCounts)
{
- if (SortButtonForSW(SuperWeaponTypeClass::Array->Items[data[i]], pType, pTypeExt, ownerBits))
+ if (this->SWSidebarSort(SuperWeaponTypeClass::Array->Items[data[i]], pType, pTypeExt, ownerBits))
{
move = true;
int buffer = data[i];
@@ -357,7 +431,7 @@ bool TacticalButtonClass::InsertButtonForSW(int& superIndex)
return overflow;
}
-bool TacticalButtonClass::SortButtonForSW(SuperWeaponTypeClass* pDataType, SuperWeaponTypeClass* pAddType, SWTypeExt::ExtData* pAddTypeExt, unsigned int ownerBits)
+bool TacticalButtonsClass::SWSidebarSort(SuperWeaponTypeClass* pDataType, SuperWeaponTypeClass* pAddType, SWTypeExt::ExtData* pAddTypeExt, unsigned int ownerBits)
{
SWTypeExt::ExtData* const pDataTypeExt = SWTypeExt::ExtMap.Find(pDataType);
@@ -385,14 +459,9 @@ bool TacticalButtonClass::SortButtonForSW(SuperWeaponTypeClass* pDataType, Super
return wcscmp(pDataType->UIName, pAddType->UIName) > 0;
}
-void TacticalButtonClass::TriggerButtonForSW(int buttonIndex)
+void TacticalButtonsClass::SWSidebarTrigger(int buttonIndex)
{
- if (ScenarioClass::Instance->UserInputLocked || !this->SuperVisible)
- return;
-
- const int superIndex = this->SWButtonData[buttonIndex - 1];
-
- if (superIndex < 0)
+ if (ScenarioClass::Instance->UserInputLocked || !this->SuperVisible || static_cast(buttonIndex) > this->SWButtonData.size())
return;
SidebarClass* const pSidebar = SidebarClass::Instance;
@@ -401,12 +470,85 @@ void TacticalButtonClass::TriggerButtonForSW(int buttonIndex)
DummySelectClass pButton;
pButton.LinkTo = &pSidebar->Tabs[pSidebar->ActiveTabIndex];
pButton.unknown_int_30 = 0x7FFFFFFF;
- pButton.SWIndex = superIndex;
+ pButton.SWIndex = this->SWButtonData[buttonIndex - 1];
DWORD KeyNum = 0;
reinterpret_cast(0x6AAD00)(&pButton, GadgetFlag::LeftPress, &KeyNum, KeyModifier::None); // SelectClass_Action
}
+inline bool TacticalButtonsClass::IndexIsSWSwitch()
+{
+ return this->ButtonIndex == 11;
+}
+
+void TacticalButtonsClass::SWSidebarSwitch()
+{
+ this->SuperVisible = !this->SuperVisible;
+ this->RecheckButtonIndex();
+
+ MessageListClass::Instance->PrintMessage
+ (
+ (this->SuperVisible ?
+ GeneralUtils::LoadStringUnlessMissing("TXT_EX_SW_BAR_VISIBLE", L"Set exclusive SW sidebar visible.") :
+ GeneralUtils::LoadStringUnlessMissing("TXT_EX_SW_BAR_INVISIBLE", L"Set exclusive SW sidebar invisible.")),
+ RulesClass::Instance->MessageDelay,
+ HouseClass::CurrentPlayer->ColorSchemeIndex,
+ true
+ );
+}
+
+bool TacticalButtonsClass::SWQuickLaunch(int superIndex)
+{
+ bool keyboardCall = false;
+
+ if (this->KeyboardCall)
+ {
+ this->KeyboardCall = false;
+ keyboardCall = true;
+ }
+
+ SuperWeaponTypeClass* const pType = SuperWeaponTypeClass::Array->Items[superIndex];
+
+ if (SWTypeExt::ExtData* const pTypeExt = SWTypeExt::ExtMap.Find(pType))
+ {
+ if (pTypeExt->SW_QuickFireAtMouse && keyboardCall)
+ {
+ const CoordStruct mouseCoords = TacticalClass::Instance->ClientToCoords(WWMouseClass::Instance->XY1);
+
+ if (mouseCoords != CoordStruct::Empty)
+ {
+ EventClass event
+ (
+ HouseClass::CurrentPlayer->ArrayIndex,
+ EventType::SpecialPlace,
+ pType->ArrayIndex,
+ CellClass::Coord2Cell(mouseCoords)
+ );
+ EventClass::AddEvent(event);
+
+ return true;
+ }
+ }
+ else if (!pTypeExt->SW_QuickFireInScreen)
+ {
+ return false;
+ }
+
+ EventClass event
+ (
+ HouseClass::CurrentPlayer->ArrayIndex,
+ EventType::SpecialPlace,
+ pType->ArrayIndex,
+ CellClass::Coord2Cell(TacticalClass::Instance->ClientToCoords(Point2D{ (DSurface::Composite->Width >> 1), (DSurface::Composite->Height >> 1) }))
+ );
+ EventClass::AddEvent(event);
+
+ return true;
+ }
+
+ return false;
+}
+
// Hooks
// Mouse trigger hooks
@@ -414,7 +556,7 @@ DEFINE_HOOK(0x6931A5, ScrollClass_WindowsProcedure_PressLeftMouseButton, 0x6)
{
enum { SkipGameCode = 0x6931B4 };
- TacticalButtonClass* const pButtons = &TacticalButtonClass::Instance;
+ TacticalButtonsClass* const pButtons = &TacticalButtonsClass::Instance;
if (!pButtons->MouseIsOverTactical())
{
@@ -433,7 +575,7 @@ DEFINE_HOOK(0x693268, ScrollClass_WindowsProcedure_ReleaseLeftMouseButton, 0x5)
{
enum { SkipGameCode = 0x693276 };
- TacticalButtonClass* const pButtons = &TacticalButtonClass::Instance;
+ TacticalButtonsClass* const pButtons = &TacticalButtonsClass::Instance;
if (pButtons->PressedInButtonsLayer)
{
@@ -452,7 +594,7 @@ DEFINE_HOOK(0x69330E, ScrollClass_WindowsProcedure_PressRightMouseButton, 0x6)
{
enum { SkipGameCode = 0x69334A };
- TacticalButtonClass* const pButtons = &TacticalButtonClass::Instance;
+ TacticalButtonsClass* const pButtons = &TacticalButtonsClass::Instance;
if (!pButtons->MouseIsOverTactical())
{
@@ -469,7 +611,7 @@ DEFINE_HOOK(0x693397, ScrollClass_WindowsProcedure_ReleaseRightMouseButton, 0x6)
{
enum { SkipGameCode = 0x6933CB };
- TacticalButtonClass* const pButtons = &TacticalButtonClass::Instance;
+ TacticalButtonsClass* const pButtons = &TacticalButtonsClass::Instance;
if (pButtons->PressedInButtonsLayer)
{
@@ -485,14 +627,12 @@ DEFINE_HOOK(0x693397, ScrollClass_WindowsProcedure_ReleaseRightMouseButton, 0x6)
// Mouse suspend hooks
DEFINE_HOOK(0x692F85, ScrollClass_MouseUpdate_SkipMouseLongPress, 0x7)
{
- enum { CheckMousePress = 0x692F8E, CheckMouseNoPress = 0x692FDC, SkipGameCode = 0x692FAE };
+ enum { CheckMousePress = 0x692F8E, CheckMouseNoPress = 0x692FDC };
GET(ScrollClass*, pThis, EBX);
- if (pThis->unknown_byte_554A) // 555A: AnyMouseButtonDown
- return !TacticalButtonClass::Instance.PressedInButtonsLayer ? CheckMousePress : SkipGameCode;
-
- return CheckMouseNoPress;
+ // 555A: AnyMouseButtonDown
+ return (pThis->unknown_byte_554A && !TacticalButtonsClass::Instance.PressedInButtonsLayer) ? CheckMousePress : CheckMouseNoPress;
}
DEFINE_HOOK(0x69300B, ScrollClass_MouseUpdate_SkipMouseActionUpdate, 0x6)
@@ -500,7 +640,7 @@ DEFINE_HOOK(0x69300B, ScrollClass_MouseUpdate_SkipMouseActionUpdate, 0x6)
enum { SkipGameCode = 0x69301A };
const Point2D mousePosition = WWMouseClass::Instance->XY1;
- TacticalButtonClass* const pButtons = &TacticalButtonClass::Instance;
+ TacticalButtonsClass* const pButtons = &TacticalButtonsClass::Instance;
pButtons->SetMouseButtonIndex(&mousePosition);
if (pButtons->MouseIsOverTactical())
@@ -516,108 +656,62 @@ DEFINE_HOOK(0x6D4941, TacticalClass_Render_DrawButtonCameo, 0x6)
{
// TODO New buttons (The later draw, the higher layer)
- TacticalButtonClass::Instance.DrawButtonForSW();
+ TacticalButtonsClass::Instance.SWSidebarDraw();
+
return 0;
}
// SW buttons hooks
DEFINE_HOOK(0x4F9283, HouseClass_Update_RecheckTechTree, 0x5)
{
- TacticalButtonClass::Instance.RecheckButtonForSW();
+ TacticalButtonsClass::Instance.SWSidebarRecheck();
+
return 0;
}
DEFINE_HOOK(0x6A6314, SidebarClass_AddCameo_SupportSWButtons, 0x8)
{
- enum { SkipGameCode = 0x6A65F5 };
+ enum { SkipThisCameo = 0x6A65F5 };
GET_STACK(const AbstractType, absType, STACK_OFFSET(0x14, 0x4));
REF_STACK(int, index, STACK_OFFSET(0x14, 0x8));
- return (absType != AbstractType::Special || SuperWeaponTypeClass::Array->Count <= index || TacticalButtonClass::Instance.InsertButtonForSW(index)) ? 0 : SkipGameCode;
+ return (absType != AbstractType::Special || SuperWeaponTypeClass::Array->Count <= index || TacticalButtonsClass::Instance.SWSidebarAdd(index)) ? 0 : SkipThisCameo;
}
DEFINE_HOOK(0x6AAF46, SelectClass_Action_ButtonClick1, 0x6)
{
- enum { SkipGameCode = 0x6AB95A };
+ enum { SkipClearMouse = 0x6AB95A };
GET(const int, index, ESI);
- SuperWeaponTypeClass* const pType = SuperWeaponTypeClass::Array->Items[index];
- SWTypeExt::ExtData* const pTypeExt = SWTypeExt::ExtMap.Find(pType);
- TacticalButtonClass* const pButtons = &TacticalButtonClass::Instance;
- bool keyboardCall = false;
-
- if (pButtons->KeyboardCall)
- {
- pButtons->KeyboardCall = false;
- keyboardCall = true;
- }
-
- if (pTypeExt)
- {
- if (pTypeExt->SW_QuickFireAtMouse && keyboardCall)
- {
- const CoordStruct mouseCoords = TacticalClass::Instance->ClientToCoords(WWMouseClass::Instance->XY1);
-
- if (mouseCoords != CoordStruct::Empty)
- {
- EventClass event
- (
- HouseClass::CurrentPlayer->ArrayIndex,
- EventType::SpecialPlace,
- pType->ArrayIndex,
- CellClass::Coord2Cell(mouseCoords)
- );
- EventClass::AddEvent(event);
-
- return SkipGameCode;
- }
- }
- else if (!pTypeExt->SW_QuickFireInScreen)
- {
- return 0;
- }
-
- EventClass event
- (
- HouseClass::CurrentPlayer->ArrayIndex,
- EventType::SpecialPlace,
- pType->ArrayIndex,
- CellClass::Coord2Cell(TacticalClass::Instance->ClientToCoords(Point2D{ (DSurface::Composite->Width >> 1), (DSurface::Composite->Height >> 1) }))
- );
- EventClass::AddEvent(event);
-
- return SkipGameCode;
- }
-
- return 0;
+ return TacticalButtonsClass::Instance.SWQuickLaunch(index) ? SkipClearMouse : 0;
}
DEFINE_HOOK_AGAIN(0x6AAD2F, SelectClass_Action_ButtonClick2, 0x7)
DEFINE_HOOK(0x6AB94F, SelectClass_Action_ButtonClick2, 0xB)
{
- enum { SkipGameCode = 0x6AAE7C };
+ enum { ForceEffective = 0x6AAE7C };
- if (!TacticalButtonClass::Instance.DummyAction)
+ if (!TacticalButtonsClass::Instance.DummyAction)
return 0;
- GET(TacticalButtonClass::DummySelectClass* const , pThis, EDI);
+ GET(TacticalButtonsClass::DummySelectClass* const , pThis, EDI);
R->Stack(STACK_OFFSET(0xAC, -0x98), pThis->SWIndex);
- return SkipGameCode;
+ return ForceEffective;
}
DEFINE_HOOK(0x6AB961, SelectClass_Action_ButtonClick3, 0x7)
{
- enum { SkipGameCode = 0x6AB975 };
+ enum { SkipControlAction = 0x6AB975 };
- TacticalButtonClass* const pButtons = &TacticalButtonClass::Instance;
+ TacticalButtonsClass* const pButtons = &TacticalButtonsClass::Instance;
if (!pButtons->DummyAction)
return 0;
pButtons->DummyAction = false;
- return SkipGameCode;
+ return SkipControlAction;
}
diff --git a/src/Misc/TacticalButtons.h b/src/Misc/TacticalButtons.h
index aece63c50c..f2c6c65d1f 100644
--- a/src/Misc/TacticalButtons.h
+++ b/src/Misc/TacticalButtons.h
@@ -2,10 +2,10 @@
#include
#include
-class TacticalButtonClass
+class TacticalButtonsClass
{
public:
- static TacticalButtonClass Instance;
+ static TacticalButtonsClass Instance;
private:
int CheckMouseOverButtons(const Point2D* pMousePosition);
@@ -21,11 +21,13 @@ class TacticalButtonClass
void PressDesignatedButton(int triggerIndex);
// Button index 1-10 : Super weapons buttons
- void DrawButtonForSW();
- void RecheckButtonForSW();
- bool InsertButtonForSW(int& superIndex);
- bool SortButtonForSW(SuperWeaponTypeClass* pDataType, SuperWeaponTypeClass* pAddType, SWTypeExt::ExtData* pAddTypeExt, unsigned int ownerBits);
- void TriggerButtonForSW(int buttonIndex);
+ inline bool IndexInSWButtons();
+
+ void SWSidebarDraw();
+ void SWSidebarRecheck();
+ bool SWSidebarAdd(int& superIndex);
+ bool SWSidebarSort(SuperWeaponTypeClass* pDataType, SuperWeaponTypeClass* pAddType, SWTypeExt::ExtData* pAddTypeExt, unsigned int ownerBits);
+ void SWSidebarTrigger(int buttonIndex);
struct DummySelectClass
{
@@ -36,7 +38,15 @@ class TacticalButtonClass
int SWIndex { -1 }; // New
};
- // TODO New buttons (Start from index = 11)
+ // Button index 11 : SW sidebar switch
+ inline bool IndexIsSWSwitch();
+
+ void SWSidebarSwitch();
+
+ // Extra functions
+ bool SWQuickLaunch(int superIndex);
+
+ // TODO New buttons (Start from index = 12)
public:
bool PressedInButtonsLayer { false }; // Check press
@@ -44,9 +54,8 @@ class TacticalButtonClass
// Button index 1-10 : Super weapons buttons
bool DummyAction { false };
bool KeyboardCall { false };
- bool SuperVisible { true };
- // TODO New buttons (Start from index = 11)
+ // TODO New buttons (Start from index = 12)
private:
int ButtonIndex { -1 }; // -1 -> above no buttons, 0 -> above buttons background, POSITIVE -> above button who have this index
@@ -56,5 +65,8 @@ class TacticalButtonClass
std::vector SWButtonData;
SuperClass* RecordSuper { nullptr }; // Cannot be used, only for comparison purposes
- // TODO New buttons (Start from index = 11)
+ // Button index 11 : SW sidebar switch
+ bool SuperVisible { true };
+
+ // TODO New buttons (Start from index = 12)
};
From 8caa92bca46c00904c0157006a3509b8e2a2379f Mon Sep 17 00:00:00 2001
From: CrimRecya <335958461@qq.com>
Date: Fri, 20 Sep 2024 01:59:25 +0800
Subject: [PATCH 04/12] Draw shortcut key
---
src/Misc/TacticalButtons.cpp | 254 ++++++++++++++++++++++++++++++++++-
src/Misc/TacticalButtons.h | 5 +
2 files changed, 252 insertions(+), 7 deletions(-)
diff --git a/src/Misc/TacticalButtons.cpp b/src/Misc/TacticalButtons.cpp
index 6c4a1bc0f0..d79e8d7d68 100644
--- a/src/Misc/TacticalButtons.cpp
+++ b/src/Misc/TacticalButtons.cpp
@@ -16,6 +16,141 @@
TacticalButtonsClass TacticalButtonsClass::Instance;
+static PhobosMap CreateKeyboardCodeTextMap()
+{
+ PhobosMap Code2Text;
+
+ Code2Text[0x00] = L" ";
+ Code2Text[0x01] = L"MouseLeft";
+ Code2Text[0x02] = L"MouseRight";
+ Code2Text[0x03] = L"Cancel";
+ Code2Text[0x04] = L"MouseCenter";
+
+ Code2Text[0x08] = L"Back";
+ Code2Text[0x09] = L"Tab";
+
+ Code2Text[0x0C] = L"Clear";
+ Code2Text[0x0D] = L"Enter";
+
+ Code2Text[0x10] = L"Shift";
+ Code2Text[0x11] = L"Ctrl";
+ Code2Text[0x12] = L"Alt";
+ Code2Text[0x13] = L"Pause";
+ Code2Text[0x14] = L"CapsLock";
+
+ Code2Text[0x1B] = L"Esc";
+
+ Code2Text[0x20] = L"Space";
+ Code2Text[0x21] = L"PageUp";
+ Code2Text[0x22] = L"PageDown";
+ Code2Text[0x23] = L"End";
+ Code2Text[0x24] = L"Home";
+ Code2Text[0x25] = L"Left";
+ Code2Text[0x26] = L"Up";
+ Code2Text[0x27] = L"Right";
+ Code2Text[0x28] = L"Down";
+ Code2Text[0x29] = L"Select";
+ Code2Text[0x2A] = L"Print";
+ Code2Text[0x2B] = L"Execute";
+ Code2Text[0x2C] = L"PrintScreen";
+ Code2Text[0x2D] = L"Insert";
+ Code2Text[0x2E] = L"Delete";
+ Code2Text[0x2F] = L"Help";
+ Code2Text[0x30] = L"0";
+ Code2Text[0x31] = L"1";
+ Code2Text[0x32] = L"2";
+ Code2Text[0x33] = L"3";
+ Code2Text[0x34] = L"4";
+ Code2Text[0x35] = L"5";
+ Code2Text[0x36] = L"6";
+ Code2Text[0x37] = L"7";
+ Code2Text[0x38] = L"8";
+ Code2Text[0x39] = L"9";
+
+ Code2Text[0x41] = L"A";
+ Code2Text[0x42] = L"B";
+ Code2Text[0x43] = L"C";
+ Code2Text[0x44] = L"D";
+ Code2Text[0x45] = L"E";
+ Code2Text[0x46] = L"F";
+ Code2Text[0x47] = L"G";
+ Code2Text[0x48] = L"H";
+ Code2Text[0x49] = L"I";
+ Code2Text[0x4A] = L"J";
+ Code2Text[0x4B] = L"K";
+ Code2Text[0x4C] = L"L";
+ Code2Text[0x4D] = L"M";
+ Code2Text[0x4E] = L"N";
+ Code2Text[0x4F] = L"O";
+ Code2Text[0x50] = L"P";
+ Code2Text[0x51] = L"Q";
+ Code2Text[0x52] = L"R";
+ Code2Text[0x53] = L"S";
+ Code2Text[0x54] = L"T";
+ Code2Text[0x55] = L"U";
+ Code2Text[0x56] = L"V";
+ Code2Text[0x57] = L"W";
+ Code2Text[0x58] = L"X";
+ Code2Text[0x59] = L"Y";
+ Code2Text[0x5A] = L"Z";
+ Code2Text[0x5B] = L"LWin";
+ Code2Text[0x5C] = L"RWin";
+ Code2Text[0x5D] = L"Menu";
+
+ Code2Text[0x60] = L"Num0";
+ Code2Text[0x61] = L"Num1";
+ Code2Text[0x62] = L"Num2";
+ Code2Text[0x63] = L"Num3";
+ Code2Text[0x64] = L"Num4";
+ Code2Text[0x65] = L"Num5";
+ Code2Text[0x66] = L"Num6";
+ Code2Text[0x67] = L"Num7";
+ Code2Text[0x68] = L"Num8";
+ Code2Text[0x69] = L"Num9";
+ Code2Text[0x6A] = L"Num*";
+ Code2Text[0x6B] = L"Num+";
+ Code2Text[0x6C] = L"Separator";
+ Code2Text[0x6D] = L"Num-";
+ Code2Text[0x6E] = L"Num.";
+ Code2Text[0x6F] = L"Num/";
+ Code2Text[0x70] = L"F1";
+ Code2Text[0x71] = L"F2";
+ Code2Text[0x72] = L"F3";
+ Code2Text[0x73] = L"F4";
+ Code2Text[0x74] = L"F5";
+ Code2Text[0x75] = L"F6";
+ Code2Text[0x76] = L"F7";
+ Code2Text[0x77] = L"F8";
+ Code2Text[0x78] = L"F9";
+ Code2Text[0x79] = L"F10";
+ Code2Text[0x7A] = L"F11";
+ Code2Text[0x7B] = L"F12";
+
+ Code2Text[0x90] = L"NumLock";
+ Code2Text[0x91] = L"ScrollLock";
+
+ Code2Text[0xBA] = L";";
+ Code2Text[0xBB] = L"=";
+ Code2Text[0xBC] = L",";
+ Code2Text[0xBD] = L"-";
+ Code2Text[0xBE] = L".";
+ Code2Text[0xBF] = L"/";
+ Code2Text[0xC0] = L"`";
+
+ Code2Text[0xDB] = L"[";
+ Code2Text[0xDC] = L"\\";
+ Code2Text[0xDD] = L"]";
+ Code2Text[0xDE] = L"'";
+
+ Code2Text[static_cast< int >( WWKey::Shift )] = L"Shift+";
+ Code2Text[static_cast< int >( WWKey::Ctrl )] = L"Ctrl+";
+ Code2Text[static_cast< int >( WWKey::Alt )] = L"Alt+";
+
+ return Code2Text;
+}
+
+PhobosMap TacticalButtonsClass::KeyboardCodeTextMap = CreateKeyboardCodeTextMap();
+
// Functions
// Private functions
@@ -175,6 +310,21 @@ inline bool TacticalButtonsClass::IndexInSWButtons()
return this->ButtonIndex <= 10;
}
+inline const wchar_t* TacticalButtonsClass::Key2ConcatText(const wchar_t* showText, int key, int overlay)
+{
+ if (key & overlay)
+ {
+ const wchar_t* text = KeyboardCodeTextMap[overlay];
+ const int Length = std::wcslen(text) + std::wcslen(showText) + 1;
+ wchar_t* newText = new wchar_t[Length];
+ swprintf(newText ,Length ,L"%ls%ls" ,text ,showText);
+ newText[Length] = L'\0';
+ delete[] showText;
+ return newText;
+ }
+ return showText;
+}
+
void TacticalButtonsClass::SWSidebarDraw()
{
const int currentCounts = this->SWButtonData.size();
@@ -291,14 +441,18 @@ void TacticalButtonsClass::SWSidebarDraw()
}
}
- // Flash cameo
- const int delay = pSWType->FlashSidebarTabFrames;
+ const bool ready = !pSuper->IsSuspended && (pSWType->UseChargeDrain ? pSuper->ChargeDrainState == ChargeDrainState::Ready : pSuper->IsReady);
- if (delay > 0 && !pSuper->IsSuspended && (pSuper->IsReady || (pSWType->UseChargeDrain && pSuper->ChargeDrainState != ChargeDrainState::Charging))
- && ((Unsorted::CurrentFrame - pSuper->ReadyFrame) % (delay << 1)) > delay)
+ // Flash cameo
+ if (ready)
{
- DSurface::Composite->DrawSHP(FileSystem::SIDEBAR_PAL, Make_Global(0xB07BC0), 0, &position, &rect,
- BlitterFlags(0x406), 0, 0, ZGradient::Ground, 1000, 0, 0, 0, 0, 0);
+ const int delay = pSWType->FlashSidebarTabFrames;
+
+ if (delay > 0 && ((Unsorted::CurrentFrame - pSuper->ReadyFrame) % (delay << 1)) > delay)
+ {
+ DSurface::Composite->DrawSHP(FileSystem::SIDEBAR_PAL, Make_Global(0xB07BC0), 0, &position, &rect,
+ BlitterFlags(0x406), 0, 0, ZGradient::Ground, 1000, 0, 0, 0, 0, 0);
+ }
}
// SW charge progress
@@ -310,8 +464,20 @@ void TacticalButtonsClass::SWSidebarDraw()
BlitterFlags(0x404), 0, 0, ZGradient::Ground, 1000, 0, 0, 0, 0, 0);
}
+ const wchar_t* pKey = this->keyCodeText[i];
+
// SW status
- if (const wchar_t* pName = pSuper->NameReadiness())
+ if (ready && pKey)
+ {
+ Point2D textLocation { 35, position.Y + 1 };
+ const TextPrintType printType = TextPrintType::Center | TextPrintType::FullShadow | TextPrintType::Point8;
+ RectangleStruct textRect = Drawing::GetTextDimensions(pKey, textLocation, static_cast(printType), 2, 1);
+
+ // Text black background
+ reinterpret_cast(0x621B80)(&textRect, DSurface::Composite, 0, 0xAFu);
+ DSurface::Composite->DrawTextA(pKey, &rect, &textLocation, static_cast(color), COLOR_BLACK, printType);
+ }
+ else if (const wchar_t* pName = pSuper->NameReadiness())
{
Point2D textLocation { 35, position.Y + 1 };
const TextPrintType printType = TextPrintType::Center | TextPrintType::FullShadow | TextPrintType::Point8;
@@ -476,6 +642,38 @@ void TacticalButtonsClass::SWSidebarTrigger(int buttonIndex)
reinterpret_cast(0x6AAD00)(&pButton, GadgetFlag::LeftPress, &KeyNum, KeyModifier::None); // SelectClass_Action
}
+void TacticalButtonsClass::SWSidebarRecord(int buttonIndex, int key)
+{
+ const int index = buttonIndex - 1;
+
+ if (this->keyCodeData[index] == key)
+ return;
+
+ this->keyCodeData[index] = key;
+ const int pureKey = key & 0xFF;
+ const wchar_t* showText;
+
+ if (KeyboardCodeTextMap.contains(pureKey))
+ {
+ const wchar_t* pureText = KeyboardCodeTextMap[pureKey];
+ const int pureLength = std::wcslen(pureText) + 1;
+ wchar_t* text = new wchar_t[pureLength];
+ wcscpy_s( text , pureLength ,pureText);
+ text[pureLength] = L'\0';
+ showText = text;
+ }
+ else
+ {
+ showText = L"Unknown";
+ }
+
+ showText = this->Key2ConcatText(showText, key, static_cast(WWKey::Shift));
+ showText = this->Key2ConcatText(showText, key, static_cast(WWKey::Ctrl));
+ showText = this->Key2ConcatText(showText, key, static_cast(WWKey::Alt));
+
+ this->keyCodeText[index] = showText;
+}
+
inline bool TacticalButtonsClass::IndexIsSWSwitch()
{
return this->ButtonIndex == 11;
@@ -679,6 +877,7 @@ DEFINE_HOOK(0x6A6314, SidebarClass_AddCameo_SupportSWButtons, 0x8)
return (absType != AbstractType::Special || SuperWeaponTypeClass::Array->Count <= index || TacticalButtonsClass::Instance.SWSidebarAdd(index)) ? 0 : SkipThisCameo;
}
+// Extra function hooks
DEFINE_HOOK(0x6AAF46, SelectClass_Action_ButtonClick1, 0x6)
{
enum { SkipClearMouse = 0x6AB95A };
@@ -715,3 +914,44 @@ DEFINE_HOOK(0x6AB961, SelectClass_Action_ButtonClick3, 0x7)
return SkipControlAction;
}
+
+// Shortcuts keys hooks
+DEFINE_HOOK(0x533E69, UnknownClass_sub_533D20_LoadKeyboardCodeFromINI, 0x6)
+{
+ GET(CommandClass*, pCommand, ESI);
+ GET(int, key, EDI);
+
+ TacticalButtonsClass* const pButtons = &TacticalButtonsClass::Instance;
+ const char* name = pCommand->GetName();
+ char buffer[29];
+
+ for (int i = 1; i <= 10; ++i)
+ {
+ sprintf_s(buffer, "SW Sidebar Shortcuts Num %2d", i);
+
+ if (!_strcmpi(name, buffer))
+ pButtons->SWSidebarRecord(i, key);
+ }
+
+ return 0;
+}
+
+DEFINE_HOOK(0x5FB992, UnknownClass_sub_5FB320_SaveKeyboardCodeToINI, 0x6)
+{
+ GET(CommandClass*, pCommand, ECX);
+ GET(int, key, EAX);
+
+ TacticalButtonsClass* const pButtons = &TacticalButtonsClass::Instance;
+ const char* name = pCommand->GetName();
+ char buffer[29];
+
+ for (int i = 1; i <= 10; ++i)
+ {
+ sprintf_s(buffer, "SW Sidebar Shortcuts Num %2d", i);
+
+ if (!_strcmpi(name, buffer))
+ pButtons->SWSidebarRecord(i, key);
+ }
+
+ return 0;
+}
diff --git a/src/Misc/TacticalButtons.h b/src/Misc/TacticalButtons.h
index f2c6c65d1f..b8447db5d7 100644
--- a/src/Misc/TacticalButtons.h
+++ b/src/Misc/TacticalButtons.h
@@ -6,6 +6,7 @@ class TacticalButtonsClass
{
public:
static TacticalButtonsClass Instance;
+ static PhobosMap KeyboardCodeTextMap;
private:
int CheckMouseOverButtons(const Point2D* pMousePosition);
@@ -22,12 +23,14 @@ class TacticalButtonsClass
// Button index 1-10 : Super weapons buttons
inline bool IndexInSWButtons();
+ inline const wchar_t* Key2ConcatText(const wchar_t* showText, int key, int overlay);
void SWSidebarDraw();
void SWSidebarRecheck();
bool SWSidebarAdd(int& superIndex);
bool SWSidebarSort(SuperWeaponTypeClass* pDataType, SuperWeaponTypeClass* pAddType, SWTypeExt::ExtData* pAddTypeExt, unsigned int ownerBits);
void SWSidebarTrigger(int buttonIndex);
+ void SWSidebarRecord(int buttonIndex, int key);
struct DummySelectClass
{
@@ -54,6 +57,8 @@ class TacticalButtonsClass
// Button index 1-10 : Super weapons buttons
bool DummyAction { false };
bool KeyboardCall { false };
+ const wchar_t* keyCodeText[10] {};
+ int keyCodeData[10] {};
// TODO New buttons (Start from index = 12)
From 376a593f1bd29130822a505f600d713b77bfb50e Mon Sep 17 00:00:00 2001
From: CrimRecya <335958461@qq.com>
Date: Fri, 20 Sep 2024 02:09:47 +0800
Subject: [PATCH 05/12] Fix space
---
src/Misc/TacticalButtons.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/Misc/TacticalButtons.cpp b/src/Misc/TacticalButtons.cpp
index d79e8d7d68..23ab1f3c77 100644
--- a/src/Misc/TacticalButtons.cpp
+++ b/src/Misc/TacticalButtons.cpp
@@ -317,7 +317,7 @@ inline const wchar_t* TacticalButtonsClass::Key2ConcatText(const wchar_t* showTe
const wchar_t* text = KeyboardCodeTextMap[overlay];
const int Length = std::wcslen(text) + std::wcslen(showText) + 1;
wchar_t* newText = new wchar_t[Length];
- swprintf(newText ,Length ,L"%ls%ls" ,text ,showText);
+ swprintf(newText, Length, L"%ls%ls", text, showText);
newText[Length] = L'\0';
delete[] showText;
return newText;
@@ -658,7 +658,7 @@ void TacticalButtonsClass::SWSidebarRecord(int buttonIndex, int key)
const wchar_t* pureText = KeyboardCodeTextMap[pureKey];
const int pureLength = std::wcslen(pureText) + 1;
wchar_t* text = new wchar_t[pureLength];
- wcscpy_s( text , pureLength ,pureText);
+ wcscpy_s(text, pureLength, pureText);
text[pureLength] = L'\0';
showText = text;
}
From f22f1fdcaa13d9bdc0e49fbee59a456d370d717c Mon Sep 17 00:00:00 2001
From: CrimRecya <335958461@qq.com>
Date: Fri, 20 Sep 2024 03:16:29 +0800
Subject: [PATCH 06/12] Supplement the missing parts
---
src/Commands/Commands.cpp | 2 ++
src/Misc/PhobosToolTip.cpp | 2 +-
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/Commands/Commands.cpp b/src/Commands/Commands.cpp
index 3069c3ea32..0f289835b9 100644
--- a/src/Commands/Commands.cpp
+++ b/src/Commands/Commands.cpp
@@ -20,6 +20,7 @@ DEFINE_HOOK(0x533066, CommandClassCallback_Register, 0x6)
MakeCommand();
MakeCommand();
MakeCommand();
+ MakeCommand>();
MakeCommand>();
MakeCommand>();
MakeCommand>();
@@ -29,6 +30,7 @@ DEFINE_HOOK(0x533066, CommandClassCallback_Register, 0x6)
MakeCommand>();
MakeCommand>();
MakeCommand>();
+ MakeCommand>();
if (Phobos::Config::DevelopmentCommands)
{
diff --git a/src/Misc/PhobosToolTip.cpp b/src/Misc/PhobosToolTip.cpp
index 7786a2058d..9e29ee0bf7 100644
--- a/src/Misc/PhobosToolTip.cpp
+++ b/src/Misc/PhobosToolTip.cpp
@@ -212,7 +212,7 @@ DEFINE_HOOK(0x4AE511, DisplayClass_GetToolTip_SkipTacticalTip, 0x5)
if (!buttonIndex)
return SkipGameCode;
- if (buttonIndex <= 8)
+ if (buttonIndex <= 10)
R->EAX(PhobosToolTip::Instance.GetBuffer());
else
R->EAX(0);
From 2920f922a71e2d29bd86621528430961c8440652 Mon Sep 17 00:00:00 2001
From: CrimRecya <335958461@qq.com>
Date: Fri, 20 Sep 2024 16:42:01 +0800
Subject: [PATCH 07/12] Fix wrong index
---
src/Misc/TacticalButtons.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Misc/TacticalButtons.cpp b/src/Misc/TacticalButtons.cpp
index 23ab1f3c77..31ab863298 100644
--- a/src/Misc/TacticalButtons.cpp
+++ b/src/Misc/TacticalButtons.cpp
@@ -635,7 +635,7 @@ void TacticalButtonsClass::SWSidebarTrigger(int buttonIndex)
DummySelectClass pButton;
pButton.LinkTo = &pSidebar->Tabs[pSidebar->ActiveTabIndex];
- pButton.unknown_int_30 = 0x7FFFFFFF;
+ pButton.unknown_int_30 = 0x7FFFFFFF - (2 * pButton.LinkTo->TopRowIndex);
pButton.SWIndex = this->SWButtonData[buttonIndex - 1];
DWORD KeyNum = 0;
From 6b84fe12aebb7f3c485047b2c7aaeefadb25caec Mon Sep 17 00:00:00 2001
From: CrimRecya <335958461@qq.com>
Date: Fri, 20 Sep 2024 19:51:32 +0800
Subject: [PATCH 08/12] Optimize
---
src/Commands/SWShortcuts.h | 89 +++++++++++-------------------------
src/Misc/TacticalButtons.cpp | 65 ++++++++++----------------
src/Misc/TacticalButtons.h | 3 +-
3 files changed, 51 insertions(+), 106 deletions(-)
diff --git a/src/Commands/SWShortcuts.h b/src/Commands/SWShortcuts.h
index 595b4a8be0..a0dc2baccb 100644
--- a/src/Commands/SWShortcuts.h
+++ b/src/Commands/SWShortcuts.h
@@ -6,6 +6,29 @@
#include
// Super Weapon Sidebar Keyboard shortcut command class
+constexpr const char* ShortcutNames[11] = { "SW Sidebar Display",
+ "SW Sidebar Shortcuts Num 01", "SW Sidebar Shortcuts Num 02", "SW Sidebar Shortcuts Num 03",
+ "SW Sidebar Shortcuts Num 04", "SW Sidebar Shortcuts Num 05", "SW Sidebar Shortcuts Num 06",
+ "SW Sidebar Shortcuts Num 07", "SW Sidebar Shortcuts Num 08", "SW Sidebar Shortcuts Num 09",
+ "SW Sidebar Shortcuts Num 10" };
+constexpr const char* ShortcutUINamesTXT[11] = { "TXT_EX_SW_SWITCH",
+ "TXT_EX_SW_BUTTON_01", "TXT_EX_SW_BUTTON_02", "TXT_EX_SW_BUTTON_03", "TXT_EX_SW_BUTTON_04", "TXT_EX_SW_BUTTON_05",
+ "TXT_EX_SW_BUTTON_06", "TXT_EX_SW_BUTTON_07", "TXT_EX_SW_BUTTON_08", "TXT_EX_SW_BUTTON_09", "TXT_EX_SW_BUTTON_10" };
+constexpr const wchar_t* ShortcutUINames[11] = { L"SW sidebar display",
+ L"Quick Select SW 01", L"Quick Select SW 02", L"Quick Select SW 03", L"Quick Select SW 04", L"Quick Select SW 05",
+ L"Quick Select SW 06", L"Quick Select SW 07", L"Quick Select SW 08", L"Quick Select SW 09", L"Quick Select SW 10" };
+constexpr const char* ShortcutUIDescriptionsTXT[11] = { "TXT_EX_SW_SWITCH_DESC",
+ "TXT_EX_SW_BUTTON_01_DESC", "TXT_EX_SW_BUTTON_02_DESC", "TXT_EX_SW_BUTTON_03_DESC",
+ "TXT_EX_SW_BUTTON_04_DESC", "TXT_EX_SW_BUTTON_05_DESC", "TXT_EX_SW_BUTTON_06_DESC",
+ "TXT_EX_SW_BUTTON_07_DESC", "TXT_EX_SW_BUTTON_08_DESC", "TXT_EX_SW_BUTTON_09_DESC",
+ "TXT_EX_SW_BUTTON_10_DESC" };
+constexpr const wchar_t* ShortcutUIDescriptions[11] = {
+ L"Switch between visible/invisible modes for exclusive SW sidebar",
+ L"Select No.01 SW in left sidebar", L"Select No.02 SW in left sidebar", L"Select No.03 SW in left sidebar",
+ L"Select No.04 SW in left sidebar", L"Select No.05 SW in left sidebar", L"Select No.06 SW in left sidebar",
+ L"Select No.07 SW in left sidebar", L"Select No.08 SW in left sidebar", L"Select No.09 SW in left sidebar",
+ L"Select No.10 SW in left sidebar"};
+
template
class SWShortcutsCommandClass : public CommandClass
{
@@ -21,53 +44,13 @@ class SWShortcutsCommandClass : public CommandClass
template
inline const char* SWShortcutsCommandClass::GetName() const
{
- if (KeyIndex > 0)
- {
- class to_string_t
- {
- public:
- char buffer[29];
-
- public:
- constexpr to_string_t() noexcept
- : buffer { "" }
- {
- sprintf_s(buffer, "SW Sidebar Shortcuts Num %2d", KeyIndex);
- }
-
- constexpr operator char* () noexcept { return buffer; }
- };
- static to_string_t name;
- return name;
- }
-
- return "SW Sidebar Display";
+ return ShortcutNames[KeyIndex];
}
template
inline const wchar_t* SWShortcutsCommandClass::GetUIName() const
{
- if (KeyIndex > 0)
- {
- class to_string_t
- {
- public:
- wchar_t buffer[20];
-
- public:
- constexpr to_string_t() noexcept
- : buffer { L"" }
- {
- swprintf_s(buffer, L"Quick Select SW %2d", KeyIndex);
- }
-
- constexpr operator wchar_t* () noexcept { return buffer; }
- };
- static to_string_t name;
- return StringTable::TryFetchString("TXT_SW_XX_FORWARD", name);
- }
-
- return GeneralUtils::LoadStringUnlessMissing("TXT_SW_XX_FORWARD", L"SW sidebar display");
+ return GeneralUtils::LoadStringUnlessMissing(ShortcutUINamesTXT[KeyIndex], ShortcutUINames[KeyIndex]);
}
template
@@ -79,27 +62,7 @@ inline const wchar_t* SWShortcutsCommandClass::GetUICategory() const
template
inline const wchar_t* SWShortcutsCommandClass::GetUIDescription() const
{
- if (KeyIndex > 0)
- {
- class to_string_t
- {
- public:
- wchar_t buffer[34];
-
- public:
- constexpr to_string_t() noexcept
- : buffer { L"" }
- {
- swprintf_s(buffer, L"Select No.%02d SW in left sidebar", KeyIndex);
- }
-
- constexpr operator wchar_t* () noexcept { return buffer; }
- };
- static to_string_t name;
- return StringTable::TryFetchString("TXT_SW_XX_FORWARD_DESC", name);
- }
-
- return GeneralUtils::LoadStringUnlessMissing("TXT_SW_XX_FORWARD_DESC", L"Switch between visible/invisible modes for exclusive SW sidebar");
+ return GeneralUtils::LoadStringUnlessMissing(ShortcutUIDescriptionsTXT[KeyIndex], ShortcutUIDescriptions[KeyIndex]);
}
template
diff --git a/src/Misc/TacticalButtons.cpp b/src/Misc/TacticalButtons.cpp
index 31ab863298..2de9e1cc74 100644
--- a/src/Misc/TacticalButtons.cpp
+++ b/src/Misc/TacticalButtons.cpp
@@ -10,6 +10,8 @@
#include
#include
#include
+#include
+#include
#include "PhobosToolTip.h"
#include "TacticalButtons.h"
@@ -142,9 +144,9 @@ static PhobosMap CreateKeyboardCodeTextMap()
Code2Text[0xDD] = L"]";
Code2Text[0xDE] = L"'";
- Code2Text[static_cast< int >( WWKey::Shift )] = L"Shift+";
- Code2Text[static_cast< int >( WWKey::Ctrl )] = L"Ctrl+";
- Code2Text[static_cast< int >( WWKey::Alt )] = L"Alt+";
+ Code2Text[static_cast(WWKey::Shift)] = L"Shift";
+ Code2Text[static_cast(WWKey::Ctrl)] = L"Ctrl";
+ Code2Text[static_cast(WWKey::Alt)] = L"Alt";
return Code2Text;
}
@@ -310,21 +312,6 @@ inline bool TacticalButtonsClass::IndexInSWButtons()
return this->ButtonIndex <= 10;
}
-inline const wchar_t* TacticalButtonsClass::Key2ConcatText(const wchar_t* showText, int key, int overlay)
-{
- if (key & overlay)
- {
- const wchar_t* text = KeyboardCodeTextMap[overlay];
- const int Length = std::wcslen(text) + std::wcslen(showText) + 1;
- wchar_t* newText = new wchar_t[Length];
- swprintf(newText, Length, L"%ls%ls", text, showText);
- newText[Length] = L'\0';
- delete[] showText;
- return newText;
- }
- return showText;
-}
-
void TacticalButtonsClass::SWSidebarDraw()
{
const int currentCounts = this->SWButtonData.size();
@@ -464,11 +451,10 @@ void TacticalButtonsClass::SWSidebarDraw()
BlitterFlags(0x404), 0, 0, ZGradient::Ground, 1000, 0, 0, 0, 0, 0);
}
- const wchar_t* pKey = this->keyCodeText[i];
-
// SW status
- if (ready && pKey)
+ if (ready && !this->keyCodeText[i].empty())
{
+ const wchar_t* pKey = this->keyCodeText[i].c_str();
Point2D textLocation { 35, position.Y + 1 };
const TextPrintType printType = TextPrintType::Center | TextPrintType::FullShadow | TextPrintType::Point8;
RectangleStruct textRect = Drawing::GetTextDimensions(pKey, textLocation, static_cast(printType), 2, 1);
@@ -650,28 +636,25 @@ void TacticalButtonsClass::SWSidebarRecord(int buttonIndex, int key)
return;
this->keyCodeData[index] = key;
+ std::wostringstream oss;
+
+ if (key & static_cast(WWKey::Shift))
+ oss << KeyboardCodeTextMap[static_cast(WWKey::Shift)] << L"+";
+
+ if (key & static_cast(WWKey::Ctrl))
+ oss << KeyboardCodeTextMap[static_cast(WWKey::Ctrl)] << L"+";
+
+ if (key & static_cast(WWKey::Alt))
+ oss << KeyboardCodeTextMap[static_cast(WWKey::Alt)] << L"+";
+
const int pureKey = key & 0xFF;
- const wchar_t* showText;
if (KeyboardCodeTextMap.contains(pureKey))
- {
- const wchar_t* pureText = KeyboardCodeTextMap[pureKey];
- const int pureLength = std::wcslen(pureText) + 1;
- wchar_t* text = new wchar_t[pureLength];
- wcscpy_s(text, pureLength, pureText);
- text[pureLength] = L'\0';
- showText = text;
- }
+ oss << KeyboardCodeTextMap[pureKey];
else
- {
- showText = L"Unknown";
- }
+ oss << L"Unknown";
- showText = this->Key2ConcatText(showText, key, static_cast(WWKey::Shift));
- showText = this->Key2ConcatText(showText, key, static_cast(WWKey::Ctrl));
- showText = this->Key2ConcatText(showText, key, static_cast(WWKey::Alt));
-
- this->keyCodeText[index] = showText;
+ this->keyCodeText[index] = oss.str();
}
inline bool TacticalButtonsClass::IndexIsSWSwitch()
@@ -927,7 +910,7 @@ DEFINE_HOOK(0x533E69, UnknownClass_sub_533D20_LoadKeyboardCodeFromINI, 0x6)
for (int i = 1; i <= 10; ++i)
{
- sprintf_s(buffer, "SW Sidebar Shortcuts Num %2d", i);
+ sprintf_s(buffer, "SW Sidebar Shortcuts Num %02d", i);
if (!_strcmpi(name, buffer))
pButtons->SWSidebarRecord(i, key);
@@ -943,11 +926,11 @@ DEFINE_HOOK(0x5FB992, UnknownClass_sub_5FB320_SaveKeyboardCodeToINI, 0x6)
TacticalButtonsClass* const pButtons = &TacticalButtonsClass::Instance;
const char* name = pCommand->GetName();
- char buffer[29];
+ char buffer[30];
for (int i = 1; i <= 10; ++i)
{
- sprintf_s(buffer, "SW Sidebar Shortcuts Num %2d", i);
+ sprintf_s(buffer, "SW Sidebar Shortcuts Num %02d", i);
if (!_strcmpi(name, buffer))
pButtons->SWSidebarRecord(i, key);
diff --git a/src/Misc/TacticalButtons.h b/src/Misc/TacticalButtons.h
index b8447db5d7..9b5b9efe00 100644
--- a/src/Misc/TacticalButtons.h
+++ b/src/Misc/TacticalButtons.h
@@ -23,7 +23,6 @@ class TacticalButtonsClass
// Button index 1-10 : Super weapons buttons
inline bool IndexInSWButtons();
- inline const wchar_t* Key2ConcatText(const wchar_t* showText, int key, int overlay);
void SWSidebarDraw();
void SWSidebarRecheck();
@@ -57,7 +56,7 @@ class TacticalButtonsClass
// Button index 1-10 : Super weapons buttons
bool DummyAction { false };
bool KeyboardCall { false };
- const wchar_t* keyCodeText[10] {};
+ std::wstring keyCodeText[10] {};
int keyCodeData[10] {};
// TODO New buttons (Start from index = 12)
From 8806cea02cf758ca1ae24feef9cdc9e754d2f014 Mon Sep 17 00:00:00 2001
From: CrimRecya <335958461@qq.com>
Date: Fri, 20 Sep 2024 19:52:57 +0800
Subject: [PATCH 09/12] Doc
---
docs/User-Interface.md | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/docs/User-Interface.md b/docs/User-Interface.md
index dd09844e22..bfd069d445 100644
--- a/docs/User-Interface.md
+++ b/docs/User-Interface.md
@@ -294,6 +294,12 @@ SelectionFlashDuration=0 ; integer, number of frames
- Switches on/off [frame by frame mode](Miscellanous.html#frame-step-in).
- For localization add `TXT_FRAME_BY_FRAME` and `TXT_FRAME_BY_FRAME_DESC` into your `.csf` file.
+### `[ ]` Exclusive SW Sidebar Shortcuts
+- Switches visible/invisible [this](#Exclusive-sidebar-for-superweapons).
+- For localization add `TXT_EX_SW_SWITCH` and `TXT_EX_SW_SWITCH_DESC` into your `.csf` file.
+- And Select the SWs in this exclusive sidebar.
+- For localization add `TXT_EX_SW_BUTTON_XX` and `TXT_EX_SW_BUTTON_XX_DESC` into your `.csf` file. (`XX` -> `03`, `10` .etc)
+
## Loading screen
- PCX files can now be used as loadscreen images.
@@ -376,6 +382,10 @@ SW.QuickFireAtMouse=false ; boolean
SW.QuickFireInScreen=false ; boolean
```
+```{note}
+If you want to change the printing message of switch on/off, for localization add `TXT_EX_SW_BAR_VISIBLE` and `TXT_EX_SW_BAR_INVISIBLE` into your `.csf` file.
+```
+
### Harvester counter

From dc266017fa059a0d96e65b3ac873bd47eed6f851 Mon Sep 17 00:00:00 2001
From: CrimRecya <335958461@qq.com>
Date: Sun, 22 Sep 2024 02:43:40 +0800
Subject: [PATCH 10/12] Some unimportant simplifications
---
src/Misc/TacticalButtons.cpp | 38 ++++++++++++------------------------
src/Misc/TacticalButtons.h | 4 ++--
2 files changed, 14 insertions(+), 28 deletions(-)
diff --git a/src/Misc/TacticalButtons.cpp b/src/Misc/TacticalButtons.cpp
index 2de9e1cc74..a95bb2fec1 100644
--- a/src/Misc/TacticalButtons.cpp
+++ b/src/Misc/TacticalButtons.cpp
@@ -375,16 +375,12 @@ void TacticalButtonsClass::SWSidebarDraw()
if (drawSWSidebarBackground)
{
+ RectangleStruct drawRect { 0, backPosition.Y, 80, 20 };
+
if (BSurface* const CameoPCX = pSideExt->SWSidebarBackground_TopPCX.GetSurface())
- {
- RectangleStruct drawRect { backPosition.X, backPosition.Y, 60, 48 };
PCX::Instance->BlitToSurface(&drawRect, DSurface::Composite, CameoPCX);
- }
else
- {
- RectangleStruct backRect { 0, backPosition.Y, 80, 20};
- DSurface::Composite->FillRect(&backRect, COLOR_BLACK);
- }
+ DSurface::Composite->FillRect(&drawRect, COLOR_BLACK);
}
// Draw each buttons
@@ -394,17 +390,12 @@ void TacticalButtonsClass::SWSidebarDraw()
if (drawSWSidebarBackground)
{
backPosition.Y = position.Y - 1;
+ RectangleStruct drawRect { 0, backPosition.Y, 80, 50 };
if (BSurface* const CameoPCX = pSideExt->SWSidebarBackground_CenterPCX.GetSurface())
- {
- RectangleStruct drawRect { backPosition.X, backPosition.Y, 60, 48 };
PCX::Instance->BlitToSurface(&drawRect, DSurface::Composite, CameoPCX);
- }
else
- {
- RectangleStruct backRect { 0, backPosition.Y, 80, 50};
- DSurface::Composite->FillRect(&backRect, COLOR_BLACK);
- }
+ DSurface::Composite->FillRect(&drawRect, COLOR_BLACK);
}
// Get SW data
@@ -452,9 +443,9 @@ void TacticalButtonsClass::SWSidebarDraw()
}
// SW status
- if (ready && !this->keyCodeText[i].empty())
+ if (ready && !this->KeyCodeText[i].empty())
{
- const wchar_t* pKey = this->keyCodeText[i].c_str();
+ const wchar_t* pKey = this->KeyCodeText[i].c_str();
Point2D textLocation { 35, position.Y + 1 };
const TextPrintType printType = TextPrintType::Center | TextPrintType::FullShadow | TextPrintType::Point8;
RectangleStruct textRect = Drawing::GetTextDimensions(pKey, textLocation, static_cast(printType), 2, 1);
@@ -482,17 +473,12 @@ void TacticalButtonsClass::SWSidebarDraw()
if (drawSWSidebarBackground)
{
backPosition.Y = position.Y - 1;
+ RectangleStruct drawRect { 0, backPosition.Y, 80, 20};
if (BSurface* const CameoPCX = pSideExt->SWSidebarBackground_BottomPCX.GetSurface())
- {
- RectangleStruct drawRect { backPosition.X, backPosition.Y, 60, 48 };
PCX::Instance->BlitToSurface(&drawRect, DSurface::Composite, CameoPCX);
- }
else
- {
- RectangleStruct backRect { 0, backPosition.Y, 80, 20};
- DSurface::Composite->FillRect(&backRect, COLOR_BLACK);
- }
+ DSurface::Composite->FillRect(&drawRect, COLOR_BLACK);
}
// Draw mouse hover rectangle
@@ -632,10 +618,10 @@ void TacticalButtonsClass::SWSidebarRecord(int buttonIndex, int key)
{
const int index = buttonIndex - 1;
- if (this->keyCodeData[index] == key)
+ if (this->KeyCodeData[index] == key)
return;
- this->keyCodeData[index] = key;
+ this->KeyCodeData[index] = key;
std::wostringstream oss;
if (key & static_cast(WWKey::Shift))
@@ -654,7 +640,7 @@ void TacticalButtonsClass::SWSidebarRecord(int buttonIndex, int key)
else
oss << L"Unknown";
- this->keyCodeText[index] = oss.str();
+ this->KeyCodeText[index] = oss.str();
}
inline bool TacticalButtonsClass::IndexIsSWSwitch()
diff --git a/src/Misc/TacticalButtons.h b/src/Misc/TacticalButtons.h
index 9b5b9efe00..05f6303573 100644
--- a/src/Misc/TacticalButtons.h
+++ b/src/Misc/TacticalButtons.h
@@ -56,8 +56,8 @@ class TacticalButtonsClass
// Button index 1-10 : Super weapons buttons
bool DummyAction { false };
bool KeyboardCall { false };
- std::wstring keyCodeText[10] {};
- int keyCodeData[10] {};
+ std::wstring KeyCodeText[10] {};
+ int KeyCodeData[10] {};
// TODO New buttons (Start from index = 12)
From f6f8fa4e18a7c50e86b47e81ef2a6227d56c5208 Mon Sep 17 00:00:00 2001
From: CrimRecya <335958461@qq.com>
Date: Sun, 22 Sep 2024 18:41:30 +0800
Subject: [PATCH 11/12] Fit with missing cameo and cameo palette
---
src/Ext/SWType/Body.cpp | 2 ++
src/Ext/SWType/Body.h | 2 ++
src/Misc/TacticalButtons.cpp | 28 ++++++++++++++++++++++++++--
3 files changed, 30 insertions(+), 2 deletions(-)
diff --git a/src/Ext/SWType/Body.cpp b/src/Ext/SWType/Body.cpp
index adf5875d3b..f42e85d5ac 100644
--- a/src/Ext/SWType/Body.cpp
+++ b/src/Ext/SWType/Body.cpp
@@ -25,6 +25,7 @@ void SWTypeExt::ExtData::Serialize(T& Stm)
.Process(this->SW_InitialReady)
.Process(this->SW_PostDependent)
.Process(this->SidebarPCX)
+ .Process(this->CameoPal)
.Process(this->UIDescription)
.Process(this->CameoPriority)
.Process(this->LimboDelivery_Types)
@@ -87,6 +88,7 @@ void SWTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI)
this->SW_InitialReady.Read(exINI, pSection, "SW.InitialReady");
this->SW_PostDependent.Read(exINI, pSection, "SW.PostDependent");
this->SidebarPCX.Read(pINI, pSection, "SidebarPCX");
+ this->CameoPal.LoadFromINI(pINI, pSection, "SidebarPalette");
this->UIDescription.Read(exINI, pSection, "UIDescription");
this->CameoPriority.Read(exINI, pSection, "CameoPriority");
diff --git a/src/Ext/SWType/Body.h b/src/Ext/SWType/Body.h
index 82bb80549b..bf00d7a60e 100644
--- a/src/Ext/SWType/Body.h
+++ b/src/Ext/SWType/Body.h
@@ -37,6 +37,7 @@ class SWTypeExt
Valueable SW_InitialReady;
ValueableIdx SW_PostDependent;
PhobosPCXFile SidebarPCX;
+ CustomPalette CameoPal;
Valueable UIDescription;
Valueable CameoPriority;
@@ -91,6 +92,7 @@ class SWTypeExt
, SW_NegBuildings {}
, SW_InitialReady { false }
, SW_PostDependent {}
+ , CameoPal {}
, UIDescription {}
, CameoPriority { 0 }
, LimboDelivery_Types {}
diff --git a/src/Misc/TacticalButtons.cpp b/src/Misc/TacticalButtons.cpp
index a95bb2fec1..9bc8a1ec4f 100644
--- a/src/Misc/TacticalButtons.cpp
+++ b/src/Misc/TacticalButtons.cpp
@@ -414,8 +414,32 @@ void TacticalButtonsClass::SWSidebarDraw()
}
else if (SHPStruct* const pSHP = pSWType->SidebarImage)
{
- DSurface::Composite->DrawSHP(FileSystem::CAMEO_PAL, pSHP, 0, &position, &rect,
- BlitterFlags::bf_400, 0, 0, ZGradient::Ground, 1000, 0, 0, 0, 0, 0);
+ SHPReference* const pCameoRef = pSHP->AsReference();
+
+ char pFilename[0x20];
+ strcpy_s(pFilename, RulesExt::Global()->MissingCameo.data());
+ _strlwr_s(pFilename);
+
+ if (!_stricmp(pCameoRef->Filename, GameStrings::XXICON_SHP) && strstr(pFilename, ".pcx"))
+ {
+ PCX::Instance->LoadFile(pFilename);
+ RectangleStruct drawRect { position.X, position.Y, 60, 48 };
+
+ if (BSurface* const MissingCameoPCX = PCX::Instance->GetSurface(pFilename))
+ PCX::Instance->BlitToSurface(&drawRect, DSurface::Composite, MissingCameoPCX);
+ else
+ DSurface::Composite->FillRect(&drawRect, COLOR_WHITE);
+ }
+ else
+ {
+ DSurface::Composite->DrawSHP(pTypeExt->CameoPal.GetOrDefaultConvert(FileSystem::CAMEO_PAL), pSHP, 0, &position, &rect,
+ BlitterFlags::bf_400, 0, 0, ZGradient::Ground, 1000, 0, 0, 0, 0, 0);
+ }
+ }
+ else
+ {
+ RectangleStruct drawRect { position.X, position.Y, 60, 48 };
+ DSurface::Composite->FillRect(&drawRect, COLOR_WHITE);
}
}
From 0485dd514a8e37c9191998d807dfd2a9e05d0da8 Mon Sep 17 00:00:00 2001
From: CrimRecya <335958461@qq.com>
Date: Thu, 26 Sep 2024 19:06:01 +0800
Subject: [PATCH 12/12] Notes
---
src/Misc/TacticalButtons.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/Misc/TacticalButtons.cpp b/src/Misc/TacticalButtons.cpp
index 9bc8a1ec4f..64a104245c 100644
--- a/src/Misc/TacticalButtons.cpp
+++ b/src/Misc/TacticalButtons.cpp
@@ -852,7 +852,7 @@ DEFINE_HOOK(0x6D4941, TacticalClass_Render_DrawButtonCameo, 0x6)
return 0;
}
-// SW buttons hooks
+// SW buttons update hooks
DEFINE_HOOK(0x4F9283, HouseClass_Update_RecheckTechTree, 0x5)
{
TacticalButtonsClass::Instance.SWSidebarRecheck();
@@ -880,6 +880,7 @@ DEFINE_HOOK(0x6AAF46, SelectClass_Action_ButtonClick1, 0x6)
return TacticalButtonsClass::Instance.SWQuickLaunch(index) ? SkipClearMouse : 0;
}
+// SW buttons trigger hooks
DEFINE_HOOK_AGAIN(0x6AAD2F, SelectClass_Action_ButtonClick2, 0x7)
DEFINE_HOOK(0x6AB94F, SelectClass_Action_ButtonClick2, 0xB)
{