Merge branch 'master' of git://github.com/wesnoth/wesnoth-old into tmp

This commit is contained in:
Bär Halberkamp 2013-09-05 11:35:45 +02:00
commit 6d39f8a221
572 changed files with 37071 additions and 42324 deletions

View file

@ -1,18 +1,30 @@
Version 1.11.6+dev:
* Add-ons client:
* Report errors caused by faulty local .pbl files properly instead of presenting
them as network errors.
* Report errors caused by faulty local .pbl files properly instead of
presenting them as network errors.
* AI:
* Micro AIs:
* New Simple Attack Micro AI
* Messenger MAI now works with units (both messenger and escort) without
weapons and when path to next waypoint is entirely blocked
* Fixed bug that prevented removal of sticky MAIs
* Graphics
* Full animations for the Dwarven Thunderer line.
* Language and i18n:
* Updated translations: German, Lithuanian
* Updated translations: German, Greek, Lithuanian, Portuguese, Vietnamese
* Lua API:
* Added scroll_to_leader field (read/write) to wesnoth.sides table elements.
* Added scroll_to_leader field (read/write) to wesnoth.sides table
elements.
* WML engine:
* [store_side] now stores the scroll_to_leader attribute from sides.
* Miscellaneous and bug fixes:
* Added -256 and -512 color shifts to FADE_TO_BLACK and FADE_TO_BLACK_HOLD
macros to account for ToD color shifts greater than -31, guaranteeing complete
darkness.
* Unit WML frames with image modifications now shown correctly for hits/death.
macros to account for ToD color shifts greater than -31, guaranteeing
complete darkness.
* Unit WML frames with image modifications now shown correctly for
hits/death.
* Fixed compare_images.py (called by wesnoth-optipng) and pofix.py to
function with python-3.2
Version 1.11.6:
* Add-ons client:

View file

