Utils = { printWithShadow = function(text, x, y) local cr, cg, cb, ca = love.graphics.getColor() love.graphics.setColor(Config.TEXT_SHADOW_OFFSET_COLOR[1], Config.TEXT_SHADOW_OFFSET_COLOR[2], Config.TEXT_SHADOW_OFFSET_COLOR[3], ca) love.graphics.print(text, x + Config.TEXT_SHADOW_OFFSET_X, y + Config.TEXT_SHADOW_OFFSET_Y) love.graphics.setColor(cr, cg, cb, ca) love.graphics.print(text, x, y) end, getTableKeys = function(table) local keyset = {} local n = 0 for k, v in pairs(table) do n = n + 1 keyset[n] = k end return keyset end, getWeightFromValue = function(value) if type(value) == "table" then return value.weight or 1 elseif type(value) == "number" then return value end return 1 end, pickRandomKeyFromWeightedTable = function(table) local keyset = Utils.getTableKeys(table) local totalWeight = 0 for _, key in ipairs(keyset) do totalWeight = totalWeight + Utils.getWeightFromValue(table[key]) end local r = math.random() * totalWeight local cumulative = 0 for _, key in ipairs(keyset) do cumulative = cumulative + Utils.getWeightFromValue(table[key]) if r <= cumulative then return key end end return keyset[#keyset] end, mergeTables = function(a, b) if type(a) == 'table' and type(b) == 'table' then for k, v in pairs(b) do if type(v) == 'table' and type(a[k] or false) == 'table' then Utils.mergeTables(a[k], v) else a[k] = v end end end return a end, maskIsSolidAt = function(x, y, mask) local r, g, b, a = mask:getPixel(x, y) local brightness = (r + g + b) / 3 return brightness < 0.5 end, filterCombatantsByTeam = function(combatants, team) local filtered = {} for _, c in ipairs(combatants) do if c.team == team and c.health > 0 then table.insert(filtered, c) end end return filtered end, filterCombatantsByOpposingTeams = function(combatants, team) local filtered = {} for _, c in ipairs(combatants) do if c.team ~= team and c.health > 0 then table.insert(filtered, c) end end return filtered end, getDistance = function(x1, y1, x2, y2) local dx = x1 - x2 local dy = y1 - y2 return math.sqrt(dx * dx + dy * dy) end, findNearestCombatant = function(combatants, x, y) local nearest = nil local nearestDist = math.huge for _, cmbt in ipairs(combatants) do local dist = Utils.getDistance(cmbt.x + cmbt.width / 2, cmbt.y + cmbt.height / 2, x, y) if dist < nearestDist then nearestDist = dist nearest = cmbt end end return nearest, nearestDist end, findCombatantsWithinRange = function(combatants, x, y, range) local out = {} for _, cmbt in ipairs(combatants) do local dist = Utils.getDistance(cmbt.x + cmbt.width / 2, cmbt.y + cmbt.height / 2, x, y) if dist <= range then table.insert(out, cmbt) end end return out end, }