Skip to content

Commit

Permalink
Merge branch 'master' of github.com:wesnoth/wesnoth
Browse files Browse the repository at this point in the history
  • Loading branch information
AI0867 committed Apr 1, 2014
2 parents ea8a3bb + e1bbfc4 commit 116c6a6
Show file tree
Hide file tree
Showing 13 changed files with 364 additions and 182 deletions.
20 changes: 11 additions & 9 deletions data/ai/micro_ais/cas/ca_big_animals.lua
@@ -1,6 +1,7 @@
local H = wesnoth.require "lua/helper.lua"
local AH = wesnoth.require "ai/lua/ai_helper.lua"
local LS = wesnoth.require "lua/location_set.lua"
local MAIUV = wesnoth.dofile "ai/micro_ais/micro_ai_unit_variables.lua"

local ca_big_animals = {}

Expand Down Expand Up @@ -33,15 +34,18 @@ function ca_big_animals:execution(ai, cfg)
--AH.put_labels(avoid)

for i,unit in ipairs(units) do
local goal = MAIUV.get_mai_unit_variables(unit, cfg.ai_id)

-- Unit gets a new goal if none exist or on any move with 10% random chance
local r = math.random(10)
if (not unit.variables.goal_x) or (r == 1) then
if (not goal.goal_x) or (r == 1) then
local locs = AH.get_passable_locations(cfg.filter_location or {})
local rand = math.random(#locs)
--print(type, ': #locs', #locs, rand)
unit.variables.goal_x, unit.variables.goal_y = locs[rand][1], locs[rand][2]
goal.goal_x, goal.goal_y = locs[rand][1], locs[rand][2]
MAIUV.set_mai_unit_variables(unit, cfg.ai_id, goal)
end
--print('Big animal goto: ', type, unit.variables.goal_x, unit.variables.goal_y, r)
--print('Big animal goto: ', unit.id, goal.goal_x, goal.goal_y, r)

-- hexes the unit can reach
local reach_map = AH.get_reachable_unocc(unit)
Expand All @@ -57,7 +61,7 @@ function ca_big_animals:execution(ai, cfg)
local max_rating, best_hex = -9e99, {}
reach_map:iter( function(x, y, v)
-- Distance from goal is first rating
local rating = - H.distance_between(x, y, unit.variables.goal_x, unit.variables.goal_y)
local rating = - H.distance_between(x, y, goal.goal_x, goal.goal_y)

-- Proximity to an enemy unit is a plus
local enemy_hp = 500
Expand Down Expand Up @@ -87,14 +91,12 @@ function ca_big_animals:execution(ai, cfg)
else -- If animal did not move, we need to stop it (also delete the goal)
AH.checked_stopunit_moves(ai, unit)
if (not unit) or (not unit.valid) then return end
unit.variables.goal_x = nil
unit.variables.goal_y = nil
MAIUV.delete_mai_unit_variables(unit, cfg.ai_id)
end

-- Or if this gets the unit to the goal, we also delete the goal
if (unit.x == unit.variables.goal_x) and (unit.y == unit.variables.goal_y) then
unit.variables.goal_x = nil
unit.variables.goal_y = nil
if (unit.x == goal.goal_x) and (unit.y == goal.goal_y) then
MAIUV.delete_mai_unit_variables(unit, cfg.ai_id)
end

-- Finally, if the unit ended up next to enemies, attack the weakest of those
Expand Down
8 changes: 4 additions & 4 deletions data/ai/micro_ais/cas/ca_goto.lua
Expand Up @@ -22,7 +22,7 @@ function ca_goto:evaluation(ai, cfg, self)
-- which case we do not do anything
if cfg.release_all_units_at_goal then
for rel in H.child_range(self.data, "goto_release_all") do
if (rel.id == cfg.ca_id) then
if (rel.id == cfg.ai_id) then
return 0
end
end
Expand Down Expand Up @@ -65,7 +65,7 @@ function ca_goto:evaluation(ai, cfg, self)
if cfg.release_unit_at_goal then
for i_unit=#units,1,-1 do
for rel in H.child_range(self.data, "goto_release_unit") do
if (rel.id == cfg.ca_id .. '_' .. units[i_unit].id) then
if (rel.id == cfg.ai_id .. '_' .. units[i_unit].id) then
table.remove(units, i_unit)
break
end
Expand Down Expand Up @@ -227,12 +227,12 @@ function ca_goto:execution(ai, cfg, self)
-- 2. Keys cannot contain certain characters -> everything potentially user-defined needs to be in values
if unit_at_goal then
if cfg.release_unit_at_goal then
table.insert(self.data, { "goto_release_unit" , { id = cfg.ca_id .. '_' .. best_unit.id } } )
table.insert(self.data, { "goto_release_unit" , { id = cfg.ai_id .. '_' .. best_unit.id } } )
end

if cfg.release_all_units_at_goal then
--print("Releasing all units")
table.insert(self.data, { "goto_release_all", { id = cfg.ca_id } } )
table.insert(self.data, { "goto_release_all", { id = cfg.ai_id } } )
end
end
end
Expand Down
17 changes: 10 additions & 7 deletions data/ai/micro_ais/cas/ca_hang_out.lua
@@ -1,15 +1,16 @@
local H = wesnoth.require "lua/helper.lua"
local AH = wesnoth.require "ai/lua/ai_helper.lua"
local LS = wesnoth.require "lua/location_set.lua"
local MAIUV = wesnoth.dofile "ai/micro_ais/micro_ai_unit_variables.lua"

local ca_hang_out = {}

function ca_hang_out:evaluation(ai, cfg, self)
cfg = cfg or {}

-- Return 0 if the mobilize condition has previously been met
for mobilze in H.child_range(self.data, "hangout_mobilize_units") do
if (mobilze.id == cfg.ca_id) then
for mobilize in H.child_range(self.data, "hangout_mobilize_units") do
if (mobilize.id == cfg.ai_id) then
return 0
end
end
Expand All @@ -18,12 +19,12 @@ function ca_hang_out:evaluation(ai, cfg, self)
if (cfg.mobilize_condition and wesnoth.eval_conditional(cfg.mobilize_condition))
or (cfg.mobilize_on_gold_less_than and (wesnoth.sides[wesnoth.current.side].gold < cfg.mobilize_on_gold_less_than))
then
table.insert(self.data, { "hangout_mobilize_units" , { id = cfg.ca_id } } )
table.insert(self.data, { "hangout_mobilize_units" , { id = cfg.ai_id } } )

-- Need to unmark all units also
local units = wesnoth.get_units { side = wesnoth.current.side, { "and", cfg.filter } }
for i,u in ipairs(units) do
u.variables.mai_hangout_moved = nil
MAIUV.delete_mai_unit_variables(u, cfg.ai_id)
end

return 0
Expand Down Expand Up @@ -85,7 +86,7 @@ function ca_hang_out:execution(ai, cfg, self)
local best_hex, best_unit, max_rating = {}, {}, -9e99
for i,u in ipairs(units) do
-- Only consider units that have not been marked yet
if (not u.variables.mai_hangout_moved) then
if (not MAIUV.get_mai_unit_variables(u, cfg.ai_id, "moved")) then
local best_hex_unit, max_rating_unit = {}, -9e99

-- Check out all unoccupied hexes the unit can reach
Expand Down Expand Up @@ -128,12 +129,14 @@ function ca_hang_out:execution(ai, cfg, self)
for i,u in ipairs(units) do
AH.checked_stopunit_moves(ai, u)
-- Also remove the markers
if u and u.valid then u.variables.mai_hangout_moved = nil end
if u and u.valid then MAIUV.delete_mai_unit_variables(u, cfg.ai_id) end
end
else
-- Otherwise move unit and mark as having been used
AH.checked_move(ai, best_unit, best_hex[1], best_hex[2])
if best_unit and best_unit.valid then best_unit.variables.mai_hangout_moved = true end
if best_unit and best_unit.valid then
MAIUV.set_mai_unit_variables(best_unit, cfg.ai_id, { moved = true })
end
end
end

Expand Down
47 changes: 28 additions & 19 deletions data/ai/micro_ais/cas/ca_hunter.lua
@@ -1,6 +1,7 @@
local H = wesnoth.require "lua/helper.lua"
local W = H.set_wml_action_metatable {}
local AH = wesnoth.require "ai/lua/ai_helper.lua"
local MAIUV = wesnoth.dofile "ai/micro_ais/micro_ai_unit_variables.lua"

local ca_hunter = {}

Expand Down Expand Up @@ -64,17 +65,19 @@ function ca_hunter:execution(ai, cfg)
)[1]

-- If hunting_status is not set for the unit -> default behavior -> hunting
if (not unit.variables.hunting_status) then
local hunter_vars = MAIUV.get_mai_unit_variables(unit, cfg.ai_id)
if (not hunter_vars.hunting_status) then
-- Unit gets a new goal if none exist or on any move with 10% random chance
local r = math.random(10)
if (not unit.variables.goal_x) or (r <= 1) then
if (not hunter_vars.goal_x) or (r <= 1) then
-- 'locs' includes border hexes, but that does not matter here
locs = AH.get_passable_locations((cfg.filter_location or {}), unit)
local rand = math.random(#locs)
--print('#locs', #locs, rand)
unit.variables.goal_x, unit.variables.goal_y = locs[rand][1], locs[rand][2]
hunter_vars.goal_x, hunter_vars.goal_y = locs[rand][1], locs[rand][2]
MAIUV.set_mai_unit_variables(unit, cfg.ai_id, hunter_vars)
end
--print('Hunter goto: ', unit.variables.goal_x, unit.variables.goal_y, r)
--print('Hunter goto: ', hunter_vars.goal_x, hunter_vars.goal_y, r)

-- Hexes the unit can reach
local reach_map = AH.get_reachable_unocc(unit)
Expand All @@ -83,7 +86,7 @@ function ca_hunter:execution(ai, cfg)
local max_rating, best_hex = -9e99, {}
reach_map:iter( function(x, y, v)
-- Distance from goal is first rating
local rating = - H.distance_between(x, y, unit.variables.goal_x, unit.variables.goal_y)
local rating = - H.distance_between(x, y, hunter_vars.goal_x, hunter_vars.goal_y)

-- Proximity to an enemy unit is a plus
local enemy_hp = 500
Expand All @@ -109,21 +112,24 @@ function ca_hunter:execution(ai, cfg)
else -- If hunter did not move, we need to stop it (also delete the goal)
AH.checked_stopunit_moves(ai, unit)
if (not unit) or (not unit.valid) then return end
unit.variables.goal_x, unit.variables.goal_y = nil, nil
hunter_vars.goal_x, hunter_vars.goal_y = nil, nil
MAIUV.set_mai_unit_variables(unit, cfg.ai_id, hunter_vars)
end

-- Or if this gets the unit to the goal, we also delete the goal
if (unit.x == unit.variables.goal_x) and (unit.y == unit.variables.goal_y) then
unit.variables.goal_x, unit.variables.goal_y = nil, nil
if (unit.x == hunter_vars.goal_x) and (unit.y == hunter_vars.goal_y) then
hunter_vars.goal_x, hunter_vars.goal_y = nil, nil
MAIUV.set_mai_unit_variables(unit, cfg.ai_id, hunter_vars)
end

-- Finally, if the unit ended up next to enemies, attack the weakest of those
local attack_status = hunter_attack_weakest_adj_enemy(ai, unit)

-- If the enemy was killed, hunter returns home
if unit.valid and (attack_status == 'killed') then
unit.variables.goal_x, unit.variables.goal_y = nil, nil
unit.variables.hunting_status = 'return'
hunter_vars.goal_x, hunter_vars.goal_y = nil, nil
hunter_vars.hunting_status = 'return'
MAIUV.set_mai_unit_variables(unit, cfg.ai_id, hunter_vars)
if cfg.show_messages then
W.message { speaker = unit.id, message = 'Now that I have eaten, I will go back home.' }
end
Expand All @@ -134,7 +140,7 @@ function ca_hunter:execution(ai, cfg)
end

-- If we got here, this means the unit is either returning, or resting
if (unit.variables.hunting_status == 'return') then
if (hunter_vars.hunting_status == 'return') then
goto_x, goto_y = wesnoth.find_vacant_tile(cfg.home_x, cfg.home_y)
--print('Go home:', home_x, home_y, goto_x, goto_y)

Expand Down Expand Up @@ -163,10 +169,11 @@ function ca_hunter:execution(ai, cfg)

-- If the unit got home, start the resting counter
if (unit.x == cfg.home_x) and (unit.y == cfg.home_y) then
unit.variables.hunting_status = 'resting'
unit.variables.resting_until = wesnoth.current.turn + (cfg.rest_turns or 3)
hunter_vars.hunting_status = 'resting'
hunter_vars.resting_until = wesnoth.current.turn + (cfg.rest_turns or 3)
MAIUV.set_mai_unit_variables(unit, cfg.ai_id, hunter_vars)
if cfg.show_messages then
W.message { speaker = unit.id, message = 'I made it home - resting now until the end of Turn ' .. unit.variables.resting_until .. ' or until fully healed.' }
W.message { speaker = unit.id, message = 'I made it home - resting now until the end of Turn ' .. hunter_vars.resting_until .. ' or until fully healed.' }
end
end

Expand All @@ -175,7 +182,7 @@ function ca_hunter:execution(ai, cfg)
end

-- If we got here, the only remaining action is resting
if (unit.variables.hunting_status == 'resting') then
if (hunter_vars.hunting_status == 'resting') then
-- So all we need to do is take moves away from the unit
AH.checked_stopunit_moves(ai, unit)
if (not unit) or (not unit.valid) then return end
Expand All @@ -185,9 +192,10 @@ function ca_hunter:execution(ai, cfg)
if (not unit) or (not unit.valid) then return end

-- If this is the last turn of resting, we also remove the status and turn variable
if (unit.hitpoints >= unit.max_hitpoints) and (unit.variables.resting_until <= wesnoth.current.turn) then
unit.variables.hunting_status = nil
unit.variables.resting_until = nil
if (unit.hitpoints >= unit.max_hitpoints) and (hunter_vars.resting_until <= wesnoth.current.turn) then
hunter_vars.hunting_status = nil
hunter_vars.resting_until = nil
MAIUV.set_mai_unit_variables(unit, cfg.ai_id, hunter_vars)
if cfg.show_messages then
W.message { speaker = unit.id, message = 'I am done resting. It is time to go hunting again next turn.' }
end
Expand All @@ -196,7 +204,8 @@ function ca_hunter:execution(ai, cfg)
end

-- In principle we should never get here, but just in case: reset variable, so that unit goes hunting on next turn
unit.variables.hunting_status = nil
hunter_vars.hunting_status = nil
MAIUV.set_mai_unit_variables(unit, cfg.ai_id, hunter_vars)
end

return ca_hunter
4 changes: 3 additions & 1 deletion data/ai/micro_ais/cas/ca_messenger_escort_move.lua
@@ -1,6 +1,7 @@
local H = wesnoth.require "lua/helper.lua"
local AH = wesnoth.require "ai/lua/ai_helper.lua"
local LS = wesnoth.require "lua/location_set.lua"
local MAIUV = wesnoth.dofile "ai/micro_ais/micro_ai_unit_variables.lua"

local ca_messenger_escort_move = {}

Expand Down Expand Up @@ -58,7 +59,8 @@ function ca_messenger_escort_move:execution(ai, cfg)
local max_messenger_rating = -9e99
for _,m in ipairs(messengers) do
local messenger_rating = 1. / (H.distance_between(x, y, m.x, m.y) + 2.)
messenger_rating = messenger_rating * 10. * (1. + m.variables.wp_rating * 2.)
local wp_rating = MAIUV.get_mai_unit_variables(m, cfg.ai_id, "wp_rating")
messenger_rating = messenger_rating * 10. * (1. + wp_rating * 2.)

if (messenger_rating > max_messenger_rating) then
max_messenger_rating = messenger_rating
Expand Down
7 changes: 3 additions & 4 deletions data/ai/micro_ais/cas/ca_messenger_f_next_waypoint.lua
@@ -1,5 +1,6 @@
local H = wesnoth.require "lua/helper.lua"
local AH = wesnoth.require "ai/lua/ai_helper.lua"
local MAIUV = wesnoth.dofile "ai/micro_ais/micro_ai_unit_variables.lua"

return function(cfg)
-- Calculate next waypoint and rating for all messengers
Expand All @@ -26,16 +27,14 @@ return function(cfg)
for i, m in ipairs(messengers) do
-- To avoid code duplication and ensure consistency, we store some pieces of
-- information in the messenger units, even though it could be calculated each time it is needed
local wp_i = m.variables.wp_i or 1
local wp_i = MAIUV.get_mai_unit_variables(m, cfg.ai_id, "wp_i") or 1
local wp_x, wp_y = waypoint_x[wp_i], waypoint_y[wp_i]

-- If this messenger is within 3 hexes of the next waypoint, we go on to the one after that
-- except if that one's the last one already
local dist_wp = H.distance_between(m.x, m.y, wp_x, wp_y)
if (dist_wp <= 3) and (wp_i < #waypoint_x) then wp_i = wp_i + 1 end

m.variables.wp_i, m.variables.wp_x, m.variables.wp_y = wp_i, wp_x, wp_y

-- Also store the rating for each messenger
-- For now, this is simply a "forward rating"
local rating = wp_i - dist_wp / 1000.
Expand All @@ -47,7 +46,7 @@ return function(cfg)
rating = #waypoint_x - rating
end

m.variables.wp_rating = rating
MAIUV.set_mai_unit_variables(m, cfg.ai_id, { wp_i = wp_i, wp_x = wp_x, wp_y = wp_y, wp_rating = rating })

-- Find the messenger with the highest rating that has MP left
if (m.moves > 0) and (rating > max_rating) then
Expand Down

0 comments on commit 116c6a6

Please sign in to comment.