Merge branch 'master' of git://github.com/wesnoth/wesnoth-old into tmp
26
changelog
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
91
data/ai/micro_ais/ais/mai_simple_attack_engine.lua
Normal 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
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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]
|
||||
|
|
233
data/ai/micro_ais/scenarios/simple_attack.cfg
Normal 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]
|
After Width: | Height: | Size: 109 KiB |
|
@ -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
|
||||
|
|
After Width: | Height: | Size: 121 KiB |
After Width: | Height: | Size: 118 KiB |
Before Width: | Height: | Size: 130 KiB |
|
@ -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
|
||||
|
|
After Width: | Height: | Size: 2.2 MiB |
|
@ -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
|
||||
|
|
After Width: | Height: | Size: 105 KiB |
|
@ -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
|
||||
|
|
After Width: | Height: | Size: 209 KiB |
|
@ -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
|
||||
|
|
After Width: | Height: | Size: 168 KiB |
|
@ -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
|
||||
|
|
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-n-1.png
Normal file
After Width: | Height: | Size: 6.7 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-n-10.png
Normal file
After Width: | Height: | Size: 3.7 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-n-11.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-n-12.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-n-13.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-n-14.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-n-15.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-n-16.png
Normal file
After Width: | Height: | Size: 3.9 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-n-17.png
Normal file
After Width: | Height: | Size: 3.7 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-n-2.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-n-3.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-n-4.png
Normal file
After Width: | Height: | Size: 8.9 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-n-5.png
Normal file
After Width: | Height: | Size: 8.4 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-n-6.png
Normal file
After Width: | Height: | Size: 6.7 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-n-7.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-n-8.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-n-9.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-ne-1.png
Normal file
After Width: | Height: | Size: 7.4 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-ne-10.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-ne-11.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-ne-12.png
Normal file
After Width: | Height: | Size: 4.8 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-ne-13.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-ne-14.png
Normal file
After Width: | Height: | Size: 4.5 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-ne-15.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-ne-16.png
Normal file
After Width: | Height: | Size: 4 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-ne-17.png
Normal file
After Width: | Height: | Size: 3.7 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-ne-2.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-ne-3.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-ne-4.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-ne-5.png
Normal file
After Width: | Height: | Size: 8.9 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-ne-6.png
Normal file
After Width: | Height: | Size: 5.4 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-ne-7.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-ne-8.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-ne-9.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-s-1.png
Normal file
After Width: | Height: | Size: 7.2 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-s-10.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-s-11.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-s-12.png
Normal file
After Width: | Height: | Size: 4.5 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-s-13.png
Normal file
After Width: | Height: | Size: 4.8 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-s-14.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-s-15.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-s-16.png
Normal file
After Width: | Height: | Size: 3.9 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-s-17.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-s-2.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-s-3.png
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-s-4.png
Normal file
After Width: | Height: | Size: 9.8 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-s-5.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-s-6.png
Normal file
After Width: | Height: | Size: 5.9 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-s-7.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-s-8.png
Normal file
After Width: | Height: | Size: 3.7 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-s-9.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-se-1.png
Normal file
After Width: | Height: | Size: 8.5 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-se-10.png
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-se-11.png
Normal file
After Width: | Height: | Size: 4.5 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-se-12.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-se-13.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-se-14.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-se-15.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-se-16.png
Normal file
After Width: | Height: | Size: 3.9 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-se-17.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-se-2.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-se-3.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-se-4.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-se-5.png
Normal file
After Width: | Height: | Size: 8.6 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-se-6.png
Normal file
After Width: | Height: | Size: 6.6 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-se-7.png
Normal file
After Width: | Height: | Size: 3.7 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-se-8.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
data/core/images/halo/dragonguard/dg-muzzle-flash-se-9.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
BIN
data/core/images/maps/l10n/pt/titlescreen--overlay.png
Normal file
After Width: | Height: | Size: 2.2 MiB |
Before Width: | Height: | Size: 963 B |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 889 B |
Before Width: | Height: | Size: 960 B |
Before Width: | Height: | Size: 1.2 KiB |