Skip to content

Commit 3fd1674

Browse files
author
efrec
committed
isolate shield bounce code a bit
why didn't I even look at what the engine does for repulsion, tbh. idk. that's a good question, man.
1 parent 0e60629 commit 3fd1674

File tree

1 file changed

+45
-35
lines changed

1 file changed

+45
-35
lines changed

luarules/gadgets/unit_custom_weapons_cluster.lua

Lines changed: 45 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -256,12 +256,6 @@ local waterFullDeflection = 0.85 -- 1 - vertical response loss
256256
---Water is generally incompressible so acts like solid terrain of lower density
257257
-- when it takes hard impacts or impulses. We take a fast estimate of its added
258258
-- bulk to the solid terrain below and shift the surface direction toward level.
259-
---@param slope number in radians? in what? is this [0, 1]?
260-
---@param elevation number in elmos, always negative
261-
---@return number percentX
262-
---@return number percentY
263-
---@return number percentZ
264-
---@return number depth
265259
local function getWaterDeflection(slope, elevation)
266260
elevation = max(elevation * waterDepthCoef, waterDepthDeflects)
267261
local waterDeflectFraction = min(1, elevation / waterDepthDeflects)
@@ -276,6 +270,50 @@ local function getWaterDeflection(slope, elevation)
276270
end
277271
end
278272

273+
---Shields can overlap with units, terrain, and other shields, so we should avoid both:
274+
-- (1) exaggerating other responses by adding new responses in the same direction, and
275+
-- (2) destructively negating other strong responses (> 1) when opposite in direction.
276+
local function getShieldDeflection(dx, dy, dz, shieldUnits)
277+
local ox, oy, oz = dx, dy, dz
278+
local responseMax = max(1, diag(ox, oy, oz))
279+
280+
-- Current code does not detect all shields that should have been "hit" via AOE,
281+
-- but multiple hits, while rare, can and do happen, still, in typical gameplay.
282+
for _, shieldUnitID in pairs(shieldUnits) do
283+
local sx, sy, sz, radius = getShieldPosition(shieldUnitID)
284+
285+
if sx then
286+
sx, sy, sz = dx + (x - sx) / radius, dy + (y - sy) / radius, dz + (z - sz) / radius
287+
local response = diag(sx, sy, sz)
288+
local limitMin, limitMax = 1, responseMax
289+
290+
if limitMax > 1 then
291+
-- Limits above 1 are in the direction of the original response,
292+
-- with the limits at 90 degrees from that direction equal to 1,
293+
-- and the limits facing > 90 degrees away from it less than 1.
294+
local codirection = (ox * sx + oy * sy + oz * sz) / limitMax
295+
if codirection < 0 then
296+
limitMin = min(-codirection, limitMin)
297+
limitMax = 1
298+
codirection = codirection + 1
299+
end
300+
limitMax = clamp(codirection, limitMin, limitMax)
301+
end
302+
303+
-- Shields can overlap units, terrain, and other shields, so
304+
-- they need to avoid exaggerating other existing responses.
305+
if response > limitMax and response > 0 then
306+
local ratio = limitMax / response
307+
sx, sy, sz = sx * ratio, sy * ratio, sz * ratio
308+
end
309+
310+
dx, dy, dz = sx, sy, sz
311+
end
312+
end
313+
314+
return dx, dy, dz
315+
end
316+
279317
---Deflection from solid terrain and unit collider surfaces plus water by depth.
280318
local function getSurfaceDeflection(x, y, z, shieldUnits)
281319
local elevation = spGetGroundHeight(x, z)
@@ -340,35 +378,7 @@ local function getSurfaceDeflection(x, y, z, shieldUnits)
340378

341379
-- Additional deflection from shields, which are solid-terrain-like.
342380
if shieldUnits then
343-
local ox, oy, oz = dx, dy, dz
344-
local responseMax = max(1, diag(ox, oy, oz)) -- limit responses when > 1
345-
346-
-- A hit to multiple shields is an exceptional case since they don't seem to be damaged by AOE.
347-
for _, shieldUnitID in pairs(shieldUnits) do
348-
unitX, unitY, unitZ, radius = getShieldPosition(shieldUnitID)
349-
if unitX then
350-
local rx, ry, rz = dx + (x - unitX) / radius, dy + (y - unitY) / radius, dz + (z - unitZ) / radius
351-
local response = diag(rx, ry, rz)
352-
353-
local limitMin, limitMax = 1, responseMax
354-
if limitMax > 1 then
355-
-- Shields can overlap units so we want to avoid an exaggerated response.
356-
local codirection = (ox * rx + oy * ry + oz * rz) / limitMax
357-
if codirection < 0 then
358-
limitMin = min(-codirection, limitMin) -- don't produce over-corrections
359-
codirection = codirection + 1 -- directions were opposite of each other
360-
limitMax = 1 -- don't produce under-corrections
361-
end
362-
limitMax = clamp(codirection, limitMin, limitMax)
363-
end
364-
if response > limitMax and response > 0 then
365-
local ratio = limitMax / response
366-
rx, ry, rz = rx * ratio, ry * ratio, rz * ratio
367-
end
368-
369-
dx, dy, dz = rx, ry, rz
370-
end
371-
end
381+
dx, dy, dz = getShieldDeflection(dx, dy, dz, shieldUnits)
372382
end
373383

374384
return dx, dy, dz

0 commit comments

Comments
 (0)