diff --git a/game/engines/default/engine/ai/simple.lua b/game/engines/default/engine/ai/simple.lua index c1c5a98bd80dd024b9e5d2351da9e2fea4be9570..152b1b921eaf68c8f38d4f207a60056260461798 100644 --- a/game/engines/default/engine/ai/simple.lua +++ b/game/engines/default/engine/ai/simple.lua @@ -24,7 +24,13 @@ local Astar = require "engine.Astar" newAI("move_simple", function(self) if self.ai_target.actor then - local tx, ty = self:aiSeeTargetPos(self.ai_target.actor) + local tx, ty + -- Move towards the last seen position if we have one + if self.ai_state.target_last_seen then + tx, ty = self.ai_state.target_last_seen.x, self.ai_state.target_last_seen.y + else + tx, ty = self:aiSeeTargetPos(self.ai_target.actor) + end return self:moveDirection(tx, ty) end end) @@ -167,25 +173,44 @@ newAI("move_blocked_astar", function(self) end end) +newAI("move_wander", function(self) + local coords = {} + for _, coor in pairs(util.adjacentCoords(self.x, self.y)) do + if self:canMove(coor[1], coor[2]) then + coords[#coords+1] = coor + end + end + if #coords > 0 then + local selected = rng.table(coords) + return self:moveDirection(selected[1], selected[2]) + end +end) + newAI("move_complex", function(self) if self.ai_target.actor and self.x and self.y then local tx, ty = self:aiSeeTargetPos(self.ai_target.actor) local moved + -- Can we use A* due to damage? if not moved and self.ai_state.damaged_turns and self.ai_state.damaged_turns > 0 then moved = self:runAI("move_astar") end + -- Wander if it has been a while since we last saw the target + if not moved and self.ai_state.target_last_seen and (game.turn - (self.ai_state.target_last_seen.turn or game.turn)) / (game.energy_to_act / game.energy_per_tick) > 10 then + moved = self:runAI("move_wander") + end + -- Check if we can use dmap if not moved then moved = self:runAI("move_dmap") end -- Check blocking - if not moved then + if not moved and self:hasLOS(tx, ty) then -- Make sure that we are indeed blocked moved = self:runAI("move_simple") - if not moved and self:hasLOS(tx, ty) then + if not moved then -- Wait at least 5 turns of not moving before switching to blocked_astar -- add 2 since we remove 1 every turn self.ai_state.blocked_turns = (self.ai_state.blocked_turns or 0) + 2 diff --git a/game/engines/default/engine/ai/talented.lua b/game/engines/default/engine/ai/talented.lua index b49356ebdf1cc855d67ce515e4a14c2c6deefb53..e0150260ba69f55a0c1bce533ab3c6418e6155c1 100644 --- a/game/engines/default/engine/ai/talented.lua +++ b/game/engines/default/engine/ai/talented.lua @@ -23,7 +23,8 @@ newAI("dumb_talented", function(self) -- Find available talents local avail = {} - local target_dist = core.fov.distance(self.x, self.y, self.ai_target.actor.x, self.ai_target.actor.y) + local tx, ty = self:aiSeeTargetPos(self.ai_target.actor) + local target_dist = core.fov.distance(self.x, self.y, tx, ty) for tid, _ in pairs(self.talents) do local t = self:getTalentFromId(tid) -- print(self.name, self.uid, "dumb ai talents can try use", t.name, tid, "::", t.mode, not self:isTalentCoolingDown(t), target_dist <= self:getTalentRange(t), self:preUseTalent(t, true), self:canProject({type="bolt"}, self.ai_target.actor.x, self.ai_target.actor.y)) @@ -33,7 +34,7 @@ newAI("dumb_talented", function(self) local tg = {type=util.getval(t.direct_hit, self, t) and "hit" or "bolt", range=total_range} if t.mode == "activated" and not t.no_npc_use and not self:isTalentCoolingDown(t) and self:preUseTalent(t, true, true) and - (not self:getTalentRequiresTarget(t) or self:canProject(tg, self.ai_target.actor.x, self.ai_target.actor.y)) + (not self:getTalentRequiresTarget(t) or self:canProject(tg, tx, ty)) then avail[#avail+1] = tid print(self.name, self.uid, "dumb ai talents can use", t.name, tid) diff --git a/game/engines/default/engine/interface/ActorAI.lua b/game/engines/default/engine/interface/ActorAI.lua index 933ca4af7bc7b2c0221e2f0b9912916c7849a020..3df5ba6f7203d35042cbd9cf90af33e1435a545b 100644 --- a/game/engines/default/engine/interface/ActorAI.lua +++ b/game/engines/default/engine/interface/ActorAI.lua @@ -154,14 +154,18 @@ end 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 and self.ai_state.target_last_seen then tx, ty = self.ai_state.target_last_seen.x, self.ai_state.target_last_seen.y end + local spread = 0 + + if target == self.ai_target.actor and self.ai_state.target_last_seen and not self:hasLOS(self.ai_state.target_last_seen.x, self.ai_state.target_last_seen.y) then + tx, ty = self.ai_state.target_last_seen.x, self.ai_state.target_last_seen.y + spread = spread + math.floor((game.turn - (self.ai_state.target_last_seen.turn or game.turn)) / (game.energy_to_act / game.energy_per_tick)) + 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) - -- Additional spread due to last_seen - spread = spread + math.floor((game.turn - (self.ai_state.target_last_seen and self.ai_state.target_last_seen.turn or game.turn)) / (game.energy_to_act / game.energy_per_tick)) -- We don't know the exact position, so we obfuscate if spread > 0 then diff --git a/game/modules/tome/ai/tactical.lua b/game/modules/tome/ai/tactical.lua index 1d332f4dbf9a301a672782508d39b8976d3536c2..39f6520ae96d2cb615fbbc74321fbd3546bcd40c 100644 --- a/game/modules/tome/ai/tactical.lua +++ b/game/modules/tome/ai/tactical.lua @@ -25,8 +25,9 @@ local canFleeDmapKeepLos = function(self) if self.never_move then return false end -- Dont move, dont flee if self.ai_target.actor then local act = self.ai_target.actor + local ax, ay = self:aiSeeTargetPos(self.ai_target.actor) local dir, c - if self:hasLOS(act.x, act.y) then + if self:hasLOS(ax, ay) then dir = 5 c = act:distanceMap(self.x, self.y) if not c then return end @@ -34,7 +35,7 @@ local canFleeDmapKeepLos = function(self) for _, i in ipairs(util.adjacentDirs()) do local sx, sy = util.coordAddDir(self.x, self.y, i) -- Check LOS first - if self:hasLOS(act.x, act.y, nil, nil, sx, sy) then + if self:hasLOS(ax, ay, nil, nil, sx, sy) then local cd = act:distanceMap(sx, sy) -- print("looking for dmap", dir, i, "::", c, cd) if not cd or ((not c or cd < c) and self:canMove(sx, sy)) then c = cd; dir = i end