From 3bf055fda00986e8eb320c0a2389f6264fd147cb Mon Sep 17 00:00:00 2001 From: clyf Date: Wed, 15 May 2024 02:51:40 -0700 Subject: [PATCH] Salvation Undershoot Fix (#6185) --- changelog/snippets/fix.6185.md | 1 + .../Core/Blueprints/ProjectileBlueprint.lua | 2 + engine/Sim/Projectile.lua | 1 + lua/sim/weapons/DefaultProjectileWeapon.lua | 2 +- .../AIFFragmentationSensorShell01_proj.bp | 5 +- .../AIFFragmentationSensorShell01_script.lua | 54 +++++++++---- .../AIFFragmentationSensorShell02_proj.bp | 7 +- .../AIFFragmentationSensorShell02_script.lua | 76 ++++++++++++++----- 8 files changed, 109 insertions(+), 39 deletions(-) create mode 100644 changelog/snippets/fix.6185.md diff --git a/changelog/snippets/fix.6185.md b/changelog/snippets/fix.6185.md new file mode 100644 index 0000000000..c164db00ca --- /dev/null +++ b/changelog/snippets/fix.6185.md @@ -0,0 +1 @@ +(#6185) Fix Salvation Undershooting - reworks Salvation projectile code to not drop short and use blueprint values for speed and fragment spread \ No newline at end of file diff --git a/engine/Core/Blueprints/ProjectileBlueprint.lua b/engine/Core/Blueprints/ProjectileBlueprint.lua index 0e0bc70c2d..f39a85cf61 100644 --- a/engine/Core/Blueprints/ProjectileBlueprint.lua +++ b/engine/Core/Blueprints/ProjectileBlueprint.lua @@ -138,4 +138,6 @@ ---@field RealisticOrdinance boolean --- bombs that always drop stright down ---@field StraightDownOrdinance boolean +--- for projectiles that spawn spreads of sub-projectiles, how large the impact radius should be +---@field FragmentRadius number ---@field OnLostTargetLifetime? number diff --git a/engine/Sim/Projectile.lua b/engine/Sim/Projectile.lua index 8ded5c5a1e..d25feaa598 100644 --- a/engine/Sim/Projectile.lua +++ b/engine/Sim/Projectile.lua @@ -170,6 +170,7 @@ end ---@param velX number ---@param velY? number ---@param velZ? number +---@return Projectile function Projectile:SetVelocity(velX, velY, velZ) end diff --git a/lua/sim/weapons/DefaultProjectileWeapon.lua b/lua/sim/weapons/DefaultProjectileWeapon.lua index d0e0e326dd..18cb6361bc 100644 --- a/lua/sim/weapons/DefaultProjectileWeapon.lua +++ b/lua/sim/weapons/DefaultProjectileWeapon.lua @@ -402,7 +402,7 @@ DefaultProjectileWeapon = ClassWeapon(Weapon) { end self.EconDrain = CreateEconomyEvent(self.unit, nrgReq, 0, time) self.FirstShot = true - self.unit:ForkThread(self.EconomyDrainThread) + ForkThread(self.EconomyDrainThread, self) end end end, diff --git a/projectiles/AIFFragmentationSensorShell01/AIFFragmentationSensorShell01_proj.bp b/projectiles/AIFFragmentationSensorShell01/AIFFragmentationSensorShell01_proj.bp index 1681557886..14a5600c67 100644 --- a/projectiles/AIFFragmentationSensorShell01/AIFFragmentationSensorShell01_proj.bp +++ b/projectiles/AIFFragmentationSensorShell01/AIFFragmentationSensorShell01_proj.bp @@ -39,13 +39,14 @@ ProjectileBlueprint { Physics = { DestroyOnWater = true, DetonateBelowHeight = 45, - InitialSpeed = 14.6, + InitialSpeed = 16, InitialSpeedRange = 3, InitialSpeedReduceDistance = 30, LeadTarget = false, TurnRate = 360, VelocityAlign = true, Fragments = 6, - FragmentId = '/projectiles/AIFFragmentationSensorShell02/AIFFragmentationSensorShell02_proj.bp' + FragmentId = '/projectiles/AIFFragmentationSensorShell02/AIFFragmentationSensorShell02_proj.bp', + FragmentRadius = 7, }, } diff --git a/projectiles/AIFFragmentationSensorShell01/AIFFragmentationSensorShell01_script.lua b/projectiles/AIFFragmentationSensorShell01/AIFFragmentationSensorShell01_script.lua index a8317cb199..2b34633049 100644 --- a/projectiles/AIFFragmentationSensorShell01/AIFFragmentationSensorShell01_script.lua +++ b/projectiles/AIFFragmentationSensorShell01/AIFFragmentationSensorShell01_script.lua @@ -8,6 +8,15 @@ local EffectTemplate = import("/lua/effecttemplates.lua") local AArtilleryFragmentationSensorShellProjectile = import("/lua/aeonprojectiles.lua").AArtilleryFragmentationSensorShellProjectile local RandomFloat = import("/lua/utilities.lua").GetRandomFloat +local MathSqrt = math.sqrt +local MathPow = math.pow +local MathPi = math.pi +local MathSin = math.sin +local MathCos = math.cos + +-- Gravitational constant +local g = -4.9 + ---@class AIFFragmentationSensorShell01 : AArtilleryFragmentationSensorShellProjectile AIFFragmentationSensorShell01 = ClassProjectile(AArtilleryFragmentationSensorShellProjectile) { @@ -23,33 +32,50 @@ AIFFragmentationSensorShell01 = ClassProjectile(AArtilleryFragmentationSensorShe CreateEmitterAtBone( self, -1, self.Army, v ) end + local detonationHeight = bp.DetonateBelowHeight local vx, vy, vz = self:GetVelocity() - local velocity = 16 + -- Normalize our velocity to ogrids/second + vx, vy, vz = vx*10, vy*10, vz*10 + local vMult = bp.InitialSpeed/(10 * self:GetCurrentSpeed()) + + -- Time to impact (with our reduced speed) is calculated using the quadratic formula and vMult. + local timeToImpact = ((-vy - MathSqrt(MathPow(vy,2) - 2*g*detonationHeight))/g) / vMult + + -- Calculate the new ballistic acceleration + local ballisticAcceleration = -2 * (detonationHeight + vy*vMult * timeToImpact) / MathPow(timeToImpact, 2) + + -- Update our velocity values to their new lower values + vx, vy, vz = vx*vMult, vy*vMult, vz*vMult -- One initial projectile following same directional path as the original - self:CreateChildProjectile(bp.FragmentId):SetVelocity(vx,0.8*vy, vz):SetVelocity(velocity):PassDamageData(self.DamageData) + self:CreateChildProjectile(bp.FragmentId) + :SetVelocity(vx, vy, vz) + :SetBallisticAcceleration(ballisticAcceleration).DamageData = self.DamageData -- Create several other projectiles in a dispersal pattern local numProjectiles = bp.Fragments - 1 - local angle = (2 * math.pi) / numProjectiles + local angle = (2 * MathPi) / numProjectiles local angleInitial = RandomFloat( 0, angle ) -- Randomization of the spread local angleVariation = angle * 8 -- Adjusts angle variance spread - local spreadMul = 0.8 -- Adjusts the width of the dispersal - - local xVec = 0 - local yVec = vy*0.8 - local zVec = 0 + local spreadMagnitude = bp.FragmentRadius / timeToImpact -- Adjusts the width of the dispersal + local xVec + local zVec + local offsetAngle + local magnitudeVariation + -- Launch projectiles at semi-random angles away from split location for i = 0, numProjectiles - 1 do - xVec = vx + (math.sin(angleInitial + (i*angle) + RandomFloat(-angleVariation, angleVariation))) * spreadMul - zVec = vz + (math.cos(angleInitial + (i*angle) + RandomFloat(-angleVariation, angleVariation))) * spreadMul - local proj = self:CreateChildProjectile(bp.FragmentId) - proj:SetVelocity(xVec,yVec,zVec) - proj:SetVelocity(velocity) - proj.DamageData = self.DamageData + offsetAngle = angleInitial + (i*angle) + RandomFloat(-angleVariation, angleVariation) + magnitudeVariation = RandomFloat(0.9, 1.1) + xVec = vx + MathSin(offsetAngle) * spreadMagnitude * magnitudeVariation + zVec = vz + MathCos(offsetAngle) * spreadMagnitude * magnitudeVariation + self:CreateChildProjectile(bp.FragmentId) + :SetVelocity(xVec, vy, zVec) + :SetVelocity(bp.InitialSpeed + RandomFloat(-bp.InitialSpeedRange, bp.InitialSpeedRange)) + :SetBallisticAcceleration(ballisticAcceleration).DamageData = self.DamageData end self:Destroy() diff --git a/projectiles/AIFFragmentationSensorShell02/AIFFragmentationSensorShell02_proj.bp b/projectiles/AIFFragmentationSensorShell02/AIFFragmentationSensorShell02_proj.bp index 9a388ae9d7..041b84eb34 100644 --- a/projectiles/AIFFragmentationSensorShell02/AIFFragmentationSensorShell02_proj.bp +++ b/projectiles/AIFFragmentationSensorShell02/AIFFragmentationSensorShell02_proj.bp @@ -39,15 +39,14 @@ ProjectileBlueprint { Physics = { DestroyOnWater = true, DetonateBelowHeight = 24, - InitialSpeed = 14.6, + InitialSpeed = 12, InitialSpeedRange = 3, InitialSpeedReduceDistance = 30, LeadTarget = false, - MaxZigZag = 0, TurnRate = 360, VelocityAlign = true, - ZigZagFrequency = 0, Fragments = 6, - FragmentId = '/projectiles/AIFFragmentationSensorShell03/AIFFragmentationSensorShell03_proj.bp' + FragmentId = '/projectiles/AIFFragmentationSensorShell03/AIFFragmentationSensorShell03_proj.bp', + FragmentRadius = 4, }, } diff --git a/projectiles/AIFFragmentationSensorShell02/AIFFragmentationSensorShell02_script.lua b/projectiles/AIFFragmentationSensorShell02/AIFFragmentationSensorShell02_script.lua index 07b97be7b6..f7423795c8 100644 --- a/projectiles/AIFFragmentationSensorShell02/AIFFragmentationSensorShell02_script.lua +++ b/projectiles/AIFFragmentationSensorShell02/AIFFragmentationSensorShell02_script.lua @@ -8,6 +8,22 @@ local EffectTemplate = import("/lua/effecttemplates.lua") local AArtilleryFragmentationSensorShellProjectile = import("/lua/aeonprojectiles.lua").AArtilleryFragmentationSensorShellProjectile02 local RandomFloat = import("/lua/utilities.lua").GetRandomFloat +local MathSqrt = math.sqrt +local MathPow = math.pow +local MathPi = math.pi +local MathSin = math.sin +local MathCos = math.cos + +-- We'll update our ballistic parameters so we still hit the target, but only need +-- to do it once for the subprojectiles, because the velocity delta will be very similar +-- and these won't change much/at all. +local ballisticAcceleration +local vMult +local spreadMagnitude + +-- Gravitational constant +local g = -4.9 + --- Aeon Quantic Cluster Fragmentation Sensor shell script , Child Projectile after 1st split - XAB2307 ---@class AIFFragmentationSensorShell02 : AArtilleryFragmentationSensorShellProjectile02 AIFFragmentationSensorShell02 = ClassProjectile(AArtilleryFragmentationSensorShellProjectile) { @@ -25,35 +41,59 @@ AIFFragmentationSensorShell02 = ClassProjectile(AArtilleryFragmentationSensorShe end local vx, vy, vz = self:GetVelocity() - local velocity = 12 + -- Normalize our velocity to ogrids/second + vx, vy, vz = vx*10, vy*10, vz*10 + + -- If we haven't already calculated our ballistic acceleration, do so now + -- This shouldn't change much between subprojectiles, so we only need to do it once + if not ballisticAcceleration then + local detonationHeight = bp.DetonateBelowHeight + vMult = bp.InitialSpeed/(10 * self:GetCurrentSpeed()) + + -- Time to impact (with our reduced speed) is calculated using the quadratic formula and vMult. + local timeToImpact = ((-vy - MathSqrt(MathPow(vy,2) - 2*g*detonationHeight))/g) / vMult + + -- Calculate the new ballistic acceleration + ballisticAcceleration = -2 * (detonationHeight + vy*vMult * timeToImpact) / MathPow(timeToImpact, 2) + spreadMagnitude = bp.FragmentRadius / timeToImpact + end + + -- Update our velocity values + -- There appears to be inevitable decay with child projectiles, so we give a slight vertical lift to compensate + vx, vy, vz = vx*vMult, vy*vMult + 2, vz*vMult -- One initial projectile following same directional path as the original - self:CreateChildProjectile(bp.FragmentId):SetVelocity(vx,0.8*vy, vz):SetVelocity(velocity):PassDamageData(self.DamageData) + self:CreateChildProjectile(bp.FragmentId) + :SetVelocity(vx, vy, vz) + :SetVelocity(bp.InitialSpeed) + :SetBallisticAcceleration(ballisticAcceleration).DamageData = self.DamageData -- Create several other projectiles in a dispersal pattern local numProjectiles = bp.Fragments - 1 - local angle = (2 * math.pi) / numProjectiles + local angle = (2 * MathPi) / numProjectiles local angleInitial = RandomFloat( 0, angle ) -- Randomization of the spread local angleVariation = angle * 13 -- Adjusts angle variance spread - local spreadMul = 0.4 -- Adjusts the width of the dispersal - local xVec = 0 - local yVec = vy*0.8 - local zVec = 0 - - -- Launch projectiles at semi-random angles away from split location - for i = 0, numProjectiles - 1 do - xVec = vx + (math.sin(angleInitial + (i*angle) + RandomFloat(-angleVariation, angleVariation))) * spreadMul - zVec = vz + (math.cos(angleInitial + (i*angle) + RandomFloat(-angleVariation, angleVariation))) * spreadMul - local proj = self:CreateChildProjectile(bp.FragmentId) - proj:SetVelocity(xVec,yVec,zVec) - proj:SetVelocity(velocity) - proj.DamageData = self.DamageData - end + local xVec + local zVec + local offsetAngle + local magnitudeVariation + + -- Launch projectiles at semi-random angles away from split location + for i = 0, numProjectiles - 1 do + offsetAngle = angleInitial + (i*angle) + RandomFloat(-angleVariation, angleVariation) + magnitudeVariation = RandomFloat(0.9, 1.1) + xVec = vx + MathSin(offsetAngle) * spreadMagnitude * magnitudeVariation + zVec = vz + MathCos(offsetAngle) * spreadMagnitude * magnitudeVariation + self:CreateChildProjectile(bp.FragmentId) + :SetVelocity(xVec, vy, zVec) + :SetVelocity(bp.InitialSpeed + RandomFloat(-bp.InitialSpeedRange, bp.InitialSpeedRange)) + :SetBallisticAcceleration(ballisticAcceleration).DamageData = self.DamageData + end self:Destroy() else - self:DoDamage( self, self.DamageData, TargetEntity) + self:DoDamage(self, self.DamageData, TargetEntity) self:OnImpactDestroy(TargetType, TargetEntity) end end,