Skip to content

Commit ffb7b9c

Browse files
committed
Always filter units by target teamId. For enemies use ENEMY_UNITS.
alt - filter by unitDefId and teamId ctrl - filter by teamId. When targeting wreck, filter by techLevel instead
1 parent 0dae4c1 commit ffb7b9c

File tree

1 file changed

+90
-58
lines changed

1 file changed

+90
-58
lines changed

luaui/Widgets/cmd_area_commands_filter.lua

Lines changed: 90 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
local widget = widget ---@type RulesUnsyncedCallins
22

33
-- When performing an area command for one of the `allowedCommands` below:
4-
-- - If Ctrl is pressed and hovering over a unit, targets all units with the same alliance (enemy/allied) in the area.
5-
-- - If Alt is pressed and hovering over a unit, targets all units that share the same unitdefid in the area.
4+
-- - If enemy unit is targeted then targetAllegiance=ENEMY_UNITS otherwise targetAllegiance=targetTeamId
5+
-- - If Ctrl is pressed and hovering over a unit, targets all units in the area. For wrecks, it targets all wrecks with the same tech level
6+
-- - If Alt is pressed and hovering over a unit, targets all units that share the same unitDefId in the area.
67
-- - If Meta is pressed, orders are put in front of the order queue.
78
-- - If Meta and Shift are pressed, splits orders between selected units. Orders are placed at the end of the queue
89
function widget:GetInfo()
@@ -29,20 +30,23 @@ local spWorldToScreenCoords = Spring.WorldToScreenCoords
2930
local spTraceScreenRay = Spring.TraceScreenRay
3031
local spGetUnitDefID = Spring.GetUnitDefID
3132
local spGetUnitAllyTeam = Spring.GetUnitAllyTeam
33+
local spGetUnitTeam = Spring.GetUnitTeam
3234
local spGetFeatureDefID = Spring.GetFeatureDefID
3335
local spGetFeaturesInCylinder = Spring.GetFeaturesInCylinder
3436
local spGetSpectatingState = Spring.GetSpectatingState
35-
local spGetMyTeamID = Spring.GetMyTeamID
3637
local spGetMyAllyTeamID = Spring.GetMyAllyTeamID
3738
local spGetUnitIsTransporting = Spring.GetUnitIsTransporting
3839
local spGetUnitPosition = Spring.GetUnitPosition
3940
local spGetFeaturePosition = Spring.GetFeaturePosition
4041
local spGetUnitArrayCentroid = Spring.GetUnitArrayCentroid
4142
local spGetFeatureResurrect = Spring.GetFeatureResurrect
42-
local spGetUnitTeam = Spring.GetUnitTeam
43-
local spAreTeamsAllied = Spring.AreTeamsAllied
4443

45-
local myTeamID
44+
local ENEMY_UNITS = Spring.ENEMY_UNITS
45+
local ALLY_UNITS = Spring.ALLY_UNITS
46+
local ALL_UNITS = Spring.ALL_UNITS
47+
local FEATURE = "feature"
48+
local UNIT = "unit"
49+
4650
local myAllyTeamID
4751

