Improved Sniper AI

Improved Sniper AI

Discuss Lua based Spring scripts (LuaUI widgets, mission scripts, gaia scripts, mod-rules scripts, scripted keybindings, etc...)

Moderator: Moderators

Post Reply
User avatar
Guessmyname
Posts: 3301
Joined: 28 Apr 2005, 21:07

Improved Sniper AI

Post by Guessmyname »

Tired of having long-reload, high damage units snipe the first scout they see, I'm trying to devise a cleverer way for sniping units to behave on the 'automatic targetting' front (ie auto-attacking in-range enemies, as opposed to player-ordered targets).

Current idea is like this:
  • Target enters sight and range. Unit wants to shoot target.
  • Wait a set time (unit specific?)
  • If a more 'interesting' unit enters sight and range, reacquire that unit as preferred target and go back to step one.
  • Otherwise, shoot.
Two things: firstly, "is this lua-able?". Secondly, "How to define interesting?". I think at the moment it's probably just best to say 'hitpoints'; ie snipers are high damage units so prioritising high health targets makes more sense and hey; it's a good way of differentiating between a tank and a scout car, though it's still a bit of a vague way of telling between unit types; alternatively could attempt to use unit categories in some way.

What does everyone think?
User avatar
Sucky_Lord
Posts: 531
Joined: 22 Aug 2008, 16:29

Re: Improved Sniper AI

Post by Sucky_Lord »

This would be so awesome bro.

I advise something like "target units that have the highest amount of health that doesn't exceed sniper bullet damage" so you're getting 1 shot kills and bullets arent being wasted.
User avatar
Niobium
Posts: 456
Joined: 07 Dec 2008, 02:35

Re: Improved Sniper AI

Post by Niobium »

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
Google_Frog
Moderator
Posts: 2464
Joined: 12 Oct 2007, 09:24

Re: Improved Sniper AI

Post by Google_Frog »

I've been thinking of something like this.

The AllowWeaponTargetCheck and AllowWeaponTarget callins have promising names.

I know that Spring.SetUnitTarget works.

With a combination of these it should be possible to make any unit attacking AI.
Post Reply

Return to “Lua Scripts”