From 52ec449c2136208ec69e2bf237c311f4c08be045 Mon Sep 17 00:00:00 2001
From: RAZER <79311432+CnCRAZER@users.noreply.github.com>
Date: Thu, 5 Mar 2026 12:50:23 -0600
Subject: [PATCH 1/7] Add 'Build Last' commands and tracking
Introduce BuildLastOfTab commands to re-queue the last produced item from each sidebar tab (Power/Infrastructure, Defense/Combat, Infantry, Vehicles/Aircraft). Adds BuildLastOfTab.cpp/.h with a templated CommandClass (explicit instantiations for tabs 0..3) and UI strings. Register the new commands in Commands.cpp and add sources to the Visual Studio project file. Add per-tab last-built tracking to HouseExt (LastBuiltPerTab, LastBuiltRTTIPerTab, LastBuiltIsNavalPerTab), initialize defaults, and include them in serialization. Add a hook (Hooks.BuildLastTab.cpp) into HouseClass object delivery to update the per-tab last-built info when the current player's factory delivers an object.
---
Phobos.vcxproj | 2 +
src/Commands/BuildLastOfTab.cpp | 96 ++++++++++++++++++++++++++++
src/Commands/BuildLastOfTab.h | 16 +++++
src/Commands/Commands.cpp | 5 ++
src/Ext/House/Body.cpp | 3 +
src/Ext/House/Body.h | 9 +++
src/Ext/House/Hooks.BuildLastTab.cpp | 42 ++++++++++++
7 files changed, 173 insertions(+)
create mode 100644 src/Commands/BuildLastOfTab.cpp
create mode 100644 src/Commands/BuildLastOfTab.h
create mode 100644 src/Ext/House/Hooks.BuildLastTab.cpp
diff --git a/Phobos.vcxproj b/Phobos.vcxproj
index d45a6ac91f..4198646853 100644
--- a/Phobos.vcxproj
+++ b/Phobos.vcxproj
@@ -36,6 +36,7 @@
+
@@ -132,6 +133,7 @@
+
diff --git a/src/Commands/BuildLastOfTab.cpp b/src/Commands/BuildLastOfTab.cpp
new file mode 100644
index 0000000000..74b11fc0cc
--- /dev/null
+++ b/src/Commands/BuildLastOfTab.cpp
@@ -0,0 +1,96 @@
+#include "BuildLastOfTab.h"
+
+#include
+#include
+#include
+#include
+
+static constexpr const char* BuildLastTabNames[4] =
+{
+ "BuildLastOfTab_Power",
+ "BuildLastOfTab_Defense",
+ "BuildLastOfTab_Infantry",
+ "BuildLastOfTab_Vehicles",
+};
+
+static constexpr const char* BuildLastTabDescKeys[4] =
+{
+ "BuildLastOfTab_Power_Desc",
+ "BuildLastOfTab_Defense_Desc",
+ "BuildLastOfTab_Infantry_Desc",
+ "BuildLastOfTab_Vehicles_Desc",
+};
+
+static constexpr const wchar_t* BuildLastTabUINames[4] =
+{
+ L"Build Last (Power/Resources)",
+ L"Build Last (Defense/Combat)",
+ L"Build Last (Infantry)",
+ L"Build Last (Vehicles/Aircraft)",
+};
+
+static constexpr const wchar_t* BuildLastTabUIDescs[4] =
+{
+ L"Re-queue the last produced Power/Resources building.",
+ L"Re-queue the last produced Defense/Combat building.",
+ L"Re-queue the last produced Infantry unit.",
+ L"Re-queue the last produced Vehicle or Aircraft.",
+};
+
+template
+const char* BuildLastOfTabCommandClass::GetName() const
+{
+ return BuildLastTabNames[TabIndex];
+}
+
+template
+const wchar_t* BuildLastOfTabCommandClass::GetUIName() const
+{
+ return GeneralUtils::LoadStringUnlessMissing(BuildLastTabNames[TabIndex], BuildLastTabUINames[TabIndex]);
+}
+
+template
+const wchar_t* BuildLastOfTabCommandClass::GetUICategory() const
+{
+ return CATEGORY_INTERFACE;
+}
+
+template
+const wchar_t* BuildLastOfTabCommandClass::GetUIDescription() const
+{
+ static_assert(TabIndex >= 0 && TabIndex < 4, "TabIndex out of range");
+ return GeneralUtils::LoadStringUnlessMissing(BuildLastTabDescKeys[TabIndex], BuildLastTabUIDescs[TabIndex]);
+}
+
+template
+void BuildLastOfTabCommandClass::Execute(WWKey eInput) const
+{
+ auto const pPlayer = HouseClass::CurrentPlayer;
+ if (!pPlayer)
+ return;
+
+ auto const pExt = HouseExt::ExtMap.Find(pPlayer);
+ if (!pExt)
+ return;
+
+ auto const typeIndex = pExt->LastBuiltPerTab[TabIndex];
+ if (typeIndex < 0)
+ return;
+
+ auto const rtti = pExt->LastBuiltRTTIPerTab[TabIndex];
+ auto const isNaval = pExt->LastBuiltIsNavalPerTab[TabIndex];
+
+ EventClass::OutList.Add(EventClass(
+ pPlayer->ArrayIndex,
+ EventType::Produce,
+ static_cast(rtti),
+ typeIndex,
+ isNaval ? TRUE : FALSE
+ ));
+}
+
+// Explicit instantiations
+template class BuildLastOfTabCommandClass<0>;
+template class BuildLastOfTabCommandClass<1>;
+template class BuildLastOfTabCommandClass<2>;
+template class BuildLastOfTabCommandClass<3>;
diff --git a/src/Commands/BuildLastOfTab.h b/src/Commands/BuildLastOfTab.h
new file mode 100644
index 0000000000..35929fe334
--- /dev/null
+++ b/src/Commands/BuildLastOfTab.h
@@ -0,0 +1,16 @@
+#pragma once
+
+#include "Commands.h"
+
+// Re-queue the last produced item from a specific production tab.
+// TabIndex: 0 = Power/Infrastructure, 1 = Defense/Combat, 2 = Infantry, 3 = Vehicles/Aircraft
+template
+class BuildLastOfTabCommandClass : 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;
+};
diff --git a/src/Commands/Commands.cpp b/src/Commands/Commands.cpp
index 2460c6b971..54c3235e71 100644
--- a/src/Commands/Commands.cpp
+++ b/src/Commands/Commands.cpp
@@ -12,6 +12,7 @@
#include "ToggleSWSidebar.h"
#include "FireTacticalSW.h"
#include "ToggleMessageList.h"
+#include "BuildLastOfTab.h"
#include
@@ -28,6 +29,10 @@ DEFINE_HOOK(0x533066, CommandClassCallback_Register, 0x6)
MakeCommand();
MakeCommand();
MakeCommand();
+ MakeCommand>();
+ MakeCommand>();
+ MakeCommand>();
+ MakeCommand>();
if (Phobos::Config::SuperWeaponSidebarCommands)
{
diff --git a/src/Ext/House/Body.cpp b/src/Ext/House/Body.cpp
index 176b2a680c..34c34d9dcd 100644
--- a/src/Ext/House/Body.cpp
+++ b/src/Ext/House/Body.cpp
@@ -696,6 +696,9 @@ void HouseExt::ExtData::Serialize(T& Stm)
.Process(this->RestrictedFactoryPlants)
.Process(this->LastBuiltNavalVehicleType)
.Process(this->ProducingNavalUnitTypeIndex)
+ .Process(this->LastBuiltPerTab)
+ .Process(this->LastBuiltRTTIPerTab)
+ .Process(this->LastBuiltIsNavalPerTab)
.Process(this->CombatAlertTimer)
.Process(this->NumAirpads_NonMFB)
.Process(this->NumBarracks_NonMFB)
diff --git a/src/Ext/House/Body.h b/src/Ext/House/Body.h
index 3c1109a7e1..e3333d69fb 100644
--- a/src/Ext/House/Body.h
+++ b/src/Ext/House/Body.h
@@ -46,6 +46,12 @@ class HouseExt
int LastBuiltNavalVehicleType;
int ProducingNavalUnitTypeIndex;
+ // Per-tab last-built tracking for the Build Last commands.
+ // Indexed by sidebar tab: 0=Power/Infra, 1=Combat, 2=Infantry, 3=Vehicles/Aircraft.
+ int LastBuiltPerTab[4];
+ AbstractType LastBuiltRTTIPerTab[4];
+ bool LastBuiltIsNavalPerTab[4];
+
// Factories that exist but don't count towards multiple factory bonus.
int NumAirpads_NonMFB;
int NumBarracks_NonMFB;
@@ -85,6 +91,9 @@ class HouseExt
, RestrictedFactoryPlants {}
, LastBuiltNavalVehicleType { -1 }
, ProducingNavalUnitTypeIndex { -1 }
+ , LastBuiltPerTab { -1, -1, -1, -1 }
+ , LastBuiltRTTIPerTab { AbstractType::None, AbstractType::None, AbstractType::None, AbstractType::None }
+ , LastBuiltIsNavalPerTab { false, false, false, false }
, CombatAlertTimer {}
, NumAirpads_NonMFB { 0 }
, NumBarracks_NonMFB { 0 }
diff --git a/src/Ext/House/Hooks.BuildLastTab.cpp b/src/Ext/House/Hooks.BuildLastTab.cpp
new file mode 100644
index 0000000000..0632760702
--- /dev/null
+++ b/src/Ext/House/Hooks.BuildLastTab.cpp
@@ -0,0 +1,42 @@
+#include "Body.h"
+
+#include
+#include
+#include
+
+// Hook into HouseClass::RegisterObjectGain_FromFactory (0x4FB6B0).
+// Fires when a unit or building is delivered from a factory.
+// At this point: EDI = HouseClass*, EBP = TechnoClass* (the object being delivered).
+// We track the delivered type per sidebar tab so the "Build Last" commands can re-queue it.
+
+DEFINE_HOOK(0x4FB6C2, HouseClass_RegisterObjectGain_TrackLastBuiltTab, 0x7)
+{
+ GET(HouseClass* const, pThis, EDI);
+ GET(TechnoClass* const, pTechno, EBP);
+
+ if (pThis != HouseClass::CurrentPlayer)
+ return 0;
+
+ auto const pType = pTechno->GetTechnoType();
+ if (!pType)
+ return 0;
+
+ auto const absType = pType->WhatAmI();
+ auto const isNaval = pType->Naval;
+
+ auto buildCat = BuildCat::DontCare;
+ if (absType == AbstractType::BuildingType)
+ buildCat = static_cast(pType)->BuildCat;
+
+ int const tabIdx = SidebarClass::GetObjectTabIdx(absType, buildCat, isNaval);
+
+ if (tabIdx >= 0 && tabIdx < 4)
+ {
+ auto const pExt = HouseExt::ExtMap.Find(pThis);
+ pExt->LastBuiltPerTab[tabIdx] = pType->GetArrayIndex();
+ pExt->LastBuiltRTTIPerTab[tabIdx] = absType;
+ pExt->LastBuiltIsNavalPerTab[tabIdx] = isNaval;
+ }
+
+ return 0;
+}
From 4c8c18a8e87295cecf4db79630abee8588b42ffa Mon Sep 17 00:00:00 2001
From: RAZER <79311432+CnCRAZER@users.noreply.github.com>
Date: Thu, 5 Mar 2026 13:08:11 -0600
Subject: [PATCH 2/7] Update BuildLastOfTab.cpp
---
src/Commands/BuildLastOfTab.cpp | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/src/Commands/BuildLastOfTab.cpp b/src/Commands/BuildLastOfTab.cpp
index 74b11fc0cc..35d22ca294 100644
--- a/src/Commands/BuildLastOfTab.cpp
+++ b/src/Commands/BuildLastOfTab.cpp
@@ -4,6 +4,7 @@
#include
#include
#include
+#include
static constexpr const char* BuildLastTabNames[4] =
{
@@ -77,6 +78,13 @@ void BuildLastOfTabCommandClass::Execute(WWKey eInput) const
if (typeIndex < 0)
return;
+ // Focus the sidebar to the corresponding tab.
+ if (SidebarClass::Instance.IsSidebarActive)
+ {
+ SidebarClass::Instance.ActiveTabIndex = TabIndex;
+ SidebarClass::Instance.SidebarNeedsRepaint();
+ }
+
auto const rtti = pExt->LastBuiltRTTIPerTab[TabIndex];
auto const isNaval = pExt->LastBuiltIsNavalPerTab[TabIndex];
From 659478bab2f55f0347f7e4dbb786af3fe7aa5083 Mon Sep 17 00:00:00 2001
From: RAZER <79311432+CnCRAZER@users.noreply.github.com>
Date: Thu, 5 Mar 2026 13:21:36 -0600
Subject: [PATCH 3/7] Update BuildLastOfTab.cpp
---
src/Commands/BuildLastOfTab.cpp | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/src/Commands/BuildLastOfTab.cpp b/src/Commands/BuildLastOfTab.cpp
index 35d22ca294..8122be3167 100644
--- a/src/Commands/BuildLastOfTab.cpp
+++ b/src/Commands/BuildLastOfTab.cpp
@@ -8,26 +8,26 @@
static constexpr const char* BuildLastTabNames[4] =
{
- "BuildLastOfTab_Power",
- "BuildLastOfTab_Defense",
- "BuildLastOfTab_Infantry",
- "BuildLastOfTab_Vehicles",
+ "RebuildStructure",
+ "RebuildDefense",
+ "RebuildInfantry",
+ "RebuildVehicle",
};
static constexpr const char* BuildLastTabDescKeys[4] =
{
- "BuildLastOfTab_Power_Desc",
- "BuildLastOfTab_Defense_Desc",
- "BuildLastOfTab_Infantry_Desc",
- "BuildLastOfTab_Vehicles_Desc",
+ "RebuildStructure_Desc",
+ "RebuildDefense_Desc",
+ "RebuildInfantry_Desc",
+ "RebuildVehicle_Desc",
};
static constexpr const wchar_t* BuildLastTabUINames[4] =
{
- L"Build Last (Power/Resources)",
- L"Build Last (Defense/Combat)",
- L"Build Last (Infantry)",
- L"Build Last (Vehicles/Aircraft)",
+ L"Rebuild Structure",
+ L"Rebuild Defense",
+ L"Rebuild Infantry",
+ L"Rebuild Vehicle",
};
static constexpr const wchar_t* BuildLastTabUIDescs[4] =
From ce2ddf9e11c08ff9e7fea5700a2ade810a0a9ef6 Mon Sep 17 00:00:00 2001
From: RAZER <79311432+CnCRAZER@users.noreply.github.com>
Date: Thu, 5 Mar 2026 13:50:33 -0600
Subject: [PATCH 4/7] Add docs for Rebuild keyboard commands
Document four new keyboard commands (Rebuild Structure, Rebuild Defense, Rebuild Infantry, Rebuild Vehicle) in docs/User-Interface.md, add a What's New entry in docs/Whats-New.md, and credit RAZER in CREDITS.md. Adds brief descriptions and localization note for the new commands.
---
CREDITS.md | 1 +
docs/User-Interface.md | 12 ++++++++++++
docs/Whats-New.md | 1 +
3 files changed, 14 insertions(+)
diff --git a/CREDITS.md b/CREDITS.md
index e7dfbace7b..4c4a502c84 100644
--- a/CREDITS.md
+++ b/CREDITS.md
@@ -763,3 +763,4 @@ This page lists all the individual contributions to the project by their author.
- **RAZER**:
- Wall overlay unit sell exploit fix
- Multiplayer gamespeed fix for RealTimeTimers
+ - Rebuild **X** keyboard commands
diff --git a/docs/User-Interface.md b/docs/User-Interface.md
index e459622af6..b1d1bfd4f6 100644
--- a/docs/User-Interface.md
+++ b/docs/User-Interface.md
@@ -521,6 +521,18 @@ For this command to work in multiplayer - you need to use a version of [YRpp spa
- Switches on/off [Task subtitles' label in the middle of the screen](#task-subtitles-display-in-the-middle-of-the-screen).
- For localization add `TXT_TOGGLE_MESSAGE` and `TXT_TOGGLE_MESSAGE_DESC` into your `.csf` file.
+### `[ ]` Rebuild Structure
+- Re-queue the last produced Power/Resource/Tech Building you placed.
+
+### `[ ]` Rebuild Defense
+- Re-queue the last produced Defensive Building you placed.
+
+### `[ ]` Rebuild Infantry
+- Re-queue the last produced Infantry you built.
+
+### `[ ]` Rebuild Vehicle
+- Re-queue the last produced Vehicle you built.
+
## Loading screen
- PCX files can now be used as loadscreen images.
diff --git a/docs/Whats-New.md b/docs/Whats-New.md
index 5d9d1aa65b..38952ef1f4 100644
--- a/docs/Whats-New.md
+++ b/docs/Whats-New.md
@@ -656,6 +656,7 @@ Fixes / interactions with other extensions:
- Fixed the issue that technos cannot spawn survivors due to non-probabilistic reasons when the tech type was destroyed (by NetsuNegi)
- Fixed the bug that vehicle survivor can spawn on wrong position when transport has been destroyed (by NetsuNegi)
- Fixed the bug that building with `Explodes=yes` use Ares's rubble logic will cause it's owner cannot defeat normally (by NetsuNegi)
+- Four new keyboard commands under `Interface`: `Rebuild Structure`, `Rebuild Defense`, `Rebuild Infantry` and `Rebuild Vehicle` (by RAZER)
```
### 0.4.0.3
From b80444a13e2b7208f3b1d9e553b848c1cf36f08f Mon Sep 17 00:00:00 2001
From: RAZER <79311432+CnCRAZER@users.noreply.github.com>
Date: Fri, 6 Mar 2026 10:34:19 -0600
Subject: [PATCH 5/7] Update CREDITS.md
---
CREDITS.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/CREDITS.md b/CREDITS.md
index 4c4a502c84..c2fc181c27 100644
--- a/CREDITS.md
+++ b/CREDITS.md
@@ -763,4 +763,4 @@ This page lists all the individual contributions to the project by their author.
- **RAZER**:
- Wall overlay unit sell exploit fix
- Multiplayer gamespeed fix for RealTimeTimers
- - Rebuild **X** keyboard commands
+ - Rebuild last technotype keyboard commands
From 73edb17f8357043718486afb87c5f2f73c7a62de Mon Sep 17 00:00:00 2001
From: RAZER <79311432+CnCRAZER@users.noreply.github.com>
Date: Fri, 6 Mar 2026 13:03:24 -0600
Subject: [PATCH 6/7] Add rebuild commands for tab 3 subtypes
Introduce dedicated rebuild commands for tab 3: RebuildVehicle, RebuildAircraft and RebuildNaval. Adds new header/source (src/Commands/RebuildTab3Subtypes.*), registers the commands in Commands.cpp and includes them in the VCXPROJ and project includes. Track per-subtype last-built data in HouseExt (Body.h/Body.cpp) including type indices and RTTI, persist them in serialization, and update the existing BuildLastTab hook to maintain these per-subtype fields. Commands enqueue Produce events and focus the sidebar to tab 3 when executed, with UI strings loaded via GeneralUtils.
---
Phobos.vcxproj | 2 +
src/Commands/Commands.cpp | 4 +
src/Commands/RebuildTab3Subtypes.cpp | 137 +++++++++++++++++++++++++++
src/Commands/RebuildTab3Subtypes.h | 38 ++++++++
src/Ext/House/Body.cpp | 6 ++
src/Ext/House/Body.h | 14 +++
src/Ext/House/Hooks.BuildLastTab.cpp | 20 ++++
7 files changed, 221 insertions(+)
create mode 100644 src/Commands/RebuildTab3Subtypes.cpp
create mode 100644 src/Commands/RebuildTab3Subtypes.h
diff --git a/Phobos.vcxproj b/Phobos.vcxproj
index 4198646853..e36e118307 100644
--- a/Phobos.vcxproj
+++ b/Phobos.vcxproj
@@ -37,6 +37,7 @@
+
@@ -228,6 +229,7 @@
+
diff --git a/src/Commands/Commands.cpp b/src/Commands/Commands.cpp
index 54c3235e71..3dfc7f52e7 100644
--- a/src/Commands/Commands.cpp
+++ b/src/Commands/Commands.cpp
@@ -13,6 +13,7 @@
#include "FireTacticalSW.h"
#include "ToggleMessageList.h"
#include "BuildLastOfTab.h"
+#include "RebuildTab3Subtypes.h"
#include
@@ -33,6 +34,9 @@ DEFINE_HOOK(0x533066, CommandClassCallback_Register, 0x6)
MakeCommand>();
MakeCommand>();
MakeCommand>();
+ MakeCommand();
+ MakeCommand();
+ MakeCommand();
if (Phobos::Config::SuperWeaponSidebarCommands)
{
diff --git a/src/Commands/RebuildTab3Subtypes.cpp b/src/Commands/RebuildTab3Subtypes.cpp
new file mode 100644
index 0000000000..8ef657d4ff
--- /dev/null
+++ b/src/Commands/RebuildTab3Subtypes.cpp
@@ -0,0 +1,137 @@
+#include "RebuildTab3Subtypes.h"
+
+#include
+#include
+#include
+#include
+#include
+
+// Helper: issue a Produce event for a tracked subtype and focus sidebar to tab 3.
+static void ExecuteRebuildSubtype(int typeIndex, AbstractType rtti, bool isNaval)
+{
+ auto const pPlayer = HouseClass::CurrentPlayer;
+ if (!pPlayer)
+ return;
+
+ if (typeIndex < 0)
+ return;
+
+ if (SidebarClass::Instance.IsSidebarActive)
+ {
+ SidebarClass::Instance.ActiveTabIndex = 3;
+ SidebarClass::Instance.SidebarNeedsRepaint();
+ }
+
+ EventClass::OutList.Add(EventClass(
+ pPlayer->ArrayIndex,
+ EventType::Produce,
+ static_cast(rtti),
+ typeIndex,
+ isNaval ? TRUE : FALSE
+ ));
+}
+
+// --- RebuildVehicle (non-naval UnitType) ---
+
+const char* RebuildVehicleCommandClass::GetName() const
+{
+ return "RebuildVehicleOnly";
+}
+
+const wchar_t* RebuildVehicleCommandClass::GetUIName() const
+{
+ return GeneralUtils::LoadStringUnlessMissing("RebuildVehicleOnly", L"Rebuild Vehicle");
+}
+
+const wchar_t* RebuildVehicleCommandClass::GetUICategory() const
+{
+ return CATEGORY_INTERFACE;
+}
+
+const wchar_t* RebuildVehicleCommandClass::GetUIDescription() const
+{
+ return GeneralUtils::LoadStringUnlessMissing("RebuildVehicleOnly_Desc", L"Re-queue the last produced ground vehicle (non-naval).");
+}
+
+void RebuildVehicleCommandClass::Execute(WWKey eInput) const
+{
+ auto const pPlayer = HouseClass::CurrentPlayer;
+ if (!pPlayer)
+ return;
+
+ auto const pExt = HouseExt::ExtMap.Find(pPlayer);
+ if (!pExt)
+ return;
+
+ ExecuteRebuildSubtype(pExt->LastBuiltVehicleTypeIndex, pExt->LastBuiltVehicleRTTI, false);
+}
+
+// --- RebuildAircraft (AircraftType) ---
+
+const char* RebuildAircraftCommandClass::GetName() const
+{
+ return "RebuildAircraft";
+}
+
+const wchar_t* RebuildAircraftCommandClass::GetUIName() const
+{
+ return GeneralUtils::LoadStringUnlessMissing("RebuildAircraft", L"Rebuild Aircraft");
+}
+
+const wchar_t* RebuildAircraftCommandClass::GetUICategory() const
+{
+ return CATEGORY_INTERFACE;
+}
+
+const wchar_t* RebuildAircraftCommandClass::GetUIDescription() const
+{
+ return GeneralUtils::LoadStringUnlessMissing("RebuildAircraft_Desc", L"Re-queue the last produced aircraft.");
+}
+
+void RebuildAircraftCommandClass::Execute(WWKey eInput) const
+{
+ auto const pPlayer = HouseClass::CurrentPlayer;
+ if (!pPlayer)
+ return;
+
+ auto const pExt = HouseExt::ExtMap.Find(pPlayer);
+ if (!pExt)
+ return;
+
+ ExecuteRebuildSubtype(pExt->LastBuiltAircraftTypeIndex, pExt->LastBuiltAircraftRTTI, false);
+}
+
+// --- RebuildNaval (naval UnitType) ---
+
+const char* RebuildNavalCommandClass::GetName() const
+{
+ return "RebuildNaval";
+}
+
+const wchar_t* RebuildNavalCommandClass::GetUIName() const
+{
+ return GeneralUtils::LoadStringUnlessMissing("RebuildNaval", L"Rebuild Naval");
+}
+
+const wchar_t* RebuildNavalCommandClass::GetUICategory() const
+{
+ return CATEGORY_INTERFACE;
+}
+
+const wchar_t* RebuildNavalCommandClass::GetUIDescription() const
+{
+ return GeneralUtils::LoadStringUnlessMissing("RebuildNaval_Desc", L"Re-queue the last produced naval unit.");
+}
+
+void RebuildNavalCommandClass::Execute(WWKey eInput) const
+{
+ auto const pPlayer = HouseClass::CurrentPlayer;
+ if (!pPlayer)
+ return;
+
+ auto const pExt = HouseExt::ExtMap.Find(pPlayer);
+ if (!pExt)
+ return;
+
+ ExecuteRebuildSubtype(pExt->LastBuiltNavalTypeIndex, pExt->LastBuiltNavalRTTI, true);
+}
diff --git a/src/Commands/RebuildTab3Subtypes.h b/src/Commands/RebuildTab3Subtypes.h
new file mode 100644
index 0000000000..b19603e379
--- /dev/null
+++ b/src/Commands/RebuildTab3Subtypes.h
@@ -0,0 +1,38 @@
+#pragma once
+
+#include "Commands.h"
+
+// Dedicated rebuild commands for tab 3 subtypes.
+// RebuildVehicle: re-queues the last non-naval UnitType.
+// RebuildAircraft: re-queues the last AircraftType.
+// RebuildNaval: re-queues the last naval UnitType.
+
+class RebuildVehicleCommandClass : 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 RebuildAircraftCommandClass : 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 RebuildNavalCommandClass : 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;
+};
diff --git a/src/Ext/House/Body.cpp b/src/Ext/House/Body.cpp
index 34c34d9dcd..2def8d5c16 100644
--- a/src/Ext/House/Body.cpp
+++ b/src/Ext/House/Body.cpp
@@ -699,6 +699,12 @@ void HouseExt::ExtData::Serialize(T& Stm)
.Process(this->LastBuiltPerTab)
.Process(this->LastBuiltRTTIPerTab)
.Process(this->LastBuiltIsNavalPerTab)
+ .Process(this->LastBuiltVehicleTypeIndex)
+ .Process(this->LastBuiltAircraftTypeIndex)
+ .Process(this->LastBuiltNavalTypeIndex)
+ .Process(this->LastBuiltVehicleRTTI)
+ .Process(this->LastBuiltAircraftRTTI)
+ .Process(this->LastBuiltNavalRTTI)
.Process(this->CombatAlertTimer)
.Process(this->NumAirpads_NonMFB)
.Process(this->NumBarracks_NonMFB)
diff --git a/src/Ext/House/Body.h b/src/Ext/House/Body.h
index e3333d69fb..07b9f7b939 100644
--- a/src/Ext/House/Body.h
+++ b/src/Ext/House/Body.h
@@ -52,6 +52,14 @@ class HouseExt
AbstractType LastBuiltRTTIPerTab[4];
bool LastBuiltIsNavalPerTab[4];
+ // Per-subtype tracking within tab 3 for dedicated rebuild commands.
+ int LastBuiltVehicleTypeIndex; // Last non-naval UnitType
+ int LastBuiltAircraftTypeIndex; // Last AircraftType
+ int LastBuiltNavalTypeIndex; // Last naval UnitType
+ AbstractType LastBuiltVehicleRTTI;
+ AbstractType LastBuiltAircraftRTTI;
+ AbstractType LastBuiltNavalRTTI;
+
// Factories that exist but don't count towards multiple factory bonus.
int NumAirpads_NonMFB;
int NumBarracks_NonMFB;
@@ -94,6 +102,12 @@ class HouseExt
, LastBuiltPerTab { -1, -1, -1, -1 }
, LastBuiltRTTIPerTab { AbstractType::None, AbstractType::None, AbstractType::None, AbstractType::None }
, LastBuiltIsNavalPerTab { false, false, false, false }
+ , LastBuiltVehicleTypeIndex { -1 }
+ , LastBuiltAircraftTypeIndex { -1 }
+ , LastBuiltNavalTypeIndex { -1 }
+ , LastBuiltVehicleRTTI { AbstractType::None }
+ , LastBuiltAircraftRTTI { AbstractType::None }
+ , LastBuiltNavalRTTI { AbstractType::None }
, CombatAlertTimer {}
, NumAirpads_NonMFB { 0 }
, NumBarracks_NonMFB { 0 }
diff --git a/src/Ext/House/Hooks.BuildLastTab.cpp b/src/Ext/House/Hooks.BuildLastTab.cpp
index 0632760702..13fa4db0b7 100644
--- a/src/Ext/House/Hooks.BuildLastTab.cpp
+++ b/src/Ext/House/Hooks.BuildLastTab.cpp
@@ -36,6 +36,26 @@ DEFINE_HOOK(0x4FB6C2, HouseClass_RegisterObjectGain_TrackLastBuiltTab, 0x7)
pExt->LastBuiltPerTab[tabIdx] = pType->GetArrayIndex();
pExt->LastBuiltRTTIPerTab[tabIdx] = absType;
pExt->LastBuiltIsNavalPerTab[tabIdx] = isNaval;
+
+ // Track per-subtype within tab 3 for dedicated rebuild commands.
+ if (tabIdx == 3)
+ {
+ if (absType == AbstractType::AircraftType)
+ {
+ pExt->LastBuiltAircraftTypeIndex = pType->GetArrayIndex();
+ pExt->LastBuiltAircraftRTTI = absType;
+ }
+ else if (isNaval)
+ {
+ pExt->LastBuiltNavalTypeIndex = pType->GetArrayIndex();
+ pExt->LastBuiltNavalRTTI = absType;
+ }
+ else
+ {
+ pExt->LastBuiltVehicleTypeIndex = pType->GetArrayIndex();
+ pExt->LastBuiltVehicleRTTI = absType;
+ }
+ }
}
return 0;
From cb9ffcd6cd2c7537588d196bdc611b06fa44a999 Mon Sep 17 00:00:00 2001
From: RAZER <79311432+CnCRAZER@users.noreply.github.com>
Date: Fri, 6 Mar 2026 13:27:26 -0600
Subject: [PATCH 7/7] Add Rebuild Aircraft/Naval; adjust BuildLast tabs
Introduce dedicated Rebuild Aircraft and Rebuild Naval commands and remove the Vehicle entry from the generic BuildLast tab set. Update BuildLastOfTab to use 3 tabs (Structure, Defense, Infantry) by shrinking the name/description/UI arrays and the static_assert, and remove the template instantiation/registration for the 4th tab. Register the new RebuildVehicle, RebuildAircraft and RebuildNaval commands in Commands.cpp instead of using a mixed Vehicle/Aircraft entry. Update docs: User-Interface.md wording ("Unit") and add UI entries for Rebuild Aircraft and Rebuild Naval, and Whats-New.md to list the new commands.
---
docs/User-Interface.md | 10 ++++++++--
docs/Whats-New.md | 2 +-
src/Commands/BuildLastOfTab.cpp | 15 +++++----------
src/Commands/Commands.cpp | 1 -
4 files changed, 14 insertions(+), 14 deletions(-)
diff --git a/docs/User-Interface.md b/docs/User-Interface.md
index b1d1bfd4f6..9db0f6c40f 100644
--- a/docs/User-Interface.md
+++ b/docs/User-Interface.md
@@ -528,10 +528,16 @@ For this command to work in multiplayer - you need to use a version of [YRpp spa
- Re-queue the last produced Defensive Building you placed.
### `[ ]` Rebuild Infantry
-- Re-queue the last produced Infantry you built.
+- Re-queue the last produced Infantry Unit you built.
### `[ ]` Rebuild Vehicle
-- Re-queue the last produced Vehicle you built.
+- Re-queue the last produced Vehicle Unit you built.
+
+### `[ ]` Rebuild Aircraft
+- Re-queue the last produced Aircraft Unit you built.
+
+### `[ ]` Rebuild Naval
+- Re-queue the last produced Naval Unit you built.
## Loading screen
diff --git a/docs/Whats-New.md b/docs/Whats-New.md
index 38952ef1f4..4ddd364b8f 100644
--- a/docs/Whats-New.md
+++ b/docs/Whats-New.md
@@ -656,7 +656,7 @@ Fixes / interactions with other extensions:
- Fixed the issue that technos cannot spawn survivors due to non-probabilistic reasons when the tech type was destroyed (by NetsuNegi)
- Fixed the bug that vehicle survivor can spawn on wrong position when transport has been destroyed (by NetsuNegi)
- Fixed the bug that building with `Explodes=yes` use Ares's rubble logic will cause it's owner cannot defeat normally (by NetsuNegi)
-- Four new keyboard commands under `Interface`: `Rebuild Structure`, `Rebuild Defense`, `Rebuild Infantry` and `Rebuild Vehicle` (by RAZER)
+- New keyboard commands under `Interface`: `Rebuild Structure`, `Rebuild Defense`, `Rebuild Infantry`, `Rebuild Vehicle`,`Rebuild Aircraft`, `Rebuild Naval` (by RAZER)
```
### 0.4.0.3
diff --git a/src/Commands/BuildLastOfTab.cpp b/src/Commands/BuildLastOfTab.cpp
index 8122be3167..6420c3e835 100644
--- a/src/Commands/BuildLastOfTab.cpp
+++ b/src/Commands/BuildLastOfTab.cpp
@@ -6,36 +6,32 @@
#include
#include
-static constexpr const char* BuildLastTabNames[4] =
+static constexpr const char* BuildLastTabNames[3] =
{
"RebuildStructure",
"RebuildDefense",
"RebuildInfantry",
- "RebuildVehicle",
};
-static constexpr const char* BuildLastTabDescKeys[4] =
+static constexpr const char* BuildLastTabDescKeys[3] =
{
"RebuildStructure_Desc",
"RebuildDefense_Desc",
"RebuildInfantry_Desc",
- "RebuildVehicle_Desc",
};
-static constexpr const wchar_t* BuildLastTabUINames[4] =
+static constexpr const wchar_t* BuildLastTabUINames[3] =
{
L"Rebuild Structure",
L"Rebuild Defense",
L"Rebuild Infantry",
- L"Rebuild Vehicle",
};
-static constexpr const wchar_t* BuildLastTabUIDescs[4] =
+static constexpr const wchar_t* BuildLastTabUIDescs[3] =
{
L"Re-queue the last produced Power/Resources building.",
L"Re-queue the last produced Defense/Combat building.",
L"Re-queue the last produced Infantry unit.",
- L"Re-queue the last produced Vehicle or Aircraft.",
};
template
@@ -59,7 +55,7 @@ const wchar_t* BuildLastOfTabCommandClass::GetUICategory() const
template
const wchar_t* BuildLastOfTabCommandClass::GetUIDescription() const
{
- static_assert(TabIndex >= 0 && TabIndex < 4, "TabIndex out of range");
+ static_assert(TabIndex >= 0 && TabIndex < 3, "TabIndex out of range");
return GeneralUtils::LoadStringUnlessMissing(BuildLastTabDescKeys[TabIndex], BuildLastTabUIDescs[TabIndex]);
}
@@ -101,4 +97,3 @@ void BuildLastOfTabCommandClass::Execute(WWKey eInput) const
template class BuildLastOfTabCommandClass<0>;
template class BuildLastOfTabCommandClass<1>;
template class BuildLastOfTabCommandClass<2>;
-template class BuildLastOfTabCommandClass<3>;
diff --git a/src/Commands/Commands.cpp b/src/Commands/Commands.cpp
index 3dfc7f52e7..15375158ba 100644
--- a/src/Commands/Commands.cpp
+++ b/src/Commands/Commands.cpp
@@ -33,7 +33,6 @@ DEFINE_HOOK(0x533066, CommandClassCallback_Register, 0x6)
MakeCommand>();
MakeCommand>();
MakeCommand>();
- MakeCommand>();
MakeCommand();
MakeCommand();
MakeCommand();