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();