Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
MicroAIs: Refactor code to make it easy for add-ons to add new ones
- Loading branch information
1 parent
6ed3406
commit c19ddba
Showing
12 changed files
with
585 additions
and
511 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
local H = wesnoth.require "lua/helper.lua" | ||
local MAIH = wesnoth.require("ai/micro_ais/micro_ai_helper.lua") | ||
|
||
function wesnoth.micro_ais.big_animals(cfg) | ||
local required_keys = { "filter"} | ||
local optional_keys = { "avoid_unit", "filter_location", "filter_location_wander" } | ||
local CA_parms = { | ||
ai_id = 'mai_big_animals', | ||
{ ca_id = "move", location = 'ca_big_animals.lua', score = cfg.ca_score or 300000 } | ||
} | ||
return required_keys, optional_keys, CA_parms | ||
end | ||
|
||
function wesnoth.micro_ais.wolves(cfg) | ||
local required_keys = { "filter", "filter_second" } | ||
local optional_keys = { "attack_only_prey", "avoid_type" } | ||
local score = cfg.ca_score or 90000 | ||
local CA_parms = { | ||
ai_id = 'mai_wolves', | ||
{ ca_id = "move", location = 'ca_wolves_move.lua', score = score }, | ||
{ ca_id = "wander", location = 'ca_wolves_wander.lua', score = score - 1 } | ||
} | ||
|
||
if cfg.attack_only_prey then | ||
local wolves_aspects = { | ||
{ | ||
aspect = "attacks", | ||
facet = { | ||
name = "ai_default_rca::aspect_attacks", | ||
id = "dont_attack", | ||
invalidate_on_gamestate_change = "yes", | ||
{ "filter_enemy", { | ||
{ "and", H.get_child(cfg, "filter_second") } | ||
} } | ||
} | ||
} | ||
} | ||
if (cfg.action == "delete") then | ||
MAIH.delete_aspects(cfg.side, wolves_aspects) | ||
else | ||
MAIH.add_aspects(cfg.side, wolves_aspects) | ||
end | ||
elseif cfg.avoid_type then | ||
local wolves_aspects = { | ||
{ | ||
aspect = "attacks", | ||
facet = { | ||
name = "ai_default_rca::aspect_attacks", | ||
id = "dont_attack", | ||
invalidate_on_gamestate_change = "yes", | ||
{ "filter_enemy", { | ||
{ "not", { | ||
type=cfg.avoid_type | ||
} } | ||
} } | ||
} | ||
} | ||
} | ||
if (cfg.action == "delete") then | ||
MAIH.delete_aspects(cfg.side, wolves_aspects) | ||
else | ||
MAIH.add_aspects(cfg.side, wolves_aspects) | ||
end | ||
end | ||
return required_keys, optional_keys, CA_parms | ||
end | ||
|
||
function wesnoth.micro_ais.herding(cfg) | ||
local required_keys = { "filter_location", "filter", "filter_second", "herd_x", "herd_y" } | ||
local optional_keys = { "attention_distance", "attack_distance" } | ||
local score = cfg.ca_score or 300000 | ||
local CA_parms = { | ||
ai_id = 'mai_herding', | ||
{ ca_id = "attack_close_enemy", location = 'ca_herding_attack_close_enemy.lua', score = score }, | ||
{ ca_id = "sheep_runs_enemy", location = 'ca_herding_sheep_runs_enemy.lua', score = score - 1 }, | ||
{ ca_id = "sheep_runs_dog", location = 'ca_herding_sheep_runs_dog.lua', score = score - 2 }, | ||
{ ca_id = "herd_sheep", location = 'ca_herding_herd_sheep.lua', score = score - 3 }, | ||
{ ca_id = "sheep_move", location = 'ca_herding_sheep_move.lua', score = score - 4 }, | ||
{ ca_id = "dog_move", location = 'ca_herding_dog_move.lua', score = score - 5 }, | ||
{ ca_id = "dog_stopmove", location = 'ca_herding_dog_stopmove.lua', score = score - 6 } | ||
} | ||
return required_keys, optional_keys, CA_parms | ||
end | ||
|
||
function wesnoth.micro_ais.forest_animals(cfg) | ||
local optional_keys = { "rabbit_type", "rabbit_number", "rabbit_enemy_distance", "rabbit_hole_img", | ||
"tusker_type", "tusklet_type", "deer_type", "filter_location" | ||
} | ||
local score = cfg.ca_score or 300000 | ||
local CA_parms = { | ||
ai_id = 'mai_forest_animals', | ||
{ ca_id = "new_rabbit", location = 'ca_forest_animals_new_rabbit.lua', score = score }, | ||
{ ca_id = "tusker_attack", location = 'ca_forest_animals_tusker_attack.lua', score = score - 1 }, | ||
{ ca_id = "move", location = 'ca_forest_animals_move.lua', score = score - 2 }, | ||
{ ca_id = "tusklet_move", location = 'ca_forest_animals_tusklet_move.lua', score = score - 3 } | ||
} | ||
return {}, optional_keys, CA_parms | ||
end | ||
|
||
function wesnoth.micro_ais.swarm(cfg) | ||
local optional_keys = { "scatter_distance", "vision_distance", "enemy_distance" } | ||
local score = cfg.ca_score or 300000 | ||
local CA_parms = { | ||
ai_id = 'mai_swarm', | ||
{ ca_id = "scatter", location = 'ca_swarm_scatter.lua', score = score }, | ||
{ ca_id = "move", location = 'ca_swarm_move.lua', score = score - 1 } | ||
} | ||
return {}, optional_keys, CA_parms | ||
end | ||
|
||
function wesnoth.micro_ais.wolves_multipacks(cfg) | ||
local optional_keys = { "type", "pack_size", "show_pack_number" } | ||
local score = cfg.ca_score or 300000 | ||
local CA_parms = { | ||
ai_id = 'mai_wolves_multipacks', | ||
{ ca_id = "attack", location = 'ca_wolves_multipacks_attack.lua', score = score }, | ||
{ ca_id = "wander", location = 'ca_wolves_multipacks_wander.lua', score = score - 1 } | ||
} | ||
return {}, optional_keys, CA_parms | ||
end | ||
|
||
function wesnoth.micro_ais.hunter(cfg) | ||
if (cfg.action ~= 'delete') and (not cfg.id) and (not H.get_child(cfg, "filter")) then | ||
H.wml_error("Hunter [micro_ai] tag requires either id= key or [filter] tag") | ||
end | ||
local required_keys = { "home_x", "home_y" } | ||
local optional_keys = { "id", "filter", "filter_location", "rest_turns", "show_messages" } | ||
local CA_parms = { | ||
ai_id = 'mai_hunter', | ||
{ ca_id = "move", location = 'ca_hunter.lua', score = cfg.ca_score or 300000 } | ||
} | ||
return required_keys, optional_keys, CA_parms | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
|
||
function wesnoth.micro_ais.bottleneck_defense(cfg) | ||
local required_keys = { "x", "y", "enemy_x", "enemy_y" } | ||
local optional_keys = { "healer_x", "healer_y", "leadership_x", "leadership_y", "active_side_leader" } | ||
local score = cfg.ca_score or 300000 | ||
local CA_parms = { | ||
ai_id = 'mai_bottleneck', | ||
{ ca_id = 'move', location = 'ca_bottleneck_move.lua', score = score }, | ||
{ ca_id = 'attack', location = 'ca_bottleneck_attack.lua', score = score - 1 } | ||
} | ||
return required_keys, optional_keys, CA_parms | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
local H = wesnoth.require "lua/helper.lua" | ||
|
||
function wesnoth.micro_ais.messenger_escort(cfg) | ||
if (cfg.action ~= 'delete') and (not cfg.id) and (not H.get_child(cfg, "filter")) then | ||
H.wml_error("Messenger [micro_ai] tag requires either id= key or [filter] tag") | ||
end | ||
local required_keys = { "waypoint_x", "waypoint_y" } | ||
local optional_keys = { "id", "enemy_death_chance", "filter", "filter_second", "invert_order", "messenger_death_chance" } | ||
local score = cfg.ca_score or 300000 | ||
local CA_parms = { | ||
ai_id = 'mai_messenger', | ||
{ ca_id = 'attack', location = 'ca_messenger_attack.lua', score = score }, | ||
{ ca_id = 'move', location = 'ca_messenger_move.lua', score = score - 1 }, | ||
{ ca_id = 'escort_move', location = 'ca_messenger_escort_move.lua', score = score - 2 } | ||
} | ||
return required_keys, optional_keys, CA_parms | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
local H = wesnoth.require "lua/helper.lua" | ||
local W = H.set_wml_action_metatable {} | ||
|
||
function wesnoth.micro_ais.fast_ai(cfg) | ||
local optional_keys = { | ||
"attack_hidden_enemies", "avoid", "dungeon_mode", | ||
"filter", "filter_second", "include_occupied_attack_hexes", | ||
"leader_additional_threat", "leader_attack_max_units", "leader_weight", "move_cost_factor", | ||
"weak_units_first", "skip_combat_ca", "skip_move_ca", "threatened_leader_fights" | ||
} | ||
local CA_parms = { | ||
ai_id = 'mai_fast', | ||
{ ca_id = 'combat', location = 'ca_fast_combat.lua', score = 100000 }, | ||
{ ca_id = 'move', location = 'ca_fast_move.lua', score = 20000 }, | ||
{ ca_id = 'combat_leader', location = 'ca_fast_combat_leader.lua', score = 19900 } | ||
} | ||
|
||
-- Also need to delete/add some default CAs | ||
if (cfg.action == 'delete') then | ||
-- This can be done independently of whether these were removed earlier | ||
W.modify_ai { | ||
side = cfg.side, | ||
action = "add", | ||
path = "stage[main_loop].candidate_action", | ||
{ "candidate_action", { | ||
id="combat", | ||
engine="cpp", | ||
name="ai_default_rca::combat_phase", | ||
max_score=100000, | ||
score=100000 | ||
} } | ||
} | ||
|
||
W.modify_ai { | ||
side = cfg.side, | ||
action = "add", | ||
path = "stage[main_loop].candidate_action", | ||
{ "candidate_action", { | ||
id="villages", | ||
engine="cpp", | ||
name="ai_default_rca::get_villages_phase", | ||
max_score=60000, | ||
score=60000 | ||
} } | ||
} | ||
|
||
W.modify_ai { | ||
side = cfg.side, | ||
action = "add", | ||
path = "stage[main_loop].candidate_action", | ||
{ "candidate_action", { | ||
id="retreat", | ||
engine="cpp", | ||
name="ai_default_rca::retreat_phase", | ||
max_score=40000, | ||
score=40000 | ||
} } | ||
} | ||
|
||
W.modify_ai { | ||
side = cfg.side, | ||
action = "add", | ||
path = "stage[main_loop].candidate_action", | ||
{ "candidate_action", { | ||
id="move_to_targets", | ||
engine="cpp", | ||
name="ai_default_rca::move_to_targets_phase", | ||
max_score=20000, | ||
score=20000 | ||
} } | ||
} | ||
else | ||
if (not cfg.skip_combat_ca) then | ||
W.modify_ai { | ||
side = cfg.side, | ||
action = "try_delete", | ||
path = "stage[main_loop].candidate_action[combat]" | ||
} | ||
else | ||
for i,parm in ipairs(CA_parms) do | ||
if (parm.ca_id == 'combat') or (parm.ca_id == 'combat_leader') then | ||
table.remove(CA_parms, i) | ||
end | ||
end | ||
end | ||
|
||
if (not cfg.skip_move_ca) then | ||
W.modify_ai { | ||
side = cfg.side, | ||
action = "try_delete", | ||
path = "stage[main_loop].candidate_action[villages]" | ||
} | ||
|
||
W.modify_ai { | ||
side = cfg.side, | ||
action = "try_delete", | ||
path = "stage[main_loop].candidate_action[retreat]" | ||
} | ||
|
||
W.modify_ai { | ||
side = cfg.side, | ||
action = "try_delete", | ||
path = "stage[main_loop].candidate_action[move_to_targets]" | ||
} | ||
else | ||
for i,parm in ipairs(CA_parms) do | ||
if (parm.ca_id == 'move') then | ||
table.remove(CA_parms, i) | ||
break | ||
end | ||
end | ||
end | ||
end | ||
return {}, optional_keys, CA_parms | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
local H = wesnoth.require "lua/helper.lua" | ||
|
||
function wesnoth.micro_ais.stationed_guardian(cfg) | ||
if (cfg.action ~= 'delete') and (not cfg.id) and (not H.get_child(cfg, "filter")) then | ||
H.wml_error("Stationed Guardian [micro_ai] tag requires either id= key or [filter] tag") | ||
end | ||
local required_keys = { "distance", "station_x", "station_y" } | ||
local optional_keys = { "id", "filter", "guard_x", "guard_y" } | ||
local CA_parms = { | ||
ai_id = 'mai_stationed_guardian', | ||
{ ca_id = 'move', location = 'ca_stationed_guardian.lua', score = cfg.ca_score or 300000 } | ||
} | ||
return required_keys, optional_keys, CA_parms | ||
end | ||
|
||
function wesnoth.micro_ais.zone_guardian(cfg) | ||
if (cfg.action ~= 'delete') and (not cfg.id) and (not H.get_child(cfg, "filter")) then | ||
H.wml_error("Zone Guardian [micro_ai] tag requires either id= key or [filter] tag") | ||
end | ||
local required_keys = { "filter_location" } | ||
local optional_keys = { "id", "filter", "filter_location_enemy", "station_x", "station_y" } | ||
local CA_parms = { | ||
ai_id = 'mai_zone_guardian', | ||
{ ca_id = 'move', location = 'ca_zone_guardian.lua', score = cfg.ca_score or 300000 } | ||
} | ||
return required_keys, optional_keys, CA_parms | ||
end | ||
|
||
function wesnoth.micro_ais.return_guardian(cfg) | ||
if (cfg.action ~= 'delete') and (not cfg.id) and (not H.get_child(cfg, "filter")) then | ||
H.wml_error("Return Guardian [micro_ai] tag requires either id= key or [filter] tag") | ||
end | ||
local required_keys = { "return_x", "return_y" } | ||
local optional_keys = { "id", "filter" } | ||
local CA_parms = { | ||
ai_id = 'mai_return_guardian', | ||
{ ca_id = 'move', location = 'ca_return_guardian.lua', score = cfg.ca_score or 100010 } | ||
} | ||
return required_keys, optional_keys, CA_parms | ||
end | ||
|
||
function wesnoth.micro_ais.coward(cfg) | ||
if (cfg.action ~= 'delete') and (not cfg.id) and (not H.get_child(cfg, "filter")) then | ||
H.wml_error("Coward [micro_ai] tag requires either id= key or [filter] tag") | ||
end | ||
local required_keys = { "distance" } | ||
local optional_keys = { "attack_if_trapped", "id", "filter", "filter_second", "seek_x", "seek_y","avoid_x","avoid_y" } | ||
local CA_parms = { | ||
ai_id = 'mai_coward', | ||
{ ca_id = 'move', location = 'ca_coward.lua', score = cfg.ca_score or 300000 } | ||
} | ||
return required_keys, optional_keys, CA_parms | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
|
||
function wesnoth.micro_ais.healer_support(cfg) | ||
local optional_keys = { "aggression", "injured_units_only", "max_threats", "filter", "filter_second" } | ||
-- Scores for this AI need to be hard-coded, it does not work otherwise | ||
local CA_parms = { | ||
ai_id = 'mai_healer', | ||
{ ca_id = 'initialize', location = 'ca_healer_initialize.lua', score = 999990 }, | ||
{ ca_id = 'move', location = 'ca_healer_move.lua', score = 105000 }, | ||
} | ||
|
||
-- The healers_can_attack CA is only added to the table if aggression ~= 0 | ||
-- But: make sure we always try removal | ||
if (cfg.action == 'delete') or (tonumber(cfg.aggression) ~= 0) then | ||
table.insert(CA_parms, { ca_id = 'may_attack', location = 'ca_healer_may_attack.lua', score = 99990 }) | ||
end | ||
return {}, optional_keys, CA_parms | ||
end |
Oops, something went wrong.