@ -1017,15 +1017,15 @@ end
---------- Attack related helper functions --------------
function ai_helper.get_attacks_unit(unit, cfg)
-- Get all attacks a unit can do
function ai_helper.get_attacks(units, cfg)
-- Get all attacks the units stored in 'units' can do
-- This includes a variety of configurable options, passed in the 'cfg' table
-- cfg: table with config parameters
-- moves: "current" (default for units on current side) or "max" (always used for units on other sides)
-- include_occupied (false): if set, also include hexes occupied by own-side units that can move away
-- simulate_combat (false): if set, also simulate the combat and return result (this is slow; only set if needed)
-- Returns {} if no attacks can be done, otherwise table with fields
-- Returns {} if no attacks can be done, otherwise table with fields:
-- dst: { x = x, y = y } of attack position
-- src: { x = x, y = y } of attacking unit (don't use id, could be ambiguous)
-- target: { x = x, y = y } of defending unit
@ -1034,139 +1034,127 @@ function ai_helper.get_attacks_unit(unit, cfg)
cfg = cfg or {}
local attacks = {}
if (not units[1]) then return attacks end
local side = units[1].side -- all units need to be on same side
-- 'moves' can be either "current" or "max"
-- For unit on current side: use "current" by default, or override by cfg.moves
local moves = cfg.moves or "current"
-- For unit on any other side, only moves="max" makes sense
if (unit.side ~= wesnoth.current.side) then moves = "max" end
if (side ~= wesnoth.current.side) then moves = "max" end
-- Need to find reachable hexes that are
-- 1. next to a (non-petrified) enemy unit
-- 2. not occupied by a unit of a different side (incl. allies)
W.store_reachable_locations {
{ "filter", { x = unit.x, y = unit.y } },
{ "filter_location", {
{ "filter_adjacent_location", {
{ "filter", {
{ "filter_side",
{ { "enemy_of", { side = unit.side } } }
},
{ "not", {
{ "filter_wml", {
{ "status", { petrified = "yes" } } -- This is important!
} }
} }
} }
} },
{ "not", {
{ "filter", { { "not", { side = unit.side } } } }
} }
} },
moves = moves,
variable = "tmp_locs"
}
local attack_loc = H.get_variable_array("tmp_locs")
W.clear_variable { name = "tmp_locs" }
--print("reachable attack locs:", unit.id, #attack_loc)
-- Variable to store attacks
local attacks = {}
-- Current position of unit
local x1, y1 = unit.x, unit.y
-- Go through all attack locations
for i,p in pairs(attack_loc) do
-- At this point, units on the side of 'unit' can still be at the attack hex.
-- By default, exclude those hexes, but if 'include_occupied' is set
-- units that can move away are fine
-- Flag whether a potential unit_in_way can move away
-- We also set this to true if there is no unit in the way
local can_move_away = true
local unit_in_way = wesnoth.get_unit(p.x, p.y)
-- If unit_in_way is the unit itself, that doesn't count
if unit_in_way and (unit_in_way.x == unit.x) and (unit_in_way.y == unit.y) then unit_in_way = nil end
-- If there's a unit_in_way, and it is not the unit itself, check whether it can move away
if unit_in_way then
if (not cfg.include_occupied) then
can_move_away = false
else
local move_away = ai_helper.get_reachable_unocc(unit_in_way, { moves = moves })
if (move_away:size() <= 1) then can_move_away = false end
--print('Can move away:', unit_in_way.id, can_move_away)
end
end
-- Now can_move_away = true if there's no unit, or if it can move away
if can_move_away then
-- Put 'unit' at this position
-- Remove any unit that might be there first, except if this is the unit itself
if unit_in_way then wesnoth.extract_unit(unit_in_way) end
wesnoth.put_unit(p.x, p.y, unit)
--print(i,' attack pos:',p.x,p.y)
-- As there might be several attackable units from a position, need to find all those
local targets = wesnoth.get_units {
{ "filter_side",
{ { "enemy_of", { side = unit.side } } }
},
{ "not", {
{ "filter_wml", {
{ "status", { petrified = "yes" } } -- This is important!
} }
} },
{ "filter_location",
{ { "filter_adjacent_location", { x = p.x, y = p.y } } }
}
}
--print(' number targets: ',#targets)
local attack_hex_occupied = false
if unit_in_way then attack_hex_occupied = true end
for j,t in pairs(targets) do
local att_stats, def_stats = nil, nil
if cfg.simulate_combat then
att_stats, def_stats = wesnoth.simulate_combat(unit, t)
end
table.insert(attacks, {
dst = { x = p.x, y = p.y },
src = { x = x1, y = y1 },
target = { x = t.x, y = t.y },
att_stats = att_stats,
def_stats = def_stats,
attack_hex_occupied = attack_hex_occupied
} )
end
-- Put unit(s) back
wesnoth.put_unit(x1, y1, unit)
if unit_in_way then wesnoth.put_unit(p.x, p.y, unit_in_way) end
local old_moves = {}
if (moves == "max") then
for i,u in ipairs(units) do
old_moves[i] = u.moves
u.moves = u.max_moves
end
end
return attacks
end
-- Note: the remainder is optimized for speed, so we only get_units once,
-- do not use WML filters, etc.
local all_units = wesnoth.get_units {}
function ai_helper.get_attacks(units, cfg)
-- Wrapper function for ai_helper.get_attacks_unit
-- Returns the same sort of table (and cfg has the same structure), but for the attacks of several units
local enemy_map, my_unit_map, other_unit_map = LS.create(), LS.create(), LS.create()
for i,u in ipairs(all_units) do
-- The value of all the location sets is the index of the
-- unit in the all_units array
if wesnoth.is_enemy(u.side, side) and (not u.status.petrified) then
enemy_map:insert(u.x, u.y, i)
end
local attacks = {}
for k,u in pairs(units) do
local attacks_unit = ai_helper.get_attacks_unit(u, cfg)
if (u.side == side) then
my_unit_map:insert(u.x, u.y, i)
else
other_unit_map:insert(u.x, u.y, i)
end
end
if attacks_unit[1] then
for i,a in ipairs(attacks_unit) do
table.insert(attacks, a)
local attack_hex_map = LS.create()
enemy_map:iter(function(e_x, e_y, i)
for x, y in H.adjacent_tiles(e_x, e_y) do
-- If there's no unit of another side on this hex, include it
-- as possible attack location (this includes hexes occupied
-- by own units at this time)
if (not other_unit_map:get(x, y)) then
local target_table = attack_hex_map:get(x, y) or {}
table.insert(target_table, { x = e_x, y = e_y, i = i })
attack_hex_map:insert(x, y, target_table)
end
end
end)
-- So that we at most need to do find_reach() once per unit
-- It is needed for all units in 'units' and for testing whether
-- units can move out of the way
local reaches = LS.create()
for i_u,u in ipairs(units) do
local reach
if reaches:get(u.x, u.y) then
reach = reaches:get(u.x, u.y)
else
reach = wesnoth.find_reach(u)
reaches:insert(u.x, u.y, reach)
end
for i_r,r in ipairs(reach) do
if attack_hex_map:get(r[1], r[2]) then
local add_target = true
local attack_hex_occupied = false
-- If another unit of same side is on this hex:
if my_unit_map:get(r[1], r[2]) and ((r[1] ~= u.x) or (r[2] ~= u.y)) then
attack_hex_occupied = true
if (not cfg.include_occupied) then
add_target = false
else -- test whether it can move out of the way
local unit_in_way = all_units[my_unit_map:get(r[1], r[2])]
local uiw_reach
if reaches:get(unit_in_way.x, unit_in_way.y) then
uiw_reach = reaches:get(unit_in_way.x, unit_in_way.y)
else
uiw_reach = wesnoth.find_reach(unit_in_way)
reaches:insert(unit_in_way.x, unit_in_way.y, uiw_reach)
end
-- Units that cannot move away have only one hex in uiw_reach
if (#uiw_reach <= 1) then add_target = false end
end
end
if add_target then
for i_t,target in ipairs(attack_hex_map:get(r[1], r[2])) do
local att_stats, def_stats
if cfg.simulate_combat then
local unit_dst = wesnoth.copy_unit(u)
unit_dst.x, unit_dst.y = r[1], r[2]
local enemy = all_units[target.i]
att_stats, def_stats = wesnoth.simulate_combat(unit_dst, enemy)
end
table.insert(attacks, {
src = { x = u.x, y = u.y },
dst = { x = r[1], y = r[2] },
target = { x = target.x, y = target.y },
att_stats = att_stats,
def_stats = def_stats,
attack_hex_occupied = attack_hex_occupied
})
end
end
end
end
end
if (moves == "max") then
for i,u in ipairs(units) do
u.moves = old_moves[i]
end
end
return attacks

View file

@ -98,7 +98,15 @@ return {
local my_units = wesnoth.get_units{ side = wesnoth.current.side, formula = '$this_unit.attacks_left > 0',
{ "not", { id = unit.id } }
}
-- Eliminate units without attacks
for i = #my_units,1,-1 do
if (not H.get_child(my_units[i].__cfg, 'attack')) then
table.remove(my_units, i)
end
end
--print('#my_units', #my_units)
if (not my_units[1]) then return end
local my_attacks = AH.get_attacks(my_units, { simulate_combat = true })
@ -203,6 +211,7 @@ return {
x, y = wesnoth.find_vacant_tile( x, y, messenger)
end
local next_hop = AH.next_hop(messenger, x, y)
if (not next_hop) then next_hop = { messenger.x, messenger.y } end
-- Compare this to the "ideal path"
local path, cost = wesnoth.find_path(messenger, x, y, { ignore_units = 'yes' })
@ -227,11 +236,11 @@ return {
wesnoth.put_unit(opt_hop[1], opt_hop[2], messenger)
local tmp, cost2 = wesnoth.find_path(messenger, x, y, {ignore_units = 'yes'})
wesnoth.put_unit(x1, y1, messenger)
--print(cost1, cost2)
--print(cost1, cost2)
-- If cost2 is significantly less, that means that the other path might overall be faster
-- even though it is currently blocked
if (cost2 + 4 < cost1) then next_hop = opt_hop end
if (cost2 + messenger.max_moves/2 < cost1) then next_hop = opt_hop end
--print(next_hop[1], next_hop[2])
if next_hop and ((next_hop[1] ~= messenger.x) or (next_hop[2] ~= messenger.y)) then
@ -241,6 +250,8 @@ return {
end
-- We also test whether an attack without retaliation or with little damage is possible
if (not H.get_child(messenger.__cfg, 'attack')) then return end
local targets = wesnoth.get_units {
{ "filter_side", { {"enemy_of", {side = wesnoth.current.side} } } },
{ "filter_adjacent", { id = cfg.id } }
@ -274,17 +285,22 @@ return {
end
end
local target = wesnoth.get_units {
x = cfg.waypoint_x[#cfg.waypoint_x],
y = cfg.waypoint_y[#cfg.waypoint_y],
{ "filter_side", { {"enemy_of", {side = wesnoth.current.side} } } },
{ "filter_adjacent", { id = cfg.id } }
}[1]
if max_rating > -9e99 then
ai.attack(messenger, best_tar, best_weapon)
elseif target then
ai.attack(messenger, target)
else
-- Otherwise, always attack enemy on last waypoint
local waypoint_x = AH.split(cfg.waypoint_x, ",")
local waypoint_y = AH.split(cfg.waypoint_y, ",")
local target = wesnoth.get_units {
x = tonumber(waypoint_x[#waypoint_x]),
y = tonumber(waypoint_y[#waypoint_y]),
{ "filter_side", { {"enemy_of", {side = wesnoth.current.side} } } },
{ "filter_adjacent", { id = cfg.id } }
}[1]
if target then
ai.attack(messenger, target)
end
end
-- Finally, make sure unit is really done after this

View file

@ -0,0 +1,91 @@
return {
init = function(ai, existing_engine)
local engine = existing_engine or {}
local H = wesnoth.require "lua/helper.lua"
local AH = wesnoth.require "ai/lua/ai_helper.lua"
local BC = wesnoth.require "ai/lua/battle_calcs.lua"
local LS = wesnoth.require "lua/location_set.lua"
function engine:mai_simple_attack_eval(cfg)
-- Find all units that can attack and match the SUF
local units = wesnoth.get_units {
side = wesnoth.current.side,
formula = '$this_unit.attacks_left > 0',
{ "and", cfg.filter }
}
-- Eliminate units without attacks
for i = #units,1,-1 do
if (not H.get_child(units[i].__cfg, 'attack')) then
table.remove(units, i)
end
end
--print('#units', #units)
if (not units[1]) then return 0 end
-- Get all possible attacks
local attacks = AH.get_attacks(units, { include_occupied = true })
--print('#attacks', #attacks)
if (not attacks[1]) then return 0 end
-- If cfg.filter_second is set, set up a map (location set)
-- of enemies that it is okay to attack
local enemy_map
if cfg.filter_second then
local enemies = wesnoth.get_units {
{ "filter_side", {{ "enemy_of", { side = wesnoth.current.side } }} },
{ "and", cfg.filter_second }
}
--print('#enemies', #enemies)
if (not enemies[1]) then return 0 end
enemy_map = LS.create()
for i,e in ipairs(enemies) do enemy_map:insert(e.x, e.y) end
end
-- Now find the best of the possible attacks
local max_rating, best_attack = -9e99, {}
for i, att in ipairs(attacks) do
local valid_target = true
if cfg.filter_second and (not enemy_map:get(att.target.x, att.target.y)) then
valid_target = false
end
if valid_target then
local attacker = wesnoth.get_unit(att.src.x, att.src.y)
local enemy = wesnoth.get_unit(att.target.x, att.target.y)
local dst = { att.dst.x, att.dst.y }
local rating = BC.attack_rating(attacker, enemy, dst)
--print('rating:', rating, attacker.id, enemy.id)
if (rating > max_rating) then
max_rating = rating
best_attack = att
end
end
end
if (max_rating > -9e99) then
self.data.attack = best_attack
return cfg.ca_score
end
return 0
end
function engine:mai_simple_attack_exec()
local attacker = wesnoth.get_unit(self.data.attack.src.x, self.data.attack.src.y)
local defender = wesnoth.get_unit(self.data.attack.target.x, self.data.attack.target.y)
AH.movefull_outofway_stopunit(ai, attacker, self.data.attack.dst.x, self.data.attack.dst.y)
ai.attack(attacker, defender)
self.data.attack = nil
end
return engine
end
}

View file

@ -69,17 +69,22 @@ local function add_CAs(side, CA_parms, CA_cfg)
end
end
local function delete_CAs(side, CA_parms)
local function delete_CAs(side, CA_parms, unit_id)
-- Delete the candidate actions defined in 'CA_parms' from the AI of 'side'
-- CA_parms is an array of tables, one for each CA to be removed
-- We can simply pass the one used for add_CAs(), although only the
-- CA_parms.ca_id field is needed
-- For sticky CAs, unit_id is also needed
for i,parms in ipairs(CA_parms) do
local ca_id = parms.ca_id
-- If it's a sticky behavior CA, we also add the unit id to ca_id
if parms.sticky then ca_id = ca_id .. "_" .. unit_id end
W.modify_ai {
side = side,
action = "try_delete",
path = "stage[main_loop].candidate_action[" .. parms.ca_id .. "]"
path = "stage[main_loop].candidate_action[" .. ca_id .. "]"
}
end
end
@ -468,6 +473,11 @@ function wesnoth.wml_actions.micro_ai(cfg)
optional_keys = { "filter", "filter_location", "avoid", "mobilize_condition", "mobilize_on_gold_less_than" }
CA_parms = { { ca_id = 'mai_hang_out', score = cfg.ca_score or 170000 } }
--------- Simple Attack Micro AI - side-wide AI ---------------------------
elseif (cfg.ai_type == 'simple_attack') then
optional_keys = { "filter", "filter_second" }
CA_parms = { { ca_id = 'mai_simple_attack', score = cfg.ca_score or 110000 } }
-- If we got here, none of the valid ai_types was specified
else
H.wml_error("unknown value for ai_type= in [micro_ai]")
@ -484,9 +494,10 @@ function wesnoth.wml_actions.micro_ai(cfg)
end
end
-- If action=delete, we do that and are done
-- If action=delete, we do that and are done, but we do need to pass
-- cfg.id for sticky CAs (existence of which has been checked above)
if (cfg.action == 'delete') then
delete_CAs(cfg.side, CA_parms)
delete_CAs(cfg.side, CA_parms, cfg.id)
return
end
@ -513,7 +524,7 @@ function wesnoth.wml_actions.micro_ai(cfg)
-- Finally, set up the candidate actions themselves
if (cfg.action == 'add') then add_CAs(cfg.side, CA_parms, CA_cfg) end
if (cfg.action == 'change') then
delete_CAs(cfg.side, CA_parms)
delete_CAs(cfg.side, CA_parms, cfg.id)
add_CAs(cfg.side, CA_parms, CA_cfg)
end
end

View file

@ -155,7 +155,7 @@ Note: This scenario uses a combination of two Micro AIs, the Hang Out Micro AI w
id=Bad Outlaw
[/filter]
{MESSAGE (Good Bandit) "" "" _"We got him! Now whatever it is we are fighting for is safe."}
{MESSAGE (Good Bandit) "" "" _"We got him! Now whatever it is we are fighting for is safe."}
# So that game goes on to next scenario
[modify_side]
@ -179,7 +179,7 @@ Note: This scenario uses a combination of two Micro AIs, the Hang Out Micro AI w
x,y=36,19
[/filter]
{MESSAGE (Bad Outlaw) "" "" _"I made it! Now we can keep fighting for whatever it is that we are fighting for."}
{MESSAGE (Bad Outlaw) "" "" _"I made it! Now we can keep fighting for whatever it is that we are fighting for."}
[endlevel]
result=defeat
[/endlevel]

View file

@ -85,6 +85,9 @@
{PLACE_IMAGE "scenery/signpost.png" 13 19}
{SET_LABEL 13 19 _"Hang Out and Messenger"}
{PLACE_IMAGE "scenery/signpost.png" 14 19}
{SET_LABEL 14 19 _"Simple Attack"}
{VARIABLE scenario_name micro_ai_test}
# Menu items explaining the different scenarios
@ -312,6 +315,21 @@
{MESSAGE Grnk "" _"Combined Hang Out and Messenger Escort Micro AI demo" _"This scenario is a demonstration of the Hang Out Micro AI which keeps units around a (customizable) location until a (customizable) condition is met. After that the units are released to follow other AI behavior. The scenario also shows how to combine two Micro AIs on the same side by having the Messenger Escort Micro AI take over at that point."}
[/command]
[/set_menu_item]
[set_menu_item]
id=m14_simple_attack
description= _ "Simple Attack Micro AI demo"
image=units/undead/soulless.png~CROP(27,14,24,24)
[filter_location]
x,y=14,19
[/filter_location]
[show_if]
{VARIABLE_CONDITIONAL scenario_name equals micro_ai_test}
[/show_if]
[command]
{MESSAGE Grnk "" _"Simple Attack Micro AI demo" _"This scenario demonstrates how certain attacks can be executed with higher priority than the standard Wesnoth attacks and how the AI can be forced to do attacks that it would otherwise avoid."}
[/command]
[/set_menu_item]
[/event]
[event]
@ -589,4 +607,21 @@ Information about each demonstration can be accessed by right-clicking on the re
replay_save=no
[/endlevel]
[/event]
[event]
name=moveto
[filter]
x,y=14,19
[/filter]
[endlevel]
result=victory
next_scenario=simple_attack
bonus=no
carryover_percentage=0
carryover_report=no
linger_mode=no
replay_save=no
[/endlevel]
[/event]
[/test]

View file

@ -0,0 +1,233 @@
#textdomain wesnoth-ai
[test]
id=simple_attack
name= _ "Simple Attack"
next_scenario=micro_ai_test
map_data="{multiplayer/maps/Dark_Forecast.map}"
{DEFAULT_SCHEDULE}
turns=-1
[side]
side=1
controller=human
id=Grospur
name= _ "Grospur"
type=General
x,y=15,14
persistent=no
canrecruit=yes
recruit=Swordsman,Longbowman,Spearman,Bowman
gold=100
[/side]
[side]
side=2
controller=ai
type=Ancient Lich
id=Uralt
name= _ "Uralt"
x,y=8,6
persistent=no
canrecruit=yes
gold=10000
{MICRO_AI_SIMPLE_ATTACK}
[/side]
[side] # This side is only here because we need one persistent side for the game to go on
side=3
controller=null
persistent=yes
save_id=Grnk
hidden=yes
[/side]
[event]
name=prestart
{VARIABLE scenario_name simple_attack}
{UNIT 1 Longbowman 11 14 random_traits,experience=no,67}
{UNIT 1 Longbowman 15 12 random_traits,experience=no,67}
{UNIT 1 Longbowman 13 17 random_traits,experience=no,67}
{UNIT 1 (Master Bowman) 13 13 random_traits,experience=no,149}
{UNIT 1 (Master Bowman) 11 16 random_traits,experience=no,149}
{UNIT 1 (Master Bowman) 15 18 random_traits,experience=no,149}
{UNIT 1 Sergeant 14 14 id=sergeant}
{GENERIC_UNIT 1 Javelineer 15 13}
{GENERIC_UNIT 1 (Iron Mauler) 15 17}
{SCATTER_UNITS 12 "Soulless" 1 (x,y=5-9,8-22) (side=2)}
{SCATTER_UNITS 6 "Skeleton,Skeleton Archer" 1 (x,y=5-9,8-22) (side=2)}
[lua]
code=<<
function close_to_advancing(unit)
if (unit.experience >= unit.max_experience-1) then
return true
else
return false
end
end
>>
[/lua]
[micro_ai]
side=2
ai_type=simple_attack
action=add
ca_score=110001
[filter]
type=Soulless # No Walking Corpses; L0 units don't advance enemy
[/filter]
[filter_second]
lua_function = "close_to_advancing"
[/filter_second]
[/micro_ai]
[micro_ai]
side=2
ai_type=simple_attack
action=add
ca_score=110000
[filter]
type=Soulless,Walking Corpse
[/filter]
[/micro_ai]
[modify_side]
side=2
[ai]
aggression=1.0
caution=-9999
[/ai]
[/modify_side]
[/event]
[event]
name=start
{SCROLL_TO 11 16}
{MESSAGE sergeant "" "" _"General Grospur, what do we do? These undead will surely wipe us out."}
{MESSAGE Grospur "" "" _"Don't be such a chicken, Sergeant! I have placed units with lots of experience around the perimeter. The undead will not dare to attack them. And those few that sneak through... we can easily dispose of them once they make it inside.
<i>In other words, the Wesnoth AI does generally not attack units one XP from leveling if there is no chance of killing the unit with a single attack. However, some of the attacks by the undead are handle by the Simple Attack Micro AI in this scenario. General Grospur might be in for a surprise.</i>"}
[objectives]
summary= _ "Watch the undead take care of business"
[objective]
description= _ "Don't even try. You can't reach the Lich."
condition=win
[/objective]
[objective]
description= _ "Death of the last of Grospur's units"
condition=lose
[/objective]
[note]
description= _ "When your leader dies, side leadership passes on to another unit"
[/note]
[/objectives]
[/event]
# Guards don't get moves on Turn 1
[event]
name=turn refresh
[modify_unit]
[filter]
side=1
type=Longbowman,Swordsman
[/filter]
moves=0
[/modify_unit]
[/event]
[event]
name=attack
[filter_second]
side=1
lua_function = "close_to_advancing"
[/filter_second]
{MESSAGE $second_unit.id "" "" _"What the ... ?!? They are not supposed to attack me. That just doesn't happen in Wesnoth!"}
{MESSAGE Uralt "" "" _"Hahahahaha !! I have given special instruction to my Soulless to attack all you almost-advanced units first. Also watch how those same Soulless will throw themselves mercilessly at your pitiful soldiers after that, saving my more valuable skeleton minions for later. I have taken the term 'disposable units' to a whole new level. Watch in awe !!
<i>Translation: The undead side includes two instances of the Simple Attack Micro AI. The first makes the Soulless attack all units 1 XP from leveling up, such that they can be eliminated afterward. The second executes all remaining attacks possible by Soulless (and Walking Corpses), without regard for their own safety. Only after that does the default Wesnoth attack mechanism kick in to attack with the remaining units (skeletons).</i>"}
[/event]
# Put more undead out there when less than 25 left
[event]
name=side 2 turn end
first_time_only=no
[if]
[have_unit]
side=2
count=0-24
[/have_unit]
[then]
{MESSAGE Uralt "" "" _"Rise, minions!"}
{SCATTER_UNITS 6 "Soulless" 1 (x,y=5-9,8-22) (side=2)}
{SCATTER_UNITS 3 "Skeleton,Skeleton Archer" 1 (x,y=5-9,8-22) (side=2)}
[/then]
[/if]
[/event]
# When the leader dies, transfer leadership to another unit.
# If this was the last unit, end scenario.
[event]
name=die
first_time_only=no
[filter]
side=1
canrecruit=yes
[/filter]
[if]
[have_unit]
side=1
[/have_unit]
[then]
[store_unit]
[filter]
side=1
[/filter]
variable=tmp_units
[/store_unit]
{MODIFY_UNIT id=$tmp_units[1].id canrecruit yes}
{CLEAR_VARIABLE tmp_units}
[/then]
[else]
[kill]
id=$unit.id
[/kill]
# So that game goes on to next scenario
[modify_side]
side=3
controller=human
[/modify_side]
{MESSAGE Uralt "" "" _"And that's how the undead AI executes total annihilation ..."}
[endlevel]
result=victory
bonus=no
carryover_percentage=0
carryover_report=no
linger_mode=no
[/endlevel]
[/else]
[/if]
[/event]
[/test]

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

View file

@ -3,11 +3,15 @@
#define AOI_BIGMAP
[background_layer]
image=maps/background.jpg
keep_aspect_ratio=no
scale_vertically=yes
scale_horizontally=no
keep_aspect_ratio=yes
[/background_layer]
[background_layer]
image=maps/aoi.png
scale=no
scale_vertically=yes
scale_horizontally=no
keep_aspect_ratio=yes
base_layer=yes
[/background_layer]
#enddef

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 KiB

View file

@ -3,11 +3,15 @@
#define DID_BIGMAP
[background_layer]
image=maps/background.jpg
keep_aspect_ratio=no
scale_vertically=yes
scale_horizontally=no
keep_aspect_ratio=yes
[/background_layer]
[background_layer]
image=maps/did.png
scale=no
scale_vertically=yes
scale_horizontally=no
keep_aspect_ratio=yes
base_layer=yes
[/background_layer]
#enddef

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

View file

@ -3,11 +3,15 @@
#define HTTT_BIGMAP
[background_layer]
image=maps/background.jpg
keep_aspect_ratio=no
scale_vertically=yes
scale_horizontally=no
keep_aspect_ratio=yes
[/background_layer]
[background_layer]
image=maps/httt.png
scale=no
scale_vertically=yes
scale_horizontally=no
keep_aspect_ratio=yes
base_layer=yes
[/background_layer]
#enddef

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

View file

@ -1,11 +1,15 @@
#define SOF_BIGMAP
[background_layer]
image=maps/background.jpg
keep_aspect_ratio=no
scale_vertically=yes
scale_horizontally=no
keep_aspect_ratio=yes
[/background_layer]
[background_layer]
image=maps/sof.png
scale=no
scale_vertically=yes
scale_horizontally=no
keep_aspect_ratio=yes
base_layer=yes
[/background_layer]
#enddef

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 KiB

View file

@ -3,11 +3,15 @@
#define SOTBE_BIGMAP
[background_layer]
image=maps/background.jpg
keep_aspect_ratio=no
scale_vertically=yes
scale_horizontally=no
keep_aspect_ratio=yes
[/background_layer]
[background_layer]
image=maps/sotbe.png
scale=no
scale_vertically=yes
scale_horizontally=no
keep_aspect_ratio=yes
base_layer=yes
[/background_layer]
#enddef

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

View file

@ -3,11 +3,15 @@
#define TSG_BIGMAP
[background_layer]
image=maps/background.jpg
keep_aspect_ratio=no
scale_vertically=yes
scale_horizontally=no
keep_aspect_ratio=yes
[/background_layer]
[background_layer]
image=maps/tsg.png
scale=no
scale_vertically=yes
scale_horizontally=no
keep_aspect_ratio=yes
base_layer=yes
[/background_layer]
#enddef

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 963 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 889 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 960 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Some files were not shown because too many files have changed in this diff Show more