4852
---------------------------------------------------------------------------------------
@@ -303,18 +307,23 @@ local function sortTargetsByDistance(selectedUnits, filteredTargets, closestFirs
303307
end
304308

305309
local function giveOrders(cmdId, selectedUnits, filteredTargets, options)
306-
local count = 0
307-
for _, targetId in ipairs(filteredTargets) do
310+
local firstTarget = true
311+
local selectedUnitsLen = #selectedUnits
312+
for i, targetId in ipairs(filteredTargets) do
308313
local cmdOpts = {}
309-
if count > 0 or options.shift then
314+
if not firstTarget or options.shift then
310315
tableInsert(cmdOpts, "shift")
311316
end
312317
if options.meta and not options.shift then
313318
spGiveOrderToUnitArray(selectedUnits, CMD.INSERT, { 0, cmdId, 0, targetId }, CMD.OPT_ALT)
314319
else
315320
spGiveOrderToUnitArray(selectedUnits, cmdId, { targetId }, cmdOpts)
316321
end
317-
count = count + 1
322+
firstTarget = false
323+
if i * selectedUnitsLen > 1000 then
324+
Spring.Log(widget:GetInfo().name, LOG.WARNING, "Command count exceeded, target selection may be incomplete")
325+
return
326+
end
318327
end
319328
end
320329

@@ -373,62 +382,64 @@ local function loadUnitsHandler(cmdId, selectedUnits, filteredTargets, options)
373382
end
374383
end
375384

376-
local FEATURE = "feature"
377-
local UNIT = "unit"
378-
379385
---@class CommandConfig
380386
---@field handle function
381387
---@field allowedTargetTypes table
382-
---@field skipAlliedUnits? boolean
388+
---@field targetAllegiance number AllUnits = -1, MyUnits = -2, AllyUnits = -3, EnemyUnits = -4
389+
390+
local function commandConfig(targetTypes, targetAllegiance, handler)
391+
local allowedTargetTypes = {}
392+
for _, targetType in ipairs(targetTypes) do
393+
allowedTargetTypes[targetType] = true
394+
end
395+
local config = {} --- @type CommandConfig
396+
config.handle = handler or defaultHandler
397+
config.allowedTargetTypes = allowedTargetTypes
398+
config.targetAllegiance = targetAllegiance
399+
return config
400+
end
383401

384402
---@type table<number, CommandConfig>
385403
local allowedCommands = {
386-
[CMD.ATTACK] = { handle = defaultHandler, allowedTargetTypes = { [UNIT] = true }, skipAlliedUnits = true },
387-
[CMD.GUARD] = { handle = defaultHandler, allowedTargetTypes = { [UNIT] = true } },
388-
[CMD.RECLAIM] = { handle = defaultHandler, allowedTargetTypes = { [UNIT] = true, [FEATURE] = true } },
389-
[CMD.REPAIR] = { handle = defaultHandler, allowedTargetTypes = { [UNIT] = true } },
390-
[CMD.CAPTURE] = { handle = defaultHandler, allowedTargetTypes = { [UNIT] = true } },
391-
[GameCMD.UNIT_SET_TARGET] = { handle = defaultHandler, allowedTargetTypes = { [UNIT] = true } },
392-
[GameCMD.UNIT_SET_TARGET_NO_GROUND] = { handle = defaultHandler, allowedTargetTypes = { [UNIT] = true } },
393-
[CMD.RESURRECT] = { handle = defaultHandler, allowedTargetTypes = { [FEATURE] = true } },
394-
[CMD.LOAD_UNITS] = { handle = loadUnitsHandler, allowedTargetTypes = { [UNIT] = true } },
404+
[CMD.ATTACK] = commandConfig({ UNIT }, ENEMY_UNITS),
405+
[CMD.CAPTURE] = commandConfig({ UNIT }, ENEMY_UNITS),
406+
[GameCMD.UNIT_SET_TARGET] = commandConfig({ UNIT }, ENEMY_UNITS),
407+
[GameCMD.UNIT_SET_TARGET_NO_GROUND] = commandConfig({ UNIT }, ENEMY_UNITS),
408+
[CMD.GUARD] = commandConfig({ UNIT }, ALLY_UNITS),
409+
[CMD.REPAIR] = commandConfig({ UNIT }, ALLY_UNITS),
410+
[CMD.RECLAIM] = commandConfig({ UNIT, FEATURE }, ALL_UNITS),
411+
[CMD.LOAD_UNITS] = commandConfig({ UNIT }, ALL_UNITS, loadUnitsHandler),
412+
[CMD.RESURRECT] = commandConfig({ FEATURE }),
395413
}
396414

397-
local function filterUnits(targetId, cmdX, cmdZ, radius, options, skipAlliedUnits)
415+
local function filterUnits(targetId, cmdX, cmdZ, radius, options, targetAllegiance)
416+
local alt = options.alt
417+
local ctrl = options.ctrl
398418
local filteredTargets = {}
399419
local unitDefId = spGetUnitDefID(targetId)
400420
if not unitDefId then
401421
return nil
402422
end
403423

404-
local isEnemyTarget = (spGetUnitAllyTeam(targetId) ~= myAllyTeamID)
424+
local isEnemyTarget = spGetUnitAllyTeam(targetId) ~= myAllyTeamID
425+
if isEnemyTarget and targetAllegiance ~= ALL_UNITS and targetAllegiance ~= ENEMY_UNITS then
426+
-- targeting enemy when only allies are allowed
427+
return nil
428+
end
405429

406-
local unitsInArea
407430
if isEnemyTarget then
408-
unitsInArea = spGetUnitsInCylinder(cmdX, cmdZ, radius, Spring.ENEMY_UNITS)
409-
elseif not skipAlliedUnits then
410-
local nearbyUnits = spGetUnitsInCylinder(cmdX, cmdZ, radius)
411-
if not nearbyUnits then
412-
return nil
413-
end
431+
targetAllegiance = ENEMY_UNITS
432+
else
433+
targetAllegiance = spGetUnitTeam(targetId)
434+
end
414435

415-
unitsInArea = {}
416-
for i = 1, #nearbyUnits do
417-
local unitID = nearbyUnits[i]
418-
if spAreTeamsAllied(spGetUnitTeam(unitID), myTeamID) then
419-
unitsInArea[#unitsInArea + 1] = unitID
420-
end
421-
end
436+
local unitsInArea = spGetUnitsInCylinder(cmdX, cmdZ, radius, targetAllegiance)
422437

423-
if #unitsInArea == 0 then
424-
return nil
425-
end
426-
end
427438
if not unitsInArea then
428439
return nil
429440
end
430441

431-
if options.ctrl then
442+
if ctrl then
432443
return unitsInArea
433444
end
434445

@@ -438,14 +449,18 @@ local function filterUnits(targetId, cmdX, cmdZ, radius, options, skipAlliedUnit
438449
tableInsert(filteredTargets, unitID)
439450
end
440451
end
452+
441453
return filteredTargets
442454
end
443455

444-
local function filterFeatures(targetId, cmdX, cmdZ, radius, options)
445-
if not options.alt then
446-
return nil
447-
end
456+
local function getTechLevel(unitDefName)
457+
local unitDef = UnitDefNames[unitDefName]
458+
return unitDef and unitDef.customParams.techlevel
459+
end
448460

461+
local function filterFeatures(targetId, cmdX, cmdZ, radius, options, targetUnitDefName)
462+
local alt = options.alt
463+
local ctrl = options.ctrl
449464
local filteredTargets = {}
450465
local featureDefId = spGetFeatureDefID(targetId)
451466
if not featureDefId then
@@ -457,13 +472,31 @@ local function filterFeatures(targetId, cmdX, cmdZ, radius, options)
457472
return nil
458473
end
459474

475+
local targetTechLevel
476+
if ctrl then
477+
targetTechLevel = getTechLevel(targetUnitDefName)
478+
end
479+
460480
for i = 1, #featuresInArea do
461481
local featureId = featuresInArea[i]
462-
if spGetFeatureDefID(featureId) == featureDefId then
463-
-- featureId is normalised to Game.maxUnits + featureId because of:
464-
-- https://springrts.com/wiki/Lua_CMDs#CMDTYPE.ICON_UNIT_FEATURE_OR_AREA
465-
-- "expect 1 parameter in return (unitid or Game.maxUnits+featureid)"
466-
featureId = Game.maxUnits + featureId
482+
local shouldInsert = false
483+
if alt and spGetFeatureDefID(featureId) == featureDefId then
484+
shouldInsert = true
485+
elseif ctrl then
486+
local unitDefName = spGetFeatureResurrect(featureId)
487+
local unitTechLevel = getTechLevel(unitDefName)
488+
if unitTechLevel == targetTechLevel then
489+
shouldInsert = true
490+
end
491+
end
492+
if shouldInsert then
493+
if not Engine.FeatureSupport.noOffsetForFeatureID then
494+
-- featureId is normalised to Game.maxUnits + featureId because of:
495+
-- https://springrts.com/wiki/Lua_CMDs#CMDTYPE.ICON_UNIT_FEATURE_OR_AREA
496+
-- "expect 1 parameter in return (unitd or Game.maxUnits+featureid)"
497+
-- offset due to be removed in future engine version
498+
featureId = featureId + Game.maxUnits
499+
end
467500
tableInsert(filteredTargets, featureId)
468501
end
469502
end
@@ -500,14 +533,14 @@ function widget:CommandNotify(cmdId, params, options)
500533
local filteredTargets
501534

502535
if targetType == UNIT then
503-
filteredTargets = filterUnits(targetId, cmdX, cmdZ, radius, options, currentCommand.skipAlliedUnits)
536+
filteredTargets = filterUnits(targetId, cmdX, cmdZ, radius, options, currentCommand.targetAllegiance)
504537
elseif targetType == FEATURE then
505-
local featureDefName = spGetFeatureResurrect(targetId)
538+
local unitDefName = spGetFeatureResurrect(targetId)
506539
-- filter only wrecks which can be resurrected
507-
if featureDefName == nil or featureDefName == "" then
540+
if unitDefName == nil or unitDefName == "" then
508541
return false
509542
end
510-
filteredTargets = filterFeatures(targetId, cmdX, cmdZ, radius, options)
543+
filteredTargets = filterFeatures(targetId, cmdX, cmdZ, radius, options, unitDefName)
511544
end
512545

513546
if not filteredTargets or #filteredTargets == 0 then
@@ -522,7 +555,6 @@ local function initialize()
522555
if spGetSpectatingState() then
523556
widgetHandler:RemoveWidget()
524557
end
525-
myTeamID = spGetMyTeamID()
526558
myAllyTeamID = spGetMyAllyTeamID()
527559
end
528560

0 commit comments

Comments
 (0)