Idea was simple and interesting enough that I went and coded up a really basic version. What the code below does is take complete control of snipers that are standing still by putting them on hold fire and then issuing attack commands manually on enemies that enter LOS, making sure not to overkill units by assigning too many snipers. Snipers are set to fire-at-will when they start moving again.
What it doesn't do (and probably should, before getting released as proper widget):
- Doesn't work for anything other than snipers
- Will attack scouts
- Won't allow user any/much control over things like firestate
- did-the-sniper-shot-hit logic is pretty arbitrary (wait-and-see)
- no special handling of when snipers miss shots (they are left reloading and with the attack order still there)
- Not multiplayer tested for ping effects (probably will be fine)
Code: Select all
function widget:GetInfo()
return {
name = "Testing VI",
desc = "Testing VI",
author = "Niobium",
date = "Jan 14th, 2009",
license = "GNU GPL v2",
layer = 0,
enabled = false
}
end
local armsnipe = UnitDefNames.armsnipe.id
local sniperRange = 900
local sniperDamage = 2500
local waitTime = 60 -- If unit isn't dead after waitTime frames, damage is reset
local idlers = {}
local damaged = {}
local attackFrame = {}
function widget:UnitIdle(uID, uDefID, uTeam)
if uDefID == armsnipe and uTeam == Spring.GetMyTeamID() then
idlers[uID] = true
Spring.GiveOrderToUnit(uID, CMD.FIRE_STATE, {0}, 0)
end
end
function widget:UnitCommand(uID, uDefID, uTeam, cmdID)
if cmdID ~= CMD.FIRE_STATE and idlers[uID] then
idlers[uID] = nil
Spring.GiveOrderToUnit(uID, CMD.FIRE_STATE, {2}, 0)
end
end
function widget:UnitDestroyed(uID)
idlers[uID] = nil
end
function widget:GameFrame(n)
for uID, _ in pairs(idlers) do
local _, reloaded = Spring.GetUnitWeaponState(uID, 0)
if reloaded then
local ux, uy, uz = Spring.GetUnitPosition(uID)
local targets = Spring.GetUnitsInCylinder(ux, uz, sniperRange, Spring.ENEMY_UNITS)
for i = 1, #targets do
local eID = targets[i]
local eHP = Spring.GetUnitHealth(eID) -- This acts as a in-los check
if eHP and not (damaged[eID] and damaged[eID] >= eHP and n < attackFrame[eID] + waitTime) then
Spring.GiveOrderToUnit(uID, CMD.ATTACK, {eID}, 0)
idlers[uID] = nil -- Will become idle again after target is dead
damaged[eID] = (damaged[eID] or 0) + sniperDamage
attackFrame[eID] = n
end
end
end
end
end