diff --git a/changelog/snippets/fix.7051.md b/changelog/snippets/fix.7051.md new file mode 100644 index 00000000000..c8437c87134 --- /dev/null +++ b/changelog/snippets/fix.7051.md @@ -0,0 +1 @@ +- (#7051) Fix a unit-transfer exploit that adds silo progress to nuke subs and the Seraphim battleship for free. diff --git a/engine/Core/Blueprints/WeaponBlueprint.lua b/engine/Core/Blueprints/WeaponBlueprint.lua index 2aad3796013..2be5646e000 100644 --- a/engine/Core/Blueprints/WeaponBlueprint.lua +++ b/engine/Core/Blueprints/WeaponBlueprint.lua @@ -280,7 +280,9 @@ ---@field RateOfFire number --- if this weapon will find new target on miss events ---@field ReTargetOnMiss? boolean ---- if `true`, will set the orange work progress bar to display the reload progress of this weapon +--- if `true`, will set the orange work progress bar to display the reload progress of this weapon. +--- Should not be used for units with silo weapons, as the work progress of the reload will transfer +--- as silo build progress after unit transfer. ---@field RenderFireClock? boolean --- used by the XSL0402 (Othuy "lighting storm") to define the time to re-aquire a new target before going --- through the next lighting strike process diff --git a/lua/SimUtils.lua b/lua/SimUtils.lua index e9f44fde83e..f9d193cd3ea 100644 --- a/lua/SimUtils.lua +++ b/lua/SimUtils.lua @@ -289,7 +289,7 @@ function TransferUnitsOwnership(units, toArmy, captured, noRestrictions) -- B E F O R E local orientation = unit:GetOrientation() - local workprogress = unit:GetWorkProgress() + local siloWorkProgress = unit:IsUnitState("SiloBuildingAmmo") and unit:GetWorkProgress() or 0 local numNukes = unit:GetNukeSiloAmmoCount() -- nuclear missiles; SML or SMD local numTacMsl = unit:GetTacticalSiloAmmoCount() local massKilled = unit.VetExperience @@ -448,7 +448,7 @@ function TransferUnitsOwnership(units, toArmy, captured, noRestrictions) end if newUnit.Blueprint.CategoriesHash["SILO"] then - newUnit:GiveNukeSiloBlocks(workprogress) + newUnit:GiveNukeSiloBlocks(siloWorkProgress) end local newShield = newUnit.MyShield diff --git a/lua/sim/Unit.lua b/lua/sim/Unit.lua index e0b93be0a2b..a445068ed9e 100644 --- a/lua/sim/Unit.lua +++ b/lua/sim/Unit.lua @@ -2556,6 +2556,11 @@ Unit = ClassUnit(moho.unit_methods, IntelComponent, VeterancyComponent, DebugUni self.SiloWeapon = weapon self.SiloProjectile = weapon:GetProjectileBlueprint() + -- Prevent work progress set by weapons using `RenderFireClock` from + -- turning into silo progress after ownership transfer of a unit paused + -- in the silo build state without having updated progress by the engine. + self:SetWorkProgress(0) + -- for AI events self.Brain:OnUnitSiloBuildStart(self, weapon) end, diff --git a/lua/sim/weapons/DefaultProjectileWeapon.lua b/lua/sim/weapons/DefaultProjectileWeapon.lua index ecf9d09f2ea..448b8a834e5 100644 --- a/lua/sim/weapons/DefaultProjectileWeapon.lua +++ b/lua/sim/weapons/DefaultProjectileWeapon.lua @@ -935,10 +935,14 @@ DefaultProjectileWeapon = ClassWeapon(Weapon) { local unit = self.unit local clockTime = math.round(10 * rateOfFire) local totalTime = clockTime - while clockTime >= 0 and - not self:BeenDestroyed() and - not unit.Dead do - unit:SetWorkProgress(1 - clockTime / totalTime) + while clockTime >= 0 + and not self:BeenDestroyed() + and not unit.Dead + do + -- do not override work progress that is used for replenishing silo ammo upon unit transfer + if not unit:IsUnitState("SiloBuildingAmmo") then + unit:SetWorkProgress(1 - clockTime / totalTime) + end clockTime = clockTime - 1 WaitSeconds(0.1) end