From 0f48f16c4a2dda3e2357dc08ad6493b21d031ffa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=88=AA=E5=91=B3=E9=BA=BB=E9=85=B1?= <93972760+TaranDahl@users.noreply.github.com> Date: Wed, 7 Jan 2026 16:32:00 +0800 Subject: [PATCH 1/3] core --- CREDITS.md | 1 + Phobos.vcxproj | 2 ++ docs/User-Interface.md | 12 ++++++++++ docs/Whats-New.md | 1 + src/Ext/Event/Body.cpp | 40 ++++++++++++++++++++++++++----- src/Ext/Event/Body.h | 37 +++++++++++++++++++++------- src/Ext/House/Body.cpp | 1 + src/Ext/House/Body.h | 3 +++ src/Ext/House/Hooks.cpp | 53 +++++++++++++++++++++++++++++++++++++++++ src/Ext/Rules/Body.cpp | 3 +++ src/Ext/Rules/Body.h | 4 ++++ 11 files changed, 142 insertions(+), 15 deletions(-) diff --git a/CREDITS.md b/CREDITS.md index db73b2649c..bce4653df0 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -662,6 +662,7 @@ This page lists all the individual contributions to the project by their author. - Toggle per-target warhead effects apply timing - Extra range for chasing and pre-firing - Fix an issue that rockets do not consider the destination altitude during climbing + - Replace vanilla repairing with togglable auto repairing - **solar-III (凤九歌)** - Target scanning delay customization (documentation) - Skip target scanning function calling for unarmed technos (documentation) diff --git a/Phobos.vcxproj b/Phobos.vcxproj index 2def0db9a8..afe15b208e 100644 --- a/Phobos.vcxproj +++ b/Phobos.vcxproj @@ -19,6 +19,7 @@ + @@ -218,6 +219,7 @@ + diff --git a/docs/User-Interface.md b/docs/User-Interface.md index 28212091ca..7657fe8488 100644 --- a/docs/User-Interface.md +++ b/docs/User-Interface.md @@ -700,6 +700,18 @@ In `rulesmd.ini`: Sidebar.ProducingProgress.Offset=0,0 ; X,Y, pixels relative to default ``` +### Replace vanilla repairing with togglable auto repairing + +- Now you can replace the vanilla repair method with a togglable auto-repair. + - Pressing repair button or hotkey will no longer change your mouse, but will toggle your auto-repair state on/off. + - When auto-repair state is toggled off, buildings will stop repairing. + + In `rulesmd.ini`: +```ini +[General] +ExtendedPlayerRepair=false ; boolean +``` + ### Specify Sidebar style - It's now possible to switch hardcoded sidebar button coords to use GDI sidebar coords by setting `Sidebar.GDIPosition`. Defaults to true for first side, false for all others. diff --git a/docs/Whats-New.md b/docs/Whats-New.md index 10c5a6a3ec..3bf417950b 100644 --- a/docs/Whats-New.md +++ b/docs/Whats-New.md @@ -480,6 +480,7 @@ New: - Allow techno type considered as other type when recruiting techno for teams (by NetsuNegi) - Map Action [`511` Undeploy Building to Waypoint](AI-Scripting-and-Mapping.md#undeploy-building-to-waypoint), [`609` Set Radar Mode](AI-Scripting-and-Mapping.md#set-radar-mode), [`610` Set house's `TeamDelays` value](AI-Scripting-and-Mapping.md#set-house-s-teamdelays-value) (by FlyStar) - Fixed an issue that rockets do not consider the destination altitude during climbing (by TaranDahl) +- [Replace vanilla repairing with togglable auto repairing](User-Interface.md#replace-vanilla-repairing-with-togglable-auto-repairing) (by TaranDahl) Vanilla fixes: - Fixed sidebar not updating queued unit numbers when adding or removing units when the production is on hold (by CrimRecya) diff --git a/src/Ext/Event/Body.cpp b/src/Ext/Event/Body.cpp index c4c471c55d..c05290f29b 100644 --- a/src/Ext/Event/Body.cpp +++ b/src/Ext/Event/Body.cpp @@ -1,8 +1,12 @@ -/* + #include "Body.h" +#include + #include #include +#include +#include bool EventExt::AddEvent() { @@ -13,8 +17,8 @@ void EventExt::RespondEvent() { switch (this->Type) { - case EventTypeExt::Sample: - // Place the handler here + case EventTypeExt::TogglePlayerAutoRepair: + this->RespondToTogglePlayerAutoRepair(); break; } } @@ -23,8 +27,8 @@ size_t EventExt::GetDataSize(EventTypeExt type) { switch (type) { - case EventTypeExt::Sample: - return sizeof(EventExt::Sample); + case EventTypeExt::TogglePlayerAutoRepair: + return sizeof(EventExt::TogglePlayerAutoRepair); } return 0; @@ -35,6 +39,30 @@ bool EventExt::IsValidType(EventTypeExt type) return (type >= EventTypeExt::FIRST && type <= EventTypeExt::LAST); } +void EventExt::RespondToTogglePlayerAutoRepair() +{ + if (this->HouseIndex >= HouseClass::Array.Count) + return; + + if (!RulesExt::Global()->ExtendedPlayerRepair) + return; + + auto pHouse = HouseClass::Array.GetItem(this->HouseIndex); + auto pHouseExt = HouseExt::ExtMap.Find(pHouse); + pHouseExt->PlayerAutoRepair = !pHouseExt->PlayerAutoRepair; + + if (HouseClass::CurrentPlayer == pHouse) + { + SidebarClass::Instance.SidebarNeedsRedraw = true; + auto pButton = &Make_Global(0xB0B3A0); + + if (pHouseExt->PlayerAutoRepair) + pButton->TurnOn(); + else + pButton->TurnOff(); + } +} + // hooks DEFINE_HOOK(0x4C6CC8, Networking_RespondToEvent, 0x5) @@ -98,4 +126,4 @@ DEFINE_HOOK(0x64C30E, sub_64BDD0_GetEventSize2, 0x6) return 0; } -*/ + diff --git a/src/Ext/Event/Body.h b/src/Ext/Event/Body.h index a9d37294e6..d4f81096e4 100644 --- a/src/Ext/Event/Body.h +++ b/src/Ext/Event/Body.h @@ -1,18 +1,20 @@ #pragma once -/* + #include #include +#include + enum class EventTypeExt : uint8_t { // Vanilla game used Events from 0x00 to 0x2F // CnCNet reserved Events from 0x30 to 0x3F // Ares used Events 0x60 and 0x61 - Sample = 0x40, // Sample event, remove it when Phobos needs its own events + TogglePlayerAutoRepair = 0x40, - FIRST = Sample, - LAST = Sample + FIRST = TogglePlayerAutoRepair, + LAST = TogglePlayerAutoRepair }; #pragma pack(push, 1) @@ -27,15 +29,32 @@ class EventExt { char DataBuffer[104]; - struct Sample - { - char DataBuffer[104]; - } Sample; + struct TogglePlayerAutoRepair + { } TogglePlayerAutoRepair; }; bool AddEvent(); void RespondEvent(); + EventExt(EventTypeExt type) + { + this->Type = type; + this->IsExecuted = false; + this->HouseIndex = (char)HouseClass::CurrentPlayer->ArrayIndex; + this->Frame = Unsorted::CurrentFrame; + + switch (type) + { + case EventTypeExt::TogglePlayerAutoRepair: + this->TogglePlayerAutoRepair = {}; + break; + default: + this->TogglePlayerAutoRepair = {}; + break; + } + } + void RespondToTogglePlayerAutoRepair(); + static size_t GetDataSize(EventTypeExt type); static bool IsValidType(EventTypeExt type); }; @@ -43,4 +62,4 @@ class EventExt static_assert(sizeof(EventExt) == 111); static_assert(offsetof(EventExt, DataBuffer) == 7); #pragma pack(pop) -*/ + diff --git a/src/Ext/House/Body.cpp b/src/Ext/House/Body.cpp index 3adeb78310..6cbcd54496 100644 --- a/src/Ext/House/Body.cpp +++ b/src/Ext/House/Body.cpp @@ -688,6 +688,7 @@ void HouseExt::ExtData::Serialize(T& Stm) .Process(this->TeamDelay) .Process(this->FreeRadar) .Process(this->ForceRadar) + .Process(this->PlayerAutoRepair) ; } diff --git a/src/Ext/House/Body.h b/src/Ext/House/Body.h index 8d1e60518c..1bd619f404 100644 --- a/src/Ext/House/Body.h +++ b/src/Ext/House/Body.h @@ -72,6 +72,8 @@ class HouseExt bool FreeRadar; bool ForceRadar; + bool PlayerAutoRepair; + ExtData(HouseClass* OwnerObject) : Extension(OwnerObject) , PowerPlantEnhancers {} , OwnedLimboDeliveredBuildings {} @@ -105,6 +107,7 @@ class HouseExt , TeamDelay(-1) , FreeRadar(false) , ForceRadar(false) + , PlayerAutoRepair(false) { } bool OwnsLimboDeliveredBuilding(BuildingClass* pBuilding) const; diff --git a/src/Ext/House/Hooks.cpp b/src/Ext/House/Hooks.cpp index 0489338586..e024a81b5e 100644 --- a/src/Ext/House/Hooks.cpp +++ b/src/Ext/House/Hooks.cpp @@ -4,6 +4,8 @@ #include #include "Ext/Techno/Body.h" #include "Ext/Building/Body.h" +#include + #include DEFINE_HOOK(0x508C30, HouseClass_UpdatePower_UpdateCounter, 0x5) @@ -528,3 +530,54 @@ DEFINE_HOOK(0x508E17, HouseClass_UpdateRadar_FreeRadar, 0x8) return Continue; } + +#pragma region PlayerAutoRepair + +DEFINE_HOOK(0x536FA0, ToggleRepariModeCommandClass_Execute_PlayerAutoRepair, 0x7) +{ + if (!RulesExt::Global()->ExtendedPlayerRepair) + return 0; + + EventExt(EventTypeExt::TogglePlayerAutoRepair).AddEvent(); + return 0x536FAC; +} + +DEFINE_HOOK(0x6A78F6, SidebarClass_Update_ToggleRepair, 0x9) +{ + if (!RulesExt::Global()->ExtendedPlayerRepair) + MapClass::Instance.SetRepairMode(-1); + else + EventExt(EventTypeExt::TogglePlayerAutoRepair).AddEvent(); + return 0x6A78FF; +} + +DEFINE_HOOK(0x6A7AE1, SidebarClass_Update_RepairButton, 0x6) +{ + if (!RulesExt::Global()->ExtendedPlayerRepair) + return 0; + + R->AL(HouseExt::ExtMap.Find(HouseClass::CurrentPlayer)->PlayerAutoRepair); + return 0x6A7AE7; +} + +DEFINE_HOOK(0x45063F, BuildingClass_UpdateRepairSell_PlayerAutoRepair, 0x6) +{ + enum { CanAutoRepair = 0x450659, CanNotAutoRepair = 0x450813 }; + + if (!RulesExt::Global()->ExtendedPlayerRepair) + return 0; + + GET(BuildingClass*, pThis, ESI); + + if (HouseExt::ExtMap.Find(pThis->Owner)->PlayerAutoRepair) + { + return CanAutoRepair; + } + else + { + pThis->SetRepairState(0); + return CanNotAutoRepair; + } +} + +#pragma endregion diff --git a/src/Ext/Rules/Body.cpp b/src/Ext/Rules/Body.cpp index df18a5bd60..128507991d 100644 --- a/src/Ext/Rules/Body.cpp +++ b/src/Ext/Rules/Body.cpp @@ -350,6 +350,8 @@ void RulesExt::ExtData::LoadBeforeTypeData(RulesClass* pThis, CCINIClass* pINI) this->ExtraRange_Prefiring.Read(exINI, GameStrings::General, "ExtraRange.Prefiring"); this->ExtraRange_Prefiring_IncludeBurst.Read(exINI, GameStrings::General, "ExtraRange.Prefiring.IncludeBurst"); + this->ExtendedPlayerRepair.Read(exINI, GameStrings::General, "ExtendedPlayerRepair"); + // Section AITargetTypes int itemsCount = pINI->GetKeyCount("AITargetTypes"); for (int i = 0; i < itemsCount; ++i) @@ -634,6 +636,7 @@ void RulesExt::ExtData::Serialize(T& Stm) .Process(this->ExtraRange_FirerMoving) .Process(this->ExtraRange_Prefiring) .Process(this->ExtraRange_Prefiring_IncludeBurst) + .Process(this->ExtendedPlayerRepair) ; } diff --git a/src/Ext/Rules/Body.h b/src/Ext/Rules/Body.h index 6d0b6404ab..4a51cb4bc9 100644 --- a/src/Ext/Rules/Body.h +++ b/src/Ext/Rules/Body.h @@ -298,6 +298,8 @@ class RulesExt Valueable ExtraRange_Prefiring_IncludeBurst; Valueable ApplyPerTargetEffectsOnDetonate; + + Valueable ExtendedPlayerRepair; ExtData(RulesClass* OwnerObject) : Extension(OwnerObject) , Storage_TiberiumIndex { -1 } @@ -536,6 +538,8 @@ class RulesExt , ExtraRange_FirerMoving { Leptons(0) } , ExtraRange_Prefiring { Leptons(0) } , ExtraRange_Prefiring_IncludeBurst { true } + + , ExtendedPlayerRepair { false } { } virtual ~ExtData() = default; From 04a36210b7b644554b73cf311c141e4d91dac466 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=88=AA=E5=91=B3=E9=BA=BB=E9=85=B1?= <93972760+TaranDahl@users.noreply.github.com> Date: Wed, 7 Jan 2026 22:46:20 +0800 Subject: [PATCH 2/3] update --- src/Ext/Event/Body.cpp | 10 ++++++++++ src/Ext/Event/Body.h | 18 +----------------- src/Ext/House/Hooks.cpp | 4 ++-- 3 files changed, 13 insertions(+), 19 deletions(-) diff --git a/src/Ext/Event/Body.cpp b/src/Ext/Event/Body.cpp index c05290f29b..7a159ad0d4 100644 --- a/src/Ext/Event/Body.cpp +++ b/src/Ext/Event/Body.cpp @@ -23,6 +23,16 @@ void EventExt::RespondEvent() } } +void EventExt::RaiseTogglePlayerAutoRepair() +{ + EventExt eventExt {}; + eventExt.Type = EventTypeExt::TogglePlayerAutoRepair; + eventExt.HouseIndex = (char)HouseClass::CurrentPlayer->ArrayIndex; // not used + eventExt.Frame = Unsorted::CurrentFrame; + eventExt.AddEvent(); + Debug::LogGame("Adding event TOGGLE_PLAYER_AUTOREPAIR\n"); +} + size_t EventExt::GetDataSize(EventTypeExt type) { switch (type) diff --git a/src/Ext/Event/Body.h b/src/Ext/Event/Body.h index d4f81096e4..b0e3b279b7 100644 --- a/src/Ext/Event/Body.h +++ b/src/Ext/Event/Body.h @@ -36,23 +36,7 @@ class EventExt bool AddEvent(); void RespondEvent(); - EventExt(EventTypeExt type) - { - this->Type = type; - this->IsExecuted = false; - this->HouseIndex = (char)HouseClass::CurrentPlayer->ArrayIndex; - this->Frame = Unsorted::CurrentFrame; - - switch (type) - { - case EventTypeExt::TogglePlayerAutoRepair: - this->TogglePlayerAutoRepair = {}; - break; - default: - this->TogglePlayerAutoRepair = {}; - break; - } - } + static void RaiseTogglePlayerAutoRepair(); void RespondToTogglePlayerAutoRepair(); static size_t GetDataSize(EventTypeExt type); diff --git a/src/Ext/House/Hooks.cpp b/src/Ext/House/Hooks.cpp index e024a81b5e..eb710358d3 100644 --- a/src/Ext/House/Hooks.cpp +++ b/src/Ext/House/Hooks.cpp @@ -538,7 +538,7 @@ DEFINE_HOOK(0x536FA0, ToggleRepariModeCommandClass_Execute_PlayerAutoRepair, 0x7 if (!RulesExt::Global()->ExtendedPlayerRepair) return 0; - EventExt(EventTypeExt::TogglePlayerAutoRepair).AddEvent(); + EventExt::RaiseTogglePlayerAutoRepair(); return 0x536FAC; } @@ -547,7 +547,7 @@ DEFINE_HOOK(0x6A78F6, SidebarClass_Update_ToggleRepair, 0x9) if (!RulesExt::Global()->ExtendedPlayerRepair) MapClass::Instance.SetRepairMode(-1); else - EventExt(EventTypeExt::TogglePlayerAutoRepair).AddEvent(); + EventExt::RaiseTogglePlayerAutoRepair(); return 0x6A78FF; } From 460a742b8e4fef63477aa5f1a23534fc4bedd5cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=88=AA=E5=91=B3=E9=BA=BB=E9=85=B1?= <93972760+TaranDahl@users.noreply.github.com> Date: Wed, 7 Jan 2026 23:01:37 +0800 Subject: [PATCH 3/3] Update Hooks.cpp --- src/Ext/House/Hooks.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Ext/House/Hooks.cpp b/src/Ext/House/Hooks.cpp index eb710358d3..5377434fa0 100644 --- a/src/Ext/House/Hooks.cpp +++ b/src/Ext/House/Hooks.cpp @@ -575,7 +575,8 @@ DEFINE_HOOK(0x45063F, BuildingClass_UpdateRepairSell_PlayerAutoRepair, 0x6) } else { - pThis->SetRepairState(0); + if (pThis->IsBeingRepaired) + pThis->SetRepairState(0); return CanNotAutoRepair; } }