@@ -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
265259local 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
277271end
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.
280318local 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