Skip to content

Commit

Permalink
got lua regex wrong (#4002)
Browse files Browse the repository at this point in the history
* docs

* Fix lua regexpr escapes, organize, comment badsmells

* microscopic fix

* remove spawnceg 'success' test; will return true for invalid cegs

* docs for tots

---------

Co-authored-by: efrec <[email protected]>
  • Loading branch information
efrec and efrec authored Dec 8, 2024
1 parent 4def08d commit 2cacd3d
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 42 deletions.
6 changes: 3 additions & 3 deletions effects/fire.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1460,7 +1460,7 @@ local definitions = {
}

-- Keep array in sync with values in unit_area_timed_damage:
local areaCegSizes = { 37.5, 46, 54, 62.5, 75, 87.5, 100, 125, 150, 175, 200, 225, 250, 275, 300 }
local areaSizePresets = { 37.5, 46, 54, 63, 75, 88, 100, 125, 150, 175, 200, 225, 250, 275, 300 }

local debugEffects = false
local debugCircle = {
Expand Down Expand Up @@ -1510,9 +1510,9 @@ definitions["fire-burnground-large-repeat"].flamemattalways.properties.particles
definitions["fire-burnground-large-repeat"].flamemattrandom.properties.particlesize = radiusFlame
definitions["fire-burnground-large-repeat"].flamemattrandom.properties.particlesizespread = radiusFlameLarge * 1.4

for ii = 1, #areaCegSizes do
for ii = 1, #areaSizePresets do
local expgen = table.copy(definitions['fire-area-repeat'])
local radius = areaCegSizes[ii]
local radius = areaSizePresets[ii]

local radiusFlame = 56
local inset = radiusFlame * 0.5
Expand Down
2 changes: 1 addition & 1 deletion effects/raptors/raptor-effects.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2416,7 +2416,7 @@ local definitions = {
},
}

local areaSizesUnitTimedDamage = { 37.5, 46, 54, 62.5, 75, 87.5, 100, 125, 150, 175, 200, 225, 250, 275, 300 }
local areaSizesUnitTimedDamage = { 37.5, 46, 54, 63, 75, 88, 100, 125, 150, 175, 200, 225, 250, 275, 300 }
local areaSizesUnitDefinitions = { 75, 150, 192 } -- from raptor defs

local debugEffects = false
Expand Down
90 changes: 52 additions & 38 deletions luarules/gadgets/unit_area_timed_damage.lua
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,31 @@ local areaSizePresets = {
local prefixes = { unit = 'area_ondeath_', weapon = 'area_onhit_' }
local damage, time, range, resistance = 30, 10, 75, "none"

-- Customparams are named like <prefix>_<paramName>, for ex. "area_onhit_ceg".
-- ceg - ceg to spawn when explosion happens
-- damageCeg - ceg to spawn when damage is dealt
-- time - how long the effect should stay
-- damage - damage per second
-- range - from center to edge, in elmos
-- resistance - defines which units are resistant to this type of damage when it matches with 'areadamageresistance' customparameter in a unit.
--[[
customparams = {
<prefix>_damage := <number> The damage done per second
<prefix>_time := <number> Duration of the timed area
<prefix>_range := <number> The radius of the timed area
<prefix>_damageCeg := <ceg_name> Spawns repeatedly for duration
<prefix>_resistance := <string> Matched against areadamageresistance
}
prefix := area_ondeath | area_onhit Units use ondeath; weapons use onhit.
When adding timed areas to existing weapons, you should tweak the weapon's
explosion ceg, too. There's a short delay between the hit and the area ceg,
which you can mask/make look nice with an explosion lasting about 0.5 secs.
]]--

--------------------------------------------------------------------------------
-- Cached globals --------------------------------------------------------------

local max = math.max
local spGetFeaturesInSphere = Spring.GetFeaturesInSphere
local spGetGroundHeight = Spring.GetGroundHeight
local spGetGroundNormal = Spring.GetGroundNormal
local spGetUnitDefID = Spring.GetUnitDefID
local spGetUnitsInSphere = Spring.GetUnitsInSphere
local spSpawnCEG = Spring.SpawnCEG

--------------------------------------------------------------------------------
-- Local variables -------------------------------------------------------------
Expand All @@ -53,9 +71,13 @@ local unitDamageImmunity = {}
local aliveExplosions = {}
local frameExplosions = {}
local frameNumber = 0

local explosionCount = 0

local regexArea, regexRepeat = '%-area%-', '%-repeat'
local regexDigits = "%d+"
local regexCegRadius = regexArea..regexDigits..regexRepeat
local regexCegToRadius = regexArea.."("..regexDigits..")"..regexRepeat

--------------------------------------------------------------------------------
-- Local functions -------------------------------------------------------------

Expand All @@ -76,37 +98,36 @@ local function getExplosionParams(def, prefix)
return params
end

-- Change (eg) fire-area-150-repeat to fire-area-<range>-repeat for tweakdefs:
local sub1, sub2 = '-area-', '-repeat'
local pattern = sub1..[[\d+]]..sub2
local midX, midZ = Game.mapSizeX / 2, Game.mapSizeZ / 2
local lowY = Spring.GetGroundHeight(midX, midZ) - 10000
local function getNearestCEG(params)
local ceg, range = params.ceg, params.range

-- We can't check properties of the ceg, so use the name to compare 'size'. Yes, "that is bad".
if string.find(ceg, "-"..math.floor(range).."-", nil, true) then
local _, _, _, namedRange = string.find(ceg, regexCegToRadius, nil, true)
if tonumber(namedRange) == math.floor(range) then
return ceg, range
end
end

-- User tweaks have modified the ceg and/or range; update both to the best-fitting preset.
local sizeBest, diffBest = math.huge, math.huge
for ii = 1, #areaSizePresets do
local size = areaSizePresets[ii]
local diff = math.abs(range / size - size / range)
if diff < diffBest then
local cegTest = string.gsub(ceg, pattern, sub1..math.floor(sizeBest)..sub2)
local success, cegID = Spring.SpawnCEG(cegTest, midX, lowY, midZ) -- hidden-ish
if success and cegID then
diffBest = diff
sizeBest = size
end
diffBest = diff
sizeBest = size
end
end
if sizeBest < math.huge then
ceg = string.gsub(ceg, [[\d+]], sizeBest, 1)
ceg = string.gsub(ceg, regexDigits, sizeBest, 1)
return ceg, sizeBest
end
end

local spGetGroundHeight = Spring.GetGroundHeight
local spGetGroundNormal = Spring.GetGroundNormal
local function addTimedExplosion(weaponDefID, px, py, pz, attackerID, projectileID)
local explosion = timedDamageWeapons[weaponDefID]
local elevation = math.max(spGetGroundHeight(px, pz), 0)
local elevation = max(spGetGroundHeight(px, pz), 0)
if py <= elevation + explosion.range then
local dx, dy, dz
if elevation > 0 then
Expand All @@ -132,18 +153,12 @@ local function addTimedExplosion(weaponDefID, px, py, pz, attackerID, projectile
end
end

local spSpawnCEG = Spring.SpawnCEG

local function spawnAreaCEGs(loopIndex)
for index, area in pairs(aliveExplosions[loopIndex]) do
spSpawnCEG(area.ceg, area.x, area.y, area.z, area.dx, area.dy, area.dz)
end
end

local spGetUnitsInSphere = Spring.GetUnitsInSphere
local spGetFeaturesInSphere = Spring.GetFeaturesInSphere
local spGetUnitDefID = Spring.GetUnitDefID

local function damageTargetsInAreas(timedAreas, gameFrame)
for index, area in pairs(timedAreas) do
local unitsInRange = spGetUnitsInSphere(area.x, area.y, area.z, area.range)
Expand Down Expand Up @@ -198,15 +213,15 @@ function gadget:Initialize()
-- This simplifies writing tweakdefs to modify area_on[x]_range for balance,
-- e.g. setting all ranges to 80% their original amount will work correctly.
for weaponDefID, params in pairs(timedDamageWeapons) do
if string.find(params.ceg, pattern, nil, false) and not
string.find(params.ceg, sub1..math.floor(params.range)..sub2)
then
if string.find(params.ceg, regexCegRadius, nil, false) then
local ceg, range = getNearestCEG(params)
local name = WeaponDefs[weaponDefID].name
if ceg and range then
params.ceg = ceg
params.range = range
Spring.Log(gadget:GetInfo().name, LOG.INFO, 'Set '..name..' to range, ceg = '..params.range..', '..params.ceg)
if params.ceg ~= ceg or params.range ~= range then
params.ceg = ceg
params.range = range
Spring.Log(gadget:GetInfo().name, LOG.INFO, 'Set '..name..' to range, ceg = '..range..', '..ceg)
end
else
timedDamageWeapons[weaponDefID] = nil
Spring.Log(gadget:GetInfo().name, LOG.WARN, 'Removed '..name..' from area timed damage weapons.')
Expand Down Expand Up @@ -275,12 +290,11 @@ end
function gadget:GameFrame(frame)
local indexDamage = 1 + (frame % frameInterval)
local indexExpGen = 1 + ((frame + frameCegShift) % frameInterval)
local frameAreas = aliveExplosions[indexDamage]

spawnAreaCEGs(indexExpGen)

local frameAreas = aliveExplosions[indexDamage]
damageTargetsInAreas(frameAreas, frame)

frameExplosions = frameAreas
frameNumber = frame
end
end

0 comments on commit 2cacd3d

Please sign in to comment.