mirror of
https://github.com/wesnoth/wesnoth
synced 2025-04-24 14:52:58 +00:00
AI: Convert the FormulaAI example scenario to do all the same things using Lua
- Unit formulas are replaced by inline MicroAIs or candidate actions placed in the unit's [ai] tag. - The stationed_guardian MicroAI was chosen as the closest match to the guardian FormulaAI. It's not a perfect fit, but it's pretty close. - The goto and patrol MicroAIs are fairly obvious substitutes for the respective unit formulas. - The priority test in unit formulas is replaced by fairly basic inline non-external CAs with differing scores. - The side formulas (opening.fai) have been converted to a separate Lua stage using a new opening.lua. However, that's only a partial conversion. The move and attack functionalities of opening.fai are missing from opening.lua; instead the built-in move, move leader to keep, and combat CAs are used. - The scouting FormulaAI CA has been ported to Lua. It remains a very basic AI, probably not well-suited to genera use. - The level up attack FormulaAI CA has been ported to Lua. Like the new scouting CA, this is mostly intended to serve as an example.
This commit is contained in:
parent
98b91c9d0f
commit
2d95c0f7d3
91
data/ai/lua/ca_level_up_attack.lua
Normal file
91
data/ai/lua/ca_level_up_attack.lua
Normal file
@ -0,0 +1,91 @@
|
||||
-- An example CA that tries to level up units by attacking weakened enemies.
|
||||
-- Ported from level_up_attack_eval.fai and level_up_attack_move.fai
|
||||
|
||||
local LS = wesnoth.require "location_set"
|
||||
local F = wesnoth.require "functional"
|
||||
local level_up_attack = {}
|
||||
|
||||
local function kill_xp(unit)
|
||||
local ratio = unit.level
|
||||
if ratio == 0 then ratio = 0.5 end
|
||||
return wesnoth.game_config.kill_experience * ratio
|
||||
end
|
||||
|
||||
local function get_best_defense_loc(moves, attacker, victim)
|
||||
local attack_spots = F.filter(moves, function(v)
|
||||
return wesnoth.map.distance_between(v, victim) == 1
|
||||
end)
|
||||
return F.choose(attack_spots, function(loc)
|
||||
return attacker:defense_on(loc)
|
||||
end)
|
||||
end
|
||||
|
||||
local function iter_possible_targets(moves, attacker)
|
||||
moves = LS.of_pairs(moves)
|
||||
-- The criteria are: a) unit is reachable b) unit's health is low
|
||||
local targets = wesnoth.units.find({
|
||||
|
||||
})
|
||||
return coroutine.wrap(function()
|
||||
local checked = LS.create()
|
||||
moves:iter(function(to_x, to_y)
|
||||
for adj_x, adj_y in wesnoth.current.map:iter_adjacent(to_x, to_y) do
|
||||
if not checked:get(adj_x, adj_y) then
|
||||
checked:insert(adj_x, adj_y)
|
||||
local u = wesnoth.units.get(adj_x, adj_y)
|
||||
if u and u.hitpoints / u.max_hitpoints < 0.2 then
|
||||
coroutine.yield(u)
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
local possible_attacks
|
||||
|
||||
function level_up_attack:evaluation(cfg, data, filter_own)
|
||||
possible_attacks = LS.create()
|
||||
local moves = LS.of_raw(ai.get_src_dst())
|
||||
local units = wesnoth.units.find(filter_own)
|
||||
for _,me in ipairs(units) do
|
||||
local save_x, save_y = me.x, me.y
|
||||
if not moves[me] or #moves[me] == 0 then
|
||||
goto continue
|
||||
end
|
||||
if kill_xp(me) <= (me.max_experience - me.experience) then
|
||||
goto continue
|
||||
end
|
||||
for target in iter_possible_targets(moves[me], me) do
|
||||
local defense_loc = get_best_defense_loc(moves[me], me, target)
|
||||
me:to_map(defense_loc.x, defense_loc.y)
|
||||
local attacker_outcome, defender_outcome = wesnoth.simulate_combat(me, target)
|
||||
-- Only consider attacks where
|
||||
-- a) there's a chance the defender dies and
|
||||
-- b) there's no chance the attacker dies
|
||||
if defender_outcome.hp_chance[0] == 0 or attacker_outcome.hp_chance[0] > 0 then
|
||||
goto continue
|
||||
end
|
||||
-- If killing the defender is the most likely result, save this as a possible attack
|
||||
local best = F.choose_map(defender_outcome.hp_chance, function(k, v) return v end)
|
||||
if best.key == 0 then
|
||||
possible_attacks:insert(defense_loc, {
|
||||
chance = defender_outcome.hp_chance[0],
|
||||
attacker = me, target = target
|
||||
})
|
||||
end
|
||||
end
|
||||
::continue::
|
||||
me:to_map(save_x, save_y)
|
||||
end
|
||||
local _, best_score = F.choose_map(possible_attacks:to_map(), 'chance')
|
||||
return math.max(0, best_score) * 100000
|
||||
end
|
||||
|
||||
function level_up_attack:execution(cfg, data)
|
||||
local best_attack = F.choose_map(possible_attacks:to_map(), 'chance')
|
||||
ai.move(best_attack.value.attacker, best_attack.key)
|
||||
ai.attack(best_attack.value.attacker, best_attack.value.target)
|
||||
end
|
||||
|
||||
return level_up_attack
|
61
data/ai/lua/ca_simple_scouting.lua
Normal file
61
data/ai/lua/ca_simple_scouting.lua
Normal file
@ -0,0 +1,61 @@
|
||||
-- An example CA that tries to uncover shrouded areas of the map
|
||||
-- This is a very simple and naive scouting algorithm.
|
||||
-- It often does stupid things like sending one unit to a village on one turn,
|
||||
-- but then changing its mind and sending a different unit to that village on the next turn.
|
||||
-- Or sending a faraway unit instead of a close unit to a given village.
|
||||
|
||||
local LS = wesnoth.require "location_set"
|
||||
local F = wesnoth.require "functional"
|
||||
local AH = wesnoth.require "ai/lua/ai_helper"
|
||||
local simple_scouting = {}
|
||||
|
||||
local possible_scouts, shroud
|
||||
|
||||
function simple_scouting:evaluation(cfg, data, filter_own)
|
||||
shroud = LS.of_pairs(wesnoth.map.find{
|
||||
include_borders = false,
|
||||
wml.tag.filter_vision{
|
||||
visible = false,
|
||||
respect_fog = false,
|
||||
side = ai.side,
|
||||
}
|
||||
})
|
||||
if shroud:size() == 0 then return 0 end
|
||||
possible_scouts = wesnoth.units.find{
|
||||
side = ai.side,
|
||||
canrecruit = false,
|
||||
formula = "max_moves > 5 and moves > 0",
|
||||
wml.tag["and"](filter_own)
|
||||
}
|
||||
if #possible_scouts == 0 then return 0 end
|
||||
return 30000
|
||||
end
|
||||
|
||||
function simple_scouting:execution(cfg, data, filter_own)
|
||||
local villages = LS.of_pairs(wesnoth.map.find{owner_side = 0, gives_income = true})
|
||||
while villages:size() > 0 and #possible_scouts > 0 do
|
||||
local current_scout = table.remove(possible_scouts)
|
||||
local best = F.choose(villages:to_pairs(), function(loc)
|
||||
return -wesnoth.map.distance_between(loc, current_scout)
|
||||
end)
|
||||
if not best then
|
||||
table.insert(possible_scouts, current_scout)
|
||||
break
|
||||
end
|
||||
local hop = AH.next_hop(current_scout, best.x, best.y)
|
||||
ai.move(current_scout, hop)
|
||||
villages:remove(best)
|
||||
end
|
||||
while shroud:size() > 0 and #possible_scouts > 0 do
|
||||
local current_scout = table.remove(possible_scouts)
|
||||
local best = F.choose(shroud:to_pairs(), function(loc)
|
||||
return -wesnoth.map.distance_between(loc, current_scout)
|
||||
end)
|
||||
if not best then break end
|
||||
local hop = AH.next_hop(current_scout, best.x, best.y)
|
||||
ai.move(current_scout, hop)
|
||||
shroud:remove(best)
|
||||
end
|
||||
end
|
||||
|
||||
return simple_scouting
|
31
data/ai/lua/opening.lua
Normal file
31
data/ai/lua/opening.lua
Normal file
@ -0,0 +1,31 @@
|
||||
-- An extremely simplistic example of an AI that does certain fixed moves
|
||||
-- It's meant to be used as a custom stage preceding the RCA stage
|
||||
-- This is a highly specific example and probably not suitable to be directly used in other places
|
||||
|
||||
if wesnoth.current.turn == 1 then
|
||||
ai.recruit('Skeleton Archer', 11,21)
|
||||
ai.recruit('Dark Adept', 11,22)
|
||||
ai.recruit('Dark Adept', 10,22)
|
||||
ai.recruit('Skeleton Archer', 9,22)
|
||||
ai.recruit('Ghost', 11,24)
|
||||
ai.move(11,23, 14,22)
|
||||
elseif wesnoth.current.turn == 2 then
|
||||
ai.move(11,21, 13,17)
|
||||
ai.move(11,22, 13,18)
|
||||
ai.move(10,22, 7,19)
|
||||
ai.move(9,22, 4,22)
|
||||
ai.move(11,24, 18,24)
|
||||
ai.move(14,22, 11,23)
|
||||
ai.recruit('Dark Adept', 11,21)
|
||||
ai.recruit('Dark Adept', 11,22)
|
||||
elseif wesnoth.current.turn == 3 then
|
||||
ai.move(18,24, 20,22)
|
||||
ai.move(15,19, 17,17)
|
||||
ai.move(4,22, 5,18)
|
||||
ai.recruit('Skeleton Archer', 11,21)
|
||||
elseif wesnoth.current.turn == 4 then
|
||||
ai.recruit('Skeleton Archer', 11,21)
|
||||
else
|
||||
ai.recruit('Skeleton Archer', 11,21)
|
||||
ai.recruit('Dark Adept', 11,22)
|
||||
end
|
319
data/ai/scenarios/scenario-lua_ai_unit_actions.cfg
Normal file
319
data/ai/scenarios/scenario-lua_ai_unit_actions.cfg
Normal file
@ -0,0 +1,319 @@
|
||||
#textdomain wesnoth-test
|
||||
# @file data/scenario-test.cfg
|
||||
|
||||
[test]
|
||||
name=_"Test scenario"
|
||||
map_data="
|
||||
Hh , Hh , Gg , Wwf , Wwf , Gs^Fp , Mm , Hh , Gg , Gs^Fp , Gg , Hh , Gg , Mm , Hh , Mm , Wwf , Wwf , Hh , Gs^Fp , Hh , Mm , Mm
|
||||
Hh , Hh , Gg^Ve , Wwf , Wwf , Gs^Fp , Mm , Hh , Gg , Gs^Fp , Gg , Hh , Gg , Mm , Hh , Mm , Wwf , Wwf , Hh , Gs^Fp , Hh , Mm , Mm
|
||||
Wwf , Wwf , Wwf , Wwf , Gg , Wwf , Wwf , Hh , Gg , Gg , Wwf , Ch , Wwf , Gs^Fp , Wwf , Wwf , Re , Re , Hh , Mm , Wwf , Mm , Mm
|
||||
Mm , Mm , Wwf , Gs^Fp , Gg^Vh , Wwf , Gg , Gg , Wwf , Wwf , Wwf , 1 Kh , Ch , Wwf , Re , Re , Rd , Rd , Wwf , Wwf , Gs^Fp , Wwf , Wwf
|
||||
Wwf , Wwf , Mm , Wwf , Gs^Fp , Wwf , Wwf , Wwf , Gg^Vh , Gg , Wwf , Ch , Wwf , Ch , Rd , Rd , Wwf , Wwf , Gg^Vh , Gs^Fp , Re^Gvs , Hh , Hh
|
||||
Hh , Hh , Wwf , Gs^Fp , Wwf , Wwf , Gg , Gg , Gg , Gg , Wwf , Ch , Gg , Wwf , Wwf , Wwf , Mm , Gs^Fp , Re , Re^Gvs , Gg^Wm , Re^Gvs , Re^Gvs
|
||||
Wwf , Wwf , Mm , Wwf , Hh , Gs^Fp , Rd , Rd , Gg , Gg , Wwf , Wwf , Gs^Fp , Gg , Hh , Gg , Re , Re , Rd , Rd , Gg , Hh , Hh
|
||||
Hh , Hh , Gs^Fp , Gg , Gg , Rd , Gg , Gg , Wwf , Wwf , Gs^Fp , Wwf , Gs^Fp , Mm , Re , Re , Rd , Rd , Gg , Gg^Efm , Mm , Gs^Fp , Gs^Fp
|
||||
Gs^Fp , Gs^Fp , Gg , Gg , Wwf , Gg , Wwf , Wwf , Mm , Hh , Wwf , Wwf , Re , Re , Rd , Rd , Rd , Gg , Gs^Fp , Gs^Fp , Gs^Fp , Hh , Hh
|
||||
Hh , Hh , Wwf , Wwf , Hh , Wwf , Gg , Gg , Gg , Gg , Wwf , Re , Re , Rd , Gg , Gg , Gg , Gg^Vh , Hh , Gg , Wwf , Gg^Efm , Gg^Efm
|
||||
Wwf , Wwf , Hh , Gg^Efm , Gs^Fp , Hh^Vhh , Gg , Gg , Gg , Ss^Vhs , Hh , Ww , Gs^Fp , Gg , Gs^Fp , Hh , Wwf , Wwf , Wwf , Wwf , Gg , Wwf , Wwf
|
||||
Hh , Hh , Gg , Gg , Re , Gg , Re , Re , Gg , Ss , Gs^Fp , Ww , Hh , Mm , Ww , Wwf , Gg , Gg , Ds , Gg , Gg , Gs^Fp , Gs^Fp
|
||||
Gs^Fp , Gs^Fp , Gg , Rd , Rd , Re , Rd , Re , Hh , Mm , Wwf , Ww , Ww , Ww , Gg , Gg , Hh , Gs^Fp , Rd , Rd , Hh , Gg , Gg
|
||||
Rd , Rd , Gs^Fp , Hh , Rd , Rd , Gs^Fp , Re , Gg , Gg , Wwf , Gg , Wwf , Gg , Gg , Re , Gs^Fp , Hh , Rd , Mm , Gs^Fp , Rd , Rd
|
||||
Rd , Rd , Hh , Mm , Rd , Hh , Hh , Re , Gg , Gg , Ww , Gg , Wwf , Gg , Hh , Re , Rd , Rd , Rd , Hh , Gg , Rd , Rd
|
||||
Gg , Gg , Gg , Rd , Ds , Gs^Fp , Gg , Gg , Ww , Ww , Hh , Ww , Gs^Fp , Mm , Gg , Re , Re , Re , Re , Rd , Gg , Gs^Fp , Gs^Fp
|
||||
Gs^Fp , Gs^Fp , Gg , Gg , Wwf , Gg , Wwf , Wwf , Gs^Fp , Mm , Gs^Fp , Ww , Hh , Ss , Gg , Re , Gg , Gg , Gs^Fp , Gg , Hh , Hh , Hh
|
||||
Wwf , Wwf , Wwf , Wwf , Hh , Wwf , Gg , Hh , Gg , Gg , Re , Ww , Wwf , Ss^Vhs , Gg , Gg , Gg , Hh^Vhh , Hh , Gg^Efm , Wwf , Wwf , Wwf
|
||||
Gg^Efm , Gg^Efm , Gs^Fp , Gg , Gs^Fp , Gg^Vh , Rd , Gg , Rd , Rd , Re , Re , Wwf , Gg , Mm , Gg , Wwf , Wwf , Wwf , Wwf , Gg , Mm , Mm
|
||||
Hh , Hh , Mm , Gs^Fp , Gg , Gg , Rd , Rd , Re , Re , Gs^Fp , Wwf , Gs^Fp , Hh , Wwf , Wwf , Gg , Gg , Gg , Gg , Gs^Fp , Gs^Fp , Gs^Fp
|
||||
Gs^Fp , Gs^Fp , Gg , Gg^Efm , Rd , Rd , Re , Re , Hh , Mm , Gg , Wwf , Wwf , Wwf , Gg , Gg , Rd , Rd , Hh , Gg , Mm , Hh , Hh
|
||||
Hh , Hh , Gg^Wm , Rd , Re , Re , Mm , Gg , Wwf , Wwf , Wwf , Ch , Gg , Gg , Gg , Rd , Gg , Gs^Fp , Wwf , Wwf , Wwf , Wwf , Wwf
|
||||
Re^Gvs , Re^Gvs , Re^Gvs , Re^Gvs , Gg^Vh , Gs^Fp , Wwf , Wwf , Rd , Ch , Ch , Ch , Gg , Gg , Gg^Vh , Gg , Wwf , Wwf , Gs^Fp , Gs^Fp , Gg^Ve , Gg , Gg
|
||||
Hh , Hh , Gs^Fp , Gs^Fp , Wwf , Wwf , Rd , Rd , Re , Re , Wwf , 2 Kh , Wwf , Gg , Wwf , Wwf , Gg , Wwf , Wwf , Wwf , Wwf , Gs^Fp , Gs^Fp
|
||||
Gs^Fp , Gs^Fp , Wwf , Wwf , Mm , Rd , Gs^Fp , Hh , Wwf , Wwf , Gg , Ch , Gg , Wwf , Hh , Gg , Wwf , Wwf , Gg^Vh , Gg , Wwf , Mm , Mm
|
||||
Gs^Fp , Gs^Fp , Wwf , Wwf , Mm , Rd , Gs^Fp , Wwf , Wwf , Gg , Gg , Gg , Gg , Gg , Hh , Gg , Wwf , Wwf , Gg , Gg , Wwf , Mm , Mm
|
||||
"
|
||||
|
||||
turns=90
|
||||
id=unit_actions
|
||||
|
||||
{DEFAULT_SCHEDULE}
|
||||
|
||||
[label]
|
||||
x,y=16,5
|
||||
text=_"Patrol waypoint 1"
|
||||
[/label]
|
||||
|
||||
[label]
|
||||
x,y=16,15
|
||||
text=_"Patrol waypoint 2"
|
||||
[/label]
|
||||
|
||||
[label]
|
||||
x,y=3,14
|
||||
text=_"Priorities test"
|
||||
[/label]
|
||||
|
||||
[label]
|
||||
x,y=2,12
|
||||
text=_"first"
|
||||
[/label]
|
||||
|
||||
[label]
|
||||
x,y=3,11
|
||||
text=_"second"
|
||||
[/label]
|
||||
|
||||
[label]
|
||||
x,y=3,13
|
||||
text=_"third"
|
||||
[/label]
|
||||
|
||||
[label]
|
||||
x,y=8,5
|
||||
text=_"Location guarded (range = 3)"
|
||||
[/label]
|
||||
|
||||
[side]
|
||||
type=Dwarvish Steelclad
|
||||
id=side_1_leader
|
||||
side=1
|
||||
canrecruit=yes
|
||||
recruit=Dwarvish Guardsman,Dwarvish Fighter,Dwarvish Thunderer,Thief,Poacher,Footpad
|
||||
gold=200
|
||||
controller=human
|
||||
suppress_end_turn_confirmation=yes
|
||||
[unit]
|
||||
x,y=10,8
|
||||
type="Elvish Archer"
|
||||
hitpoints=1
|
||||
generate_name=yes
|
||||
[/unit]
|
||||
|
||||
[unit]
|
||||
x,y=3,12
|
||||
type="Elvish Fighter"
|
||||
random_traits=no
|
||||
generate_name=yes
|
||||
[modifications]
|
||||
[trait]
|
||||
id=move
|
||||
[effect]
|
||||
apply_to=movement
|
||||
set=0
|
||||
[/effect]
|
||||
[/trait]
|
||||
[trait]
|
||||
id=hp
|
||||
[effect]
|
||||
apply_to=hitpoints
|
||||
increase_total=120
|
||||
[/effect]
|
||||
[/trait]
|
||||
[/modifications]
|
||||
[/unit]
|
||||
[village]
|
||||
x,y=2,1
|
||||
[/village]
|
||||
[village]
|
||||
x,y=4,3
|
||||
[/village]
|
||||
[village]
|
||||
x,y=8,4
|
||||
[/village]
|
||||
[village]
|
||||
x,y=18,4
|
||||
[/village]
|
||||
[/side]
|
||||
|
||||
[side]
|
||||
#controller=human
|
||||
suppress_end_turn_confirmation=yes
|
||||
name=_"AI"
|
||||
type=Dark Sorcerer
|
||||
side=2
|
||||
canrecruit=yes
|
||||
recruit=Skeleton,Skeleton Archer,Walking Corpse,Ghost,Vampire Bat,Dark Adept,Ghoul
|
||||
gold=200
|
||||
shroud=yes
|
||||
|
||||
[unit]
|
||||
x,y=8,5
|
||||
type="Orcish Archer"
|
||||
generate_name=yes
|
||||
[ai]
|
||||
[micro_ai]
|
||||
ai_type=stationed_guardian
|
||||
station_x,station_y=8,5
|
||||
distance=3
|
||||
[/micro_ai]
|
||||
[/ai]
|
||||
[/unit]
|
||||
[unit]
|
||||
x,y=3,8
|
||||
type="Walking Corpse"
|
||||
generate_name=yes
|
||||
[ai]
|
||||
[micro_ai]
|
||||
ai_type=goto
|
||||
[filter_location]
|
||||
formula=castle
|
||||
[/filter_location]
|
||||
release_unit_at_goal=yes
|
||||
[/micro_ai]
|
||||
[/ai]
|
||||
[/unit]
|
||||
|
||||
[unit]
|
||||
x,y=16,5
|
||||
type="Wolf Rider"
|
||||
generate_name=yes
|
||||
[ai]
|
||||
[micro_ai]
|
||||
ai_type=patrol
|
||||
waypoint_x=16,16
|
||||
waypoint_y=5,15
|
||||
attack_range=3
|
||||
[/micro_ai]
|
||||
[/ai]
|
||||
[/unit]
|
||||
|
||||
[unit]
|
||||
x,y=3,11
|
||||
type="Goblin Spearman"
|
||||
generate_name=yes
|
||||
[ai]
|
||||
[candidate_action]
|
||||
engine=lua
|
||||
max_score=10000010
|
||||
evaluation=<<
|
||||
local u = wesnoth.units.find(select(4, ...))[1]
|
||||
if not u then return 0 end
|
||||
return ai.check_attack(u,3,12).ok and 10000010 or 0
|
||||
>>
|
||||
execution=<<
|
||||
local u = wesnoth.units.find(select(4, ...))[1]
|
||||
ai.attack(u,3,12)
|
||||
>>
|
||||
[/candidate_action]
|
||||
[/ai]
|
||||
[/unit]
|
||||
|
||||
[unit]
|
||||
x,y=3,13
|
||||
type="Goblin Spearman"
|
||||
generate_name=yes
|
||||
[ai]
|
||||
[candidate_action]
|
||||
engine=lua
|
||||
max_score=10000009
|
||||
evaluation=<<
|
||||
local u = wesnoth.units.find(select(4, ...))[1]
|
||||
if not u then return 0 end
|
||||
return ai.check_attack(u,3,12).ok and 10000009 or 0
|
||||
>>
|
||||
execution=<<
|
||||
local u = wesnoth.units.find(select(4, ...))[1]
|
||||
ai.attack(u,3,12)
|
||||
>>
|
||||
[/candidate_action]
|
||||
[/ai]
|
||||
[/unit]
|
||||
|
||||
[unit]
|
||||
x,y=2,12
|
||||
type="Goblin Spearman"
|
||||
generate_name=yes
|
||||
[ai]
|
||||
[candidate_action]
|
||||
engine=lua
|
||||
max_score=10000011
|
||||
evaluation=<<
|
||||
local u = wesnoth.units.find(select(4, ...))[1]
|
||||
if not u then return 0 end
|
||||
return ai.check_attack(u,3,12).ok and 10000011 or 0
|
||||
>>
|
||||
execution=<<
|
||||
local u = wesnoth.units.find(select(4, ...))[1]
|
||||
ai.attack(u,3,12)
|
||||
>>
|
||||
[/candidate_action]
|
||||
[/ai]
|
||||
[/unit]
|
||||
|
||||
[unit]
|
||||
x,y=7,20
|
||||
type="Silver Mage"
|
||||
generate_name=yes
|
||||
[/unit]
|
||||
|
||||
[unit]
|
||||
x,y=6,20
|
||||
type="Ghost"
|
||||
generate_name=yes
|
||||
[/unit]
|
||||
[unit]
|
||||
x,y=15,22
|
||||
type="Ghost"
|
||||
generate_name=yes
|
||||
[/unit]
|
||||
[unit]
|
||||
x,y=12,19
|
||||
type="Ghost"
|
||||
generate_name=yes
|
||||
[/unit]
|
||||
[unit]
|
||||
x,y=10,6
|
||||
type="Lich"
|
||||
experience=149
|
||||
generate_name=yes
|
||||
[/unit]
|
||||
|
||||
[ai]
|
||||
[stage]
|
||||
engine=lua
|
||||
code="wesnoth.dofile 'ai/lua/opening.lua'"
|
||||
[/stage]
|
||||
|
||||
[stage]
|
||||
id=main_loop
|
||||
name=ai_default_rca::candidate_action_evaluation_loop
|
||||
[candidate_action]
|
||||
engine=cpp
|
||||
name=ai_default_rca::move_leader_to_keep_phase
|
||||
max_score = 60000
|
||||
score = 60000
|
||||
[/candidate_action]
|
||||
[candidate_action]
|
||||
engine=cpp
|
||||
name=ai_default_rca::move_to_targets_phase
|
||||
max_score = 20000
|
||||
score = 20000
|
||||
[/candidate_action]
|
||||
[candidate_action]
|
||||
engine=cpp
|
||||
name=ai_default_rca::combat_phase
|
||||
max_score = 20000
|
||||
score = 20000
|
||||
[/candidate_action]
|
||||
[candidate_action]
|
||||
engine=lua
|
||||
name=scouting
|
||||
location="ai/lua/ca_simple_scouting.lua"
|
||||
max_score = 30000
|
||||
[/candidate_action]
|
||||
[candidate_action]
|
||||
engine=lua
|
||||
name=level_up_attack
|
||||
location = "ai/lua/ca_level_up_attack.lua"
|
||||
max_score = 100000
|
||||
[/candidate_action]
|
||||
[/stage]
|
||||
|
||||
[stage]
|
||||
# This exists so you can see the AI's shroud.
|
||||
engine=lua
|
||||
name=fallback
|
||||
code="ai.fallback_human()"
|
||||
[/stage]
|
||||
[/ai]
|
||||
[/side]
|
||||
[/test]
|
Loading…
x
Reference in New Issue
Block a user