Skip to content

Commit

Permalink
Started total_defense scenario and micro_ai.
Browse files Browse the repository at this point in the history
  • Loading branch information
jleldridge committed May 22, 2013
1 parent d5d0b92 commit bb47840
Show file tree
Hide file tree
Showing 8 changed files with 358 additions and 15 deletions.
6 changes: 0 additions & 6 deletions data/ai/micro_ais/ais/mai_healer_support_engine.lua
Expand Up @@ -219,12 +219,6 @@ return {
end

function healer_support:healer_support_exec()
-- Only show this message in the healer_support scenario in AI-Demos
local scenario = wesnoth.get_variable("scenario_name")
if (scenario == 'healer_support') then
W.message { speaker = self.data.HS_unit.id, message = 'Moving in to back injured and/or threatened units' }
end

AH.movefull_outofway_stopunit(ai, self.data.HS_unit, self.data.HS_hex)
self.data.HS_unit, self.data.HS_hex = nil, nil
end
Expand Down
166 changes: 166 additions & 0 deletions data/ai/micro_ais/ais/mai_total_defense_demo_engine.lua
@@ -0,0 +1,166 @@
return{
init = function(ai)

local total_defense = {}

local H = wesnoth.require "lua/helper.lua"
local W = H.set_wml_action_metatable {}
local LS = wesnoth.require "lua/location_set.lua"
local AH = wesnoth.require "ai/lua/ai_helper.lua"
local BC = wesnoth.require "ai/lua/battle_calcs.lua"
local DBG = wesnoth.require "~/add-ons/Wesnoth_Lua_Pack/debug_utils.lua"

----------------------------------------------------
---------------Total Defense CAs--------------------
----------------------------------------------------

--------Initialize Total Defense at beginning of turn----------

function total_defense:initialize_total_defense_eval()
local score = 999990
return score
end --of initialize_total_defense_eval

function total_defense:initialize_total_defense_exec()
--modify aspects and whatnot here
end --of initialize_total_defense_exec

function total_defense:defend_area_eval(cfg)
cfg = cfg or {}

local all_units = wesnoth.get_units{ side = wesnoth.current.side }
--DBG.dbms(all_units)

local units_with_mp = wesnoth.get_units{ side = wesnoth.current.side,
formula = '$this_unit.moves > 0' }

--in this simplified example defenders will be units without healing
local defenders = {}
for i,u in ipairs(all_units) do
if (u.hitpoints/u.max_hitpoints > 0.5) then
if (not wesnoth.match_unit(u, {ability="healing"})) and (not wesnoth.match_unit(u, {canrecruit="yes"})) then
table.insert(defenders, u)
end
end
end

--in this simplified example vulnerable_units will be units with healing or less than 50% hp
local vulnerable_units = wesnoth.get_units{ side = wesnoth.current.side,
ability = "healing" }

for i,u in ipairs(all_units) do
if (u.hitpoints/u.max_hitpoints <= 0.5) then
table.insert(vulnerable_units, u)
end
end

--temporary tables to hold the space to be defended
local outer_radius_table = {}
local inner_space_table = {}
for i=0, cfg.radius, 1 do
for j=0, cfg.radius, 1 do
local temp_point_1 = {}
local temp_point_2 = {}
local temp_point_3 = {}
local temp_point_4 = {}
temp_point_1.x = cfg.defend_x + i
temp_point_1.y = cfg.defend_y + j

temp_point_2.x = cfg.defend_x - i
temp_point_2.y = cfg.defend_y - j

temp_point_3.x = cfg.defend_x + i
temp_point_3.y = cfg.defend_y - j

temp_point_4.x = cfg.defend_x - i
temp_point_4.y = cfg.defend_y + j
if (i == cfg.radius) or (j == cfg.radius) then
table.insert(outer_radius_table, temp_point_1)
table.insert(outer_radius_table, temp_point_2)
table.insert(outer_radius_table, temp_point_3)
table.insert(outer_radius_table, temp_point_4)
else
table.insert(inner_space_table, temp_point_1)
table.insert(inner_space_table, temp_point_2)
table.insert(inner_space_table, temp_point_3)
table.insert(inner_space_table, temp_point_4)
end
end
end
local outer_radius_map = LS.of_pairs(outer_radius_table)
local inner_space_map = LS.of_pairs(inner_space_table)

local enemies = wesnoth.get_units {
{ "filter_side", {{"enemy_of", {side = wesnoth.current.side} }} }
}
local enemy_attack_map = BC.get_attack_map(enemies)

--if no units can move then exit this ai
if (not units_with_mp[1]) then
return 0
end

local best_hex
local best_unit

--move vulnerable units into inner space of defended area
for i,u in ipairs(vulnerable_units) do
for j,r in ipairs(wesnoth.find_reach(u)) do
if (u.moves > 0) and (not wesnoth.get_unit(r[1], r[2])) and (inner_space_map:get(r[1], r[2])) then
best_hex = {r[1], r[2]}
best_unit = u
end
end
end

--move defenders into outer radius of defended area once vulnerable units are out of the way
if (not best_hex) or (not best_unit) then
for i,u in ipairs(defenders) do
for j,r in ipairs(wesnoth.find_reach(u)) do
if (u.moves > 0) and (not wesnoth.get_unit(r[1], r[2])) and (outer_radius_map:get(r[1], r[2])) then
best_hex = {r[1], r[2]}
best_unit = u
--if the enemy can attack the prospective hex it really needs a unit there to defend
if (enemy_attack_map.units:get(r[1], r[2])) then
break
end
end
end
end
end

--if outer radius is not complete, don't move units to other places
local radius_complete = true
for i,r in ipairs(outer_radius_map) do
if (not wesnoth.get_unit(r[1], r[2])) then
radius_complete = false
end
end

if (not radius_complete) then
W.modify_ai {
side = cfg.side,
action = "try_delete",
path = "stage[main_loop].candidate_action[goto]"
}
end

if (not best_hex) or (not best_unit) then
return 0
end

self.data.unit_to_move = best_unit
self.data.target_hex = best_hex

return 999989
end --of defend_area_eval

function total_defense:defend_area_exec()
AH.movefull_outofway_stopunit(ai, self.data.unit_to_move, self.data.target_hex)
self.data.unit_to_move = nil
self.data.target_hex = nil
end --of defend_area_exec

return total_defense
end --of init
}
30 changes: 30 additions & 0 deletions data/ai/micro_ais/ais/micro_ais_wml_tags.lua
Expand Up @@ -139,6 +139,7 @@ function CA_action(action, side, CA_parms)
end

function wesnoth.wml_actions.micro_ai(cfg)

-- Set up the [micro_ai] tag functionality for each Micro AI

-- Check that the required common keys are all present and set correctly
Expand All @@ -149,6 +150,35 @@ function wesnoth.wml_actions.micro_ai(cfg)
if (cfg.action ~= 'add') and (cfg.action ~= 'delete') and (cfg.action ~= 'change') then
H.wml_error("[micro_ai] invalid value for action=. Allowed values: add, delete or change")
end

---------Total Defense Micro AI -------------------------------------------
if (cfg.ai_type == 'total_defense') then
local cfg_hs = {}
if (cfg.action ~= 'delete') then
cfg = cfg.__parsed
--the center point to be defended
cfg_hs.defend_x = cfg.defend_x
cfg_hs.defend_y = cfg.defend_y
--the radius of the area to be defended
cfg_hs.radius = cfg.radius
end

local CA_parms = {
{
id = 'initialize_total_defense', eval_name = 'initialize_total_defense_eval',
exec_name = 'initialize_total_defense_exec', max_score = 999990,
cfg_table = {}
},
{
id = 'defend_area', eval_name = 'defend_area_eval', exec_name = 'defend_area_exec',
max_score = 999989, cfg_table = cfg_hs
}
}

--add, delete, or change the CAs
CA_action(cfg.action, cfg.side, CA_parms)
return
end

--------- Healer Support Micro AI - side-wide AI ------------------------------------
if (cfg.ai_type == 'healer_support') then
Expand Down
25 changes: 16 additions & 9 deletions data/ai/micro_ais/scenarios/healer_support.cfg
Expand Up @@ -74,18 +74,25 @@

aggression=0 # wmllint: ignore
[/micro_ai]

[modify_side]
side = 1
[ai]
[goal]
name=protect_location
[criteria]
x,y=18,9
[/criteria]
protect_radius=5
value=20
[/goal]
[/ai]
[/modify_side]
[/event]

[event]
name=start

# wmllint: unbalanced-on
{MESSAGE Rebels1 "" "" _"In this scenario, we demonstrate the use of the Healer Support Micro AI. This AI configures the healers of a side to stay behind the battle lines and heal injured and/or threatened units rather than participate in the attacks under all circumstances. It includes several configurable options (which are set differently for the two sides in this scenario) that determine how aggressive/careful the healers are, whether they also attack, how much risk they are willing to take, etc.
For clarity, each healer announces her upcoming support move. If you don't want to see that each time, just hit 'esc' when it happens the first time.
Note: The Healer Support AI is coded as a Micro AI. A Micro AI can be added and adapted to the need of a scenario easily using only WML and the [micro_ai] tag. Check out the <span color='#00A000'>Micro AI wiki page</span> at http://wiki.wesnoth.org/Micro_AIs for more information."}
# wmllint: unbalanced-off
name=turn 4
{MODIFY_AI_DELETE_CANDIDATE_ACTION 1 main_loop recruitment}
[/event]

# Stop if the leader of one side died
Expand Down
22 changes: 22 additions & 0 deletions data/ai/micro_ais/scenarios/scenario-micro_ai.cfg
Expand Up @@ -39,6 +39,10 @@
# The labels and signposts to go on to the next scenario
[event]
name=prestart

#My Scenario
{PLACE_IMAGE "scenery/signpost.png" 5 15}
{SET_LABEL 5 15 _"Total Defense"}

{PLACE_IMAGE "scenery/signpost.png" 9 13}
{SET_LABEL 9 13 _"Animals"}
Expand Down Expand Up @@ -317,6 +321,24 @@ Information about each demonstration can be accessed by right-clicking on the re
[/event]

# Events for going on to next scenarios, when Grnk goes to a signpost
#My Scenario
[event]
name=moveto
[filter]
x,y=5,15
[/filter]

[endlevel]
result = victory
next_scenario=total_defense
bonus=no
carryover_percentage=0
carryover_report=no
linger_mode=no
replay_save=no
[/endlevel]
[/event]

[event]
name=moveto
[filter]
Expand Down

0 comments on commit bb47840

Please sign in to comment.