Skip to content
Snippets Groups Projects
Commit fc392075 authored by dg's avatar dg
Browse files

Ai when fooled by teleports will not go straight to the player, they'll search...

Ai when fooled by teleports will not go straight to the player, they'll search at semi random aruond them in an increasing radius


git-svn-id: http://svn.net-core.org/repos/t-engine4@6208 51575b47-30f0-44d4-a5cc-537603b46e54
parent 2b103e76
No related branches found
No related tags found
No related merge requests found
......@@ -32,19 +32,28 @@ end)
newAI("move_dmap", function(self)
if self.ai_target.actor and self.x and self.y then
local a = self.ai_target.actor
if self:hasLOS(a.x, a.y) then return self:runAI("move_simple") end
local ax, ay = self:aiSeeTargetPos(a)
-- If we have a vision, go straight towards the target
if self:hasLOS(ax, ay) then
return self:runAI("move_simple")
end
local c = a:distanceMap(self.x, self.y)
if not c then return self:runAI("move_simple") end
local dir = 5
for _, i in ipairs(util.adjacentDirs()) do
local sx, sy = util.coordAddDir(self.x, self.y, i)
local cd = a:distanceMap(sx, sy)
-- print("looking for dmap", dir, i, "::", c, cd)
if cd and cd > c and self:canMove(sx, sy) then c = cd; dir = i end
end
return self:moveDirection(util.coordAddDir(self.x, self.y, dir))
if c and ax == a.x and ay == a.y then
for _, i in ipairs(util.adjacentDirs()) do
local sx, sy = util.coordAddDir(self.x, self.y, i)
local cd = a:distanceMap(sx, sy)
-- print("looking for dmap", dir, i, "::", c, cd)
local tile_available = self:canMove(sx, sy) or (sx == ax and sy == ay)
if cd and cd > c and tile_available then c = cd; dir = i end
end
return self:moveDirection(util.coordAddDir(self.x, self.y, dir))
else
return self:runAI("move_simple")
end
end
end)
......@@ -159,8 +168,6 @@ newAI("move_blocked_astar", function(self)
end)
newAI("move_complex", function(self)
do return self:runAI("move_dmap") end
if self.ai_target.actor and self.x and self.y then
local tx, ty = self:aiSeeTargetPos(self.ai_target.actor)
local moved
......@@ -177,7 +184,7 @@ newAI("move_complex", function(self)
-- Check blocking
if not moved then
-- Make sure that we are indeed blocked
-- moved = self:runAI("move_simple")
moved = self:runAI("move_simple")
if not moved and self:hasLOS(tx, ty) then
-- Wait at least 5 turns of not moving before switching to blocked_astar
-- add 2 since we remove 1 every turn
......
......@@ -114,6 +114,12 @@ function _M:doAI()
-- we forget it
if self.ai_target.actor and self.ai_target.actor.dead then self.ai_target.actor = nil end
-- Update the ai_target table
local target_pos = self.ai_target.actor and self.fov and self.fov.actors and self.fov.actors[self.ai_target.actor]
if target_pos then
self.ai_state.target_last_seen = {x=target_pos.x, y=target_pos.y, turn=self.fov_last_turn}
end
return self:runAI(self.ai)
end
......@@ -130,31 +136,32 @@ function _M:getTarget(typ)
end
--- Sets the current target
function _M:setTarget(target)
function _M:setTarget(target, last_seen)
self.ai_target.actor = target
if last_seen then
self.ai_state.target_last_seen = last_seen
else
local target_pos = target and self.fov and self.fov.actors and self.fov.actors[self.ai_target.actor] or {x=self.x, y=self.y}
self.ai_state.target_last_seen = {x=target_pos.x, y=target_pos.y, turn=game.turn}
end
end
--- Returns the seen coords of the target
-- This will usually return the exact coords, but if the target is only partially visible (or not at all)
-- it will return estimates, to throw the AI a bit off
-- @param target the target we are tracking
-- @param ignoreLOS ignores LOS check
-- @return x, y coords to move/cast to
function _M:aiSeeTargetPos(target, ignoreLOS)
function _M:aiSeeTargetPos(target)
if not target then return self.x, self.y end
local tx, ty = target.x, target.y
if target == self.ai_target.actor then tx, ty = self.ai_state.target_last_seen.x, self.ai_state.target_last_seen.y end
local see, chance = self:canSee(target)
-- Compute the maximum spread if we need to obfuscate
local spread = see and 0 or math.floor((100 - chance) / 10)
-- Do we check for LOS?
if not ignoreLOS then
local los, lx, ly = self:hasLOS(tx, ty)
if not los then
spread = math.max(spread, core.fov.distance(tx, ty, lx, ly))
end
end
-- Additional spread due to last_seen
spread = spread + math.floor((game.turn - self.ai_state.target_last_seen.turn) / (game.energy_to_act / game.energy_per_tick))
-- We don't know the exact position, so we obfuscate
if spread > 0 then
......
......@@ -43,7 +43,7 @@ newAI("target_simple", function(self)
(self:canSee(act) and (self.fov.actors[act].sqdist <= sqsense) or game.level.map.lites(act.x, act.y))
) and not act:attr("invulnerable") then
self.ai_target.actor = act
self:setTarget(act)
self:check("on_acquire_target", act)
act:check("on_targeted", self)
print("AI took for target", self.uid, self.name, "::", act.uid, act.name, self.fov.actors[act].sqdist, "<", sqsense)
......@@ -58,7 +58,7 @@ newAI("target_player_radius", function(self)
if self.ai_target.actor and not self.ai_target.actor.dead and rng.percent(90) then return true end
if core.fov.distance(self.x, self.y, game.player.x, game.player.y) < self.ai_state.sense_radius then
self.ai_target.actor = game.player
self:setTarget(game.player)
self:check("on_acquire_target", game.player)
return true
end
......@@ -69,7 +69,7 @@ newAI("target_simple_or_player_radius", function(self)
if self:runAI("target_simple") then return true end
if game.player.x and core.fov.distance(self.x, self.y, game.player.x, game.player.y) < self.ai_state.sense_radius then
self.ai_target.actor = game.player
self:setTarget(game.player)
return true
end
end)
......@@ -77,6 +77,6 @@ end)
-- Special targetting for charred scar, select a normal target, if none is found go for the player
newAI("charred_scar_target", function(self)
if self:runAI("target_simple") then return true end
self.ai_target.actor = game.player
self:setTarget(game.player)
return true
end)
......@@ -156,17 +156,34 @@ end
function _M:seen_by(who)
if self:hasEffect(self.EFF_VAULTED) and who and game.party:hasMember(who) then self:removeEffect(self.EFF_VAULTED, true, true) end
if self.ai_target.actor then return end
-- Check if we can pass target
if self.dont_pass_target then return end
if not who.ai_target then return end
if not who.ai_target.actor then return end
if not who.ai_target.actor.x then return end
-- Only receive targets from allies
if self:reactionToward(who) <= 0 then return end
if not who:canSee(who.ai_target.actor) then return end
-- Check if we can actually see the ally (range and obstacles)
if not who.x or not self:hasLOS(who.x, who.y) then return end
if core.fov.distance(self.x, self.y, who.x, who.y) > self.sight then return end
if core.fov.distance(self.x, self.y, who.ai_target.actor.x, who.ai_target.actor.y) > self.sight then return end
self:setTarget(who.ai_target.actor)
if self.ai_target.actor then
-- Pass last seen coordinates
if self.ai_target.actor == who.ai_target.actor then
local last_seen = (self.ai_state.target_last_seen.turn > who.ai_state.target_last_seen.turn) and self.ai_state.target_last_seen or who.ai_state.target_last_seen
self.ai_state.target_last_seen = last_seen
who.ai_state.target_last_seen = last_seen
end
return
end
if who.ai_state and who.ai_state.target_last_seen then
-- Don't believe allies if they saw the target far, far away
if core.fov.distance(self.x, self.y, who.ai_state.target_last_seen.x, who.ai_state.target_last_seen.y) > self.sight then return end
-- Don't believe allies if they saw the target over 10 turns ago
if (game.turn - who.ai_state.target_last_seen.turn) / (game.energy_to_act / game.energy_per_tick) > 10 then return end
end
-- And only trust the ally if they can actually see the target
if not who:canSee(who.ai_target.actor) then return end
self:setTarget(who.ai_target.actor, who.ai_state.target_last_seen)
print("[TARGET] Passing target", self.name, "from", who.name, "to", who.ai_target.actor.name)
end
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment