From 325989ff2df243b632da2275d7eef337e8db4eec Mon Sep 17 00:00:00 2001
From: CrimRecya <335958461@qq.com>
Date: Mon, 16 Dec 2024 00:48:56 +0800
Subject: [PATCH 01/30] Core
---
CREDITS.md | 1 +
Phobos.vcxproj | 2 +
docs/User-Interface.md | 11 ++
docs/Whats-New.md | 1 +
src/Commands/Commands.cpp | 3 +
src/Commands/DistributionMode.cpp | 215 ++++++++++++++++++++++++++++++
src/Commands/DistributionMode.h | 27 ++++
7 files changed, 260 insertions(+)
create mode 100644 src/Commands/DistributionMode.cpp
create mode 100644 src/Commands/DistributionMode.h
diff --git a/CREDITS.md b/CREDITS.md
index f977b2a3ed..56bbf02df6 100644
--- a/CREDITS.md
+++ b/CREDITS.md
@@ -371,6 +371,7 @@ This page lists all the individual contributions to the project by their author.
- Allow to change the speed of gas particles
- **CrimRecya**
- Fix `LimboKill` not working reliably
+ - Distribution click action mode
- **Ollerus**
- Build limit group enhancement
- Customizable rocker amplitude
diff --git a/Phobos.vcxproj b/Phobos.vcxproj
index 79495c5f4c..917e9e3566 100644
--- a/Phobos.vcxproj
+++ b/Phobos.vcxproj
@@ -31,6 +31,7 @@
+
@@ -196,6 +197,7 @@
+
diff --git a/docs/User-Interface.md b/docs/User-Interface.md
index 2e1ad86969..fcac944e00 100644
--- a/docs/User-Interface.md
+++ b/docs/User-Interface.md
@@ -317,6 +317,17 @@ 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.
+### `[ ]` Distribution Mode Spread / Filter
+
+- Change the click action.
+ - When the range is 0, it is the original default behavior of the game. The range can be adjusted to 4, 8 or 16 cells by shortcut keys.
+ - The targets within the range will be allocated equally to the selected technos. Only when the behavior to be performed by the current techno is the same as that displayed by the mouse will it be allocated. Otherwise, it will return to the original default behavior of the game (it will not be effective for technos in the air)
+ - When the filter is `None`, it is the default behavior of the game. You can adjust the filter mode to:
+ - `Auto` - if the behavior to be executed by the current techno is different from the behavior displayed by the mouse, and the behavior to be executed will make the techno move near the target, the behavior will be replaced with area guard.
+ - `Type` - on the basis of `Auto`, only targets of the same type (like infantries, vehicles or buildings) will be selected among the targets allocated in the range.
+ - `Name` - on the basis of `Type`, only targets of the same name (or with the same `GroupAs`) will be selected among the targets allocated in the range.
+- For localization add `TXT_DISTR_SPREAD`, `TXT_DISTR_FILTER`, `TXT_DISTR_SPREAD_DESC` and `TXT_DISTR_FILTER_DESC` into your `.csf` file.
+
## Loading screen
- PCX files can now be used as loadscreen images.
diff --git a/docs/Whats-New.md b/docs/Whats-New.md
index 0b6f8c19c6..85fd153e58 100644
--- a/docs/Whats-New.md
+++ b/docs/Whats-New.md
@@ -469,6 +469,7 @@ New:
- Allow infantry to use land sequences in water (by Starkku)
- `` can now be used as owner for pre-placed objects on skirmish and multiplayer maps (by Starkku)
- Allow customizing charge turret delays per burst on a weapon (by Starkku)
+- Distribution click action mode (by CrimRecya)
- Unit `Speed` setting now accepts floating point values (by Starkku)
Vanilla fixes:
diff --git a/src/Commands/Commands.cpp b/src/Commands/Commands.cpp
index 712a596467..67aa534ae3 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 "DistributionMode.h"
DEFINE_HOOK(0x533066, CommandClassCallback_Register, 0x6)
{
@@ -19,6 +20,8 @@ DEFINE_HOOK(0x533066, CommandClassCallback_Register, 0x6)
MakeCommand();
MakeCommand();
MakeCommand();
+ MakeCommand();
+ MakeCommand();
if (Phobos::Config::DevelopmentCommands)
{
diff --git a/src/Commands/DistributionMode.cpp b/src/Commands/DistributionMode.cpp
new file mode 100644
index 0000000000..4ccf19709d
--- /dev/null
+++ b/src/Commands/DistributionMode.cpp
@@ -0,0 +1,215 @@
+#include "DistributionMode.h"
+
+#include
+#include
+#include
+
+#include
+#include
+
+int DistributionMode1CommandClass::Mode = 0;
+int DistributionMode2CommandClass::Mode = 0;
+
+void __fastcall PrintDistributionModeMessage()
+{
+ wchar_t text[0x40];
+ swprintf_s(text, L"Distribution Mode < Spread: r=%2d , Filter: %s >",
+ (DistributionMode1CommandClass::Mode ? (2 << DistributionMode1CommandClass::Mode) : 0),
+ ((DistributionMode2CommandClass::Mode > 1) ? ((DistributionMode2CommandClass::Mode == 3) ? L"Name" : L"Type") : (DistributionMode2CommandClass::Mode == 1) ? L"Auto" : L"None")
+ );
+ MessageListClass::Instance->PrintMessage(text, 200, 5, true);
+}
+
+const char* DistributionMode1CommandClass::GetName() const
+{
+ return "Distribution Mode Spread";
+}
+
+const wchar_t* DistributionMode1CommandClass::GetUIName() const
+{
+ return GeneralUtils::LoadStringUnlessMissing("TXT_DISTR_SPREAD", L"Distribution spread");
+}
+
+const wchar_t* DistributionMode1CommandClass::GetUICategory() const
+{
+ return CATEGORY_CONTROL;
+}
+
+const wchar_t* DistributionMode1CommandClass::GetUIDescription() const
+{
+ return GeneralUtils::LoadStringUnlessMissing("TXT_DISTR_SPREAD_DESC", L"Automatically and averagely select similar targets around the original target. This is for changing the search range");
+}
+
+void DistributionMode1CommandClass::Execute(WWKey eInput) const
+{
+ DistributionMode1CommandClass::Mode = ((DistributionMode1CommandClass::Mode + 1) & 3);
+ PrintDistributionModeMessage();
+}
+
+const char* DistributionMode2CommandClass::GetName() const
+{
+ return "Distribution Mode Filter";
+}
+
+const wchar_t* DistributionMode2CommandClass::GetUIName() const
+{
+ return GeneralUtils::LoadStringUnlessMissing("TXT_DISTR_FILTER", L"Distribution filter");
+}
+
+const wchar_t* DistributionMode2CommandClass::GetUICategory() const
+{
+ return CATEGORY_CONTROL;
+}
+
+const wchar_t* DistributionMode2CommandClass::GetUIDescription() const
+{
+ return GeneralUtils::LoadStringUnlessMissing("TXT_DISTR_FILTER_DESC", L"Automatically and averagely select similar targets around the original target. This is for changing the filter criteria");
+}
+
+void DistributionMode2CommandClass::Execute(WWKey eInput) const
+{
+ DistributionMode2CommandClass::Mode = ((DistributionMode2CommandClass::Mode + 1) & 3);
+ PrintDistributionModeMessage();
+}
+
+DEFINE_HOOK(0x4AE818, DisplayClass_sub_4AE750_AutoDistribution, 0xA)
+{
+ enum { SkipGameCode = 0x4AE85C };
+
+ GET(ObjectClass* const, pTarget, EBP);
+ GET_STACK(const Action, mouseAction, STACK_OFFSET(0x20, 0xC));
+
+ const auto count = ObjectClass::CurrentObjects->Count;
+
+ if (count > 0)
+ {
+ const auto mode1 = DistributionMode1CommandClass::Mode;
+ const auto mode2 = DistributionMode2CommandClass::Mode;
+
+ // Distribution mode main
+ if (mode1 && count > 1 && mouseAction != Action::NoMove && !PlanningNodeClass::PlanningModeActive && (pTarget->AbstractFlags & AbstractFlags::Techno) != AbstractFlags::None && !pTarget->IsInAir())
+ {
+ const auto pSpecial = HouseClass::FindSpecial();
+ const auto pCivilian = HouseClass::FindCivilianSide();
+ const auto pNeutral = HouseClass::FindNeutral();
+
+ const auto pTargetHouse = static_cast(pTarget)->Owner;
+ const bool targetIsNeutral = pTargetHouse == pSpecial || pTargetHouse == pCivilian || pTargetHouse == pNeutral;
+
+ const auto range = (2 << mode1);
+ const auto pItems = Helpers::Alex::getCellSpreadItems(pTarget->Location, range);
+ std::map record;
+ int current = 1;
+
+ for (const auto& pItem : pItems)
+ record[pItem] = 0;
+
+ for (const auto& pSelect : ObjectClass::CurrentObjects())
+ {
+ TechnoClass* pCanTarget = nullptr;
+ TechnoClass* pNewTarget = nullptr;
+
+ for (const auto& [pItem, num] : record)
+ {
+ if (pSelect->MouseOverObject(pItem) == mouseAction && (targetIsNeutral || (pItem->Owner != pSpecial && pItem->Owner != pCivilian && pItem->Owner != pNeutral))
+ && (mode2 < 2 || (pItem->WhatAmI() == pTarget->WhatAmI()
+ && (mode2 < 3 || TechnoTypeExt::GetSelectionGroupID(pItem->GetTechnoType()) == TechnoTypeExt::GetSelectionGroupID(pTarget->GetTechnoType())))))
+ {
+ pCanTarget = pItem;
+
+ if (num < current)
+ {
+ pNewTarget = pCanTarget;
+ break;
+ }
+ }
+ }
+
+ if (!pNewTarget)
+ {
+ if (pCanTarget)
+ {
+ ++current;
+ pNewTarget = pCanTarget;
+ }
+ }
+
+ if (pNewTarget)
+ {
+ if (record.contains(pNewTarget))
+ ++record[pNewTarget];
+
+ pSelect->ObjectClickedAction(mouseAction, pNewTarget, false);
+ }
+ else
+ {
+ const auto currentAction = pSelect->MouseOverObject(pTarget);
+
+ if (mode2 && currentAction == Action::NoMove && (pSelect->AbstractFlags & AbstractFlags::Techno) != AbstractFlags::None)
+ static_cast(pSelect)->ClickedMission(Mission::Area_Guard, reinterpret_cast(pSelect->GetCellAgain()), nullptr, nullptr);
+ else
+ pSelect->ObjectClickedAction(currentAction, pTarget, false);
+ }
+
+ Unsorted::MoveFeedback = false;
+ }
+ }
+ else // Vanilla
+ {
+ for (const auto& pSelect : ObjectClass::CurrentObjects())
+ {
+ const auto currentAction = pSelect->MouseOverObject(pTarget);
+
+ if (mode2 && mouseAction != Action::NoMove && currentAction == Action::NoMove && (pSelect->AbstractFlags & AbstractFlags::Techno) != AbstractFlags::None)
+ static_cast(pSelect)->ClickedMission(Mission::Area_Guard, reinterpret_cast(pSelect->GetCellAgain()), nullptr, nullptr);
+ else
+ pSelect->ObjectClickedAction(currentAction, pTarget, false);
+
+ Unsorted::MoveFeedback = false;
+ }
+ }
+ }
+
+ return SkipGameCode;
+}
+/*
+DEFINE_HOOK(0x4F4596, GScreenClass_DrawOnTop_DrawDistributionModeShape, 0x7)
+{
+ const auto mode1 = DistributionMode1CommandClass::Mode;
+ const auto mode2 = DistributionMode2CommandClass::Mode;
+
+ if (mode1 || mode2)
+ {
+ auto position = WWMouseClass::Instance->XY1;
+ RectangleStruct rect = DSurface::Composite->GetRect();
+ rect.Height -= 32;
+
+ if (position.X < rect.Width && position.Y < rect.Height)
+ {
+ position.Y += 20;
+ const auto mode2Text = ((mode2 > 1) ? ((mode2 == 3) ? L"Name" : L"Type") : (mode2 == 1) ? L"Auto" : L"None");
+ wchar_t text[0x20];
+ swprintf_s(text, L"%s:%2d", mode2Text, (mode1 ? (2 << mode1) : 0));
+ RectangleStruct dim = Drawing::GetTextDimensions(text, Point2D::Empty, 0);
+ dim.Width += 4;
+ const int dX = rect.Width - dim.Width;
+ const int dY = rect.Height - dim.Height;
+
+ if (position.X >= dX)
+ position.X = dX;
+
+ if (position.Y >= dY)
+ position.Y = dY;
+
+ dim.X = position.X;
+ dim.Y = position.Y;
+ ColorStruct color { 0, 0, 0 };
+ DSurface::Composite->FillRectTrans(&dim, &color, 40);
+ position.X += 2;
+ DSurface::Composite->DrawTextA(text, &rect, &position, COLOR_WHITE, COLOR_BLACK, TextPrintType::LightShadow);
+ }
+ }
+
+ return 0;
+}
+*/
diff --git a/src/Commands/DistributionMode.h b/src/Commands/DistributionMode.h
new file mode 100644
index 0000000000..292ff49b2b
--- /dev/null
+++ b/src/Commands/DistributionMode.h
@@ -0,0 +1,27 @@
+#pragma once
+
+#include "Commands.h"
+
+class DistributionMode1CommandClass : public CommandClass
+{
+public:
+ static int Mode;
+
+ 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;
+};
+
+class DistributionMode2CommandClass : public CommandClass
+{
+public:
+ static int Mode;
+
+ 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;
+};
From 6edc48e44c0980bd55715cb9ffc66d70355d093b Mon Sep 17 00:00:00 2001
From: CrimRecya <335958461@qq.com>
Date: Sun, 26 Jan 2025 19:11:39 +0800
Subject: [PATCH 02/30] Update Whats-New.md
---
docs/Whats-New.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/Whats-New.md b/docs/Whats-New.md
index fab381ac63..33c10ebb8d 100644
--- a/docs/Whats-New.md
+++ b/docs/Whats-New.md
@@ -314,6 +314,7 @@ New:
- Enable building production queue (by CrimRecya)
- Fixed sidebar not updating queued unit numbers when adding or removing units when the production is on hold (by CrimRecya)
- Custom exit cell for infantry factory (by Starkku)
+- Distribution click action mode (by CrimRecya)
Vanilla fixes:
- Aircraft will now behave as expected according to it's `MovementZone` and `SpeedType` when moving onto different surfaces. In particular, this fixes erratic behavior when vanilla aircraft is ordered to move onto water surface and instead the movement order changes to a shore nearby (by CrimRecya)
@@ -485,7 +486,6 @@ New:
- Allow infantry to use land sequences in water (by Starkku)
- `` can now be used as owner for pre-placed objects on skirmish and multiplayer maps (by Starkku)
- Allow customizing charge turret delays per burst on a weapon (by Starkku)
-- Distribution click action mode (by CrimRecya)
- Unit `Speed` setting now accepts floating point values (by Starkku)
Vanilla fixes:
From 73a6c0b2d79f97020ba7a1d20c22b0b30ec52148 Mon Sep 17 00:00:00 2001
From: CrimRecya <335958461@qq.com>
Date: Sun, 26 Jan 2025 19:11:58 +0800
Subject: [PATCH 03/30] Draw at mouse
---
src/Commands/DistributionMode.cpp | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/Commands/DistributionMode.cpp b/src/Commands/DistributionMode.cpp
index 4ccf19709d..a2108fa6e2 100644
--- a/src/Commands/DistributionMode.cpp
+++ b/src/Commands/DistributionMode.cpp
@@ -172,7 +172,7 @@ DEFINE_HOOK(0x4AE818, DisplayClass_sub_4AE750_AutoDistribution, 0xA)
return SkipGameCode;
}
-/*
+
DEFINE_HOOK(0x4F4596, GScreenClass_DrawOnTop_DrawDistributionModeShape, 0x7)
{
const auto mode1 = DistributionMode1CommandClass::Mode;
@@ -212,4 +212,3 @@ DEFINE_HOOK(0x4F4596, GScreenClass_DrawOnTop_DrawDistributionModeShape, 0x7)
return 0;
}
-*/
From 97c070dae3584683f6fcabf13066ff93ed0c76ae Mon Sep 17 00:00:00 2001
From: CrimRecya <335958461@qq.com>
Date: Sun, 26 Jan 2025 20:22:40 +0800
Subject: [PATCH 04/30] Show range ring
---
docs/User-Interface.md | 10 +++----
src/Commands/DistributionMode.cpp | 48 ++++---------------------------
2 files changed, 11 insertions(+), 47 deletions(-)
diff --git a/docs/User-Interface.md b/docs/User-Interface.md
index b915ea2fa2..0aa2994d25 100644
--- a/docs/User-Interface.md
+++ b/docs/User-Interface.md
@@ -323,11 +323,11 @@ SelectionFlashDuration=0 ; integer, number of frames
- Change the click action.
- When the range is 0, it is the original default behavior of the game. The range can be adjusted to 4, 8 or 16 cells by shortcut keys.
- - The targets within the range will be allocated equally to the selected technos. Only when the behavior to be performed by the current techno is the same as that displayed by the mouse will it be allocated. Otherwise, it will return to the original default behavior of the game (it will not be effective for technos in the air)
- - When the filter is `None`, it is the default behavior of the game. You can adjust the filter mode to:
- - `Auto` - if the behavior to be executed by the current techno is different from the behavior displayed by the mouse, and the behavior to be executed will make the techno move near the target, the behavior will be replaced with area guard.
- - `Type` - on the basis of `Auto`, only targets of the same type (like infantries, vehicles or buildings) will be selected among the targets allocated in the range.
- - `Name` - on the basis of `Type`, only targets of the same name (or with the same `GroupAs`) will be selected among the targets allocated in the range.
+ - The targets within the range will be allocated equally to the selected technos. Only when the behavior to be performed by the current techno is the same as that displayed by the mouse will it be allocated. Otherwise, it will return to the original default behavior of the game (it will not be effective for technos in the air). This will display a range ring.
+ - When the filter is `None`, it is the default behavior of the game. If the range is not zero at this time, a green ring will be displayed. You can adjust the filter mode to:
+ - `Auto` - if the behavior to be executed by the current techno is different from the behavior displayed by the mouse, and the behavior to be executed will make the techno move near the target, the behavior will be replaced with area guard. At this time, a blue ring will be displayed.
+ - `Type` - on the basis of `Auto`, only targets of the same type (like infantries, vehicles or buildings) will be selected among the targets allocated in the range. At this time, a yellow ring will be displayed.
+ - `Name` - on the basis of `Type`, only targets of the same name (or with the same `GroupAs`) will be selected among the targets allocated in the range. At this time, a red ring will be displayed.
- For localization add `TXT_DISTR_SPREAD`, `TXT_DISTR_FILTER`, `TXT_DISTR_SPREAD_DESC` and `TXT_DISTR_FILTER_DESC` into your `.csf` file.
## Loading screen
diff --git a/src/Commands/DistributionMode.cpp b/src/Commands/DistributionMode.cpp
index a2108fa6e2..1c7b4f0f5a 100644
--- a/src/Commands/DistributionMode.cpp
+++ b/src/Commands/DistributionMode.cpp
@@ -5,21 +5,10 @@
#include
#include
-#include
int DistributionMode1CommandClass::Mode = 0;
int DistributionMode2CommandClass::Mode = 0;
-void __fastcall PrintDistributionModeMessage()
-{
- wchar_t text[0x40];
- swprintf_s(text, L"Distribution Mode < Spread: r=%2d , Filter: %s >",
- (DistributionMode1CommandClass::Mode ? (2 << DistributionMode1CommandClass::Mode) : 0),
- ((DistributionMode2CommandClass::Mode > 1) ? ((DistributionMode2CommandClass::Mode == 3) ? L"Name" : L"Type") : (DistributionMode2CommandClass::Mode == 1) ? L"Auto" : L"None")
- );
- MessageListClass::Instance->PrintMessage(text, 200, 5, true);
-}
-
const char* DistributionMode1CommandClass::GetName() const
{
return "Distribution Mode Spread";
@@ -43,7 +32,6 @@ const wchar_t* DistributionMode1CommandClass::GetUIDescription() const
void DistributionMode1CommandClass::Execute(WWKey eInput) const
{
DistributionMode1CommandClass::Mode = ((DistributionMode1CommandClass::Mode + 1) & 3);
- PrintDistributionModeMessage();
}
const char* DistributionMode2CommandClass::GetName() const
@@ -69,7 +57,6 @@ const wchar_t* DistributionMode2CommandClass::GetUIDescription() const
void DistributionMode2CommandClass::Execute(WWKey eInput) const
{
DistributionMode2CommandClass::Mode = ((DistributionMode2CommandClass::Mode + 1) & 3);
- PrintDistributionModeMessage();
}
DEFINE_HOOK(0x4AE818, DisplayClass_sub_4AE750_AutoDistribution, 0xA)
@@ -173,41 +160,18 @@ DEFINE_HOOK(0x4AE818, DisplayClass_sub_4AE750_AutoDistribution, 0xA)
return SkipGameCode;
}
-DEFINE_HOOK(0x4F4596, GScreenClass_DrawOnTop_DrawDistributionModeShape, 0x7)
+DEFINE_HOOK(0x6DBE74, TacticalClass_DrawAllRadialIndicators_DrawDistributionRange, 0x7)
{
const auto mode1 = DistributionMode1CommandClass::Mode;
const auto mode2 = DistributionMode2CommandClass::Mode;
if (mode1 || mode2)
{
- auto position = WWMouseClass::Instance->XY1;
- RectangleStruct rect = DSurface::Composite->GetRect();
- rect.Height -= 32;
-
- if (position.X < rect.Width && position.Y < rect.Height)
- {
- position.Y += 20;
- const auto mode2Text = ((mode2 > 1) ? ((mode2 == 3) ? L"Name" : L"Type") : (mode2 == 1) ? L"Auto" : L"None");
- wchar_t text[0x20];
- swprintf_s(text, L"%s:%2d", mode2Text, (mode1 ? (2 << mode1) : 0));
- RectangleStruct dim = Drawing::GetTextDimensions(text, Point2D::Empty, 0);
- dim.Width += 4;
- const int dX = rect.Width - dim.Width;
- const int dY = rect.Height - dim.Height;
-
- if (position.X >= dX)
- position.X = dX;
-
- if (position.Y >= dY)
- position.Y = dY;
-
- dim.X = position.X;
- dim.Y = position.Y;
- ColorStruct color { 0, 0, 0 };
- DSurface::Composite->FillRectTrans(&dim, &color, 40);
- position.X += 2;
- DSurface::Composite->DrawTextA(text, &rect, &position, COLOR_WHITE, COLOR_BLACK, TextPrintType::LightShadow);
- }
+ const auto pCell = MapClass::Instance->GetCellAt(DisplayClass::Instance->CurrentFoundation_CenterCell);
+ const auto color = ((mode2 > 1)
+ ? ((mode2 == 3) ? ColorStruct { 255, 0, 0 } : ColorStruct { 200, 200, 0 })
+ : (mode2 == 1) ? ColorStruct { 0, 100, 255 } : ColorStruct { 0, 255, 50 });
+ Game::DrawRadialIndicator(false, true, pCell->GetCoords(), color, (mode1 ? static_cast(2 << mode1) : 0.5), false, true);
}
return 0;
From e2426699dae0d3fb12ab818d17a28f2c159cd7c4 Mon Sep 17 00:00:00 2001
From: CrimRecya <335958461@qq.com>
Date: Sun, 26 Jan 2025 21:12:12 +0800
Subject: [PATCH 05/30] Fix a typo
---
src/Commands/DistributionMode.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Commands/DistributionMode.cpp b/src/Commands/DistributionMode.cpp
index 1c7b4f0f5a..854e66fe7c 100644
--- a/src/Commands/DistributionMode.cpp
+++ b/src/Commands/DistributionMode.cpp
@@ -171,7 +171,7 @@ DEFINE_HOOK(0x6DBE74, TacticalClass_DrawAllRadialIndicators_DrawDistributionRang
const auto color = ((mode2 > 1)
? ((mode2 == 3) ? ColorStruct { 255, 0, 0 } : ColorStruct { 200, 200, 0 })
: (mode2 == 1) ? ColorStruct { 0, 100, 255 } : ColorStruct { 0, 255, 50 });
- Game::DrawRadialIndicator(false, true, pCell->GetCoords(), color, (mode1 ? static_cast(2 << mode1) : 0.5), false, true);
+ Game::DrawRadialIndicator(false, true, pCell->GetCoords(), color, static_cast(mode1 ? (2 << mode1) : 0.5), false, true);
}
return 0;
From ab9c046302a29dd3cc70531bbef3b4661aa821e4 Mon Sep 17 00:00:00 2001
From: CrimRecya <335958461@qq.com>
Date: Mon, 3 Feb 2025 02:21:17 +0800
Subject: [PATCH 06/30] Fix target cloaked units
---
src/Commands/DistributionMode.cpp | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/src/Commands/DistributionMode.cpp b/src/Commands/DistributionMode.cpp
index 854e66fe7c..c72fd8b3ff 100644
--- a/src/Commands/DistributionMode.cpp
+++ b/src/Commands/DistributionMode.cpp
@@ -89,7 +89,10 @@ DEFINE_HOOK(0x4AE818, DisplayClass_sub_4AE750_AutoDistribution, 0xA)
int current = 1;
for (const auto& pItem : pItems)
- record[pItem] = 0;
+ {
+ if (pItem->CloakState != CloakState::Cloaked || pItem->GetCell()->Sensors_InclHouse(HouseClass::CurrentPlayer->ArrayIndex))
+ record[pItem] = 0;
+ }
for (const auto& pSelect : ObjectClass::CurrentObjects())
{
From 32c90bded6f720ad15594d11a32c5f24e11b0fcd Mon Sep 17 00:00:00 2001
From: Noble Fish <89088785+DeathFishAtEase@users.noreply.github.com>
Date: Mon, 3 Feb 2025 04:12:50 +0800
Subject: [PATCH 07/30] ")"
---
docs/Fixed-or-Improved-Logics.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/Fixed-or-Improved-Logics.md b/docs/Fixed-or-Improved-Logics.md
index d39932ba2b..5606546923 100644
--- a/docs/Fixed-or-Improved-Logics.md
+++ b/docs/Fixed-or-Improved-Logics.md
@@ -1124,7 +1124,7 @@ Palette= ; filename - excluding .pal extension and three-character the
- Instead of showing at 1 point of HP left, TerrainTypes switch to damaged frames once their health reaches `[AudioVisual]` -> `ConditionYellow.Terrain` percentage of their maximum health. Defaults to `ConditionYellow` if not set.
- In addition, TerrainTypes can now show 'crumbling' animation after their health has reached zero and before they are deleted from the map by setting `HasCrumblingFrames` to true.
- Crumbling frames start from first frame after both regular & damaged frames and ends at halfway point of the frames in TerrainType's image.
- - Note that the number of regular & damage frames considered for this depends on value of `HasDamagedFrames` and for `IsAnimated` TerrainTypes, `AnimationLength` (see [Animated TerrainTypes](#animated-terraintypes). Exercise caution and ensure there are correct amount of frames to display.
+ - Note that the number of regular & damage frames considered for this depends on value of `HasDamagedFrames` and for `IsAnimated` TerrainTypes, `AnimationLength` (see [Animated TerrainTypes](#animated-terraintypes)). Exercise caution and ensure there are correct amount of frames to display.
- Sound event from `CrumblingSound` (if set) is played when crumbling animation starts playing.
- [Destroy animation & sound](New-or-Enhanced-Logics.md#destroy-animation--sound) only play after crumbling animation has finished.
From 82ea77caa5938458bb32b1ffbeaa8eeed9e4f709 Mon Sep 17 00:00:00 2001
From: CrimRecya <335958461@qq.com>
Date: Mon, 3 Feb 2025 13:15:08 +0800
Subject: [PATCH 08/30] Add a hold down key to enable
---
src/Commands/Commands.cpp | 1 +
src/Commands/DistributionMode.cpp | 43 ++++++++++++++++++++++++++++++-
src/Commands/DistributionMode.h | 14 ++++++++++
3 files changed, 57 insertions(+), 1 deletion(-)
diff --git a/src/Commands/Commands.cpp b/src/Commands/Commands.cpp
index 67aa534ae3..885c5b79bd 100644
--- a/src/Commands/Commands.cpp
+++ b/src/Commands/Commands.cpp
@@ -22,6 +22,7 @@ DEFINE_HOOK(0x533066, CommandClassCallback_Register, 0x6)
MakeCommand();
MakeCommand();
MakeCommand();
+ MakeCommand();
if (Phobos::Config::DevelopmentCommands)
{
diff --git a/src/Commands/DistributionMode.cpp b/src/Commands/DistributionMode.cpp
index c72fd8b3ff..15b837d57a 100644
--- a/src/Commands/DistributionMode.cpp
+++ b/src/Commands/DistributionMode.cpp
@@ -8,6 +8,8 @@
int DistributionMode1CommandClass::Mode = 0;
int DistributionMode2CommandClass::Mode = 0;
+bool DistributionMode3CommandClass::Enabled = false;
+int DistributionMode3CommandClass::ShowTime = 0;
const char* DistributionMode1CommandClass::GetName() const
{
@@ -32,6 +34,7 @@ const wchar_t* DistributionMode1CommandClass::GetUIDescription() const
void DistributionMode1CommandClass::Execute(WWKey eInput) const
{
DistributionMode1CommandClass::Mode = ((DistributionMode1CommandClass::Mode + 1) & 3);
+ DistributionMode3CommandClass::ShowTime = SystemTimer::GetTime();
}
const char* DistributionMode2CommandClass::GetName() const
@@ -57,6 +60,40 @@ const wchar_t* DistributionMode2CommandClass::GetUIDescription() const
void DistributionMode2CommandClass::Execute(WWKey eInput) const
{
DistributionMode2CommandClass::Mode = ((DistributionMode2CommandClass::Mode + 1) & 3);
+ DistributionMode3CommandClass::ShowTime = SystemTimer::GetTime();
+}
+
+const char* DistributionMode3CommandClass::GetName() const
+{
+ return "Distribution Mode Hold Down";
+}
+
+const wchar_t* DistributionMode3CommandClass::GetUIName() const
+{
+ return GeneralUtils::LoadStringUnlessMissing("TXT_DISTR_HOLDDOWN", L"Distribution hold down");
+}
+
+const wchar_t* DistributionMode3CommandClass::GetUICategory() const
+{
+ return CATEGORY_CONTROL;
+}
+
+const wchar_t* DistributionMode3CommandClass::GetUIDescription() const
+{
+ return GeneralUtils::LoadStringUnlessMissing("TXT_DISTR_HOLDDOWN_DESC", L"Automatically and averagely select similar targets around the original target. This is for holding down to toggle on/off");
+}
+
+bool DistributionMode3CommandClass::ExtraTriggerCondition(WWKey eInput) const
+{
+ return true;
+}
+
+void DistributionMode3CommandClass::Execute(WWKey eInput) const
+{
+ if (eInput & WWKey::Release)
+ DistributionMode3CommandClass::Enabled = false;
+ else
+ DistributionMode3CommandClass::Enabled = true;
}
DEFINE_HOOK(0x4AE818, DisplayClass_sub_4AE750_AutoDistribution, 0xA)
@@ -74,7 +111,8 @@ DEFINE_HOOK(0x4AE818, DisplayClass_sub_4AE750_AutoDistribution, 0xA)
const auto mode2 = DistributionMode2CommandClass::Mode;
// Distribution mode main
- if (mode1 && count > 1 && mouseAction != Action::NoMove && !PlanningNodeClass::PlanningModeActive && (pTarget->AbstractFlags & AbstractFlags::Techno) != AbstractFlags::None && !pTarget->IsInAir())
+ if (DistributionMode3CommandClass::Enabled && mode1 && count > 1 && mouseAction != Action::NoMove && !PlanningNodeClass::PlanningModeActive
+ && (pTarget->AbstractFlags & AbstractFlags::Techno) != AbstractFlags::None && !pTarget->IsInAir())
{
const auto pSpecial = HouseClass::FindSpecial();
const auto pCivilian = HouseClass::FindCivilianSide();
@@ -165,6 +203,9 @@ DEFINE_HOOK(0x4AE818, DisplayClass_sub_4AE750_AutoDistribution, 0xA)
DEFINE_HOOK(0x6DBE74, TacticalClass_DrawAllRadialIndicators_DrawDistributionRange, 0x7)
{
+ if (!DistributionMode3CommandClass::Enabled && SystemTimer::GetTime() - DistributionMode3CommandClass::ShowTime > 30)
+ return 0;
+
const auto mode1 = DistributionMode1CommandClass::Mode;
const auto mode2 = DistributionMode2CommandClass::Mode;
diff --git a/src/Commands/DistributionMode.h b/src/Commands/DistributionMode.h
index 292ff49b2b..4002422af0 100644
--- a/src/Commands/DistributionMode.h
+++ b/src/Commands/DistributionMode.h
@@ -25,3 +25,17 @@ class DistributionMode2CommandClass : public CommandClass
virtual const wchar_t* GetUIDescription() const override;
virtual void Execute(WWKey eInput) const override;
};
+
+class DistributionMode3CommandClass : public CommandClass
+{
+public:
+ static bool Enabled;
+ static int ShowTime;
+
+ 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 bool ExtraTriggerCondition(WWKey eInput) const override;
+ virtual void Execute(WWKey eInput) const override;
+};
From d279944f8ec1971ce7ad576fbe416922f93f0f19 Mon Sep 17 00:00:00 2001
From: CrimRecya <335958461@qq.com>
Date: Mon, 3 Feb 2025 13:21:13 +0800
Subject: [PATCH 09/30] Doc
---
docs/User-Interface.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/docs/User-Interface.md b/docs/User-Interface.md
index 29a0a11b21..652cbcfb78 100644
--- a/docs/User-Interface.md
+++ b/docs/User-Interface.md
@@ -331,14 +331,14 @@ ShowFlashOnSelecting=false ; boolean
### `[ ]` Distribution Mode Spread / Filter
-- Change the click action.
+- Change the click action when hold down the specific hotkey.
- When the range is 0, it is the original default behavior of the game. The range can be adjusted to 4, 8 or 16 cells by shortcut keys.
- The targets within the range will be allocated equally to the selected technos. Only when the behavior to be performed by the current techno is the same as that displayed by the mouse will it be allocated. Otherwise, it will return to the original default behavior of the game (it will not be effective for technos in the air). This will display a range ring.
- When the filter is `None`, it is the default behavior of the game. If the range is not zero at this time, a green ring will be displayed. You can adjust the filter mode to:
- `Auto` - if the behavior to be executed by the current techno is different from the behavior displayed by the mouse, and the behavior to be executed will make the techno move near the target, the behavior will be replaced with area guard. At this time, a blue ring will be displayed.
- `Type` - on the basis of `Auto`, only targets of the same type (like infantries, vehicles or buildings) will be selected among the targets allocated in the range. At this time, a yellow ring will be displayed.
- `Name` - on the basis of `Type`, only targets of the same name (or with the same `GroupAs`) will be selected among the targets allocated in the range. At this time, a red ring will be displayed.
-- For localization add `TXT_DISTR_SPREAD`, `TXT_DISTR_FILTER`, `TXT_DISTR_SPREAD_DESC` and `TXT_DISTR_FILTER_DESC` into your `.csf` file.
+- For localization add `TXT_DISTR_SPREAD`, `TXT_DISTR_FILTER`, `TXT_DISTR_HOLDDOWN`, `TXT_DISTR_SPREAD_DESC`, `TXT_DISTR_FILTER_DESC` and `TXT_DISTR_HOLDDOWN_DESC` into your `.csf` file.
## Loading screen
From 44442223a04744d220496b223b771f7094c92e7b Mon Sep 17 00:00:00 2001
From: CrimRecya <335958461@qq.com>
Date: Mon, 3 Feb 2025 15:39:39 +0800
Subject: [PATCH 10/30] Fix target shrouded units
---
src/Commands/DistributionMode.cpp | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/src/Commands/DistributionMode.cpp b/src/Commands/DistributionMode.cpp
index 15b837d57a..014cf2b6c9 100644
--- a/src/Commands/DistributionMode.cpp
+++ b/src/Commands/DistributionMode.cpp
@@ -129,7 +129,16 @@ DEFINE_HOOK(0x4AE818, DisplayClass_sub_4AE750_AutoDistribution, 0xA)
for (const auto& pItem : pItems)
{
if (pItem->CloakState != CloakState::Cloaked || pItem->GetCell()->Sensors_InclHouse(HouseClass::CurrentPlayer->ArrayIndex))
- record[pItem] = 0;
+ {
+ auto coords = pItem->GetCoords();
+ coords.Z = MapClass::Instance->GetCellFloorHeight(coords);
+
+ if (MapClass::Instance->GetCellAt(coords)->ContainsBridge())
+ coords.Z += CellClass::BridgeHeight;
+
+ if (!MapClass::Instance->IsLocationShrouded(coords))
+ record[pItem] = 0;
+ }
}
for (const auto& pSelect : ObjectClass::CurrentObjects())
From 40051d9d40138d06aafe5fb9f44fe4e33f286fec Mon Sep 17 00:00:00 2001
From: CrimRecya <335958461@qq.com>
Date: Mon, 3 Feb 2025 16:58:17 +0800
Subject: [PATCH 11/30] Fix target disguised units
---
src/Commands/DistributionMode.cpp | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/Commands/DistributionMode.cpp b/src/Commands/DistributionMode.cpp
index 014cf2b6c9..545e7de7f8 100644
--- a/src/Commands/DistributionMode.cpp
+++ b/src/Commands/DistributionMode.cpp
@@ -124,11 +124,13 @@ DEFINE_HOOK(0x4AE818, DisplayClass_sub_4AE750_AutoDistribution, 0xA)
const auto range = (2 << mode1);
const auto pItems = Helpers::Alex::getCellSpreadItems(pTarget->Location, range);
std::map record;
+ record[static_cast(pTarget)] = 0;
int current = 1;
for (const auto& pItem : pItems)
{
- if (pItem->CloakState != CloakState::Cloaked || pItem->GetCell()->Sensors_InclHouse(HouseClass::CurrentPlayer->ArrayIndex))
+ if ((pItem->CloakState != CloakState::Cloaked || pItem->GetCell()->Sensors_InclHouse(HouseClass::CurrentPlayer->ArrayIndex))
+ && !pItem->IsDisguisedAs(HouseClass::CurrentPlayer))
{
auto coords = pItem->GetCoords();
coords.Z = MapClass::Instance->GetCellFloorHeight(coords);
From 2e3859421e8a67143fd8be267d91c43016ec9b4b Mon Sep 17 00:00:00 2001
From: CrimRecya <335958461@qq.com>
Date: Mon, 3 Feb 2025 16:59:01 +0800
Subject: [PATCH 12/30] Fix target outside units
---
src/Commands/DistributionMode.cpp | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src/Commands/DistributionMode.cpp b/src/Commands/DistributionMode.cpp
index 545e7de7f8..be5259c5bd 100644
--- a/src/Commands/DistributionMode.cpp
+++ b/src/Commands/DistributionMode.cpp
@@ -133,6 +133,10 @@ DEFINE_HOOK(0x4AE818, DisplayClass_sub_4AE750_AutoDistribution, 0xA)
&& !pItem->IsDisguisedAs(HouseClass::CurrentPlayer))
{
auto coords = pItem->GetCoords();
+
+ if (!MapClass::Instance->IsWithinUsableArea(coords))
+ continue;
+
coords.Z = MapClass::Instance->GetCellFloorHeight(coords);
if (MapClass::Instance->GetCellAt(coords)->ContainsBridge())
From 55723f3e5b84b5396397a20ed4b9d0a473c99fbb Mon Sep 17 00:00:00 2001
From: CrimRecya <335958461@qq.com>
Date: Thu, 13 Feb 2025 17:13:34 +0800
Subject: [PATCH 13/30] Global toggle
---
docs/User-Interface.md | 10 ++++++++--
src/Commands/Commands.cpp | 10 +++++++---
src/Phobos.INI.cpp | 3 +++
src/Phobos.h | 1 +
4 files changed, 19 insertions(+), 5 deletions(-)
diff --git a/docs/User-Interface.md b/docs/User-Interface.md
index 652cbcfb78..5153bf885e 100644
--- a/docs/User-Interface.md
+++ b/docs/User-Interface.md
@@ -329,9 +329,9 @@ ShowFlashOnSelecting=false ; boolean
- Switches on/off [frame by frame mode](Miscellanous.md#frame-step-in).
- For localization add `TXT_FRAME_BY_FRAME` and `TXT_FRAME_BY_FRAME_DESC` into your `.csf` file.
-### `[ ]` Distribution Mode Spread / Filter
+### `[ ]` Distribution Mode Spread / Filter / Enable
-- Change the click action when hold down the specific hotkey.
+- Change the click action when hold down the specific hotkey if enabled `AllowDistributionCommand`.
- When the range is 0, it is the original default behavior of the game. The range can be adjusted to 4, 8 or 16 cells by shortcut keys.
- The targets within the range will be allocated equally to the selected technos. Only when the behavior to be performed by the current techno is the same as that displayed by the mouse will it be allocated. Otherwise, it will return to the original default behavior of the game (it will not be effective for technos in the air). This will display a range ring.
- When the filter is `None`, it is the default behavior of the game. If the range is not zero at this time, a green ring will be displayed. You can adjust the filter mode to:
@@ -340,6 +340,12 @@ ShowFlashOnSelecting=false ; boolean
- `Name` - on the basis of `Type`, only targets of the same name (or with the same `GroupAs`) will be selected among the targets allocated in the range. At this time, a red ring will be displayed.
- For localization add `TXT_DISTR_SPREAD`, `TXT_DISTR_FILTER`, `TXT_DISTR_HOLDDOWN`, `TXT_DISTR_SPREAD_DESC`, `TXT_DISTR_FILTER_DESC` and `TXT_DISTR_HOLDDOWN_DESC` into your `.csf` file.
+In `rulesmd.ini`:
+```ini
+[GlobalControls]
+AllowDistributionCommand=false ; boolean
+```
+
## Loading screen
- PCX files can now be used as loadscreen images.
diff --git a/src/Commands/Commands.cpp b/src/Commands/Commands.cpp
index 885c5b79bd..c07b9ae75d 100644
--- a/src/Commands/Commands.cpp
+++ b/src/Commands/Commands.cpp
@@ -20,9 +20,13 @@ DEFINE_HOOK(0x533066, CommandClassCallback_Register, 0x6)
MakeCommand();
MakeCommand();
MakeCommand();
- MakeCommand();
- MakeCommand();
- MakeCommand();
+
+ if (Phobos::Config::AllowDistributionCommand)
+ {
+ MakeCommand();
+ MakeCommand();
+ MakeCommand();
+ }
if (Phobos::Config::DevelopmentCommands)
{
diff --git a/src/Phobos.INI.cpp b/src/Phobos.INI.cpp
index 247eb46fee..92aaa12e90 100644
--- a/src/Phobos.INI.cpp
+++ b/src/Phobos.INI.cpp
@@ -57,6 +57,7 @@ bool Phobos::Config::ShowWeedsCounter = false;
bool Phobos::Config::HideLightFlashEffects = true;
bool Phobos::Config::ShowFlashOnSelecting = false;
bool Phobos::Config::UnitPowerDrain = false;
+bool Phobos::Config::AllowDistributionCommand = false;
bool Phobos::Misc::CustomGS = false;
int Phobos::Misc::CustomGS_ChangeInterval[7] = { -1, -1, -1, -1, -1, -1, -1 };
@@ -222,6 +223,8 @@ DEFINE_HOOK(0x52D21F, InitRules_ThingsThatShouldntBeSerailized, 0x6)
#endif
Phobos::Config::ShowPlanningPath = pINI_RULESMD->ReadBool("GlobalControls", "DebugPlanningPaths", Phobos::Config::ShowPlanningPath);
+ Phobos::Config::AllowDistributionCommand = pINI_RULESMD->ReadBool("GlobalControls", "AllowDistributionCommand", Phobos::Config::AllowDistributionCommand);
+
return 0;
}
diff --git a/src/Phobos.h b/src/Phobos.h
index da85fd883b..df6d58b4fd 100644
--- a/src/Phobos.h
+++ b/src/Phobos.h
@@ -92,6 +92,7 @@ class Phobos
static bool HideLightFlashEffects;
static bool ShowFlashOnSelecting;
static bool UnitPowerDrain;
+ static bool AllowDistributionCommand;
};
class Misc
From 1c47634b4f9496c8d343fd15d81cf257de9eb28d Mon Sep 17 00:00:00 2001
From: CrimRecya <335958461@qq.com>
Date: Thu, 6 Mar 2025 17:06:16 +0800
Subject: [PATCH 14/30] Message, sound and scroll action
---
docs/User-Interface.md | 18 +++++-
src/Commands/Commands.cpp | 50 ++++++++++++++--
src/Commands/DistributionMode.cpp | 99 ++++++++++++++++++++-----------
src/Commands/DistributionMode.h | 15 ++---
src/Ext/Rules/Body.cpp | 7 +++
src/Ext/Rules/Body.h | 7 +++
src/Phobos.INI.cpp | 7 +++
src/Phobos.h | 2 +
8 files changed, 158 insertions(+), 47 deletions(-)
diff --git a/docs/User-Interface.md b/docs/User-Interface.md
index 1a92f08950..219ebe14ea 100644
--- a/docs/User-Interface.md
+++ b/docs/User-Interface.md
@@ -349,18 +349,30 @@ ShowFlashOnSelecting=false ; boolean
### `[ ]` Distribution Mode Spread / Filter / Enable
- Change the click action when hold down the specific hotkey if enabled `AllowDistributionCommand`.
- - When the range is 0, it is the original default behavior of the game. The range can be adjusted to 4, 8 or 16 cells by shortcut keys.
+ - When the range is 0, it is the original default behavior of the game. The range can be adjusted to 4, 8 or 16 cells by another shortcut key. Of course, you can also adjust this by using the mouse wheel while holding down the specific hotkey.
- The targets within the range will be allocated equally to the selected technos. Only when the behavior to be performed by the current techno is the same as that displayed by the mouse will it be allocated. Otherwise, it will return to the original default behavior of the game (it will not be effective for technos in the air). This will display a range ring.
- When the filter is `None`, it is the default behavior of the game. If the range is not zero at this time, a green ring will be displayed. You can adjust the filter mode to:
- `Auto` - if the behavior to be executed by the current techno is different from the behavior displayed by the mouse, and the behavior to be executed will make the techno move near the target, the behavior will be replaced with area guard. At this time, a blue ring will be displayed.
- `Type` - on the basis of `Auto`, only targets of the same type (like infantries, vehicles or buildings) will be selected among the targets allocated in the range. At this time, a yellow ring will be displayed.
- `Name` - on the basis of `Type`, only targets of the same name (or with the same `GroupAs`) will be selected among the targets allocated in the range. At this time, a red ring will be displayed.
-- For localization add `TXT_DISTR_SPREAD`, `TXT_DISTR_FILTER`, `TXT_DISTR_HOLDDOWN`, `TXT_DISTR_SPREAD_DESC`, `TXT_DISTR_FILTER_DESC` and `TXT_DISTR_HOLDDOWN_DESC` into your `.csf` file.
+- For localization add `TXT_DISTR_SPREAD`, `TXT_DISTR_FILTER`, `TXT_DISTR_HOLDDOWN`, `TXT_DISTR_SPREAD_DESC`, `TXT_DISTR_FILTER_DESC`, `TXT_DISTR_HOLDDOWN_DESC`, `MSG:DistributionModeOn`, `MSG:DistributionModeOff` into your `.csf` file.
In `rulesmd.ini`:
```ini
[GlobalControls]
-AllowDistributionCommand=false ; boolean
+AllowDistributionCommand=false ; boolean
+
+[AudioVisual]
+StartDistributionModeSound= ; sound entry
+EndDistributionModeSound= ; sound entry
+AddDistributionModeCommandSound= ; sound entry
+```
+
+In `ra2md.ini`:
+```ini
+[Phobos]
+DefaultDistributionSpreadMode=2 ; integer, 0 - r=0 , 1 - r=4 , 2 - r=8 , 3 - r=16
+DefaultDistributionFilterMode=2 ; integer, 0 - None , 1 - Auto , 2 - Type , 3 - Name
```
## Loading screen
diff --git a/src/Commands/Commands.cpp b/src/Commands/Commands.cpp
index c07b9ae75d..94844aa3bb 100644
--- a/src/Commands/Commands.cpp
+++ b/src/Commands/Commands.cpp
@@ -1,4 +1,3 @@
-#include
#include "Commands.h"
#include "ObjectInfo.h"
@@ -12,6 +11,10 @@
#include "SaveVariablesToFile.h"
#include "DistributionMode.h"
+#include
+
+#include
+
DEFINE_HOOK(0x533066, CommandClassCallback_Register, 0x6)
{
// Load it after Ares'
@@ -23,9 +26,9 @@ DEFINE_HOOK(0x533066, CommandClassCallback_Register, 0x6)
if (Phobos::Config::AllowDistributionCommand)
{
- MakeCommand();
- MakeCommand();
- MakeCommand();
+ MakeCommand();
+ MakeCommand();
+ MakeCommand();
}
if (Phobos::Config::DevelopmentCommands)
@@ -44,3 +47,42 @@ DEFINE_HOOK(0x533066, CommandClassCallback_Register, 0x6)
return 0;
}
+
+static void MouseWheelDownCommand()
+{
+// Debug::LogAndMessage("[Frame: %d] Mouse Wheel Down", Unsorted::CurrentFrame());
+
+ if (DistributionModeHoldDownCommandClass::Enabled)
+ DistributionModeHoldDownCommandClass::DistributionSpreadModeReduce();
+}
+
+static void MouseWheelUpCommand()
+{
+// Debug::LogAndMessage("[Frame: %d] Mouse Wheel Up", Unsorted::CurrentFrame());
+
+ if (DistributionModeHoldDownCommandClass::Enabled)
+ DistributionModeHoldDownCommandClass::DistributionSpreadModeExpand();
+}
+
+DEFINE_HOOK(0x777998, Game_WndProc_ScrollMouseWheel, 0x6)
+{
+ GET(const WPARAM, WParam, ECX);
+
+ if (WParam & 0x80000000u)
+ MouseWheelDownCommand();
+ else
+ MouseWheelUpCommand();
+
+ return 0;
+}
+
+static inline bool CheckSkipScrollSidebar()
+{
+ return DistributionModeHoldDownCommandClass::Enabled;
+}
+
+DEFINE_HOOK(0x533F50, Game_ScrollSidebar_Skip, 0x5)
+{
+ enum { SkipScrollSidebar = 0x533FC3 };
+ return CheckSkipScrollSidebar() ? SkipScrollSidebar : 0;
+}
diff --git a/src/Commands/DistributionMode.cpp b/src/Commands/DistributionMode.cpp
index be5259c5bd..7c13eb8d4f 100644
--- a/src/Commands/DistributionMode.cpp
+++ b/src/Commands/DistributionMode.cpp
@@ -6,94 +6,126 @@
#include
-int DistributionMode1CommandClass::Mode = 0;
-int DistributionMode2CommandClass::Mode = 0;
-bool DistributionMode3CommandClass::Enabled = false;
-int DistributionMode3CommandClass::ShowTime = 0;
+bool DistributionModeHoldDownCommandClass::Enabled = false;
+bool DistributionModeHoldDownCommandClass::OnMessageShowed = false;
+bool DistributionModeHoldDownCommandClass::OffMessageShowed = false;
+int DistributionModeHoldDownCommandClass::ShowTime = 0;
-const char* DistributionMode1CommandClass::GetName() const
+const char* DistributionModeSpreadCommandClass::GetName() const
{
return "Distribution Mode Spread";
}
-const wchar_t* DistributionMode1CommandClass::GetUIName() const
+const wchar_t* DistributionModeSpreadCommandClass::GetUIName() const
{
return GeneralUtils::LoadStringUnlessMissing("TXT_DISTR_SPREAD", L"Distribution spread");
}
-const wchar_t* DistributionMode1CommandClass::GetUICategory() const
+const wchar_t* DistributionModeSpreadCommandClass::GetUICategory() const
{
return CATEGORY_CONTROL;
}
-const wchar_t* DistributionMode1CommandClass::GetUIDescription() const
+const wchar_t* DistributionModeSpreadCommandClass::GetUIDescription() const
{
return GeneralUtils::LoadStringUnlessMissing("TXT_DISTR_SPREAD_DESC", L"Automatically and averagely select similar targets around the original target. This is for changing the search range");
}
-void DistributionMode1CommandClass::Execute(WWKey eInput) const
+void DistributionModeSpreadCommandClass::Execute(WWKey eInput) const
{
- DistributionMode1CommandClass::Mode = ((DistributionMode1CommandClass::Mode + 1) & 3);
- DistributionMode3CommandClass::ShowTime = SystemTimer::GetTime();
+ Phobos::Config::DistributionSpreadMode = ((Phobos::Config::DistributionSpreadMode + 1) & 3);
+ DistributionModeHoldDownCommandClass::ShowTime = SystemTimer::GetTime();
}
-const char* DistributionMode2CommandClass::GetName() const
+const char* DistributionModeFilterCommandClass::GetName() const
{
return "Distribution Mode Filter";
}
-const wchar_t* DistributionMode2CommandClass::GetUIName() const
+const wchar_t* DistributionModeFilterCommandClass::GetUIName() const
{
return GeneralUtils::LoadStringUnlessMissing("TXT_DISTR_FILTER", L"Distribution filter");
}
-const wchar_t* DistributionMode2CommandClass::GetUICategory() const
+const wchar_t* DistributionModeFilterCommandClass::GetUICategory() const
{
return CATEGORY_CONTROL;
}
-const wchar_t* DistributionMode2CommandClass::GetUIDescription() const
+const wchar_t* DistributionModeFilterCommandClass::GetUIDescription() const
{
return GeneralUtils::LoadStringUnlessMissing("TXT_DISTR_FILTER_DESC", L"Automatically and averagely select similar targets around the original target. This is for changing the filter criteria");
}
-void DistributionMode2CommandClass::Execute(WWKey eInput) const
+void DistributionModeFilterCommandClass::Execute(WWKey eInput) const
{
- DistributionMode2CommandClass::Mode = ((DistributionMode2CommandClass::Mode + 1) & 3);
- DistributionMode3CommandClass::ShowTime = SystemTimer::GetTime();
+ Phobos::Config::DistributionFilterMode = ((Phobos::Config::DistributionFilterMode + 1) & 3);
+ DistributionModeHoldDownCommandClass::ShowTime = SystemTimer::GetTime();
}
-const char* DistributionMode3CommandClass::GetName() const
+const char* DistributionModeHoldDownCommandClass::GetName() const
{
return "Distribution Mode Hold Down";
}
-const wchar_t* DistributionMode3CommandClass::GetUIName() const
+const wchar_t* DistributionModeHoldDownCommandClass::GetUIName() const
{
return GeneralUtils::LoadStringUnlessMissing("TXT_DISTR_HOLDDOWN", L"Distribution hold down");
}
-const wchar_t* DistributionMode3CommandClass::GetUICategory() const
+const wchar_t* DistributionModeHoldDownCommandClass::GetUICategory() const
{
return CATEGORY_CONTROL;
}
-const wchar_t* DistributionMode3CommandClass::GetUIDescription() const
+const wchar_t* DistributionModeHoldDownCommandClass::GetUIDescription() const
{
return GeneralUtils::LoadStringUnlessMissing("TXT_DISTR_HOLDDOWN_DESC", L"Automatically and averagely select similar targets around the original target. This is for holding down to toggle on/off");
}
-bool DistributionMode3CommandClass::ExtraTriggerCondition(WWKey eInput) const
+bool DistributionModeHoldDownCommandClass::ExtraTriggerCondition(WWKey eInput) const
{
return true;
}
-void DistributionMode3CommandClass::Execute(WWKey eInput) const
+void DistributionModeHoldDownCommandClass::Execute(WWKey eInput) const
{
if (eInput & WWKey::Release)
- DistributionMode3CommandClass::Enabled = false;
- else
- DistributionMode3CommandClass::Enabled = true;
+ {
+ DistributionModeHoldDownCommandClass::Enabled = false;
+
+ if (HouseClass::IsCurrentPlayerObserver() || SessionClass::Instance->MultiplayerObserver)
+ return;
+
+ VocClass::PlayGlobal(RulesExt::Global()->EndDistributionModeSound, 0x2000, 1.0);
+
+ if (!DistributionModeHoldDownCommandClass::OffMessageShowed)
+ {
+ DistributionModeHoldDownCommandClass::OffMessageShowed = true;
+ MessageListClass::Instance->PrintMessage(GeneralUtils::LoadStringUnlessMissing("MSG:DistributionModeOff", L"Distribution mode unabled."), RulesClass::Instance->MessageDelay, HouseClass::CurrentPlayer->ColorSchemeIndex, true);
+ }
+ }
+ else if (!HouseClass::IsCurrentPlayerObserver() && !SessionClass::Instance->MultiplayerObserver)
+ {
+ DistributionModeHoldDownCommandClass::Enabled = true;
+ VocClass::PlayGlobal(RulesExt::Global()->StartDistributionModeSound, 0x2000, 1.0);
+
+ if (!DistributionModeHoldDownCommandClass::OnMessageShowed)
+ {
+ DistributionModeHoldDownCommandClass::OnMessageShowed = true;
+ MessageListClass::Instance->PrintMessage(GeneralUtils::LoadStringUnlessMissing("MSG:DistributionModeOn", L"Distribution mode enabled."), RulesClass::Instance->MessageDelay, HouseClass::CurrentPlayer->ColorSchemeIndex, true);
+ }
+ }
+}
+
+void DistributionModeHoldDownCommandClass::DistributionSpreadModeExpand()
+{
+ Phobos::Config::DistributionSpreadMode = std::min(3, Phobos::Config::DistributionSpreadMode + 1);
+}
+
+void DistributionModeHoldDownCommandClass::DistributionSpreadModeReduce()
+{
+ Phobos::Config::DistributionSpreadMode = std::max(0, Phobos::Config::DistributionSpreadMode - 1);
}
DEFINE_HOOK(0x4AE818, DisplayClass_sub_4AE750_AutoDistribution, 0xA)
@@ -107,13 +139,14 @@ DEFINE_HOOK(0x4AE818, DisplayClass_sub_4AE750_AutoDistribution, 0xA)
if (count > 0)
{
- const auto mode1 = DistributionMode1CommandClass::Mode;
- const auto mode2 = DistributionMode2CommandClass::Mode;
+ const auto mode1 = Phobos::Config::DistributionSpreadMode;
+ const auto mode2 = Phobos::Config::DistributionFilterMode;
// Distribution mode main
- if (DistributionMode3CommandClass::Enabled && mode1 && count > 1 && mouseAction != Action::NoMove && !PlanningNodeClass::PlanningModeActive
+ if (DistributionModeHoldDownCommandClass::Enabled && mode1 && count > 1 && mouseAction != Action::NoMove && !PlanningNodeClass::PlanningModeActive
&& (pTarget->AbstractFlags & AbstractFlags::Techno) != AbstractFlags::None && !pTarget->IsInAir())
{
+ VocClass::PlayGlobal(RulesExt::Global()->AddDistributionModeCommandSound, 0x2000, 1.0);
const auto pSpecial = HouseClass::FindSpecial();
const auto pCivilian = HouseClass::FindCivilianSide();
const auto pNeutral = HouseClass::FindNeutral();
@@ -218,11 +251,11 @@ DEFINE_HOOK(0x4AE818, DisplayClass_sub_4AE750_AutoDistribution, 0xA)
DEFINE_HOOK(0x6DBE74, TacticalClass_DrawAllRadialIndicators_DrawDistributionRange, 0x7)
{
- if (!DistributionMode3CommandClass::Enabled && SystemTimer::GetTime() - DistributionMode3CommandClass::ShowTime > 30)
+ if (!DistributionModeHoldDownCommandClass::Enabled && SystemTimer::GetTime() - DistributionModeHoldDownCommandClass::ShowTime > 30)
return 0;
- const auto mode1 = DistributionMode1CommandClass::Mode;
- const auto mode2 = DistributionMode2CommandClass::Mode;
+ const auto mode1 = Phobos::Config::DistributionSpreadMode;
+ const auto mode2 = Phobos::Config::DistributionFilterMode;
if (mode1 || mode2)
{
diff --git a/src/Commands/DistributionMode.h b/src/Commands/DistributionMode.h
index 4002422af0..a90ed3db8e 100644
--- a/src/Commands/DistributionMode.h
+++ b/src/Commands/DistributionMode.h
@@ -2,11 +2,9 @@
#include "Commands.h"
-class DistributionMode1CommandClass : public CommandClass
+class DistributionModeSpreadCommandClass : public CommandClass
{
public:
- static int Mode;
-
virtual const char* GetName() const override;
virtual const wchar_t* GetUIName() const override;
virtual const wchar_t* GetUICategory() const override;
@@ -14,11 +12,9 @@ class DistributionMode1CommandClass : public CommandClass
virtual void Execute(WWKey eInput) const override;
};
-class DistributionMode2CommandClass : public CommandClass
+class DistributionModeFilterCommandClass : public CommandClass
{
public:
- static int Mode;
-
virtual const char* GetName() const override;
virtual const wchar_t* GetUIName() const override;
virtual const wchar_t* GetUICategory() const override;
@@ -26,10 +22,12 @@ class DistributionMode2CommandClass : public CommandClass
virtual void Execute(WWKey eInput) const override;
};
-class DistributionMode3CommandClass : public CommandClass
+class DistributionModeHoldDownCommandClass : public CommandClass
{
public:
static bool Enabled;
+ static bool OnMessageShowed;
+ static bool OffMessageShowed;
static int ShowTime;
virtual const char* GetName() const override;
@@ -38,4 +36,7 @@ class DistributionMode3CommandClass : public CommandClass
virtual const wchar_t* GetUIDescription() const override;
virtual bool ExtraTriggerCondition(WWKey eInput) const override;
virtual void Execute(WWKey eInput) const override;
+
+ static void DistributionSpreadModeExpand();
+ static void DistributionSpreadModeReduce();
};
diff --git a/src/Ext/Rules/Body.cpp b/src/Ext/Rules/Body.cpp
index 38c5130c0c..33e60e5894 100644
--- a/src/Ext/Rules/Body.cpp
+++ b/src/Ext/Rules/Body.cpp
@@ -211,6 +211,10 @@ void RulesExt::ExtData::LoadBeforeTypeData(RulesClass* pThis, CCINIClass* pINI)
this->CombatAlert_UseAttackVoice.Read(exINI, GameStrings::AudioVisual, "CombatAlert.UseAttackVoice");
this->CombatAlert_UseEVA.Read(exINI, GameStrings::AudioVisual, "CombatAlert.UseEVA");
+ this->StartDistributionModeSound.Read(exINI, GameStrings::AudioVisual, "StartDistributionModeSound");
+ this->EndDistributionModeSound.Read(exINI, GameStrings::AudioVisual, "EndDistributionModeSound");
+ this->AddDistributionModeCommandSound.Read(exINI, GameStrings::AudioVisual, "AddDistributionModeCommandSound");
+
this->ReplaceVoxelLightSources();
this->UseFixedVoxelLighting.Read(exINI, GameStrings::AudioVisual, "UseFixedVoxelLighting");
@@ -414,6 +418,9 @@ void RulesExt::ExtData::Serialize(T& Stm)
.Process(this->CombatAlert_UseFeedbackVoice)
.Process(this->CombatAlert_UseAttackVoice)
.Process(this->CombatAlert_UseEVA)
+ .Process(this->StartDistributionModeSound)
+ .Process(this->EndDistributionModeSound)
+ .Process(this->AddDistributionModeCommandSound)
.Process(this->UseFixedVoxelLighting)
.Process(this->GatherWhenMCVDeploy)
.Process(this->AIFireSale)
diff --git a/src/Ext/Rules/Body.h b/src/Ext/Rules/Body.h
index 7f5fc6f240..e16ee234af 100644
--- a/src/Ext/Rules/Body.h
+++ b/src/Ext/Rules/Body.h
@@ -168,6 +168,10 @@ class RulesExt
Valueable CombatAlert_UseAttackVoice;
Valueable CombatAlert_UseEVA;
+ ValueableIdx StartDistributionModeSound;
+ ValueableIdx EndDistributionModeSound;
+ ValueableIdx AddDistributionModeCommandSound;
+
Nullable> VoxelLightSource;
// Nullable> VoxelShadowLightSource;
Valueable UseFixedVoxelLighting;
@@ -311,6 +315,9 @@ class RulesExt
, CombatAlert_UseFeedbackVoice { true }
, CombatAlert_UseAttackVoice { true }
, CombatAlert_UseEVA { true }
+ , StartDistributionModeSound { -1 }
+ , EndDistributionModeSound { -1 }
+ , AddDistributionModeCommandSound { -1 }
, UseFixedVoxelLighting { false }
, GatherWhenMCVDeploy { true }
, AIFireSale { true }
diff --git a/src/Phobos.INI.cpp b/src/Phobos.INI.cpp
index 92aaa12e90..847248204a 100644
--- a/src/Phobos.INI.cpp
+++ b/src/Phobos.INI.cpp
@@ -58,6 +58,8 @@ bool Phobos::Config::HideLightFlashEffects = true;
bool Phobos::Config::ShowFlashOnSelecting = false;
bool Phobos::Config::UnitPowerDrain = false;
bool Phobos::Config::AllowDistributionCommand = false;
+int Phobos::Config::DistributionSpreadMode = 2;
+int Phobos::Config::DistributionFilterMode = 2;
bool Phobos::Misc::CustomGS = false;
int Phobos::Misc::CustomGS_ChangeInterval[7] = { -1, -1, -1, -1, -1, -1, -1 };
@@ -81,6 +83,11 @@ DEFINE_HOOK(0x5FACDF, OptionsClass_LoadSettings_LoadPhobosSettings, 0x5)
Phobos::Config::HideLightFlashEffects = CCINIClass::INI_RA2MD->ReadBool("Phobos", "HideLightFlashEffects", false);
Phobos::Config::ShowFlashOnSelecting = CCINIClass::INI_RA2MD->ReadBool("Phobos", "ShowFlashOnSelecting", false);
+ Phobos::Config::DistributionSpreadMode = CCINIClass::INI_RA2MD->ReadInteger("Phobos", "DefaultDistributionSpreadMode", 2);
+ Phobos::Config::DistributionSpreadMode = std::clamp(Phobos::Config::DistributionSpreadMode, 0, 3);
+ Phobos::Config::DistributionFilterMode = CCINIClass::INI_RA2MD->ReadInteger("Phobos", "DefaultDistributionFilterMode", 2);
+ Phobos::Config::DistributionFilterMode = std::clamp(Phobos::Config::DistributionFilterMode, 0, 3);
+
// Custom game speeds, 6 - i so that GS6 is index 0, just like in the engine
Phobos::Config::CampaignDefaultGameSpeed = 6 - CCINIClass::INI_RA2MD->ReadInteger("Phobos", "CampaignDefaultGameSpeed", 4);
if (Phobos::Config::CampaignDefaultGameSpeed > 6 || Phobos::Config::CampaignDefaultGameSpeed < 0)
diff --git a/src/Phobos.h b/src/Phobos.h
index df6d58b4fd..3672b68ccf 100644
--- a/src/Phobos.h
+++ b/src/Phobos.h
@@ -93,6 +93,8 @@ class Phobos
static bool ShowFlashOnSelecting;
static bool UnitPowerDrain;
static bool AllowDistributionCommand;
+ static int DistributionSpreadMode;
+ static int DistributionFilterMode;
};
class Misc
From 6ce7407e43b49f2bd876cd9f4a6fe481893efec6 Mon Sep 17 00:00:00 2001
From: CrimRecya <335958461@qq.com>
Date: Tue, 25 Mar 2025 22:02:56 +0800
Subject: [PATCH 15/30] Fix merge
---
src/Commands/DistributionMode.cpp | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/src/Commands/DistributionMode.cpp b/src/Commands/DistributionMode.cpp
index 7c13eb8d4f..4da7a9d3c4 100644
--- a/src/Commands/DistributionMode.cpp
+++ b/src/Commands/DistributionMode.cpp
@@ -94,7 +94,7 @@ void DistributionModeHoldDownCommandClass::Execute(WWKey eInput) const
{
DistributionModeHoldDownCommandClass::Enabled = false;
- if (HouseClass::IsCurrentPlayerObserver() || SessionClass::Instance->MultiplayerObserver)
+ if (HouseClass::IsCurrentPlayerObserver() || SessionClass::Instance.MultiplayerObserver)
return;
VocClass::PlayGlobal(RulesExt::Global()->EndDistributionModeSound, 0x2000, 1.0);
@@ -102,10 +102,10 @@ void DistributionModeHoldDownCommandClass::Execute(WWKey eInput) const
if (!DistributionModeHoldDownCommandClass::OffMessageShowed)
{
DistributionModeHoldDownCommandClass::OffMessageShowed = true;
- MessageListClass::Instance->PrintMessage(GeneralUtils::LoadStringUnlessMissing("MSG:DistributionModeOff", L"Distribution mode unabled."), RulesClass::Instance->MessageDelay, HouseClass::CurrentPlayer->ColorSchemeIndex, true);
+ MessageListClass::Instance.PrintMessage(GeneralUtils::LoadStringUnlessMissing("MSG:DistributionModeOff", L"Distribution mode unabled."), RulesClass::Instance->MessageDelay, HouseClass::CurrentPlayer->ColorSchemeIndex, true);
}
}
- else if (!HouseClass::IsCurrentPlayerObserver() && !SessionClass::Instance->MultiplayerObserver)
+ else if (!HouseClass::IsCurrentPlayerObserver() && !SessionClass::Instance.MultiplayerObserver)
{
DistributionModeHoldDownCommandClass::Enabled = true;
VocClass::PlayGlobal(RulesExt::Global()->StartDistributionModeSound, 0x2000, 1.0);
@@ -113,7 +113,7 @@ void DistributionModeHoldDownCommandClass::Execute(WWKey eInput) const
if (!DistributionModeHoldDownCommandClass::OnMessageShowed)
{
DistributionModeHoldDownCommandClass::OnMessageShowed = true;
- MessageListClass::Instance->PrintMessage(GeneralUtils::LoadStringUnlessMissing("MSG:DistributionModeOn", L"Distribution mode enabled."), RulesClass::Instance->MessageDelay, HouseClass::CurrentPlayer->ColorSchemeIndex, true);
+ MessageListClass::Instance.PrintMessage(GeneralUtils::LoadStringUnlessMissing("MSG:DistributionModeOn", L"Distribution mode enabled."), RulesClass::Instance->MessageDelay, HouseClass::CurrentPlayer->ColorSchemeIndex, true);
}
}
}
@@ -135,7 +135,7 @@ DEFINE_HOOK(0x4AE818, DisplayClass_sub_4AE750_AutoDistribution, 0xA)
GET(ObjectClass* const, pTarget, EBP);
GET_STACK(const Action, mouseAction, STACK_OFFSET(0x20, 0xC));
- const auto count = ObjectClass::CurrentObjects->Count;
+ const auto count = ObjectClass::CurrentObjects.Count;
if (count > 0)
{
@@ -167,20 +167,20 @@ DEFINE_HOOK(0x4AE818, DisplayClass_sub_4AE750_AutoDistribution, 0xA)
{
auto coords = pItem->GetCoords();
- if (!MapClass::Instance->IsWithinUsableArea(coords))
+ if (!MapClass::Instance.IsWithinUsableArea(coords))
continue;
- coords.Z = MapClass::Instance->GetCellFloorHeight(coords);
+ coords.Z = MapClass::Instance.GetCellFloorHeight(coords);
- if (MapClass::Instance->GetCellAt(coords)->ContainsBridge())
+ if (MapClass::Instance.GetCellAt(coords)->ContainsBridge())
coords.Z += CellClass::BridgeHeight;
- if (!MapClass::Instance->IsLocationShrouded(coords))
+ if (!MapClass::Instance.IsLocationShrouded(coords))
record[pItem] = 0;
}
}
- for (const auto& pSelect : ObjectClass::CurrentObjects())
+ for (const auto& pSelect : ObjectClass::CurrentObjects)
{
TechnoClass* pCanTarget = nullptr;
TechnoClass* pNewTarget = nullptr;
@@ -232,7 +232,7 @@ DEFINE_HOOK(0x4AE818, DisplayClass_sub_4AE750_AutoDistribution, 0xA)
}
else // Vanilla
{
- for (const auto& pSelect : ObjectClass::CurrentObjects())
+ for (const auto& pSelect : ObjectClass::CurrentObjects)
{
const auto currentAction = pSelect->MouseOverObject(pTarget);
@@ -259,7 +259,7 @@ DEFINE_HOOK(0x6DBE74, TacticalClass_DrawAllRadialIndicators_DrawDistributionRang
if (mode1 || mode2)
{
- const auto pCell = MapClass::Instance->GetCellAt(DisplayClass::Instance->CurrentFoundation_CenterCell);
+ const auto pCell = MapClass::Instance.GetCellAt(DisplayClass::Instance.CurrentFoundation_CenterCell);
const auto color = ((mode2 > 1)
? ((mode2 == 3) ? ColorStruct { 255, 0, 0 } : ColorStruct { 200, 200, 0 })
: (mode2 == 1) ? ColorStruct { 0, 100, 255 } : ColorStruct { 0, 255, 50 });
From 685d456fc0ee409098e9f68ca89ce5445ace605b Mon Sep 17 00:00:00 2001
From: CrimRecya <335958461@qq.com>
Date: Tue, 25 Mar 2025 22:03:28 +0800
Subject: [PATCH 16/30] Low distance first
---
src/Commands/DistributionMode.cpp | 58 +++++++++++++++++++------------
1 file changed, 36 insertions(+), 22 deletions(-)
diff --git a/src/Commands/DistributionMode.cpp b/src/Commands/DistributionMode.cpp
index 4da7a9d3c4..c41b0df7a7 100644
--- a/src/Commands/DistributionMode.cpp
+++ b/src/Commands/DistributionMode.cpp
@@ -155,15 +155,19 @@ DEFINE_HOOK(0x4AE818, DisplayClass_sub_4AE750_AutoDistribution, 0xA)
const bool targetIsNeutral = pTargetHouse == pSpecial || pTargetHouse == pCivilian || pTargetHouse == pNeutral;
const auto range = (2 << mode1);
- const auto pItems = Helpers::Alex::getCellSpreadItems(pTarget->Location, range);
- std::map record;
- record[static_cast(pTarget)] = 0;
+ const auto center = pTarget->GetCoords();
+ const auto pItems = Helpers::Alex::getCellSpreadItems(center, range);
+
+ std::vector> record;
+ const auto maxSize = pItems.size();
+ record.reserve(maxSize);
+
int current = 1;
for (const auto& pItem : pItems)
{
- if ((pItem->CloakState != CloakState::Cloaked || pItem->GetCell()->Sensors_InclHouse(HouseClass::CurrentPlayer->ArrayIndex))
- && !pItem->IsDisguisedAs(HouseClass::CurrentPlayer))
+ if (!pItem->IsDisguisedAs(HouseClass::CurrentPlayer)
+ && (pItem->CloakState != CloakState::Cloaked || pItem->GetCell()->Sensors_InclHouse(HouseClass::CurrentPlayer->ArrayIndex)))
{
auto coords = pItem->GetCoords();
@@ -176,45 +180,55 @@ DEFINE_HOOK(0x4AE818, DisplayClass_sub_4AE750_AutoDistribution, 0xA)
coords.Z += CellClass::BridgeHeight;
if (!MapClass::Instance.IsLocationShrouded(coords))
- record[pItem] = 0;
+ record.emplace_back(pItem, 0);
}
}
+ const auto recordSize = record.size();
+ std::sort(&record[0], &record[recordSize],[¢er](const auto& pairA, const auto& pairB)
+ {
+ const auto coordsA = pairA.first->GetCoords();
+ const auto distanceA = Point2D{coordsA.X, coordsA.Y}.DistanceFromSquared(Point2D{center.X, center.Y});
+ const auto coordsB = pairB.first->GetCoords();
+ const auto distanceB = Point2D{coordsB.X, coordsB.Y}.DistanceFromSquared(Point2D{center.X, center.Y});
+ return distanceA < distanceB;
+ });
+
for (const auto& pSelect : ObjectClass::CurrentObjects)
{
- TechnoClass* pCanTarget = nullptr;
- TechnoClass* pNewTarget = nullptr;
+ size_t canTargetIndex = maxSize;
+ size_t newTargetIndex = maxSize;
- for (const auto& [pItem, num] : record)
+ for (size_t i = 0; i < recordSize; ++i)
{
- if (pSelect->MouseOverObject(pItem) == mouseAction && (targetIsNeutral || (pItem->Owner != pSpecial && pItem->Owner != pCivilian && pItem->Owner != pNeutral))
+ const auto& [pItem, num] = record[i];
+
+ if (pSelect->MouseOverObject(pItem) == mouseAction
+ && (targetIsNeutral || (pItem->Owner != pSpecial && pItem->Owner != pCivilian && pItem->Owner != pNeutral))
&& (mode2 < 2 || (pItem->WhatAmI() == pTarget->WhatAmI()
- && (mode2 < 3 || TechnoTypeExt::GetSelectionGroupID(pItem->GetTechnoType()) == TechnoTypeExt::GetSelectionGroupID(pTarget->GetTechnoType())))))
+ && (mode2 < 3 || TechnoTypeExt::GetSelectionGroupID(pItem->GetTechnoType()) == TechnoTypeExt::GetSelectionGroupID(pTarget->GetTechnoType())))))
{
- pCanTarget = pItem;
+ canTargetIndex = i;
if (num < current)
{
- pNewTarget = pCanTarget;
+ newTargetIndex = i;
break;
}
}
}
- if (!pNewTarget)
+ if (newTargetIndex == maxSize && canTargetIndex != maxSize)
{
- if (pCanTarget)
- {
- ++current;
- pNewTarget = pCanTarget;
- }
+ ++current;
+ newTargetIndex = canTargetIndex;
}
- if (pNewTarget)
+ if (newTargetIndex != maxSize)
{
- if (record.contains(pNewTarget))
- ++record[pNewTarget];
+ auto& [pNewTarget, recordCount] = record[newTargetIndex];
+ ++recordCount;
pSelect->ObjectClickedAction(mouseAction, pNewTarget, false);
}
else
From 1bb257de7e73528ebe1c0cdd7f9179e61af56ab0 Mon Sep 17 00:00:00 2001
From: CrimRecya <335958461@qq.com>
Date: Tue, 25 Mar 2025 22:11:25 +0800
Subject: [PATCH 17/30] ...
---
src/Phobos.INI.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/Phobos.INI.cpp b/src/Phobos.INI.cpp
index 3f41fb8249..a326f40592 100644
--- a/src/Phobos.INI.cpp
+++ b/src/Phobos.INI.cpp
@@ -83,9 +83,9 @@ DEFINE_HOOK(0x5FACDF, OptionsClass_LoadSettings_LoadPhobosSettings, 0x5)
Phobos::Config::HideLightFlashEffects = CCINIClass::INI_RA2MD.ReadBool("Phobos", "HideLightFlashEffects", false);
Phobos::Config::ShowFlashOnSelecting = CCINIClass::INI_RA2MD.ReadBool("Phobos", "ShowFlashOnSelecting", false);
- Phobos::Config::DistributionSpreadMode = CCINIClass::INI_RA2MD->ReadInteger("Phobos", "DefaultDistributionSpreadMode", 2);
+ Phobos::Config::DistributionSpreadMode = CCINIClass::INI_RA2MD.ReadInteger("Phobos", "DefaultDistributionSpreadMode", 2);
Phobos::Config::DistributionSpreadMode = std::clamp(Phobos::Config::DistributionSpreadMode, 0, 3);
- Phobos::Config::DistributionFilterMode = CCINIClass::INI_RA2MD->ReadInteger("Phobos", "DefaultDistributionFilterMode", 2);
+ Phobos::Config::DistributionFilterMode = CCINIClass::INI_RA2MD.ReadInteger("Phobos", "DefaultDistributionFilterMode", 2);
Phobos::Config::DistributionFilterMode = std::clamp(Phobos::Config::DistributionFilterMode, 0, 3);
// Custom game speeds, 6 - i so that GS6 is index 0, just like in the engine
From 25574cc288c1369aa969f43b8d1fe37830f8c46f Mon Sep 17 00:00:00 2001
From: CrimRecya <335958461@qq.com>
Date: Sat, 5 Jul 2025 22:10:41 +0800
Subject: [PATCH 18/30] Code style
---
src/Commands/DistributionMode.cpp | 66 ++++++++++++-------------------
1 file changed, 25 insertions(+), 41 deletions(-)
diff --git a/src/Commands/DistributionMode.cpp b/src/Commands/DistributionMode.cpp
index 782afabc1f..fab3b8ebd4 100644
--- a/src/Commands/DistributionMode.cpp
+++ b/src/Commands/DistributionMode.cpp
@@ -142,46 +142,20 @@ DEFINE_HOOK(0x4AE818, DisplayClass_sub_4AE750_AutoDistribution, 0xA)
const auto mode1 = Phobos::Config::DistributionSpreadMode;
const auto mode2 = Phobos::Config::DistributionFilterMode;
- auto vanillaMethod = [mode2, mouseAction](ObjectClass* pTarget)
- {
- for (const auto& pSelect : ObjectClass::CurrentObjects)
- {
- const auto currentAction = pSelect->MouseOverObject(pTarget);
-
- if (mode2 && mouseAction != Action::NoMove && currentAction == Action::NoMove && (pSelect->AbstractFlags & AbstractFlags::Techno) != AbstractFlags::None)
- static_cast(pSelect)->ClickedMission(Mission::Area_Guard, reinterpret_cast(pSelect->GetCellAgain()), nullptr, nullptr);
- else
- pSelect->ObjectClickedAction(currentAction, pTarget, false);
-
- Unsorted::MoveFeedback = false;
- }
- };
-
// Distribution mode main
- if (DistributionModeHoldDownCommandClass::Enabled && mode1 && count > 1 && mouseAction != Action::NoMove && !PlanningNodeClass::PlanningModeActive
- && (pTarget->AbstractFlags & AbstractFlags::Techno) != AbstractFlags::None && !pTarget->IsInAir())
+ if (DistributionModeHoldDownCommandClass::Enabled
+ && mode1
+ && count > 1
+ && mouseAction != Action::NoMove
+ && !PlanningNodeClass::PlanningModeActive
+ && (pTarget->AbstractFlags & AbstractFlags::Techno) != AbstractFlags::None
+ && !pTarget->IsInAir()
+ && (HouseClass::CurrentPlayer->IsAlliedWith(static_cast(pTarget)->Owner)
+ ? Phobos::Config::AllowDistributionCommand_AffectsAllies
+ : Phobos::Config::AllowDistributionCommand_AffectsEnemies))
{
- const auto pTargetHouse = static_cast(pTarget)->Owner;
-
- if (HouseClass::CurrentPlayer->IsAlliedWith(pTargetHouse))
- {
- if (!Phobos::Config::AllowDistributionCommand_AffectsAllies)
- {
- vanillaMethod;
- return SkipGameCode;
- }
- }
- else if (!Phobos::Config::AllowDistributionCommand_AffectsEnemies)
- {
- vanillaMethod;
- return SkipGameCode;
- }
-
VocClass::PlayGlobal(RulesExt::Global()->AddDistributionModeCommandSound, 0x2000, 1.0);
- const auto pSpecial = HouseClass::FindSpecial();
- const auto pCivilian = HouseClass::FindCivilianSide();
- const auto pNeutral = HouseClass::FindNeutral();
- const bool targetIsNeutral = pTargetHouse == pSpecial || pTargetHouse == pCivilian || pTargetHouse == pNeutral;
+ const bool targetIsNeutral = static_cast(pTarget)->Owner->IsNeutral();
const auto range = (2 << mode1);
const auto center = pTarget->GetCoords();
@@ -233,7 +207,7 @@ DEFINE_HOOK(0x4AE818, DisplayClass_sub_4AE750_AutoDistribution, 0xA)
const auto& [pItem, num] = record[i];
if (pSelect->MouseOverObject(pItem) == mouseAction
- && (targetIsNeutral || (pItem->Owner != pSpecial && pItem->Owner != pCivilian && pItem->Owner != pNeutral))
+ && (targetIsNeutral || !pItem->Owner->IsNeutral())
&& (mode2 < 2 || (pItem->WhatAmI() == pTarget->WhatAmI()
&& (mode2 < 3 || TechnoTypeExt::GetSelectionGroupID(pItem->GetTechnoType()) == TechnoTypeExt::GetSelectionGroupID(pTarget->GetTechnoType())))))
{
@@ -275,7 +249,17 @@ DEFINE_HOOK(0x4AE818, DisplayClass_sub_4AE750_AutoDistribution, 0xA)
}
else
{
- vanillaMethod;
+ for (const auto& pSelect : ObjectClass::CurrentObjects)
+ {
+ const auto currentAction = pSelect->MouseOverObject(pTarget);
+
+ if (mode2 && mouseAction != Action::NoMove && currentAction == Action::NoMove && (pSelect->AbstractFlags & AbstractFlags::Techno) != AbstractFlags::None)
+ static_cast(pSelect)->ClickedMission(Mission::Area_Guard, reinterpret_cast(pSelect->GetCellAgain()), nullptr, nullptr);
+ else
+ pSelect->ObjectClickedAction(currentAction, pTarget, false);
+
+ Unsorted::MoveFeedback = false;
+ }
}
}
@@ -293,9 +277,9 @@ DEFINE_HOOK(0x6DBE74, TacticalClass_DrawAllRadialIndicators_DrawDistributionRang
if (mode1 || mode2)
{
const auto pCell = MapClass::Instance.GetCellAt(DisplayClass::Instance.CurrentFoundation_CenterCell);
- const auto color = ((mode2 > 1)
+ const auto color = (mode2 > 1)
? ((mode2 == 3) ? ColorStruct { 255, 0, 0 } : ColorStruct { 200, 200, 0 })
- : (mode2 == 1) ? ColorStruct { 0, 100, 255 } : ColorStruct { 0, 255, 50 });
+ : ((mode2 == 1) ? ColorStruct { 0, 100, 255 } : ColorStruct { 0, 255, 50 });
Game::DrawRadialIndicator(false, true, pCell->GetCoords(), color, static_cast(mode1 ? (2 << mode1) : 0.5), false, true);
}
From 3191dab8ebe0b27f6303eb2742697b3c2284f7eb Mon Sep 17 00:00:00 2001
From: Coronia <2217891145@qq.com>
Date: Thu, 17 Jul 2025 00:06:00 +0800
Subject: [PATCH 19/30] remove unnecessary Grinder process
---
src/Commands/DistributionMode.cpp | 17 +----------------
1 file changed, 1 insertion(+), 16 deletions(-)
diff --git a/src/Commands/DistributionMode.cpp b/src/Commands/DistributionMode.cpp
index fa798a16ef..5770448d67 100644
--- a/src/Commands/DistributionMode.cpp
+++ b/src/Commands/DistributionMode.cpp
@@ -143,20 +143,6 @@ DEFINE_HOOK(0x4AE818, DisplayClass_sub_4AE750_AutoDistribution, 0xA)
const auto mode2 = Phobos::Config::DistributionFilterMode;
const auto pTechno = abstract_cast(pTarget);
- auto isEnterGrinder = [mouseAction](TechnoClass* pTechno)
- {
- if (mouseAction != Action::Enter)
- return false;
-
- if (const auto pBuilding = abstract_cast(pTechno))
- {
- if (pBuilding->Type->Grinding)
- return true;
- }
-
- return false;
- };
-
// Distribution mode main
if (DistributionModeHoldDownCommandClass::Enabled
&& mode1
@@ -166,7 +152,7 @@ DEFINE_HOOK(0x4AE818, DisplayClass_sub_4AE750_AutoDistribution, 0xA)
&& pTechno
&& !pTarget->IsInAir()
&& (HouseClass::CurrentPlayer->IsAlliedWith(pTechno->Owner)
- ? (Phobos::Config::AllowDistributionCommand_AffectsAllies && !isEnterGrinder(pTechno))
+ ? Phobos::Config::AllowDistributionCommand_AffectsAllies
: Phobos::Config::AllowDistributionCommand_AffectsEnemies))
{
VocClass::PlayGlobal(RulesExt::Global()->AddDistributionModeCommandSound, 0x2000, 1.0);
@@ -223,7 +209,6 @@ DEFINE_HOOK(0x4AE818, DisplayClass_sub_4AE750_AutoDistribution, 0xA)
if (pSelect->MouseOverObject(pItem) == mouseAction
&& (targetIsNeutral || !pItem->Owner->IsNeutral())
- && !isEnterGrinder(pItem)
&& (mode2 < 2 || (pItem->WhatAmI() == pTarget->WhatAmI()
&& (mode2 < 3 || TechnoTypeExt::GetSelectionGroupID(pItem->GetTechnoType()) == TechnoTypeExt::GetSelectionGroupID(pTarget->GetTechnoType())))))
{
From b55908a658534604e7a21852b2aa59e1960a9244 Mon Sep 17 00:00:00 2001
From: CrimRecya <335958461@qq.com>
Date: Wed, 6 Aug 2025 15:47:33 +0800
Subject: [PATCH 20/30] Refactor
---
src/Commands/DistributionMode.cpp | 262 ++++++++++++++++++++----------
src/Commands/DistributionMode.h | 4 +
2 files changed, 183 insertions(+), 83 deletions(-)
diff --git a/src/Commands/DistributionMode.cpp b/src/Commands/DistributionMode.cpp
index 5770448d67..d6bc0bc686 100644
--- a/src/Commands/DistributionMode.cpp
+++ b/src/Commands/DistributionMode.cpp
@@ -1,6 +1,6 @@
#include "DistributionMode.h"
-#include
+#include
#include
#include
@@ -128,51 +128,128 @@ void DistributionModeHoldDownCommandClass::DistributionSpreadModeReduce()
Phobos::Config::DistributionSpreadMode = std::max(0, Phobos::Config::DistributionSpreadMode - 1);
}
-DEFINE_HOOK(0x4AE818, DisplayClass_sub_4AE750_AutoDistribution, 0xA)
+void __fastcall DistributionModeHoldDownCommandClass::ClickedWaypoint(ObjectClass* pSelect, int idxPath, signed char idxWP)
{
- enum { SkipGameCode = 0x4AE85C };
+ pSelect->AssignPlanningPath(idxPath, idxWP);
- GET(ObjectClass* const, pTarget, EBP);
- GET_STACK(const Action, mouseAction, STACK_OFFSET(0x20, 0xC));
+ if (const auto pFoot = abstract_cast(pSelect))
+ pFoot->unknown_bool_430 = false;
- const auto count = ObjectClass::CurrentObjects.Count;
+ if (const auto pExt = TechnoExt::ExtMap.TryFind(abstract_cast(pSelect)))
+ {
+ for (const auto& pAttachment : pExt->ChildAttachments)
+ {
+ if (pAttachment->Child && pAttachment->GetType()->InheritCommands)
+ DistributionModeHoldDownCommandClass::ClickedWaypoint(pAttachment->Child, idxPath, idxWP);
+ }
+ }
+}
- if (count > 0)
+void __fastcall DistributionModeHoldDownCommandClass::ClickedTargetAction(ObjectClass* pSelect, Action action, ObjectClass* pTarget)
+{
+ pSelect->ObjectClickedAction(action, pTarget, false);
+ Unsorted::MoveFeedback = false;
+
+ if (const auto pExt = TechnoExt::ExtMap.TryFind(abstract_cast(pSelect)))
{
- const auto mode1 = Phobos::Config::DistributionSpreadMode;
- const auto mode2 = Phobos::Config::DistributionFilterMode;
- const auto pTechno = abstract_cast(pTarget);
-
- // Distribution mode main
- if (DistributionModeHoldDownCommandClass::Enabled
- && mode1
- && count > 1
- && mouseAction != Action::NoMove
- && !PlanningNodeClass::PlanningModeActive
- && pTechno
- && !pTarget->IsInAir()
- && (HouseClass::CurrentPlayer->IsAlliedWith(pTechno->Owner)
- ? Phobos::Config::AllowDistributionCommand_AffectsAllies
- : Phobos::Config::AllowDistributionCommand_AffectsEnemies))
+ for (const auto& pAttachment : pExt->ChildAttachments)
{
- VocClass::PlayGlobal(RulesExt::Global()->AddDistributionModeCommandSound, 0x2000, 1.0);
- const bool targetIsNeutral = pTechno->Owner->IsNeutral();
+ if (pAttachment->Child && pAttachment->GetType()->InheritCommands)
+ DistributionModeHoldDownCommandClass::ClickedTargetAction(pAttachment->Child, action, pTarget);
+ }
+ }
+}
- const auto range = (2 << mode1);
- const auto center = pTarget->GetCoords();
- const auto pItems = Helpers::Alex::getCellSpreadItems(center, range);
+void __fastcall DistributionModeHoldDownCommandClass::ClickedCellAction(ObjectClass* pSelect, Action action, CellStruct* pCell, CellStruct* pSecondCell)
+{
+ pSelect->CellClickedAction(action, pCell, pSecondCell, false);
+ Unsorted::MoveFeedback = false;
- std::vector> record;
- const auto maxSize = pItems.size();
- record.reserve(maxSize);
+ if (const auto pExt = TechnoExt::ExtMap.TryFind(abstract_cast(pSelect)))
+ {
+ for (const auto& pAttachment : pExt->ChildAttachments)
+ {
+ if (pAttachment->Child && pAttachment->GetType()->InheritCommands)
+ DistributionModeHoldDownCommandClass::ClickedCellAction(pAttachment->Child, action, pCell, pSecondCell);
+ }
+ }
+}
- int current = 1;
+void __fastcall DistributionModeHoldDownCommandClass::AreaGuardAction(TechnoClass* pTechno)
+{
+ pTechno->ClickedMission(Mission::Area_Guard, reinterpret_cast(pTechno->GetCellAgain()), nullptr, nullptr);
+ Unsorted::MoveFeedback = false;
- for (const auto& pItem : pItems)
+ if (const auto pExt = TechnoExt::ExtMap.Find(pTechno))
+ {
+ for (const auto& pAttachment : pExt->ChildAttachments)
+ {
+ if (pAttachment->Child && pAttachment->GetType()->InheritCommands)
+ DistributionModeHoldDownCommandClass::AreaGuardAction(pAttachment->Child);
+ }
+ }
+}
+
+DEFINE_HOOK(0x4AE7B3, DisplayClass_ActiveClickWith_Iterate, 0x0)
+{
+ enum { SkipGameCode = 0x4AE99B };
+
+ const int count = ObjectClass::CurrentObjects.Count;
+
+ if (count > 0)
+ {
+ {
+ GET_STACK(int, idxPath, STACK_OFFSET(0x18, -0x8));
+ GET_STACK(unsigned char, idxWP, STACK_OFFSET(0x18, -0xC));
+
+ for (const auto& pSelect : ObjectClass::CurrentObjects)
{
- if (!pItem->IsDisguisedAs(HouseClass::CurrentPlayer)
- && (pItem->CloakState != CloakState::Cloaked || pItem->GetCell()->Sensors_InclHouse(HouseClass::CurrentPlayer->ArrayIndex)))
+ DistributionModeHoldDownCommandClass::ClickedWaypoint(pSelect, idxPath, idxWP);
+ }
+ }
+
+ GET_STACK(ObjectClass* const, pTarget, STACK_OFFSET(0x18, 0x4));
+ GET_STACK(Action const, action, STACK_OFFSET(0x18, 0xC));
+
+ if (pTarget)
+ {
+ const int mode1 = Phobos::Config::DistributionSpreadMode;
+ const int mode2 = Phobos::Config::DistributionFilterMode;
+ const auto pTechno = abstract_cast(pTarget);
+
+ // Distribution mode main
+ if (DistributionModeHoldDownCommandClass::Enabled
+ && mode1
+ && count > 1
+ && action != Action::NoMove
+ && !PlanningNodeClass::PlanningModeActive
+ && pTechno
+ && !pTarget->IsInAir()
+ && (HouseClass::CurrentPlayer->IsAlliedWith(pTechno->Owner)
+ ? Phobos::Config::AllowDistributionCommand_AffectsAllies
+ : Phobos::Config::AllowDistributionCommand_AffectsEnemies))
+ {
+ VocClass::PlayGlobal(RulesExt::Global()->AddDistributionModeCommandSound, 0x2000, 1.0);
+ const bool targetIsNeutral = pTechno->Owner->IsNeutral();
+
+ const int range = (2 << mode1);
+ const auto center = pTarget->GetCoords();
+ const auto pItems = Helpers::Alex::getCellSpreadItems(center, range);
+
+ std::vector> record;
+ const size_t maxSize = pItems.size();
+ record.reserve(maxSize);
+
+ int current = 1;
+
+ for (const auto& pItem : pItems)
{
+ if (pItem->IsDisguisedAs(HouseClass::CurrentPlayer))
+ continue;
+
+ if (pItem->CloakState == CloakState::Cloaked && !pItem->GetCell()->Sensors_InclHouse(HouseClass::CurrentPlayer->ArrayIndex))
+ continue;
+
auto coords = pItem->GetCoords();
if (!MapClass::Instance.IsWithinUsableArea(coords))
@@ -184,86 +261,105 @@ DEFINE_HOOK(0x4AE818, DisplayClass_sub_4AE750_AutoDistribution, 0xA)
coords.Z += CellClass::BridgeHeight;
if (!MapClass::Instance.IsLocationShrouded(coords))
- record.emplace_back(pItem, 0);
+ record.emplace_back(pItem, 0);
}
- }
- const auto recordSize = record.size();
- std::sort(&record[0], &record[recordSize],[¢er](const auto& pairA, const auto& pairB)
- {
- const auto coordsA = pairA.first->GetCoords();
- const auto distanceA = Point2D{coordsA.X, coordsA.Y}.DistanceFromSquared(Point2D{center.X, center.Y});
- const auto coordsB = pairB.first->GetCoords();
- const auto distanceB = Point2D{coordsB.X, coordsB.Y}.DistanceFromSquared(Point2D{center.X, center.Y});
- return distanceA < distanceB;
- });
+ const size_t recordSize = record.size();
+ std::sort(&record[0], &record[recordSize],[¢er](const auto& pairA, const auto& pairB)
+ {
+ const auto coordsA = pairA.first->GetCoords();
+ const double distanceA = Point2D{coordsA.X, coordsA.Y}.DistanceFromSquared(Point2D{center.X, center.Y});
- for (const auto& pSelect : ObjectClass::CurrentObjects)
- {
- size_t canTargetIndex = maxSize;
- size_t newTargetIndex = maxSize;
+ const auto coordsB = pairB.first->GetCoords();
+ const double distanceB = Point2D{coordsB.X, coordsB.Y}.DistanceFromSquared(Point2D{center.X, center.Y});
+
+ return distanceA < distanceB;
+ });
- for (size_t i = 0; i < recordSize; ++i)
+ for (const auto& pSelect : ObjectClass::CurrentObjects)
{
- const auto& [pItem, num] = record[i];
+ size_t canTargetIndex = maxSize;
+ size_t newTargetIndex = maxSize;
- if (pSelect->MouseOverObject(pItem) == mouseAction
- && (targetIsNeutral || !pItem->Owner->IsNeutral())
- && (mode2 < 2 || (pItem->WhatAmI() == pTarget->WhatAmI()
- && (mode2 < 3 || TechnoTypeExt::GetSelectionGroupID(pItem->GetTechnoType()) == TechnoTypeExt::GetSelectionGroupID(pTarget->GetTechnoType())))))
+ for (size_t i = 0; i < recordSize; ++i)
{
- canTargetIndex = i;
+ const auto& [pItem, num] = record[i];
+
+ if (pSelect->MouseOverObject(pItem) != action)
+ continue;
+
+ if (!targetIsNeutral && pItem->Owner->IsNeutral())
+ continue;
- if (num < current)
+ if (mode2 < 2 || (pItem->WhatAmI() == pTarget->WhatAmI()
+ && (mode2 < 3 || TechnoTypeExt::GetSelectionGroupID(pItem->GetTechnoType())
+ == TechnoTypeExt::GetSelectionGroupID(pTarget->GetTechnoType()))))
{
- newTargetIndex = i;
- break;
+ canTargetIndex = i;
+
+ if (num < current)
+ {
+ newTargetIndex = i;
+ break;
+ }
}
}
- }
- if (newTargetIndex == maxSize && canTargetIndex != maxSize)
- {
- ++current;
- newTargetIndex = canTargetIndex;
- }
+ if (newTargetIndex == maxSize && canTargetIndex != maxSize)
+ {
+ ++current;
+ newTargetIndex = canTargetIndex;
+ }
- if (newTargetIndex != maxSize)
- {
- auto& [pNewTarget, recordCount] = record[newTargetIndex];
+ if (newTargetIndex != maxSize)
+ {
+ auto& [pNewTarget, recordCount] = record[newTargetIndex];
+
+ DistributionModeHoldDownCommandClass::ClickedTargetAction(pSelect, action, pNewTarget);
+
+ ++recordCount;
+ continue;
+ }
- ++recordCount;
- pSelect->ObjectClickedAction(mouseAction, pNewTarget, false);
- }
- else
- {
const auto currentAction = pSelect->MouseOverObject(pTarget);
if (mode2 && currentAction == Action::NoMove && (pSelect->AbstractFlags & AbstractFlags::Techno) != AbstractFlags::None)
- static_cast(pSelect)->ClickedMission(Mission::Area_Guard, reinterpret_cast(pSelect->GetCellAgain()), nullptr, nullptr);
+ DistributionModeHoldDownCommandClass::AreaGuardAction(static_cast(pSelect));
else
- pSelect->ObjectClickedAction(currentAction, pTarget, false);
+ DistributionModeHoldDownCommandClass::ClickedTargetAction(pSelect, currentAction, pTarget);
}
+ }
+ else
+ {
+ for (const auto& pSelect : ObjectClass::CurrentObjects)
+ {
+ const auto currentAction = pSelect->MouseOverObject(pTarget);
- Unsorted::MoveFeedback = false;
+ if (mode2 && action != Action::NoMove && currentAction == Action::NoMove && (pSelect->AbstractFlags & AbstractFlags::Techno) != AbstractFlags::None)
+ DistributionModeHoldDownCommandClass::AreaGuardAction(static_cast(pSelect));
+ else
+ DistributionModeHoldDownCommandClass::ClickedTargetAction(pSelect, currentAction, pTarget);
+ }
}
}
else
{
+ LEA_STACK(CellStruct* const, pCell, STACK_OFFSET(0x18, 0x8));
+
+ auto invalidCell = CellStruct { -1, -1 };
+ auto pSecondCell = action == Action::Move || action == Action::PatrolWaypoint || action == Action::NoMove ? pCell : &invalidCell;
+
for (const auto& pSelect : ObjectClass::CurrentObjects)
{
- const auto currentAction = pSelect->MouseOverObject(pTarget);
+ const auto currentAction = pSelect->MouseOverCell(pCell, false, false);
- if (mode2 && mouseAction != Action::NoMove && currentAction == Action::NoMove && (pSelect->AbstractFlags & AbstractFlags::Techno) != AbstractFlags::None)
- static_cast(pSelect)->ClickedMission(Mission::Area_Guard, reinterpret_cast(pSelect->GetCellAgain()), nullptr, nullptr);
- else
- pSelect->ObjectClickedAction(currentAction, pTarget, false);
-
- Unsorted::MoveFeedback = false;
+ DistributionModeHoldDownCommandClass::ClickedCellAction(pSelect, currentAction, pCell, pSecondCell);
}
}
}
+ Unsorted::MoveFeedback = true;
+
return SkipGameCode;
}
diff --git a/src/Commands/DistributionMode.h b/src/Commands/DistributionMode.h
index a90ed3db8e..14617a8180 100644
--- a/src/Commands/DistributionMode.h
+++ b/src/Commands/DistributionMode.h
@@ -39,4 +39,8 @@ class DistributionModeHoldDownCommandClass : public CommandClass
static void DistributionSpreadModeExpand();
static void DistributionSpreadModeReduce();
+ static void __fastcall ClickedWaypoint(ObjectClass* pSelect, int idxPath, signed char idxWP);
+ static void __fastcall ClickedTargetAction(ObjectClass* pSelect, Action action, ObjectClass* pTarget);
+ static void __fastcall ClickedCellAction(ObjectClass* pSelect, Action action, CellStruct* pCell, CellStruct* pSecondCell);
+ static void __fastcall AreaGuardAction(TechnoClass* pTechno);
};
From 6525febbfe0860d510a16d55c2101f716496626e Mon Sep 17 00:00:00 2001
From: CrimRecya <335958461@qq.com>
Date: Wed, 6 Aug 2025 15:48:24 +0800
Subject: [PATCH 21/30] Remove useless
---
src/Commands/DistributionMode.cpp | 36 -------------------------------
1 file changed, 36 deletions(-)
diff --git a/src/Commands/DistributionMode.cpp b/src/Commands/DistributionMode.cpp
index d6bc0bc686..906386cb47 100644
--- a/src/Commands/DistributionMode.cpp
+++ b/src/Commands/DistributionMode.cpp
@@ -134,60 +134,24 @@ void __fastcall DistributionModeHoldDownCommandClass::ClickedWaypoint(ObjectClas
if (const auto pFoot = abstract_cast(pSelect))
pFoot->unknown_bool_430 = false;
-
- if (const auto pExt = TechnoExt::ExtMap.TryFind(abstract_cast(pSelect)))
- {
- for (const auto& pAttachment : pExt->ChildAttachments)
- {
- if (pAttachment->Child && pAttachment->GetType()->InheritCommands)
- DistributionModeHoldDownCommandClass::ClickedWaypoint(pAttachment->Child, idxPath, idxWP);
- }
- }
}
void __fastcall DistributionModeHoldDownCommandClass::ClickedTargetAction(ObjectClass* pSelect, Action action, ObjectClass* pTarget)
{
pSelect->ObjectClickedAction(action, pTarget, false);
Unsorted::MoveFeedback = false;
-
- if (const auto pExt = TechnoExt::ExtMap.TryFind(abstract_cast(pSelect)))
- {
- for (const auto& pAttachment : pExt->ChildAttachments)
- {
- if (pAttachment->Child && pAttachment->GetType()->InheritCommands)
- DistributionModeHoldDownCommandClass::ClickedTargetAction(pAttachment->Child, action, pTarget);
- }
- }
}
void __fastcall DistributionModeHoldDownCommandClass::ClickedCellAction(ObjectClass* pSelect, Action action, CellStruct* pCell, CellStruct* pSecondCell)
{
pSelect->CellClickedAction(action, pCell, pSecondCell, false);
Unsorted::MoveFeedback = false;
-
- if (const auto pExt = TechnoExt::ExtMap.TryFind(abstract_cast(pSelect)))
- {
- for (const auto& pAttachment : pExt->ChildAttachments)
- {
- if (pAttachment->Child && pAttachment->GetType()->InheritCommands)
- DistributionModeHoldDownCommandClass::ClickedCellAction(pAttachment->Child, action, pCell, pSecondCell);
- }
- }
}
void __fastcall DistributionModeHoldDownCommandClass::AreaGuardAction(TechnoClass* pTechno)
{
pTechno->ClickedMission(Mission::Area_Guard, reinterpret_cast(pTechno->GetCellAgain()), nullptr, nullptr);
Unsorted::MoveFeedback = false;
-
- if (const auto pExt = TechnoExt::ExtMap.Find(pTechno))
- {
- for (const auto& pAttachment : pExt->ChildAttachments)
- {
- if (pAttachment->Child && pAttachment->GetType()->InheritCommands)
- DistributionModeHoldDownCommandClass::AreaGuardAction(pAttachment->Child);
- }
- }
}
DEFINE_HOOK(0x4AE7B3, DisplayClass_ActiveClickWith_Iterate, 0x0)
From 09bae51946975f3249a542a97163c59e21748650 Mon Sep 17 00:00:00 2001
From: CrimRecya <335958461@qq.com>
Date: Wed, 6 Aug 2025 20:27:20 +0800
Subject: [PATCH 22/30] Fix default value
---
docs/User-Interface.md | 2 +-
src/Phobos.INI.cpp | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/docs/User-Interface.md b/docs/User-Interface.md
index 5030f4cb9f..3073b3eb80 100644
--- a/docs/User-Interface.md
+++ b/docs/User-Interface.md
@@ -500,7 +500,7 @@ In `ra2md.ini`:
```ini
[Phobos]
DefaultDistributionSpreadMode=2 ; integer, 0 - r=0 , 1 - r=4 , 2 - r=8 , 3 - r=16
-DefaultDistributionFilterMode=0 ; integer, 0 - None , 1 - Auto , 2 - Type , 3 - Name
+DefaultDistributionFilterMode=2 ; integer, 0 - None , 1 - Auto , 2 - Type , 3 - Name
```
## Loading screen
diff --git a/src/Phobos.INI.cpp b/src/Phobos.INI.cpp
index 40850e8dd0..1a5675f268 100644
--- a/src/Phobos.INI.cpp
+++ b/src/Phobos.INI.cpp
@@ -109,7 +109,7 @@ DEFINE_HOOK(0x5FACDF, OptionsClass_LoadSettings_LoadPhobosSettings, 0x5)
Phobos::Config::DistributionSpreadMode = CCINIClass::INI_RA2MD.ReadInteger("Phobos", "DefaultDistributionSpreadMode", 2);
Phobos::Config::DistributionSpreadMode = std::clamp(Phobos::Config::DistributionSpreadMode, 0, 3);
- Phobos::Config::DistributionFilterMode = CCINIClass::INI_RA2MD.ReadInteger("Phobos", "DefaultDistributionFilterMode", 0);
+ Phobos::Config::DistributionFilterMode = CCINIClass::INI_RA2MD.ReadInteger("Phobos", "DefaultDistributionFilterMode", 2);
Phobos::Config::DistributionFilterMode = std::clamp(Phobos::Config::DistributionFilterMode, 0, 3);
// Custom game speeds, 6 - i so that GS6 is index 0, just like in the engine
From aa509d0068fe6d9c53d22598dba94dd723187e57 Mon Sep 17 00:00:00 2001
From: CrimRecya <335958461@qq.com>
Date: Wed, 6 Aug 2025 21:21:59 +0800
Subject: [PATCH 23/30] Separate functions
---
docs/User-Interface.md | 15 +++---
src/Commands/Commands.cpp | 3 ++
src/Commands/DistributionMode.cpp | 82 +++++++++++++++++++++++--------
src/Commands/DistributionMode.h | 10 ++++
src/Phobos.INI.cpp | 8 ++-
src/Phobos.h | 2 +
6 files changed, 91 insertions(+), 29 deletions(-)
diff --git a/docs/User-Interface.md b/docs/User-Interface.md
index 3073b3eb80..df7743d6f9 100644
--- a/docs/User-Interface.md
+++ b/docs/User-Interface.md
@@ -469,20 +469,22 @@ DisplayIncome.Offset=0,0 ; X,Y, pixels relative to default
### `[ ]` Distribution Mode Spread / Filter / Enable
-- Change the click action when hold down the specific hotkey if enabled `AllowDistributionCommand`.
+- Now you can change the click action by using `AllowSwitchNoMoveCommand` hotkey. If the behavior to be executed by the current techno is different from the behavior displayed by the mouse, and the behavior to be executed will make the techno move near the target, the behavior will be replaced with area guard. Regardless of whether or not switch hotkey is used, default behavior can be changed through `DefaultApplyNoMoveCommand`.
+- Now you can also change the click action when hold down the specific hotkey if enabled `AllowDistributionCommand`. The new behavior is like using the selected objects one by one to click on each target within the range.
- `AllowDistributionCommand.SpreadMode` & `AllowDistributionCommand.FilterMode` allow you to set spread range and target filter by hotkeys, which default to `DefaultDistributionSpreadMode` and `DefaultDistributionFilterMode`.
- When the range is 0, it is the original default behavior of the game. The range can be adjusted to 4, 8 or 16 cells by another shortcut key. You can also adjust this by using the mouse wheel while holding down the specific hotkey if `AllowDistributionCommand.SpreadModeScroll` set to true;
- The targets within the range will be allocated equally to the selected technos. Only when the behavior to be performed by the current techno is the same as that displayed by the mouse will it be allocated. Otherwise, it will return to the original default behavior of the game (it will not be effective for technos in the air). This will display a range ring.
- When the filter is `None`, it is the default behavior of the game. If the range is not zero at this time, a green ring will be displayed. You can adjust the filter mode to:
- - `Auto` - if the behavior to be executed by the current techno is different from the behavior displayed by the mouse, and the behavior to be executed will make the techno move near the target, the behavior will be replaced with area guard. At this time, a blue ring will be displayed.
- - `Type` - on the basis of `Auto`, only targets of the same type (like infantries, vehicles or buildings) will be selected among the targets allocated in the range. At this time, a yellow ring will be displayed.
- - `Name` - on the basis of `Type`, only targets of the same name (or with the same `GroupAs`) will be selected among the targets allocated in the range. At this time, a red ring will be displayed.
+ - `Like` - only targets with the same armor type (Completely identical `Armor`) will be selected among the targets allocated in the range. At this time, a blue ring will be displayed.
+ - `Type` - only targets of the same type (like infantries, vehicles or buildings) will be selected among the targets allocated in the range. At this time, a yellow ring will be displayed.
+ - `Name` - only targets of the same name (or with the same `GroupAs`) will be selected among the targets allocated in the range. At this time, a red ring will be displayed.
- `AllowDistributionCommand.AffectsAllies` & `AllowDistributionCommand.AffectsEnemies` allow the distribution command to work on allies (including owner) or enemies target. If picking a target that's not eligible, it'll fallback to vanilla command.
-- For localization add `TXT_DISTR_SPREAD`, `TXT_DISTR_FILTER`, `TXT_DISTR_HOLDDOWN`, `TXT_DISTR_SPREAD_DESC`, `TXT_DISTR_FILTER_DESC`, `TXT_DISTR_HOLDDOWN_DESC`, `MSG:DistributionModeOn`, `MSG:DistributionModeOff` into your `.csf` file.
+- For localization add `TXT_SWITCH_NOMOVE`, `TXT_DISTR_SPREAD`, `TXT_DISTR_FILTER`, `TXT_DISTR_HOLDDOWN`, `TXT_SWITCH_NOMOVE_DESC`, `TXT_DISTR_SPREAD_DESC`, `TXT_DISTR_FILTER_DESC`, `TXT_DISTR_HOLDDOWN_DESC`, `MSG:DistributionModeOn`, `MSG:DistributionModeOff` into your `.csf` file.
In `rulesmd.ini`:
```ini
[GlobalControls]
+AllowSwitchNoMoveCommand=false ; boolean
AllowDistributionCommand=false ; boolean
AllowDistributionCommand.SpreadMode=true ; boolean
AllowDistributionCommand.SpreadModeScroll=true ; boolean
@@ -499,8 +501,9 @@ AddDistributionModeCommandSound= ; sound entry
In `ra2md.ini`:
```ini
[Phobos]
+DefaultApplyNoMoveCommand=true ; boolean
DefaultDistributionSpreadMode=2 ; integer, 0 - r=0 , 1 - r=4 , 2 - r=8 , 3 - r=16
-DefaultDistributionFilterMode=2 ; integer, 0 - None , 1 - Auto , 2 - Type , 3 - Name
+DefaultDistributionFilterMode=2 ; integer, 0 - None , 1 - Like , 2 - Type , 3 - Name
```
## Loading screen
diff --git a/src/Commands/Commands.cpp b/src/Commands/Commands.cpp
index 9cc388e0f8..b274d08d17 100644
--- a/src/Commands/Commands.cpp
+++ b/src/Commands/Commands.cpp
@@ -40,6 +40,9 @@ DEFINE_HOOK(0x533066, CommandClassCallback_Register, 0x6)
SWSidebarClass::Commands[9] = MakeCommand>();
}
+ if (Phobos::Config::AllowSwitchNoMoveCommand)
+ MakeCommand();
+
if (Phobos::Config::AllowDistributionCommand)
{
if (Phobos::Config::AllowDistributionCommand_SpreadMode)
diff --git a/src/Commands/DistributionMode.cpp b/src/Commands/DistributionMode.cpp
index 906386cb47..7566ab0175 100644
--- a/src/Commands/DistributionMode.cpp
+++ b/src/Commands/DistributionMode.cpp
@@ -11,6 +11,31 @@ bool DistributionModeHoldDownCommandClass::OnMessageShowed = false;
bool DistributionModeHoldDownCommandClass::OffMessageShowed = false;
int DistributionModeHoldDownCommandClass::ShowTime = 0;
+const char* SwitchNoMoveCommandClass::GetName() const
+{
+ return "Switch No Move Command";
+}
+
+const wchar_t* SwitchNoMoveCommandClass::GetUIName() const
+{
+ return GeneralUtils::LoadStringUnlessMissing("TXT_SWITCH_NOMOVE", L"Switch no-move");
+}
+
+const wchar_t* SwitchNoMoveCommandClass::GetUICategory() const
+{
+ return CATEGORY_CONTROL;
+}
+
+const wchar_t* SwitchNoMoveCommandClass::GetUIDescription() const
+{
+ return GeneralUtils::LoadStringUnlessMissing("TXT_SWITCH_NOMOVE_DESC", L"Make unit does not move around the target when receiving no-move command");
+}
+
+void SwitchNoMoveCommandClass::Execute(WWKey eInput) const
+{
+ Phobos::Config::ApplyNoMoveCommand = !Phobos::Config::ApplyNoMoveCommand;
+}
+
const char* DistributionModeSpreadCommandClass::GetName() const
{
return "Distribution Mode Spread";
@@ -177,13 +202,14 @@ DEFINE_HOOK(0x4AE7B3, DisplayClass_ActiveClickWith_Iterate, 0x0)
if (pTarget)
{
- const int mode1 = Phobos::Config::DistributionSpreadMode;
- const int mode2 = Phobos::Config::DistributionFilterMode;
+ const int spreadMode = Phobos::Config::DistributionSpreadMode;
+ const int filterMode = Phobos::Config::DistributionFilterMode;
+ const bool noMove = !Phobos::Config::ApplyNoMoveCommand;
const auto pTechno = abstract_cast(pTarget);
// Distribution mode main
if (DistributionModeHoldDownCommandClass::Enabled
- && mode1
+ && spreadMode
&& count > 1
&& action != Action::NoMove
&& !PlanningNodeClass::PlanningModeActive
@@ -196,7 +222,7 @@ DEFINE_HOOK(0x4AE7B3, DisplayClass_ActiveClickWith_Iterate, 0x0)
VocClass::PlayGlobal(RulesExt::Global()->AddDistributionModeCommandSound, 0x2000, 1.0);
const bool targetIsNeutral = pTechno->Owner->IsNeutral();
- const int range = (2 << mode1);
+ const int range = (2 << spreadMode);
const auto center = pTarget->GetCoords();
const auto pItems = Helpers::Alex::getCellSpreadItems(center, range);
@@ -255,17 +281,31 @@ DEFINE_HOOK(0x4AE7B3, DisplayClass_ActiveClickWith_Iterate, 0x0)
if (!targetIsNeutral && pItem->Owner->IsNeutral())
continue;
- if (mode2 < 2 || (pItem->WhatAmI() == pTarget->WhatAmI()
- && (mode2 < 3 || TechnoTypeExt::GetSelectionGroupID(pItem->GetTechnoType())
- == TechnoTypeExt::GetSelectionGroupID(pTarget->GetTechnoType()))))
+ if (filterMode)
{
- canTargetIndex = i;
-
- if (num < current)
+ if (filterMode == 1)
+ {
+ if (pItem->GetType()->Armor != pTarget->GetType()->Armor)
+ continue;
+ }
+ else if (filterMode == 2)
{
- newTargetIndex = i;
- break;
+ if (pItem->WhatAmI() != pTarget->WhatAmI())
+ continue;
}
+ else // filterMode == 3
+ {
+ if (TechnoTypeExt::GetSelectionGroupID(pItem->GetType()) != TechnoTypeExt::GetSelectionGroupID(pTarget->GetType()))
+ continue;
+ }
+ }
+
+ canTargetIndex = i;
+
+ if (num < current)
+ {
+ newTargetIndex = i;
+ break;
}
}
@@ -287,7 +327,7 @@ DEFINE_HOOK(0x4AE7B3, DisplayClass_ActiveClickWith_Iterate, 0x0)
const auto currentAction = pSelect->MouseOverObject(pTarget);
- if (mode2 && currentAction == Action::NoMove && (pSelect->AbstractFlags & AbstractFlags::Techno) != AbstractFlags::None)
+ if (noMove && currentAction == Action::NoMove && (pSelect->AbstractFlags & AbstractFlags::Techno) != AbstractFlags::None)
DistributionModeHoldDownCommandClass::AreaGuardAction(static_cast(pSelect));
else
DistributionModeHoldDownCommandClass::ClickedTargetAction(pSelect, currentAction, pTarget);
@@ -299,7 +339,7 @@ DEFINE_HOOK(0x4AE7B3, DisplayClass_ActiveClickWith_Iterate, 0x0)
{
const auto currentAction = pSelect->MouseOverObject(pTarget);
- if (mode2 && action != Action::NoMove && currentAction == Action::NoMove && (pSelect->AbstractFlags & AbstractFlags::Techno) != AbstractFlags::None)
+ if (noMove && action != Action::NoMove && currentAction == Action::NoMove && (pSelect->AbstractFlags & AbstractFlags::Techno) != AbstractFlags::None)
DistributionModeHoldDownCommandClass::AreaGuardAction(static_cast(pSelect));
else
DistributionModeHoldDownCommandClass::ClickedTargetAction(pSelect, currentAction, pTarget);
@@ -332,16 +372,16 @@ DEFINE_HOOK(0x6DBE74, TacticalClass_DrawAllRadialIndicators_DrawDistributionRang
if (!DistributionModeHoldDownCommandClass::Enabled && SystemTimer::GetTime() - DistributionModeHoldDownCommandClass::ShowTime > 30)
return 0;
- const auto mode1 = Phobos::Config::DistributionSpreadMode;
- const auto mode2 = Phobos::Config::DistributionFilterMode;
+ const auto spreadMode = Phobos::Config::DistributionSpreadMode;
+ const auto filterMode = Phobos::Config::DistributionFilterMode;
- if (mode1 || mode2)
+ if (spreadMode || filterMode)
{
const auto pCell = MapClass::Instance.GetCellAt(DisplayClass::Instance.CurrentFoundation_CenterCell);
- const auto color = (mode2 > 1)
- ? ((mode2 == 3) ? ColorStruct { 255, 0, 0 } : ColorStruct { 200, 200, 0 })
- : ((mode2 == 1) ? ColorStruct { 0, 100, 255 } : ColorStruct { 0, 255, 50 });
- Game::DrawRadialIndicator(false, true, pCell->GetCoords(), color, static_cast(mode1 ? (2 << mode1) : 0.5), false, true);
+ const auto color = (filterMode > 1)
+ ? ((filterMode == 3) ? ColorStruct { 255, 0, 0 } : ColorStruct { 200, 200, 0 })
+ : ((filterMode == 1) ? ColorStruct { 0, 100, 255 } : ColorStruct { 0, 255, 50 });
+ Game::DrawRadialIndicator(false, true, pCell->GetCoords(), color, static_cast(spreadMode ? (2 << spreadMode) : 0.5), false, true);
}
return 0;
diff --git a/src/Commands/DistributionMode.h b/src/Commands/DistributionMode.h
index 14617a8180..49a1c051d2 100644
--- a/src/Commands/DistributionMode.h
+++ b/src/Commands/DistributionMode.h
@@ -2,6 +2,16 @@
#include "Commands.h"
+class SwitchNoMoveCommandClass : public CommandClass
+{
+public:
+ 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;
+};
+
class DistributionModeSpreadCommandClass : public CommandClass
{
public:
diff --git a/src/Phobos.INI.cpp b/src/Phobos.INI.cpp
index 1a5675f268..54287c2a38 100644
--- a/src/Phobos.INI.cpp
+++ b/src/Phobos.INI.cpp
@@ -69,12 +69,14 @@ bool Phobos::Config::ShowWeedsCounter = false;
bool Phobos::Config::HideLightFlashEffects = true;
bool Phobos::Config::ShowFlashOnSelecting = false;
bool Phobos::Config::UnitPowerDrain = false;
+bool Phobos::Config::AllowSwitchNoMoveCommand = false;
bool Phobos::Config::AllowDistributionCommand = false;
bool Phobos::Config::AllowDistributionCommand_SpreadMode = true;
bool Phobos::Config::AllowDistributionCommand_SpreadModeScroll = true;
bool Phobos::Config::AllowDistributionCommand_FilterMode = true;
bool Phobos::Config::AllowDistributionCommand_AffectsAllies = true;
bool Phobos::Config::AllowDistributionCommand_AffectsEnemies = true;
+bool Phobos::Config::ApplyNoMoveCommand = true;
int Phobos::Config::DistributionSpreadMode = 2;
int Phobos::Config::DistributionFilterMode = 2;
int Phobos::Config::SuperWeaponSidebar_RequiredSignificance = 0;
@@ -107,9 +109,10 @@ DEFINE_HOOK(0x5FACDF, OptionsClass_LoadSettings_LoadPhobosSettings, 0x5)
Phobos::Config::ShowFlashOnSelecting = CCINIClass::INI_RA2MD.ReadBool(phobosSection, "ShowFlashOnSelecting", false);
Phobos::Config::SuperWeaponSidebar_RequiredSignificance = CCINIClass::INI_RA2MD.ReadInteger(phobosSection, "SuperWeaponSidebar.RequiredSignificance", 0);
- Phobos::Config::DistributionSpreadMode = CCINIClass::INI_RA2MD.ReadInteger("Phobos", "DefaultDistributionSpreadMode", 2);
+ Phobos::Config::ApplyNoMoveCommand = CCINIClass::INI_RA2MD.ReadBool(phobosSection, "DefaultApplyNoMoveCommand", true);
+ Phobos::Config::DistributionSpreadMode = CCINIClass::INI_RA2MD.ReadInteger(phobosSection, "DefaultDistributionSpreadMode", 2);
Phobos::Config::DistributionSpreadMode = std::clamp(Phobos::Config::DistributionSpreadMode, 0, 3);
- Phobos::Config::DistributionFilterMode = CCINIClass::INI_RA2MD.ReadInteger("Phobos", "DefaultDistributionFilterMode", 2);
+ Phobos::Config::DistributionFilterMode = CCINIClass::INI_RA2MD.ReadInteger(phobosSection, "DefaultDistributionFilterMode", 2);
Phobos::Config::DistributionFilterMode = std::clamp(Phobos::Config::DistributionFilterMode, 0, 3);
// Custom game speeds, 6 - i so that GS6 is index 0, just like in the engine
@@ -288,6 +291,7 @@ DEFINE_HOOK(0x52D21F, InitRules_ThingsThatShouldntBeSerailized, 0x6)
Phobos::Config::SuperWeaponSidebarCommands = pINI_RULESMD->ReadBool("GlobalControls", "SuperWeaponSidebarKeysEnabled", Phobos::Config::SuperWeaponSidebarCommands);
Phobos::Config::ShowPlanningPath = pINI_RULESMD->ReadBool("GlobalControls", "DebugPlanningPaths", Phobos::Config::ShowPlanningPath);
+ Phobos::Config::AllowSwitchNoMoveCommand = pINI_RULESMD->ReadBool("GlobalControls", "AllowSwitchNoMoveCommand", Phobos::Config::AllowDistributionCommand);
Phobos::Config::AllowDistributionCommand = pINI_RULESMD->ReadBool("GlobalControls", "AllowDistributionCommand", Phobos::Config::AllowDistributionCommand);
Phobos::Config::AllowDistributionCommand_SpreadMode = pINI_RULESMD->ReadBool("GlobalControls", "AllowDistributionCommand.SpreadMode", Phobos::Config::AllowDistributionCommand_SpreadMode);
Phobos::Config::AllowDistributionCommand_SpreadModeScroll = pINI_RULESMD->ReadBool("GlobalControls", "AllowDistributionCommand.SpreadModeScroll", Phobos::Config::AllowDistributionCommand_SpreadModeScroll);
diff --git a/src/Phobos.h b/src/Phobos.h
index 522fff1f41..ce4a7bbdfe 100644
--- a/src/Phobos.h
+++ b/src/Phobos.h
@@ -104,12 +104,14 @@ class Phobos
static bool HideLightFlashEffects;
static bool ShowFlashOnSelecting;
static bool UnitPowerDrain;
+ static bool AllowSwitchNoMoveCommand;
static bool AllowDistributionCommand;
static bool AllowDistributionCommand_SpreadMode;
static bool AllowDistributionCommand_SpreadModeScroll;
static bool AllowDistributionCommand_FilterMode;
static bool AllowDistributionCommand_AffectsAllies;
static bool AllowDistributionCommand_AffectsEnemies;
+ static bool ApplyNoMoveCommand;
static int DistributionSpreadMode;
static int DistributionFilterMode;
static int SuperWeaponSidebar_RequiredSignificance;
From e0bbe021020b87248afe4f2d61ccf37768730599 Mon Sep 17 00:00:00 2001
From: CrimRecya <335958461@qq.com>
Date: Wed, 6 Aug 2025 21:42:09 +0800
Subject: [PATCH 24/30] Fix include
---
src/Commands/DistributionMode.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/Commands/DistributionMode.h b/src/Commands/DistributionMode.h
index 49a1c051d2..d043836e31 100644
--- a/src/Commands/DistributionMode.h
+++ b/src/Commands/DistributionMode.h
@@ -2,6 +2,8 @@
#include "Commands.h"
+#include
+
class SwitchNoMoveCommandClass : public CommandClass
{
public:
From 573d8f81e2e364cfc8d40aedff3e58e0bb75140e Mon Sep 17 00:00:00 2001
From: CrimRecya <335958461@qq.com>
Date: Tue, 26 Aug 2025 11:37:05 +0800
Subject: [PATCH 25/30] Fit with FakeOf
---
src/Commands/DistributionMode.cpp | 45 ++++++++++++++++++-------------
src/Ext/TechnoType/Body.cpp | 2 ++
src/Ext/TechnoType/Body.h | 2 ++
3 files changed, 31 insertions(+), 18 deletions(-)
diff --git a/src/Commands/DistributionMode.cpp b/src/Commands/DistributionMode.cpp
index 7566ab0175..2c0bde5f1a 100644
--- a/src/Commands/DistributionMode.cpp
+++ b/src/Commands/DistributionMode.cpp
@@ -214,16 +214,16 @@ DEFINE_HOOK(0x4AE7B3, DisplayClass_ActiveClickWith_Iterate, 0x0)
&& action != Action::NoMove
&& !PlanningNodeClass::PlanningModeActive
&& pTechno
- && !pTarget->IsInAir()
+ && !pTechno->IsInAir()
&& (HouseClass::CurrentPlayer->IsAlliedWith(pTechno->Owner)
? Phobos::Config::AllowDistributionCommand_AffectsAllies
: Phobos::Config::AllowDistributionCommand_AffectsEnemies))
{
VocClass::PlayGlobal(RulesExt::Global()->AddDistributionModeCommandSound, 0x2000, 1.0);
const bool targetIsNeutral = pTechno->Owner->IsNeutral();
-
+ const auto pType = pTechno->GetTechnoType();
const int range = (2 << spreadMode);
- const auto center = pTarget->GetCoords();
+ const auto center = pTechno->GetCoords();
const auto pItems = Helpers::Alex::getCellSpreadItems(center, range);
std::vector> record;
@@ -283,20 +283,29 @@ DEFINE_HOOK(0x4AE7B3, DisplayClass_ActiveClickWith_Iterate, 0x0)
if (filterMode)
{
- if (filterMode == 1)
- {
- if (pItem->GetType()->Armor != pTarget->GetType()->Armor)
- continue;
- }
- else if (filterMode == 2)
- {
- if (pItem->WhatAmI() != pTarget->WhatAmI())
- continue;
- }
- else // filterMode == 3
+ const auto pItemType = pItem->GetTechnoType();
+
+ if (!pItemType)
+ continue;
+
+ if (TechnoTypeExt::ExtMap.Find(pType)->FakeOf != pItemType
+ && TechnoTypeExt::ExtMap.Find(pItemType)->FakeOf != pType)
{
- if (TechnoTypeExt::GetSelectionGroupID(pItem->GetType()) != TechnoTypeExt::GetSelectionGroupID(pTarget->GetType()))
- continue;
+ if (filterMode == 1)
+ {
+ if (pItemType->Armor != pType->Armor)
+ continue;
+ }
+ else if (filterMode == 2)
+ {
+ if (pItem->WhatAmI() != pTechno->WhatAmI())
+ continue;
+ }
+ else // filterMode == 3
+ {
+ if (TechnoTypeExt::GetSelectionGroupID(pItemType) != TechnoTypeExt::GetSelectionGroupID(pType))
+ continue;
+ }
}
}
@@ -325,12 +334,12 @@ DEFINE_HOOK(0x4AE7B3, DisplayClass_ActiveClickWith_Iterate, 0x0)
continue;
}
- const auto currentAction = pSelect->MouseOverObject(pTarget);
+ const auto currentAction = pSelect->MouseOverObject(pTechno);
if (noMove && currentAction == Action::NoMove && (pSelect->AbstractFlags & AbstractFlags::Techno) != AbstractFlags::None)
DistributionModeHoldDownCommandClass::AreaGuardAction(static_cast(pSelect));
else
- DistributionModeHoldDownCommandClass::ClickedTargetAction(pSelect, currentAction, pTarget);
+ DistributionModeHoldDownCommandClass::ClickedTargetAction(pSelect, currentAction, pTechno);
}
}
else
diff --git a/src/Ext/TechnoType/Body.cpp b/src/Ext/TechnoType/Body.cpp
index 80810502d0..3f512d1675 100644
--- a/src/Ext/TechnoType/Body.cpp
+++ b/src/Ext/TechnoType/Body.cpp
@@ -924,6 +924,7 @@ void TechnoTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI)
// Ares 2.0
this->Passengers_BySize.Read(exINI, pSection, "Passengers.BySize");
+ this->FakeOf.Read(exINI, pSection, "FakeOf");
char tempBuffer[40];
@@ -1295,6 +1296,7 @@ void TechnoTypeExt::ExtData::Serialize(T& Stm)
.Process(this->DeployingAnim_UseUnitDrawer)
.Process(this->EnemyUIName)
+ .Process(this->FakeOf)
.Process(this->ForceWeapon_Check)
.Process(this->ForceWeapon_Naval_Decloaked)
diff --git a/src/Ext/TechnoType/Body.h b/src/Ext/TechnoType/Body.h
index 545b6a9d33..4a0491bc9a 100644
--- a/src/Ext/TechnoType/Body.h
+++ b/src/Ext/TechnoType/Body.h
@@ -169,6 +169,7 @@ class TechnoTypeExt
Valueable DeployingAnim_UseUnitDrawer;
Valueable EnemyUIName;
+ Valueable FakeOf;
bool ForceWeapon_Check;
Valueable ForceWeapon_Naval_Decloaked;
@@ -537,6 +538,7 @@ class TechnoTypeExt
, CombatAlert_EVA {}
, EnemyUIName {}
+ , FakeOf {}
, VoiceCreated {}
, VoicePickup {}
From 4ab98767a2d57df0d6a0b965283ab8549b7c320a Mon Sep 17 00:00:00 2001
From: CrimRecya <335958461@qq.com>
Date: Thu, 28 Aug 2025 21:19:04 +0800
Subject: [PATCH 26/30] TODO
---
src/Commands/DistributionMode.cpp | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/src/Commands/DistributionMode.cpp b/src/Commands/DistributionMode.cpp
index 2c0bde5f1a..e3dff4833a 100644
--- a/src/Commands/DistributionMode.cpp
+++ b/src/Commands/DistributionMode.cpp
@@ -395,3 +395,10 @@ DEFINE_HOOK(0x6DBE74, TacticalClass_DrawAllRadialIndicators_DrawDistributionRang
return 0;
}
+
+/*
+TODO
+- More flexible range adjustment
+- Drag mouse to adjust the range
+- Target highlight within the range
+*/
From e49a75fb8e58e1693113cb8cee4bb57108d0877d Mon Sep 17 00:00:00 2001
From: CrimRecya <335958461@qq.com>
Date: Sat, 13 Sep 2025 20:41:22 +0800
Subject: [PATCH 27/30] Update YRpp
---
YRpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/YRpp b/YRpp
index 5af96790ce..91ae0bc814 160000
--- a/YRpp
+++ b/YRpp
@@ -1 +1 @@
-Subproject commit 5af96790ce73e4ea068a390c60c124dccbc220e1
+Subproject commit 91ae0bc814feb1146908ddc53e0040f37f3e5e75
From eb552f1898cf115b67ac1bf3925699463c9b552d Mon Sep 17 00:00:00 2001
From: CrimRecya <335958461@qq.com>
Date: Sat, 13 Sep 2025 20:48:11 +0800
Subject: [PATCH 28/30] Button on bottom
---
src/Commands/Commands.cpp | 87 +++++++++++++++++++++++++++++++
src/Commands/Commands.h | 33 ++++++++++++
src/Commands/DistributionMode.cpp | 65 ++++++++++++++++-------
src/Commands/DistributionMode.h | 3 ++
4 files changed, 170 insertions(+), 18 deletions(-)
diff --git a/src/Commands/Commands.cpp b/src/Commands/Commands.cpp
index c44a749278..2324a51f33 100644
--- a/src/Commands/Commands.cpp
+++ b/src/Commands/Commands.cpp
@@ -15,11 +15,14 @@
#include "ToggleMessageList.h"
#include
+#include
#include
#include
#include
+#pragma region HotkeyCommand
+
DEFINE_HOOK(0x533066, CommandClassCallback_Register, 0x6)
{
// Load it after Ares'
@@ -76,6 +79,10 @@ DEFINE_HOOK(0x533066, CommandClassCallback_Register, 0x6)
return 0;
}
+#pragma endregion
+
+#pragma region MouseScroll
+
static void MouseWheelDownCommand()
{
if (DistributionModeHoldDownCommandClass::Enabled && Phobos::Config::AllowDistributionCommand_SpreadModeScroll)
@@ -117,3 +124,83 @@ DEFINE_HOOK(0x533F50, Game_ScrollSidebar_Skip, 0x5)
enum { SkipScrollSidebar = 0x533FC3 };
return CheckSkipScrollSidebar() ? SkipScrollSidebar : 0;
}
+
+#pragma endregion
+
+#pragma region ShapeButton
+
+int ShapeButtonHelper::NewButtonIndexes[ShapeButtonHelper::NewButtonCount] =
+{
+ -1 // DistributionMode
+ // New button initialize here
+};
+
+DEFINE_HOOK(0x6CFD08, ShapeButtonClass_FindIndex_FindNewButton, 0x5)
+{
+ enum { SetButtonIndex = 0x6CFD0D };
+
+ GET(const char*, name, ECX);
+
+ for (int i = 0; i < ShapeButtonHelper::NewButtonCount; ++i)
+ {
+ if (_strcmpi(name, ShapeButtonHelper::NewButtonNames[i]) == 0)
+ {
+ R->EAX(i + ShapeButtonHelper::OldButtonCount);
+ return SetButtonIndex;
+ }
+ }
+
+ return 0;
+}
+
+DEFINE_HOOK(0x6D0233, TabClass_Init_InitNewButtonIndex, 0x6)
+{
+ for (int i = 0; i < ShapeButtonHelper::NewButtonCount; ++i)
+ ShapeButtonHelper::NewButtonIndexes[i] = ShapeButtonClass::FindIndex(ShapeButtonHelper::NewButtonNames[i]);
+
+ return 0;
+}
+
+DEFINE_HOOK(0x6D0827, TabClass_Update_UpdateNewButton, 0x6)
+{
+ GET(const int, index, EAX);
+
+ if (ShapeButtonHelper::NewButtonIndexes[0] == index)
+ {
+ if (ShapeButtonClass::GetButton(index)->IsOn)
+ DistributionModeHoldDownCommandClass::DistributionModeOn();
+ else
+ DistributionModeHoldDownCommandClass::DistributionModeOff();
+ }
+
+ // New button trigger here
+
+ return 0;
+}
+
+DEFINE_HOOK(0x6D10DF, TabClass_InitButtonIO_InitNewHoldDownButton, 0x6)
+{
+ const int distributionModeButtonIndex = ShapeButtonHelper::NewButtonIndexes[0];
+
+ if (distributionModeButtonIndex != -1)
+ {
+ if (const auto pButton = ShapeButtonClass::GetButton(distributionModeButtonIndex))
+ {
+ // Clicking the button is different from holding down the hotkey
+ pButton->ToggleType = 1;
+ pButton->UseFlash = true;
+ }
+ }
+
+ return 0;
+}
+
+DEFINE_HOOK(0x6D14DD, TabClass_InitToolTip_InitNewButtonToolTip, 0x5)
+{
+ for (int i = 0; i < ShapeButtonHelper::NewButtonCount; ++i)
+ ShapeButtonClass::SetToolTip(ShapeButtonClass::GetButton(ShapeButtonHelper::NewButtonIndexes[i]), ShapeButtonHelper::NewButtonTipNames[i]);
+
+ return 0;
+}
+
+#pragma endregion
diff --git a/src/Commands/Commands.h b/src/Commands/Commands.h
index ae3c89f503..286eef89c8 100644
--- a/src/Commands/Commands.h
+++ b/src/Commands/Commands.h
@@ -14,6 +14,39 @@ T* MakeCommand()
return command;
};
+class ShapeButtonHelper
+{
+public:
+ static constexpr int MaxButtonCount = 25;
+ static constexpr int InUseButtonCount = 11;
+ static constexpr int UnusedButtonCount = 1;
+ static constexpr int OldButtonCount = InUseButtonCount + UnusedButtonCount;
+ static constexpr int NewButtonCount = std::min(1, (MaxButtonCount - OldButtonCount));
+ // 1. Team01
+ // 2. Team02
+ // 3. Team03
+ // 4. TypeSelect
+ // 5. Deploy
+ // 6. AttackMove
+ // 7. Guard
+ // 8. Beacon
+ // 9. Stop
+ // 10. PlanningMode
+ // 11. Cheer
+ // 12. MoveToDeploy
+ static constexpr const char* NewButtonNames[NewButtonCount] =
+ {
+ /* 13. */ "DistributionMode"
+ /* New button name here */
+ };
+ static constexpr const char* NewButtonTipNames[NewButtonCount] =
+ {
+ "Tip:DistributionMode"
+ // New button tip here
+ };
+ static int NewButtonIndexes[NewButtonCount];
+};
+
#define CATEGORY_TEAM StringTable::LoadString(GameStrings::TXT_TEAM)
#define CATEGORY_INTERFACE StringTable::LoadString(GameStrings::TXT_INTERFACE)
#define CATEGORY_TAUNT StringTable::LoadString(GameStrings::TXT_TAUNT)
diff --git a/src/Commands/DistributionMode.cpp b/src/Commands/DistributionMode.cpp
index e3dff4833a..a86bc5566c 100644
--- a/src/Commands/DistributionMode.cpp
+++ b/src/Commands/DistributionMode.cpp
@@ -5,6 +5,7 @@
#include
#include
+#include
bool DistributionModeHoldDownCommandClass::Enabled = false;
bool DistributionModeHoldDownCommandClass::OnMessageShowed = false;
@@ -116,30 +117,58 @@ bool DistributionModeHoldDownCommandClass::ExtraTriggerCondition(WWKey eInput) c
void DistributionModeHoldDownCommandClass::Execute(WWKey eInput) const
{
if (eInput & WWKey::Release)
- {
- DistributionModeHoldDownCommandClass::Enabled = false;
+ DistributionModeHoldDownCommandClass::DistributionModeOff();
+ else
+ DistributionModeHoldDownCommandClass::DistributionModeOn();
+}
+
+void DistributionModeHoldDownCommandClass::DistributionModeOn()
+{
+ if (DistributionModeHoldDownCommandClass::Enabled)
+ return;
- if (HouseClass::IsCurrentPlayerObserver() || SessionClass::Instance.MultiplayerObserver)
- return;
+ if (SessionClass::Instance.MultiplayerObserver)
+ return;
- VocClass::PlayGlobal(RulesExt::Global()->EndDistributionModeSound, 0x2000, 1.0);
+ DistributionModeHoldDownCommandClass::Enabled = true;
- if (!DistributionModeHoldDownCommandClass::OffMessageShowed)
- {
- DistributionModeHoldDownCommandClass::OffMessageShowed = true;
- MessageListClass::Instance.PrintMessage(GeneralUtils::LoadStringUnlessMissing("MSG:DistributionModeOff", L"Distribution mode unabled."), RulesClass::Instance->MessageDelay, HouseClass::CurrentPlayer->ColorSchemeIndex, true);
- }
+ if (const auto pButton = reinterpret_cast(0x6CFD40)(ShapeButtonHelper::NewButtonIndexes[0]))
+ {
+ if (!pButton->IsOn)
+ pButton->TurnOn();
+ }
+
+ VocClass::PlayGlobal(RulesExt::Global()->StartDistributionModeSound, 0x2000, 1.0);
+
+ if (!DistributionModeHoldDownCommandClass::OnMessageShowed)
+ {
+ DistributionModeHoldDownCommandClass::OnMessageShowed = true;
+ MessageListClass::Instance.PrintMessage(GeneralUtils::LoadStringUnlessMissing("MSG:DistributionModeOn", L"Distribution mode enabled."), RulesClass::Instance->MessageDelay, HouseClass::CurrentPlayer->ColorSchemeIndex, true);
}
- else if (!HouseClass::IsCurrentPlayerObserver() && !SessionClass::Instance.MultiplayerObserver)
+}
+
+void DistributionModeHoldDownCommandClass::DistributionModeOff()
+{
+ if (!DistributionModeHoldDownCommandClass::Enabled)
+ return;
+
+ DistributionModeHoldDownCommandClass::Enabled = false;
+
+ if (const auto pButton = reinterpret_cast(0x6CFD40)(ShapeButtonHelper::NewButtonIndexes[0]))
{
- DistributionModeHoldDownCommandClass::Enabled = true;
- VocClass::PlayGlobal(RulesExt::Global()->StartDistributionModeSound, 0x2000, 1.0);
+ if (pButton->IsOn)
+ pButton->TurnOff();
+ }
- if (!DistributionModeHoldDownCommandClass::OnMessageShowed)
- {
- DistributionModeHoldDownCommandClass::OnMessageShowed = true;
- MessageListClass::Instance.PrintMessage(GeneralUtils::LoadStringUnlessMissing("MSG:DistributionModeOn", L"Distribution mode enabled."), RulesClass::Instance->MessageDelay, HouseClass::CurrentPlayer->ColorSchemeIndex, true);
- }
+ if (SessionClass::Instance.MultiplayerObserver)
+ return;
+
+ VocClass::PlayGlobal(RulesExt::Global()->EndDistributionModeSound, 0x2000, 1.0);
+
+ if (!DistributionModeHoldDownCommandClass::OffMessageShowed)
+ {
+ DistributionModeHoldDownCommandClass::OffMessageShowed = true;
+ MessageListClass::Instance.PrintMessage(GeneralUtils::LoadStringUnlessMissing("MSG:DistributionModeOff", L"Distribution mode unabled."), RulesClass::Instance->MessageDelay, HouseClass::CurrentPlayer->ColorSchemeIndex, true);
}
}
diff --git a/src/Commands/DistributionMode.h b/src/Commands/DistributionMode.h
index d043836e31..fb21391e77 100644
--- a/src/Commands/DistributionMode.h
+++ b/src/Commands/DistributionMode.h
@@ -49,8 +49,11 @@ class DistributionModeHoldDownCommandClass : public CommandClass
virtual bool ExtraTriggerCondition(WWKey eInput) const override;
virtual void Execute(WWKey eInput) const override;
+ static void DistributionModeOn();
+ static void DistributionModeOff();
static void DistributionSpreadModeExpand();
static void DistributionSpreadModeReduce();
+
static void __fastcall ClickedWaypoint(ObjectClass* pSelect, int idxPath, signed char idxWP);
static void __fastcall ClickedTargetAction(ObjectClass* pSelect, Action action, ObjectClass* pTarget);
static void __fastcall ClickedCellAction(ObjectClass* pSelect, Action action, CellStruct* pCell, CellStruct* pSecondCell);
From 27ca512cb5bd1e234172bb94a824f747c1dae650 Mon Sep 17 00:00:00 2001
From: Coronia <2217891145@qq.com>
Date: Sat, 18 Oct 2025 18:46:40 +0800
Subject: [PATCH 29/30] update doc
---
YRpp | 2 +-
docs/User-Interface.md | 40 ++++++++++++++++++++++++++--------------
2 files changed, 27 insertions(+), 15 deletions(-)
diff --git a/YRpp b/YRpp
index 91ae0bc814..f01dce96b5 160000
--- a/YRpp
+++ b/YRpp
@@ -1 +1 @@
-Subproject commit 91ae0bc814feb1146908ddc53e0040f37f3e5e75
+Subproject commit f01dce96b59508d0aa78f877c28c1b8e29f3857c
diff --git a/docs/User-Interface.md b/docs/User-Interface.md
index 072fd72184..af1cd23a02 100644
--- a/docs/User-Interface.md
+++ b/docs/User-Interface.md
@@ -497,31 +497,43 @@ For this command to work in multiplayer - you need to use a version of [YRpp spa
- `Type` - only targets of the same type (like infantries, vehicles or buildings) will be selected among the targets allocated in the range. At this time, a yellow ring will be displayed.
- `Name` - only targets of the same name (or with the same `GroupAs`) will be selected among the targets allocated in the range. At this time, a red ring will be displayed.
- `AllowDistributionCommand.AffectsAllies` & `AllowDistributionCommand.AffectsEnemies` allow the distribution command to work on allies (including owner) or enemies target. If picking a target that's not eligible, it'll fallback to vanilla command.
-- For localization add `TXT_SWITCH_NOMOVE`, `TXT_DISTR_SPREAD`, `TXT_DISTR_FILTER`, `TXT_DISTR_HOLDDOWN`, `TXT_SWITCH_NOMOVE_DESC`, `TXT_DISTR_SPREAD_DESC`, `TXT_DISTR_FILTER_DESC`, `TXT_DISTR_HOLDDOWN_DESC`, `MSG:DistributionModeOn`, `MSG:DistributionModeOff` into your `.csf` file.
+- It's possible to add a button for distribution mode in the bottom bar by adding `DistributionMode` in the `ButtonList` of `AdvancedCommandBar` and `MultiplayerAdvancedCommandBar`.
+ - The positions of each button are hardcoded, so it'll only decide whether enable this button or not. Distribute Mode button is now always listed after all the vanilla ones.
+ - The asset of these buttons should be added in `sidec0x.mix` files which correspond to different sides, with the name `button12.shp`.
+- For localization add `TXT_SWITCH_NOMOVE`, `TXT_DISTR_SPREAD`, `TXT_DISTR_FILTER`, `TXT_DISTR_HOLDDOWN`, `TXT_SWITCH_NOMOVE_DESC`, `TXT_DISTR_SPREAD_DESC`, `TXT_DISTR_FILTER_DESC`, `TXT_DISTR_HOLDDOWN_DESC`, `MSG:DistributionModeOn`, `MSG:DistributionModeOff`, `TIP:DistributionMode` into your `.csf` file.
In `rulesmd.ini`:
```ini
[GlobalControls]
-AllowSwitchNoMoveCommand=false ; boolean
-AllowDistributionCommand=false ; boolean
-AllowDistributionCommand.SpreadMode=true ; boolean
-AllowDistributionCommand.SpreadModeScroll=true ; boolean
-AllowDistributionCommand.FilterMode=true ; boolean
-AllowDistributionCommand.AffectsAllies=true ; boolean
-AllowDistributionCommand.AffectsEnemies=true ; boolean
+AllowSwitchNoMoveCommand=false ; boolean
+AllowDistributionCommand=false ; boolean
+AllowDistributionCommand.SpreadMode=true ; boolean
+AllowDistributionCommand.SpreadModeScroll=true ; boolean
+AllowDistributionCommand.FilterMode=true ; boolean
+AllowDistributionCommand.AffectsAllies=true ; boolean
+AllowDistributionCommand.AffectsEnemies=true ; boolean
[AudioVisual]
-StartDistributionModeSound= ; sound entry
-EndDistributionModeSound= ; sound entry
-AddDistributionModeCommandSound= ; sound entry
+StartDistributionModeSound= ; sound entry
+EndDistributionModeSound= ; sound entry
+AddDistributionModeCommandSound= ; sound entry
```
In `ra2md.ini`:
```ini
[Phobos]
-DefaultApplyNoMoveCommand=true ; boolean
-DefaultDistributionSpreadMode=2 ; integer, 0 - r=0 , 1 - r=4 , 2 - r=8 , 3 - r=16
-DefaultDistributionFilterMode=2 ; integer, 0 - None , 1 - Like , 2 - Type , 3 - Name
+DefaultApplyNoMoveCommand=true ; boolean
+DefaultDistributionSpreadMode=2 ; integer, 0 - r=0 , 1 - r=4 , 2 - r=8 , 3 - r=16
+DefaultDistributionFilterMode=2 ; integer, 0 - None , 1 - Like , 2 - Type , 3 - Name
+```
+
+In `uimd.ini`:
+```ini
+[AdvancedCommandBar]
+ButtonList=[Button1],DistributionMode,[ButtonX] ; List of button entry
+
+[MultiplayerAdvancedCommandBar]
+ButtonList=[Button1],DistributionMode,[ButtonX] ; List of button entry
```
### `[ ]` Toggle Message Label
From 9dcbd2c513e17f1ecff5d0025e6778eaa97c9398 Mon Sep 17 00:00:00 2001
From: Coronia <2217891145@qq.com>
Date: Sat, 18 Oct 2025 21:59:59 +0800
Subject: [PATCH 30/30] revert YRpp
---
YRpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/YRpp b/YRpp
index f01dce96b5..91ae0bc814 160000
--- a/YRpp
+++ b/YRpp
@@ -1 +1 @@
-Subproject commit f01dce96b59508d0aa78f877c28c1b8e29f3857c
+Subproject commit 91ae0bc814feb1146908ddc53e0040f37f3e5e75