Fix luacheck warnings and add to CI.

Note the `exclude_files` in .luacheckrc should be deleted once the eventual Ubuntu 22.04 base image has an updated luacheck that supports lua 5.4.
This commit is contained in:
Pentarctagon 2021-11-22 16:04:41 -06:00 committed by Pentarctagon
parent 254716e41e
commit 370d03ccb7
79 changed files with 455 additions and 477 deletions

View file

@ -127,6 +127,7 @@ if [ "$CFG" == "debug" ]; then
fi
execute "WML validation" ./utils/CI/schema_validation.sh
execute "Luacheck linting" luacheck .
execute "Whitespace and WML indentation check" checkindent
execute "Doxygen check" ./utils/CI/doxygen-check.sh
execute "WML tests" ./run_wml_tests -g -c -t 20

17
.luacheckrc Normal file
View file

@ -0,0 +1,17 @@
-- ignore line length warnings
max_line_length=false
max_code_line_length=false
max_string_line_length=false
max_comment_line_length=false
-- show the warning/error codes as well
codes=true
-- don't show files with no issues
quiet=1
-- don't show undefined variable usage
-- there are thousands of warnings here because luacheck is unaware of Wesnoth's lua environment and has no way to check which have been loaded
global=false
-- don't show unused variables
unused=false
-- excluded files due to using lua 5.4 syntax that currently gets flagged as a syntax error
-- clear out once a newer Ubuntu LTS base is used for our docker images, which would then also have a newer luacheck available
exclude_files={"data/lua/core/wml.lua","data/lua/wml-flow.lua","data/lua/wml/find_path.lua","data/lua/wml/harm_unit.lua","data/lua/wml/modify_unit.lua","data/lua/wml/random_placement.lua"}

View file

@ -376,8 +376,8 @@ function ai_helper.robust_move_and_attack(ai, src, dst, target_loc, cfg)
end
-- Check whether dst hex is free now (an event could have done something funny)
local unit_in_way = wesnoth.units.get(dst_x, dst_y)
if unit_in_way then
local unit_in_way_temp = wesnoth.units.get(dst_x, dst_y)
if unit_in_way_temp then
return ai_helper.dummy_check_action(true, false, 'robust_move_and_attack::ANOTHER_UNIT_IN_WAY')
end
@ -516,7 +516,8 @@ end
function ai_helper.split(str, sep)
-- Split string @str into a table using the delimiter @sep (default: ',')
local sep, fields = sep or ",", {}
sep = sep or ","
local fields = {}
local pattern = string.format("([^%s]+)", sep)
string.gsub(str, pattern, function(c) fields[#fields+1] = c end)
return fields
@ -1277,7 +1278,7 @@ function ai_helper.get_closest_enemy(loc, side, cfg)
x, y = loc[1], loc[2]
end
local closest_distance, closest_enemy = math.huge
local closest_distance, closest_enemy = math.huge, nil
for _,enemy in ipairs(enemies) do
local enemy_distance = M.distance_between(x, y, enemy)
if (enemy_distance < closest_distance) then
@ -1360,19 +1361,19 @@ function ai_helper.get_dst_src_units(units, cfg)
local dstsrc = LS.create()
for _,unit in ipairs(units) do
local tmp = unit.moves
local tmp_moves = unit.moves
if max_moves then
unit.moves = unit.max_moves
end
local reach = wesnoth.paths.find_reach(unit, cfg)
if max_moves then
unit.moves = tmp
unit.moves = tmp_moves
end
for _,loc in ipairs(reach) do
local tmp = dstsrc:get(loc[1], loc[2]) or {}
table.insert(tmp, { x = unit.x, y = unit.y })
dstsrc:insert(loc[1], loc[2], tmp)
local tmp_dst = dstsrc:get(loc[1], loc[2]) or {}
table.insert(tmp_dst, { x = unit.x, y = unit.y })
dstsrc:insert(loc[1], loc[2], tmp_dst)
end
end
@ -1538,13 +1539,13 @@ function ai_helper.next_hop(unit, x, y, cfg)
unit:to_map(old_x, old_y)
unit_in_way:to_map()
local terrain = wesnoth.current.map[next_hop_ideal]
local move_cost_endpoint = unit:movement_on(terrain)
local terrain1 = wesnoth.current.map[next_hop_ideal]
local move_cost_endpoint = unit:movement_on(terrain1)
local inverse_reach_map = LS.create()
for _,r in pairs(inverse_reach) do
-- We want the moves left for moving into the opposite direction in which the reach map was calculated
local terrain = wesnoth.current.map[r]
local move_cost = unit:movement_on(terrain)
local terrain2 = wesnoth.current.map[r]
local move_cost = unit:movement_on(terrain2)
local inverse_cost = r[3] + move_cost - move_cost_endpoint
inverse_reach_map:insert(r[1], r[2], inverse_cost)
end
@ -1914,9 +1915,9 @@ function ai_helper.find_path_with_avoid(unit, x, y, avoid_map, options)
local enemy_zoc_map = LS.create()
if (not options.ignore_enemies) and (not unit:ability("skirmisher")) then
enemy_map:iter(function(x, y, level)
enemy_map:iter(function(xx, yy, level)
if (level > 0) then
for xa,ya in wesnoth.current.map:iter_adjacent(x, y) do
for xa,ya in wesnoth.current.map:iter_adjacent(xx, yy) do
enemy_zoc_map:insert(xa, ya, level)
end
end
@ -1952,7 +1953,7 @@ function ai_helper.find_best_move(units, rating_function, cfg)
-- If this is an individual unit, turn it into an array
if units.hitpoints then units = { units } end
local max_rating, best_hex, best_unit = - math.huge
local max_rating, best_hex, best_unit = - math.huge, nil, nil
for _,unit in ipairs(units) do
-- Hexes each unit can reach
local reach_map = ai_helper.get_reachable_unocc(unit, cfg)
@ -2000,7 +2001,7 @@ function ai_helper.move_unit_out_of_way(ai, unit, cfg)
local reach = wesnoth.paths.find_reach(unit, cfg)
local reach_map = LS.create()
local max_rating, best_hex = - math.huge
local max_rating, best_hex = - math.huge, nil
for _,loc in ipairs(reach) do
local unit_in_way = wesnoth.units.get(loc[1], loc[2])
if (not unit_in_way) -- also excludes current hex

View file

@ -353,20 +353,20 @@ function battle_calcs.battle_outcome_coefficients(cfg, cache)
-- This is so that they can be grouped by number of attacker hits/misses, for
-- subsequent simplification
-- The element value is number of times we get the given combination of hits/misses
local counts = {}
local counts1 = {}
for _,count in ipairs(hit_miss_counts) do
local i1 = count.hit_miss_counts[1]
local i2 = count.hit_miss_counts[2]
local i3 = count.hit_miss_counts[3]
local i4 = count.hit_miss_counts[4]
if not counts[i1] then counts[i1] = {} end
if not counts[i1][i2] then counts[i1][i2] = {} end
if not counts[i1][i2][i3] then counts[i1][i2][i3] = {} end
counts[i1][i2][i3][i4] = (counts[i1][i2][i3][i4] or 0) + 1
if not counts1[i1] then counts1[i1] = {} end
if not counts1[i1][i2] then counts1[i1][i2] = {} end
if not counts1[i1][i2][i3] then counts1[i1][i2][i3] = {} end
counts1[i1][i2][i3][i4] = (counts1[i1][i2][i3][i4] or 0) + 1
end
local coeffs_def = {}
for am,v1 in pairs(counts) do -- attacker miss count
for am,v1 in pairs(counts1) do -- attacker miss count
for ah,v2 in pairs(v1) do -- attacker hit count
-- Set up the exponent coefficients for attacker hits/misses
local exp = {} -- Array for an individual set of coefficients
@ -414,20 +414,20 @@ function battle_calcs.battle_outcome_coefficients(cfg, cache)
-- Now we do the same for the HP distribution of the attacker,
-- which means everything needs to be sorted by defender hits
local counts = {}
local counts2 = {}
for _,count in ipairs(hit_miss_counts) do
local i1 = count.hit_miss_counts[3] -- note that the order here is different from above
local i2 = count.hit_miss_counts[4]
local i3 = count.hit_miss_counts[1]
local i4 = count.hit_miss_counts[2]
if not counts[i1] then counts[i1] = {} end
if not counts[i1][i2] then counts[i1][i2] = {} end
if not counts[i1][i2][i3] then counts[i1][i2][i3] = {} end
counts[i1][i2][i3][i4] = (counts[i1][i2][i3][i4] or 0) + 1
if not counts2[i1] then counts2[i1] = {} end
if not counts2[i1][i2] then counts2[i1][i2] = {} end
if not counts2[i1][i2][i3] then counts2[i1][i2][i3] = {} end
counts2[i1][i2][i3][i4] = (counts2[i1][i2][i3][i4] or 0) + 1
end
local coeffs_att = {}
for dm,v1 in pairs(counts) do -- defender miss count
for dm,v1 in pairs(counts2) do -- defender miss count
for dh,v2 in pairs(v1) do -- defender hit count
-- Set up the exponent coefficients for attacker hits/misses
local exp = {} -- Array for an individual set of coefficients
@ -475,25 +475,25 @@ function battle_calcs.battle_outcome_coefficients(cfg, cache)
-- The probability for the number of hits with the most terms can be skipped
-- and 1-sum(other_terms) can be used instead. Set a flag for which term to skip
local max_number, biggest_equation = 0, -1
local max_number1, biggest_equation1 = 0, -1
for hits,v in pairs(coeffs_att) do
local number = 0
for _,c in pairs(v) do number = number + 1 end
if (number > max_number) then
max_number, biggest_equation = number, hits
if (number > max_number1) then
max_number1, biggest_equation1 = number, hits
end
end
coeffs_att[biggest_equation].skip = true
coeffs_att[biggest_equation1].skip = true
local max_number, biggest_equation = 0, -1
local max_number2, biggest_equation2 = 0, -1
for hits,v in pairs(coeffs_def) do
local number = 0
for _,c in pairs(v) do number = number + 1 end
if (number > max_number) then
max_number, biggest_equation = number, hits
if (number > max_number2) then
max_number2, biggest_equation2 = number, hits
end
end
coeffs_def[biggest_equation].skip = true
coeffs_def[biggest_equation2].skip = true
if cache then cache[cind] = { coeffs_att = coeffs_att, coeffs_def = coeffs_def } end
@ -692,11 +692,11 @@ function battle_calcs.battle_outcome(attacker, defender, cfg, cache)
local def_firstrike = false
if def_attack and def_attack.firststrike then def_firstrike = true end
local cfg = {
local att_def_cfg = {
att = { strikes = att_strikes, max_hits = att_max_hits, firststrike = att_attack.firststrike },
def = { strikes = def_strikes, max_hits = def_max_hits, firststrike = def_firstrike }
}
local att_coeffs, def_coeffs = battle_calcs.battle_outcome_coefficients(cfg, cache)
local att_coeffs, def_coeffs = battle_calcs.battle_outcome_coefficients(att_def_cfg, cache)
-- And multiply out the factors
-- Note that att_hit_prob, def_hit_prob need to be in that order for both calls
@ -798,36 +798,36 @@ function battle_calcs.attack_rating(attacker, defender, dst, cfg, cache)
-- It is multiplied by unit cost later, to get a gold equivalent value
-- Average damage to unit is negative rating
local damage = attacker.hitpoints - att_stats.average_hp
local att_damage = attacker.hitpoints - att_stats.average_hp
-- Count poisoned as additional damage done by poison times probability of being poisoned
if (att_stats.poisoned ~= 0) then
damage = damage + wesnoth.game_config.poison_amount * (att_stats.poisoned - att_stats.hp_chance[0])
att_damage = att_damage + wesnoth.game_config.poison_amount * (att_stats.poisoned - att_stats.hp_chance[0])
end
-- Count slowed as additional 6 HP damage times probability of being slowed
if (att_stats.slowed ~= 0) then
damage = damage + 6 * (att_stats.slowed - att_stats.hp_chance[0])
att_damage = att_damage + 6 * (att_stats.slowed - att_stats.hp_chance[0])
end
local map = wesnoth.current.map
-- If attack is from a healing location, count that as slightly more than the healing amount
damage = damage - 1.25 * wesnoth.terrain_types[map[dst]].healing
att_damage = att_damage - 1.25 * wesnoth.terrain_types[map[dst]].healing
-- Equivalently, if attack is adjacent to an unoccupied healing location, that's bad
for xa,ya in wesnoth.current.map:iter_adjacent(dst) do
local healing = wesnoth.terrain_types[map[{xa, ya}]].healing
if (healing > 0) and (not wesnoth.units.get(xa, ya)) then
damage = damage + 1.25 * healing
att_damage = att_damage + 1.25 * healing
end
end
if (damage < 0) then damage = 0 end
if (att_damage < 0) then att_damage = 0 end
-- Fraction damage (= fractional value of the unit)
local value_fraction = - damage / attacker.max_hitpoints
local att_value_fraction = - att_damage / attacker.max_hitpoints
-- Additional, subtract the chance to die, in order to (de)emphasize units that might die
value_fraction = value_fraction - att_stats.hp_chance[0]
att_value_fraction = att_value_fraction - att_stats.hp_chance[0]
-- In addition, potentially leveling up in this attack is a huge bonus,
-- proportional to the chance of it happening and the chance of not dying itself
@ -841,40 +841,40 @@ function battle_calcs.attack_rating(attacker, defender, dst, cfg, cache)
level_bonus = (1. - att_stats.hp_chance[0]) * def_stats.hp_chance[0]
end
end
value_fraction = value_fraction + level_bonus * level_weight
att_value_fraction = att_value_fraction + level_bonus * level_weight
-- Now convert this into gold-equivalent value
local attacker_value = attacker.cost
-- Being closer to leveling is good (this makes AI prefer units with lots of XP)
local xp_bonus = attacker.experience / attacker.max_experience
attacker_value = attacker_value * (1. + xp_bonus * xp_weight)
local att_xp_bonus = attacker.experience / attacker.max_experience
attacker_value = attacker_value * (1. + att_xp_bonus * xp_weight)
local attacker_rating = value_fraction * attacker_value
local attacker_rating = att_value_fraction * attacker_value
------ Now (most of) the same for the defender ------
-- Average damage to defender is positive rating
local damage = defender.hitpoints - def_stats.average_hp
local def_damage = defender.hitpoints - def_stats.average_hp
-- Count poisoned as additional damage done by poison times probability of being poisoned
if (def_stats.poisoned ~= 0) then
damage = damage + wesnoth.game_config.poison_amount * (def_stats.poisoned - def_stats.hp_chance[0])
def_damage = def_damage + wesnoth.game_config.poison_amount * (def_stats.poisoned - def_stats.hp_chance[0])
end
-- Count slowed as additional 6 HP damage times probability of being slowed
if (def_stats.slowed ~= 0) then
damage = damage + 6 * (def_stats.slowed - def_stats.hp_chance[0])
def_damage = def_damage + 6 * (def_stats.slowed - def_stats.hp_chance[0])
end
-- If defender is on a healing location, count that as slightly more than the healing amount
damage = damage - 1.25 * wesnoth.terrain_types[map[defender]].healing
def_damage = def_damage - 1.25 * wesnoth.terrain_types[map[defender]].healing
if (damage < 0) then damage = 0. end
if (def_damage < 0) then damage = 0. end
-- Fraction damage (= fractional value of the unit)
local value_fraction = damage / defender.max_hitpoints
local def_value_fraction = def_damage / defender.max_hitpoints
-- Additional, add the chance to kill, in order to emphasize enemies we might be able to kill
value_fraction = value_fraction + def_stats.hp_chance[0]
def_value_fraction = def_value_fraction + def_stats.hp_chance[0]
-- In addition, the defender potentially leveling up in this attack is a huge penalty,
-- proportional to the chance of it happening and the chance of not dying itself
@ -888,7 +888,7 @@ function battle_calcs.attack_rating(attacker, defender, dst, cfg, cache)
defender_level_penalty = (1. - def_stats.hp_chance[0]) * att_stats.hp_chance[0]
end
end
value_fraction = value_fraction - defender_level_penalty * defender_level_weight
def_value_fraction = def_value_fraction - defender_level_penalty * defender_level_weight
-- Now convert this into gold-equivalent value
local defender_value = defender.cost
@ -903,8 +903,8 @@ function battle_calcs.attack_rating(attacker, defender, dst, cfg, cache)
defender_value = defender_value * (1. + defender_starting_damage_fraction * defender_starting_damage_weight)
-- Being closer to leveling is good, we want to get rid of those enemies first
local xp_bonus = defender.experience / defender.max_experience
defender_value = defender_value * (1. + xp_bonus * xp_weight)
local def_xp_bonus = defender.experience / defender.max_experience
defender_value = defender_value * (1. + def_xp_bonus * xp_weight)
-- If defender is on a village, add a bonus rating (we want to get rid of those preferentially)
-- So yes, this is positive, even though it's a plus for the defender
@ -945,7 +945,7 @@ function battle_calcs.attack_rating(attacker, defender, dst, cfg, cache)
end
end
local defender_rating = value_fraction * defender_value
local defender_rating = def_value_fraction * defender_value
-- Finally apply factor of own unit weight to defender unit weight
attacker_rating = attacker_rating * own_value_weight
@ -1104,12 +1104,12 @@ function battle_calcs.attack_combo_stats(tmp_attackers, tmp_dsts, defender, cach
end
-- Get the average HP
local av_hp = 0
for hp,prob in pairs(att_stats[i].hp_chance) do av_hp = av_hp + hp * prob end
att_stats[i].average_hp = av_hp
local av_hp = 0
for hp,prob in pairs(def_stats[i].hp_chance) do av_hp = av_hp + hp * prob end
def_stats[i].average_hp = av_hp
local att_av_hp = 0
for hp,prob in pairs(att_stats[i].hp_chance) do att_av_hp = att_av_hp + hp * prob end
att_stats[i].average_hp = att_av_hp
local def_av_hp = 0
for hp,prob in pairs(def_stats[i].hp_chance) do def_av_hp = def_av_hp + hp * prob end
def_stats[i].average_hp = def_av_hp
end
-- Get the total rating for this attack combo:
@ -1161,10 +1161,10 @@ function battle_calcs.get_attack_map_unit(unit, cfg)
local units_MP = {}
if (unit.side ~= wesnoth.current.side) then
local all_units = wesnoth.units.find_on_map { side = wesnoth.current.side }
for _,unit in ipairs(all_units) do
if (unit.moves > 0) then
table.insert(units_MP, unit)
unit:extract()
for _,a_unit in ipairs(all_units) do
if (a_unit.moves > 0) then
table.insert(units_MP, a_unit)
a_unit:extract()
end
end
end
@ -1376,10 +1376,10 @@ function battle_calcs.get_attack_combos_subset(units, enemy, cfg)
----- begin add_attack() -----
-- Recursive local function adding another attack to the current combo
-- and adding the current combo to the overall attack_combos array
local function add_attack(attacks, reachable_hexes, n_reach, attack_combos, combos_str, current_combo, hexes_used, cfg)
local function add_attack(attacks, reachable_hexes, n_reach, attack_combos, combos_str, current_combo, hexes_used, inner_cfg)
local time_up = false
if cfg.max_time and (wesnoth.ms_since_init() / 1000. - cfg.start_time >= cfg.max_time) then
if inner_cfg.max_time and (wesnoth.ms_since_init() / 1000. - inner_cfg.start_time >= inner_cfg.max_time) then
time_up = true
end
@ -1390,18 +1390,18 @@ function battle_calcs.get_attack_combos_subset(units, enemy, cfg)
for _,att in ipairs(attack) do
-- But only if this hex is not used yet and
-- the cutoff criteria are not met
if (not hexes_used[att.dst]) and (not time_up) and (#attack_combos < cfg.max_combos) then
if (not hexes_used[att.dst]) and (not time_up) and (#attack_combos < inner_cfg.max_combos) then
-- Mark this hex as used by this unit
hexes_used[att.dst] = attack.src
-- Set up a string uniquely identifying the unit/attack hex pairs
-- for current_combo. This is used to exclude pairs that already
-- exist in a different order (if 'cfg.order_matters' is not set)
-- exist in a different order (if 'inner_cfg.order_matters' is not set)
-- For this, we also add the numerical value of the attack_hex to
-- the 'hexes_used' table (in addition to the line above)
local str = ''
if (not cfg.order_matters) then
if (not inner_cfg.order_matters) then
hexes_used[reachable_hexes[att.dst]] = attack.src
for ind_hex = 1,n_reach do
if hexes_used[ind_hex] then
@ -1413,12 +1413,12 @@ function battle_calcs.get_attack_combos_subset(units, enemy, cfg)
end
-- 'combos_str' contains all the strings of previous combos
-- (if 'cfg.order_matters' is not set)
-- (if 'inner_cfg.order_matters' is not set)
-- Only add this combo if it does not yet exist
if (not combos_str[str]) then
-- Add the string identifyer to the array
if (not cfg.order_matters) then
if (not inner_cfg.order_matters) then
combos_str[str] = true
end
@ -1443,7 +1443,7 @@ function battle_calcs.get_attack_combos_subset(units, enemy, cfg)
end
-- And mark the hex as usable again
if (not cfg.order_matters) then
if (not inner_cfg.order_matters) then
hexes_used[reachable_hexes[att.dst]] = nil
end
hexes_used[att.dst] = nil

View file

@ -84,15 +84,15 @@ function ca_castle_switch:evaluation(cfg, data, filter_own, recruiting_leader)
}, true)
end
local leader
local non_passive_leader
for _,l in pairs(leaders) do
if (not AH.is_passive_leader(ai.aspects.passive_leader, l.id)) then
leader = l
non_passive_leader = l
break
end
end
if not leader then
if not non_passive_leader then
-- CA is irrelevant if no leader or the leader may have moved from another CA
data.CS_leader, data.CS_leader_target = nil, nil
if AH.print_eval() then AH.done_eval_messages(start_time, ca_name) end
@ -124,7 +124,7 @@ function ca_castle_switch:evaluation(cfg, data, filter_own, recruiting_leader)
-- Look for the best keep
local overall_best_score = 0
for _,leader in ipairs(leaders) do
local best_score, best_loc, best_turns, best_path = 0, {}, 3
local best_score, best_loc, best_turns, best_path = 0, {}, 3, nil
local keeps = AH.get_locations_no_borders {
terrain = 'K*,K*^*,*^K*', -- Keeps
{ "not", { {"filter", {}} }}, -- That have no unit
@ -250,7 +250,7 @@ function ca_castle_switch:execution(cfg, data, filter_own)
if AH.show_messages() then wesnoth.wml_actions.message { speaker = data.leader.id, message = 'Switching castles' } end
AH.robust_move_and_attack(ai, data.CS_leader, data.CS_leader_target, nil, { partial_move = true })
data.CS_leader, data.CS_leader_target = nil
data.CS_leader, data.CS_leader_target = nil, nil
end
return ca_castle_switch

View file

@ -55,7 +55,7 @@ function ca_grab_villages:evaluation(cfg, data, filter_own)
local enemy_attack_map = BC.get_attack_map(enemies).units
-- Now we go through the villages and units
local max_rating, best_village, best_unit = - math.huge
local max_rating, best_village, best_unit = - math.huge, nil, nil
local village_ratings = {}
for j,v in ipairs(villages) do
-- First collect all information that only depends on the village

View file

@ -94,7 +94,7 @@ function ca_attack_highxp:evaluation(cfg, data, filter_own)
local aggression = ai.aspects.aggression
local avoid_map = LS.of_pairs(ai.aspects.avoid)
local max_ca_score, max_rating, best_attack = 0, 0
local max_ca_score, max_rating, best_attack = 0, 0, nil
for _,target_info in ipairs(target_infos) do
local target = attacks_aspect.enemy[target_info.ind_target]
local can_force_level = {}

View file

@ -35,8 +35,8 @@ function ca_move_to_any_enemy:evaluation(cfg, data, filter_own)
-- Find first unit that can reach a hex adjacent to an enemy, and find closest enemy of those reachable.
-- This does not need to find the absolutely best combination, close to that is good enough.
for i,u in ipairs(units) do
local best_cost, best_path, best_enemy = AH.no_path
for i,e in ipairs(enemies) do
local best_cost, best_path, best_enemy = AH.no_path, nil, nil
for j,e in ipairs(enemies) do
-- We only need to look at adjacent hexes. And we don't worry whether they
-- are occupied by other enemies. If that is the case, no path will be found,
-- but one of those enemies will later be found as potential target.

View file

@ -44,7 +44,7 @@ function ca_spread_poison:evaluation(cfg, data, filter_own)
local avoid_map = LS.of_pairs(ai.aspects.avoid)
-- Go through all possible attacks with poisoners
local max_rating, best_attack = - math.huge
local max_rating, best_attack = - math.huge, nil
for i,a in ipairs(attacks) do
if target_map:get(a.target.x, a.target.y) and (not avoid_map:get(a.dst.x, a.dst.y)) then
local attacker = wesnoth.units.get(a.src.x, a.src.y)

View file

@ -14,11 +14,11 @@ function ca_village_hunt:evaluation(cfg, data, filter_own)
local start_time, ca_name = wesnoth.ms_since_init() / 1000., 'village_hunt'
if AH.print_eval() then AH.print_ts(' - Evaluating village_hunt CA:') end
local avoid_map = LS.of_pairs(ai.aspects.avoid)
local avoid_map1 = LS.of_pairs(ai.aspects.avoid)
local all_villages, villages = wesnoth.map.find{gives_income = true}, {}
for _,village in ipairs(all_villages) do
if (not avoid_map:get(village[1], village[2])) then
if (not avoid_map1:get(village[1], village[2])) then
table.insert(villages, village)
end
end
@ -60,16 +60,16 @@ function ca_village_hunt:evaluation(cfg, data, filter_own)
return 0
end
local avoid_map = AH.get_avoid_map(ai, nil, true)
local avoid_map2 = AH.get_avoid_map(ai, nil, true)
VH_unit = nil
for _,unit in ipairs(units) do
local best_cost = AH.no_path
for i,v in ipairs(villages) do
if not wesnoth.map.matches(v, { {"filter_owner", { {"ally_of", { side = wesnoth.current.side }} }} }) then
local path, cost = AH.find_path_with_avoid(unit, v[1], v[2], avoid_map)
local path, cost = AH.find_path_with_avoid(unit, v[1], v[2], avoid_map2)
if (cost < best_cost) then
local dst = AH.next_hop(unit, nil, nil, { path = path, avoid_map = avoid_map })
local dst = AH.next_hop(unit, nil, nil, { path = path, avoid_map = avoid_map2 })
if (dst[1] ~= unit.x) or (dst[2] ~= unit.y) then
best_cost = cost
VH_unit = unit

View file

@ -487,7 +487,7 @@ return {
for i, unit_type in ipairs(enemy_types) do
enemy_type_count = enemy_type_count + 1
local poison_vulnerable = false
for i, recruit_id in ipairs(wesnoth.sides[wesnoth.current.side].recruit) do
for j, recruit_id in ipairs(wesnoth.sides[wesnoth.current.side].recruit) do
local analysis = recruit_lib.analyze_enemy_unit(unit_type, recruit_id)
if not recruit_effectiveness[recruit_id] then
@ -933,7 +933,7 @@ return {
-- If castle_switch CA makes the unit end up on a village, skip one village for the leader.
-- Also do so if the leader is not passive. Note that the castle_switch CA will also return zero
-- when the leader is passive, but not only in that case.
local ltv_score, skip_one_village = 0
local ltv_score, skip_one_village = 0, nil
if params.leader_takes_village then
ltv_score, skip_one_village = params.leader_takes_village(leader)
end

View file

@ -23,10 +23,12 @@ function retreat_functions.min_hp(unit)
local retreat_factor = ai.aspects.retreat_factor
-- Leaders are more valuable and should retreat earlier
if unit.canrecruit then retreat_factor = retreat_factor * 1.5 end
if unit.canrecruit then
retreat_factor = retreat_factor * 1.5
end
-- Higher retreat willingness on bad terrain
local retreat_factor = retreat_factor * (100 - unit:defense_on(wesnoth.current.map[unit])) / 50
retreat_factor = retreat_factor * (100 - unit:defense_on(wesnoth.current.map[unit])) / 50
local min_hp = retreat_factor * unit.max_hitpoints
@ -62,9 +64,9 @@ function retreat_functions.retreat_injured_units(units, avoid_map)
local abilities = wml.get_child(u.__cfg, "abilities")
local regen_amount = 0
if abilities then
for regen in wml.child_range(abilities, "regenerate") do
if regen.value > regen_amount then
regen_amount = regen.value
for regenerates in wml.child_range(abilities, "regenerate") do
if regenerates.value > regen_amount then
regen_amount = regenerates.value
end
end
end
@ -149,7 +151,7 @@ function retreat_functions.get_retreat_injured_units(healees, regen_amounts, avo
ally_attack_map = BC.get_attack_map(allies)
end
local max_rating, best_loc, best_unit = - math.huge
local max_rating, best_loc, best_unit = - math.huge, nil, nil
for i,u in ipairs(healees) do
local possible_locations = wesnoth.paths.find_reach(u)
-- TODO: avoid ally's villages (may be preferable to lower rating so they will

View file

@ -55,7 +55,7 @@ function ca_big_animals:execution(cfg)
end)
-- Now find the one of these hexes that is closest to the goal
local max_rating, best_hex = - math.huge
local max_rating, best_hex = - math.huge, nil
reach_map:iter( function(x, y, v)
local rating = -wesnoth.map.distance_between(x, y, goal.goal_x, goal.goal_y)
@ -92,7 +92,7 @@ function ca_big_animals:execution(cfg)
end
-- Finally, if the unit ended up next to enemies, attack the weakest of those
local min_hp, target = math.huge
local min_hp, target = math.huge, nil
for xa,ya in wesnoth.current.map:iter_adjacent(unit) do
local enemy = wesnoth.units.get(xa, ya)
if AH.is_attackable_enemy(enemy) then

View file

@ -14,7 +14,7 @@ function ca_bottleneck_attack:evaluation(cfg, data)
}
if (not attackers[1]) then return 0 end
local max_rating, best_attacker, best_target, best_weapon = - math.huge
local max_rating, best_attacker, best_target, best_weapon = - math.huge, nil, nil, nil
for _,attacker in ipairs(attackers) do
local targets = AH.get_attackable_enemies { { "filter_adjacent", { id = attacker.id } } }

View file

@ -26,7 +26,7 @@ local function bottleneck_is_my_territory(map, enemy_map)
dummy_unit.x, dummy_unit.y = x, y
-- Find lowest movement cost to own front-line hexes
local min_cost, best_path = math.huge
local min_cost, best_path = math.huge, nil
map:iter(function(xm, ym, v)
local path, cost = AH.find_path_with_shroud(dummy_unit, xm, ym, { ignore_units = true })
if (cost < min_cost) then
@ -35,7 +35,7 @@ local function bottleneck_is_my_territory(map, enemy_map)
end)
-- And the same to the enemy front line
local min_cost_enemy, best_path_enemy = math.huge
local min_cost_enemy, best_path_enemy = math.huge, nil
enemy_map:iter(function(xm, ym, v)
local path, cost = AH.find_path_with_shroud(dummy_unit, xm, ym, { ignore_units = true })
if (cost < min_cost_enemy) then
@ -193,7 +193,7 @@ local function bottleneck_move_out_of_way(unit_in_way, data)
occ_hexes:insert(unit.x, unit.y)
end
local best_reach, best_hex = - math.huge
local best_reach, best_hex = - math.huge, nil
for _,loc in ipairs(reach) do
if BD_is_my_territory:get(loc[1], loc[2]) and (not occ_hexes:get(loc[1], loc[2])) then
-- Criterion: MP left after the move has been done
@ -327,12 +327,12 @@ function ca_bottleneck_move:evaluation(cfg, data)
if (not AH.is_visible_unit(wesnoth.current.side, unit_in_way)) then
unit_in_way = nil
end
local data = { x = xa, y = ya,
local defender_data = { x = xa, y = ya,
defender = enemy,
defender_level = enemy.level,
unit_in_way = unit_in_way
}
table.insert(attacks, data)
table.insert(attacks, defender_data)
end
end
end
@ -349,7 +349,7 @@ function ca_bottleneck_move:evaluation(cfg, data)
allies_map:insert(ally.x, ally.y)
end
local max_rating, best_unit, best_hex = 0
local max_rating, best_unit, best_hex = 0, nil, nil
for _,unit in ipairs(units) do
local is_healer = (unit.usage == "healer")
local has_leadership = unit:matches { ability_type = "leadership" }
@ -475,8 +475,8 @@ function ca_bottleneck_move:execution(cfg, data)
end
else
-- Don't want full move, as this might be stepping out of the way
local cfg = { partial_move = true, weapon = BD_level_up_weapon }
AH.robust_move_and_attack(ai, BD_unit, BD_hex, BD_level_up_defender, cfg)
local move_attack_cfg = { partial_move = true, weapon = BD_level_up_weapon }
AH.robust_move_and_attack(ai, BD_unit, BD_hex, BD_level_up_defender, move_attack_cfg)
end
-- Now delete almost everything

View file

@ -83,10 +83,10 @@ function ca_coward:execution(cfg)
-- As final step, if there are more than one remaining locations,
-- we take the one with the minimum score in the distance-from-enemy criterion
local max_rating, best_hex = - math.huge
local max_rating1, best_hex = - math.huge, nil
for _,pos in ipairs(best_overall) do
if (pos[3] > max_rating) then
max_rating, best_hex = pos[3], pos
if (pos[3] > max_rating1) then
max_rating1, best_hex = pos[3], pos
end
end
@ -95,14 +95,14 @@ function ca_coward:execution(cfg)
-- If 'attack_if_trapped' is set, the coward attacks the weakest unit it ends up next to
if cfg.attack_if_trapped then
local max_rating, best_target = - math.huge
local max_rating2, best_target = - math.huge, nil
for xa,ya in wesnoth.current.map:iter_adjacent(coward) do
local target = wesnoth.units.get(xa, ya)
if target and wesnoth.sides.is_enemy(coward.side, target.side) then
local rating = - target.hitpoints
if (rating > max_rating) then
max_rating, best_target = rating, target
if (rating > max_rating2) then
max_rating2, best_target = rating, target
end
end
end

View file

@ -87,7 +87,7 @@ function ca_fast_combat:evaluation(cfg, data)
local attacks = AH.get_attacks({ unit }, { include_occupied = cfg.include_occupied_attack_hexes, viewing_side = viewing_side, ignore_visibility = ignore_visibility })
if (#attacks > 0) then
local max_rating, best_target, best_dst = - math.huge
local max_rating, best_target, best_dst = - math.huge, nil, nil
for _,attack in ipairs(attacks) do
if enemy_map:get(attack.target.x, attack.target.y)
and (not avoid_map:get(attack.dst.x, attack.dst.y))

View file

@ -73,14 +73,14 @@ function ca_fast_combat_leader:evaluation(cfg, data)
-- Enemy power and number maps
-- Currently, the power is simply the summed hitpoints of all enemies that
-- can get to a hex
local enemies = AH.get_live_units {
local live_enemies = AH.get_live_units {
{ "filter_side", { { "enemy_of", { side = wesnoth.current.side } } } }
}
local enemy_power_map = LS.create()
local enemy_number_map = LS.create()
for _,enemy in ipairs(enemies) do
for _,enemy in ipairs(live_enemies) do
-- Only need to consider enemies that are close enough
if (wesnoth.map.distance_between(leader.x, leader.y, enemy.x, enemy.y) <= (enemy.max_moves + leader.max_moves + 1)) then
local enemy_power = enemy.hitpoints
@ -121,7 +121,7 @@ function ca_fast_combat_leader:evaluation(cfg, data)
local attacks = AH.get_attacks({ leader }, { include_occupied = cfg.include_occupied_attack_hexes, viewing_side = viewing_side, ignore_visibility = ignore_visibility })
if (#attacks > 0) then
local max_rating, best_target, best_dst = - math.huge
local max_rating, best_target, best_dst = - math.huge, nil, nil
for _,attack in ipairs(attacks) do
if enemy_map:get(attack.target.x, attack.target.y)
and (not avoid_map:get(attack.dst.x, attack.dst.y))

View file

@ -142,7 +142,7 @@ function ca_fast_move:execution(cfg)
if (next_goal > #goals) then next_goal = 1 end
local goal = goals[next_goal]
local max_rating, best_unit_info = - math.huge
local max_rating1, best_unit_info = - math.huge, nil
for _,unit_info in ipairs(goal) do
if (not unit_info.cost) then
local _,cost =
@ -160,8 +160,8 @@ function ca_fast_move:execution(cfg)
break
elseif (unit_info.cost < 1000) then
local rating = - unit_info.cost
if (rating > max_rating) then
max_rating, best_unit_info = rating, unit_info
if (rating > max_rating1) then
max_rating1, best_unit_info = rating, unit_info
end
end
end
@ -197,7 +197,7 @@ function ca_fast_move:execution(cfg)
local reach = wesnoth.paths.find_reach(unit)
local pre_ratings = {}
local max_rating, best_hex = - math.huge
local max_rating2, best_hex = - math.huge, nil
for _,loc in ipairs(reach) do
if (not avoid_map:get(loc[1], loc[2])) then
local rating = -M.distance_between(loc[1], loc[2], short_goal[1], short_goal[2])
@ -205,15 +205,15 @@ function ca_fast_move:execution(cfg)
rating = rating + other_rating
local unit_in_way
if (rating > max_rating) then
if (rating > max_rating2) then
unit_in_way = wesnoth.units.get(loc[1], loc[2])
if (unit_in_way == unit) or (not AH.is_visible_unit(wesnoth.current.side, unit_in_way)) then
unit_in_way = nil
end
if unit_in_way and (unit_in_way.side == unit.side) then
local reach = AH.get_reachable_unocc(unit_in_way)
if (reach:size() > 1) then
local reach_unocc = AH.get_reachable_unocc(unit_in_way)
if (reach_unocc:size() > 1) then
unit_in_way = nil
rating = rating - 0.01
other_rating = other_rating - 0.01
@ -229,8 +229,8 @@ function ca_fast_move:execution(cfg)
x = loc[1], y = loc[2]
})
else
if (rating > max_rating) then
max_rating, best_hex = rating, { loc[1], loc[2] }
if (rating > max_rating2) then
max_rating2, best_hex = rating, { loc[1], loc[2] }
end
end
end
@ -245,20 +245,20 @@ function ca_fast_move:execution(cfg)
unit:extract()
local old_x, old_y = unit.x, unit.y
local max_rating = - math.huge
local max_rating3 = - math.huge
for _,pre_rating in ipairs(pre_ratings) do
-- If pre_rating is worse than the full rating, we are done because the
-- move cost can never be less than the distance, so we cannot possibly do
-- better than the pre-rating
if (pre_rating.rating <= max_rating) then break end
if (pre_rating.rating <= max_rating3) then break end
unit.x, unit.y = pre_rating.x, pre_rating.y
local _,cost = AH.find_path_with_shroud(unit, short_goal[1], short_goal[2])
local rating = - cost + pre_rating.other_rating
if (rating > max_rating) then
max_rating, best_hex = rating, { pre_rating.x, pre_rating.y }
if (rating > max_rating3) then
max_rating3, best_hex = rating, { pre_rating.x, pre_rating.y }
end
end
@ -292,8 +292,8 @@ function ca_fast_move:execution(cfg)
next_goal = next_goal - 1
end
for _,goal in ipairs(goals) do
if goal[1] then
for _,keep_moving_goal in ipairs(goals) do
if keep_moving_goal[1] then
keep_moving = true
break
end

View file

@ -91,7 +91,7 @@ function ca_forest_animals_move:execution(cfg)
AH.checked_move(ai, unit, reachable_wander_terrain[rand][1], reachable_wander_terrain[rand][2])
end
else -- Or if no close reachable terrain was found, move toward the closest
local min_dist, best_hex = math.huge
local min_dist, best_hex = math.huge, nil
for _,loc in ipairs(wander_locs) do
local dist = M.distance_between(loc[1], loc[2], unit.x, unit.y)
if dist < min_dist then

View file

@ -32,7 +32,7 @@ function ca_forest_animals_tusker_attack:execution(cfg)
local adjacent_enemies = get_adjacent_enemies(cfg)
-- Find the closest enemy to any tusker
local min_dist, attacker, target = math.huge
local min_dist, attacker, target = math.huge, nil, nil
for _,tusker in ipairs(tuskers) do
for _,enemy in ipairs(adjacent_enemies) do
local dist = M.distance_between(tusker.x, tusker.y, enemy.x, enemy.y)

View file

@ -33,7 +33,7 @@ function ca_forest_animals_tusklet_move:execution(cfg)
local tusklet = get_tusklets(cfg)[1]
local tuskers = get_tuskers(cfg)
local min_dist, goto_tusker = math.huge
local min_dist, goto_tusker = math.huge, nil
for _,tusker in ipairs(tuskers) do
local dist = M.distance_between(tusker.x, tusker.y, tusklet.x, tusklet.y)
if (dist < min_dist) then

View file

@ -21,7 +21,7 @@ local function custom_cost(x, y, unit, avoid_map, enemy_map, enemy_attack_map, m
return move_cost
end
local ca_goto, GO_units, GO_locs, GO_avoid_map = {}
local ca_goto, GO_units, GO_locs, GO_avoid_map = {}, nil, nil, nil
function ca_goto:evaluation(cfg, data)
-- If cfg.release_all_units_at_goal is set, check whether the goal has
@ -68,18 +68,18 @@ function ca_goto:evaluation(cfg, data)
local locs = {}
if cfg.unique_goals then
-- First, some cleanup of previous turn data
local str = 'goal_taken_' .. (wesnoth.current.turn - 1)
local str1 = 'goal_taken_' .. (wesnoth.current.turn - 1)
local old_goals = MAISD.get_mai_self_data(data, cfg.ai_id)
for goal,_ in pairs(old_goals) do
if string.find(goal, str) then
if string.find(goal, str1) then
old_goals[goal] = nil -- This also removes it from data
end
end
-- Now on to the current turn
for _,loc in ipairs(valid_locs) do
local str = 'goal_taken_' .. wesnoth.current.turn .. '_' .. loc[1] .. '_' .. loc[2]
if (not MAISD.get_mai_self_data(data, cfg.ai_id, str)) then
local str2 = 'goal_taken_' .. wesnoth.current.turn .. '_' .. loc[1] .. '_' .. loc[2]
if (not MAISD.get_mai_self_data(data, cfg.ai_id, str2)) then
table.insert(locs, loc)
end
end
@ -129,7 +129,7 @@ function ca_goto:execution(cfg, data)
enemy_attack_map = BC.get_attack_map(live_enemies)
end
local max_rating, closest_hex, best_path, best_unit = - math.huge
local max_rating, closest_hex, best_path, best_unit = - math.huge, nil, nil, nil
for _,unit in ipairs(units) do
for _,loc in ipairs(locs) do
-- If cfg.use_straight_line is set, we simply find the closest

View file

@ -57,11 +57,11 @@ function ca_hang_out:execution(cfg)
local default_avoid_tag = { terrain = 'C*,C*^*,*^C*' }
local avoid_map = AH.get_avoid_map(ai, avoid_tag, true, default_avoid_tag)
local max_rating, best_hex, best_unit = - math.huge
local max_rating, best_hex, best_unit = - math.huge, nil, nil
for _,unit in ipairs(units) do
-- Only consider units that have not been marked yet
if (not MAIUV.get_mai_unit_variables(unit, cfg.ai_id, "moved")) then
local max_rating_unit, best_hex_unit = - math.huge
local max_rating_unit, best_hex_unit = - math.huge, nil
-- Check out all unoccupied hexes the unit can reach
local reach_map = AH.get_reachmap(unit, { avoid_map = avoid_map, exclude_occupied = true })
@ -75,7 +75,7 @@ function ca_hang_out:execution(cfg)
-- Minor penalty for distance from current position of unit
-- so that there's not too much shuffling around
local rating = rating - M.distance_between(x, y, unit.x, unit.y) / 1000.
rating = rating - M.distance_between(x, y, unit.x, unit.y) / 1000.
if (rating > max_rating_unit) then
max_rating_unit = rating

View file

@ -2,7 +2,7 @@ local AH = wesnoth.require "ai/lua/ai_helper.lua"
local BC = wesnoth.require "ai/lua/battle_calcs.lua"
local M = wesnoth.map
local ca_healer_move, best_healer, best_hex = {}
local ca_healer_move, best_healer, best_hex = {}, nil, nil
function ca_healer_move:evaluation(cfg, data)
-- Should happen with higher priority than attacks, except at beginning of turn,
@ -74,7 +74,7 @@ function ca_healer_move:evaluation(cfg, data)
-- - either can be attacked by an enemy (15 points per enemy)
-- - or has non-perfect HP (1 point per missing HP)
local rating, adjacent_healer = 0
local rating, adjacent_healer = 0, nil
for _,healee in ipairs(healees) do
if (M.distance_between(healee.x, healee.y, x, y) == 1) then
-- Note: These ratings have to be positive or the method doesn't work

View file

@ -45,11 +45,11 @@ function ca_herding_attack_close_enemy:execution(cfg)
local dogs = get_dogs(cfg)
-- We start with enemies within attack_distance (default: 4) hexes, which will be attacked
local radius = cfg.attack_distance or 4
local enemies = get_enemies(cfg, radius)
local radius1 = cfg.attack_distance or 4
local enemies1 = get_enemies(cfg, radius1)
local max_rating, best_dog, best_enemy, best_hex = - math.huge
for _,enemy in ipairs(enemies) do
local max_rating1, best_dog1, best_enemy, best_hex1 = - math.huge, nil, nil, nil
for _,enemy in ipairs(enemies1) do
for _,dog in ipairs(dogs) do
local reach_map = AH.get_reachable_unocc(dog)
reach_map:iter( function(x, y, v)
@ -63,23 +63,23 @@ function ca_herding_attack_close_enemy:execution(cfg)
rating = rating + M.distance_between(enemy.x, enemy.y, dog.x, dog.y) / 100.
reach_map:insert(x, y, rating)
if (rating > max_rating) then
max_rating = rating
best_dog, best_enemy, best_hex = dog, enemy, { x, y }
if (rating > max_rating1) then
max_rating1 = rating
best_dog1, best_enemy, best_hex1 = dog, enemy, { x, y }
end
end)
end
end
-- If we found a move, we do it, and attack if possible
if best_dog then
AH.robust_move_and_attack(ai, best_dog, best_hex, best_enemy)
if best_dog1 then
AH.robust_move_and_attack(ai, best_dog1, best_hex1, best_enemy)
return
end
-- If we got here, no enemies to attack where found, so we go on to block other enemies
local radius = cfg.attention_distance or 8
local enemies = get_enemies(cfg, radius)
local radius2 = cfg.attention_distance or 8
local enemies2 = get_enemies(cfg, radius2)
-- We also need to remove dogs that have no moves left, since selection was done on attacks_left
for i=#dogs,1,-1 do
@ -90,8 +90,8 @@ function ca_herding_attack_close_enemy:execution(cfg)
if (not dogs[1]) then return end
-- Find closest sheep/enemy pair first
local min_dist, closest_sheep, closest_enemy = math.huge
for _,enemy in ipairs(enemies) do
local min_dist, closest_sheep, closest_enemy = math.huge, nil, nil
for _,enemy in ipairs(enemies2) do
for _,single_sheep in ipairs(sheep) do
local dist = M.distance_between(enemy.x, enemy.y, single_sheep.x, single_sheep.y)
if dist < min_dist then
@ -102,7 +102,7 @@ function ca_herding_attack_close_enemy:execution(cfg)
end
-- Move dogs in between enemies and sheep
local max_rating, best_dog, best_hex = - math.huge
local max_rating2, best_dog2, best_hex2 = - math.huge, nil, nil
for _,dog in ipairs(dogs) do
local reach_map = AH.get_reachable_unocc(dog)
reach_map:iter( function(x, y, v)
@ -118,13 +118,13 @@ function ca_herding_attack_close_enemy:execution(cfg)
rating = rating + M.distance_between(closest_enemy.x, closest_enemy.y, dog.x, dog.y) / 100.
reach_map:insert(x, y, rating)
if (rating > max_rating) then
max_rating, best_hex, best_dog = rating, { x, y }, dog
if (rating > max_rating2) then
max_rating2, best_hex2, best_dog2 = rating, { x, y }, dog
end
end)
end
AH.movefull_stopunit(ai, best_dog, best_hex)
AH.movefull_stopunit(ai, best_dog2, best_hex2)
end
return ca_herding_attack_close_enemy

View file

@ -1,7 +1,7 @@
local AH = wesnoth.require "ai/lua/ai_helper.lua"
local M = wesnoth.map
local herding_area = wesnoth.require "ai/micro_ais/cas/ca_herding_f_herding_area.lua"
local HA = wesnoth.require "ai/micro_ais/cas/ca_herding_f_herding_area.lua"
local function get_dogs(cfg)
local dogs = AH.get_units_with_moves {
@ -19,7 +19,7 @@ local function get_sheep_to_herd(cfg)
}
local sheep_to_herd = {}
local herding_area = herding_area(cfg)
local herding_area = HA(cfg)
for _,single_sheep in ipairs(all_sheep) do
if (not herding_area:get(single_sheep.x, single_sheep.y)) then
table.insert(sheep_to_herd, single_sheep)
@ -42,7 +42,7 @@ function ca_herding_herd_sheep:execution(cfg)
local dogs = get_dogs(cfg)
local sheep_to_herd = get_sheep_to_herd(cfg)
local max_rating, best_dog, best_hex = - math.huge
local max_rating, best_dog, best_hex = - math.huge, nil, nil
local herd_loc = AH.get_named_loc_xy('herd', cfg)
local c_x, c_y = herd_loc[1], herd_loc[2]
for _,single_sheep in ipairs(sheep_to_herd) do

View file

@ -1,6 +1,6 @@
local AH = wesnoth.require "ai/lua/ai_helper.lua"
local herding_area = wesnoth.require "ai/micro_ais/cas/ca_herding_f_herding_area.lua"
local HA = wesnoth.require "ai/micro_ais/cas/ca_herding_f_herding_area.lua"
local function get_next_sheep(cfg)
local sheep = AH.get_units_with_moves {
@ -42,7 +42,7 @@ function ca_herding_sheep_move:execution(cfg)
-- If this move remains within herding area or dogs have no moves left, or sheep doesn't move
-- make it a full move, otherwise partial move
local herding_area = herding_area(cfg)
local herding_area = HA(cfg)
local dogs = AH.get_units_with_moves {
side = wesnoth.current.side,
{ "and", dogs_filter }

View file

@ -11,7 +11,7 @@ local function hunter_attack_weakest_adj_enemy(ai, hunter)
if (hunter.attacks_left == 0) then return 'no_attack' end
local min_hp, target = math.huge
local min_hp, target = math.huge, nil
for xa,ya in wesnoth.current.map:iter_adjacent(hunter) do
local enemy = wesnoth.units.get(xa, ya)
if AH.is_attackable_enemy(enemy) then
@ -60,8 +60,7 @@ function ca_hunter:execution(cfg)
-- If hunting_status is not set for the hunter -> default behavior -> random wander
if (not hunter_vars.hunting_status) then
-- Hunter gets a new goal if none exist or on any move with 10% random chance
local rand = math.random(10)
if (not hunter_vars.goal_x) or (rand == 1) then
if (not hunter_vars.goal_x) or (math.random(10) == 1) then
-- 'locs' includes border hexes, but that does not matter here
local locs = AH.get_passable_locations((wml.get_child(cfg, "filter_location") or {}), hunter)
local rand = math.random(#locs)
@ -73,7 +72,7 @@ function ca_hunter:execution(cfg)
local reach_map = AH.get_reachable_unocc(hunter)
-- Now find the one of these hexes that is closest to the goal
local max_rating, best_hex = - math.huge
local max_rating, best_hex = - math.huge, nil
reach_map:iter( function(x, y, v)
-- Distance from goal is first rating
local rating = -M.distance_between(x, y, hunter_vars.goal_x, hunter_vars.goal_y)

View file

@ -34,7 +34,7 @@ function ca_lurkers:execution(cfg)
reachable_attack_terrain:inter(reach)
-- Need to restrict that to reachable and not occupied by an ally (except own position)
local reachable_attack_terrain = reachable_attack_terrain:filter(function(x, y, v)
reachable_attack_terrain = reachable_attack_terrain:filter(function(x, y, v)
local occ_hex = AH.get_visible_units(wesnoth.current.side, {
x = x, y = y,
{ "not", { x = lurker.x, y = lurker.y } }
@ -70,7 +70,7 @@ function ca_lurkers:execution(cfg)
reachable_wander_terrain:inter(reach)
-- Need to restrict that to reachable and not occupied by an ally (except own position)
local reachable_wander_terrain = reachable_wander_terrain:filter(function(x, y, v)
reachable_wander_terrain = reachable_wander_terrain:filter(function(x, y, v)
local occ_hex = AH.get_visible_units(wesnoth.current.side, {
x = x, y = y,
{ "not", { x = lurker.x, y = lurker.y } }

View file

@ -25,8 +25,10 @@ local function messenger_find_enemies_in_way(messenger, goal_x, goal_y, avoid_ma
local sub_path, sub_cost = AH.find_path_with_avoid(messenger, path[i][1], path[i][2], avoid_map, { ignore_enemies = true })
if (sub_cost <= messenger.moves) then
for xa,ya in wesnoth.current.map:iter_adjacent(path[i]) do
local enemy = wesnoth.units.get(xa, ya)
if AH.is_attackable_enemy(enemy) then return enemy end
local new_enemy = wesnoth.units.get(xa, ya)
if AH.is_attackable_enemy(new_enemy) then
return new_enemy
end
end
else -- If we've reached the end of the path for this turn
return

View file

@ -37,7 +37,7 @@ function ca_messenger_escort_move:execution(cfg)
local enemies = AH.get_attackable_enemies()
local base_rating_map = LS.create()
local max_rating, best_unit, best_hex = - math.huge
local max_rating, best_unit, best_hex = - math.huge, nil, nil
for _,unit in ipairs(escorts) do
-- Only considering hexes unoccupied by other units is good enough for this
local reach_map = AH.get_reachable_unocc(unit)

View file

@ -17,7 +17,7 @@ return function(cfg)
-- Set the next waypoint for all messengers
-- Also find those with MP left and return the one to next move, together with the WP to move toward
local max_rating, best_messenger, x, y = - math.huge
local max_rating, best_messenger, x, y = - math.huge, nil, nil, nil
for _,messenger in ipairs(messengers) do
-- To avoid code duplication and ensure consistency, we store some pieces of
-- information in the messenger units, even though it could be calculated each time it is needed

View file

@ -16,9 +16,8 @@ end
function ca_messenger_move:execution(cfg)
local messenger, x, y = messenger_next_waypoint(cfg)
local avoid_map = AH.get_avoid_map(ai, wml.get_child(cfg, "avoid"), true)
if (messenger.x ~= x) or (messenger.y ~= y) then
local avoid_map = AH.get_avoid_map(ai, wml.get_child(cfg, "avoid"), true)
local wp = AH.get_closest_location(
{ x, y },
{ { "not", { { "filter", { { "not", { side = wesnoth.current.side } } } } } } },
@ -29,16 +28,16 @@ function ca_messenger_move:execution(cfg)
local avoid_map = AH.get_avoid_map(ai, wml.get_child(cfg, "avoid"), true)
local path = AH.find_path_with_avoid(messenger, x, y, avoid_map)
if (not path) then path = { { messenger.x, messenger.y } } end
local next_hop = AH.next_hop(messenger, x, y, { path = path, avoid_map = avoid_map, ignore_own_units = true } )
local path1 = AH.find_path_with_avoid(messenger, x, y, avoid_map)
if (not path1) then path1 = { { messenger.x, messenger.y } } end
local next_hop = AH.next_hop(messenger, x, y, { path1 = path1, avoid_map = avoid_map, ignore_own_units = true } )
if (not next_hop) then next_hop = { messenger.x, messenger.y } end
-- Compare this to the "ideal path"
local path = AH.find_path_with_avoid(messenger, x, y, avoid_map, { ignore_enemies = true })
if (not path) then path = { { messenger.x, messenger.y } } end
local path2 = AH.find_path_with_avoid(messenger, x, y, avoid_map, { ignore_enemies = true })
if (not path2) then path2 = { { messenger.x, messenger.y } } end
local optimum_hop = { messenger.x, messenger.y }
for _,step in ipairs(path) do
for _,step in ipairs(path2) do
local sub_path, sub_cost = AH.find_path_with_avoid(messenger, step[1], step[2], avoid_map)
if sub_cost > messenger.moves then
break
@ -97,7 +96,7 @@ function ca_messenger_move:execution(cfg)
local targets = AH.get_attackable_enemies { { "filter_adjacent", { id = messenger.id } } }
local max_rating, best_target, best_weapon = - math.huge
local max_rating, best_target, best_weapon = - math.huge, nil, nil
for _,target in ipairs(targets) do
for n_weapon,weapon in ipairs(messenger.attacks) do
local att_stats, def_stats = wesnoth.simulate_combat(messenger, n_weapon, target)

View file

@ -57,7 +57,7 @@ local function get_best_attack(unit, loc, last_waypoint, cfg)
unit.moves, unit.loc = old_moves, old_loc
end
local max_rating, best_enemy, best_dst = -math.huge
local max_rating, best_enemy, best_dst = -math.huge, nil, nil
for _,attack in ipairs(attacks) do
for _,enemy in ipairs(enemies) do
if (attack.target.x == enemy.x) and (attack.target.y == enemy.y) then

View file

@ -1,7 +1,7 @@
local AH = wesnoth.require "ai/lua/ai_helper.lua"
local BC = wesnoth.require "ai/lua/battle_calcs.lua"
local ca_protect_unit_attack, best_attack = {}
local ca_protect_unit_attack, best_attack = {}, nil
function ca_protect_unit_attack:evaluation(cfg)
-- Find possible attacks for the units

View file

@ -1,6 +1,6 @@
local AH = wesnoth.require "ai/lua/ai_helper.lua"
local ca_protect_unit_finish, PU_unit, PU_goal = {}
local ca_protect_unit_finish, PU_unit, PU_goal = {}, nil, nil
function ca_protect_unit_finish:evaluation(cfg)
-- If a unit can make it to the goal, this is the first thing that happens

View file

@ -43,15 +43,14 @@ function ca_protect_unit_move:execution(cfg, data)
end
local reach_map = AH.get_reachable_unocc(unit)
local enemy_inverse_distance_map = AH.inverse_distance_map(enemy_units, reach_map)
local terrain_defense_map = LS.create()
reach_map:iter(function(x, y, data)
reach_map:iter(function(x, y, data1)
terrain_defense_map:insert(x, y, unit:defense_on(wesnoth.current.map[{x, y}]))
end)
local goal_distance_map = LS.create()
reach_map:iter(function(x, y, data)
reach_map:iter(function(x, y, data1)
goal_distance_map:insert(x, y, wesnoth.map.distance_between(x, y, goal[1], goal[2]))
end)
@ -70,7 +69,7 @@ function ca_protect_unit_move:execution(cfg, data)
terrain_weight = 0
end
local max_rating, best_hex = - math.huge
local max_rating, best_hex = - math.huge, nil
for ind,_ in pairs(reach_map.values) do
local rating =
(attack_map.values[ind] or 0) * my_unit_weight

View file

@ -2,7 +2,7 @@ local AH = wesnoth.require "ai/lua/ai_helper.lua"
local BC = wesnoth.require "ai/lua/battle_calcs.lua"
local LS = wesnoth.require "location_set"
local ca_simple_attack, best_attack = {}
local ca_simple_attack, best_attack = {}, nil
function ca_simple_attack:evaluation(cfg)
local units = AH.get_units_with_attacks {

View file

@ -38,14 +38,14 @@ function ca_stationed_guardian:execution(cfg)
-- simultaneously for guardian to attack
local station_loc = AH.get_named_loc_xy('station', cfg)
local guard_loc = AH.get_named_loc_xy('guard', cfg) or station_loc
local min_dist, target = math.huge
local min_dist1, target = math.huge, nil
for _,enemy in ipairs(enemies) do
local dist_s = M.distance_between(station_loc[1], station_loc[2], enemy.x, enemy.y)
local dist_g = M.distance_between(guard_loc[1], guard_loc[2], enemy.x, enemy.y)
-- If valid target found, save the one with the shortest distance from (g_x, g_y)
if (dist_s <= cfg.distance) and (dist_g <= cfg.distance) and (dist_g < min_dist) then
target, min_dist = enemy, dist_g
if (dist_s <= cfg.distance) and (dist_g <= cfg.distance) and (dist_g < min_dist1) then
target, min_dist1 = enemy, dist_g
end
end
@ -53,7 +53,7 @@ function ca_stationed_guardian:execution(cfg)
if target then
-- Find tiles adjacent to the target
-- Save the one with the highest defense rating that guardian can reach
local best_defense, attack_loc = - math.huge
local best_defense, attack_loc = - math.huge, nil
for xa,ya in wesnoth.current.map:iter_adjacent(target) do
-- Only consider unoccupied hexes
local unit_in_way = wesnoth.units.get(xa, ya)
@ -78,7 +78,7 @@ function ca_stationed_guardian:execution(cfg)
-- Go through all hexes the guardian can reach, find closest to target
-- Cannot use next_hop here since target hex is occupied by enemy
local min_dist, nh = math.huge
local min_dist2, nh = math.huge, nil
for _,hex in ipairs(reach) do
-- Only consider unoccupied hexes
local unit_in_way = wesnoth.units.get(hex[1], hex[2])
@ -86,8 +86,8 @@ function ca_stationed_guardian:execution(cfg)
or (unit_in_way == guardian)
then
local dist = M.distance_between(hex[1], hex[2], target.x, target.y)
if (dist < min_dist) then
min_dist, nh = dist, { hex[1], hex[2] }
if (dist < min_dist2) then
min_dist2, nh = dist, { hex[1], hex[2] }
end
end
end

View file

@ -48,7 +48,7 @@ function ca_wolves_move:execution(cfg)
local avoid_enemies_map = BC.get_attack_map(avoid_units).units
-- Find prey that is closest to the wolves
local min_dist, target = math.huge
local min_dist, target = math.huge, nil
for _,prey_unit in ipairs(prey) do
if (not avoid_map:get(prey_unit.x, prey_unit.y)) then
local dist = 0
@ -82,9 +82,9 @@ function ca_wolves_move:execution(cfg)
return rating
end, { avoid_map = avoid_map })
local move_result = AH.movefull_stopunit(ai, wolves[1], wolf1 or { wolf1.x, wolf1.y })
local move_result1 = AH.movefull_stopunit(ai, wolves[1], wolf1 or { wolf1.x, wolf1.y })
-- If the wolf was ambushed, return and reconsider; also if an event removed a wolf
if (AH.is_incomplete_move(move_result)) then return end
if (AH.is_incomplete_move(move_result1)) then return end
for _,check_wolf in ipairs(wolves) do
if (not check_wolf) or (not check_wolf.valid) then return end
end
@ -111,9 +111,9 @@ function ca_wolves_move:execution(cfg)
return rating
end, { avoid_map = avoid_map })
local move_result = AH.movefull_stopunit(ai, wolves[i], move or { wolves[i].x, wolves[i].y })
local move_result2 = AH.movefull_stopunit(ai, wolves[i], move or { wolves[i].x, wolves[i].y })
-- If the wolf was ambushed, return and reconsider; also if an event removed a wolf
if (AH.is_incomplete_move(move_result)) then return end
if (AH.is_incomplete_move(move_result2)) then return end
for _,check_wolf in ipairs(wolves) do
if (not check_wolf) or (not check_wolf.valid) then return end
end

View file

@ -32,7 +32,7 @@ function ca_wolves_multipacks_attack:execution(cfg)
-- This repeats until all wolves in a pack have attacked, or none can attack any more
while keep_attacking_this_pack do
local wolves, attacks = {}, {}
local wolves = {}
for _,pack_wolf in ipairs(pack) do
-- Wolf might have moved in previous attack -> use id to identify it
local wolf = wesnoth.units.find_on_map { id = pack_wolf.id }[1]
@ -85,7 +85,7 @@ function ca_wolves_multipacks_attack:execution(cfg)
end
-- Find which target can be attacked by the most units, from the most hexes; and rate by fewest HP if equal
local max_rating, best_target = - math.huge
local max_rating1, best_target = - math.huge, nil
for attack_ind,attack in pairs(attack_map_wolves) do
local number_wolves, number_hexes = 0, 0
for _,w in pairs(attack) do number_wolves = number_wolves + 1 end
@ -111,20 +111,20 @@ function ca_wolves_multipacks_attack:execution(cfg)
end
end
if rating > max_rating then
max_rating, best_target = rating, target
if rating > max_rating1 then
max_rating1, best_target = rating, target
end
end
-- Now we know the best target and need to attack
-- This is done on a wolf-by-wolf basis, the outside while loop taking care of
-- the next wolf in the pack on subsequent iterations
local max_rating, best_attack = - math.huge
local max_rating2, best_attack = - math.huge, nil
for _,attack in ipairs(attacks) do
if (attack.target.x == best_target.x) and (attack.target.y == best_target.y) then
local rating = attack.att_stats.average_hp / 2. - attack.def_stats.average_hp
if (rating > max_rating) then
max_rating, best_attack = rating, attack
if (rating > max_rating2) then
max_rating2, best_attack = rating, attack
end
end
end

View file

@ -56,7 +56,7 @@ function wolves_multipacks_functions.assign_packs(cfg)
-- First, go through packs that have less than pack_size members
for pack_number,pack in pairs(packs) do
if (#pack < pack_size) then
local min_dist, best_wolf, best_ind = math.huge
local min_dist, best_wolf, best_ind = math.huge, nil, nil
for ind,wolf in ipairs(nopack_wolves) do
-- Criterion is distance from the first two wolves of the pack
local dist1 = M.distance_between(wolf.x, wolf.y, pack[1].x, pack[1].y)
@ -95,7 +95,7 @@ function wolves_multipacks_functions.assign_packs(cfg)
-- They form the next pack
local new_pack_wolves = {}
while (#new_pack_wolves < pack_size) do
local min_dist, best_wolf, best_wolf_ind = math.huge
local min_dist, best_wolf, best_wolf_ind = math.huge, nil, nil
for ind,nopack_wolf in ipairs(nopack_wolves) do
local dist = 0
for _,pack_wolf in ipairs(new_pack_wolves) do

View file

@ -43,8 +43,7 @@ function ca_wolves_multipacks_wander:execution(cfg)
end
-- Pack gets a new goal if none exist or on any move with 10% random chance
local rand = math.random(10)
if (not goal[1]) or (rand == 1) then
if (not goal[1]) or (math.random(10) == 1) then
local all_locs = AH.get_locations_no_borders {}
local locs = {}
for _,loc in ipairs(all_locs) do
@ -99,7 +98,7 @@ function ca_wolves_multipacks_wander:execution(cfg)
-- Keep only those hexes that can be reached by all wolves in the pack
-- and add distance from goal for those
local max_rating, goto_hex = - math.huge
local max_rating, goto_hex = - math.huge, nil
reach_map:iter( function(x, y, v)
local rating = reach_map:get(x, y)
if (rating == #pack * 100) then

View file

@ -34,7 +34,7 @@ function ca_wolves_wander:execution(cfg)
local avoid_units = AH.get_attackable_enemies({ type = cfg.avoid_type })
local avoid_enemies_map = BC.get_attack_map(avoid_units).units
local max_rating, goal_hex = - math.huge
local max_rating, goal_hex = - math.huge, nil
reach_map:iter( function (x, y, v)
local rating = v + math.random(99)/100.
if avoid_enemies_map:get(x, y) then rating = rating - 1000 end

View file

@ -20,17 +20,16 @@ end
function ca_zone_guardian:execution(cfg)
local guardian = get_guardian(cfg)
local reach = wesnoth.paths.find_reach(guardian)
local zone = wml.get_child(cfg, "filter_location")
local zone_enemy = wml.get_child(cfg, "filter_location_enemy") or zone
local enemies = AH.get_attackable_enemies { { "filter_location", zone_enemy } }
if enemies[1] then
local min_dist, target = math.huge
local min_dist1, target = math.huge, nil
for _,enemy in ipairs(enemies) do
local dist = M.distance_between(guardian.x, guardian.y, enemy.x, enemy.y)
if (dist < min_dist) then
target, min_dist = enemy, dist
if (dist < min_dist1) then
target, min_dist1 = enemy, dist
end
end
@ -38,7 +37,7 @@ function ca_zone_guardian:execution(cfg)
if target then
-- Find tiles adjacent to the target
-- Save the one with the highest defense rating that guardian can reach
local best_defense, attack_loc = - math.huge
local best_defense, attack_loc = - math.huge, nil
for xa,ya in wesnoth.current.map:iter_adjacent(target) do
-- Only consider unoccupied hexes
local unit_in_way = wesnoth.units.get(xa, ya)
@ -63,7 +62,7 @@ function ca_zone_guardian:execution(cfg)
-- Go through all hexes the guardian can reach, find closest to target
-- Cannot use next_hop here since target hex is occupied by enemy
local min_dist, nh = math.huge
local min_dist2, nh = math.huge, nil
for _,hex in ipairs(reach) do
-- Only consider unoccupied hexes
local unit_in_way = wesnoth.units.get(hex[1], hex[2])
@ -71,8 +70,8 @@ function ca_zone_guardian:execution(cfg)
or (unit_in_way == guardian)
then
local dist = M.distance_between(hex[1], hex[2], target.x, target.y)
if (dist < min_dist) then
min_dist, nh = dist, { hex[1], hex[2] }
if (dist < min_dist2) then
min_dist2, nh = dist, { hex[1], hex[2] }
end
end
end

View file

@ -6,12 +6,12 @@ return {
-- This is taken almost literally from 'Ka'lian under Attack' in 'Legend of Wesmere'
function urudin:retreat()
local urudin = wesnoth.units.find_on_map({ side = 3, id = "Urudin" })[1]
if urudin and urudin.valid then
local max_hp, hp = urudin.max_hitpoints, urudin.hitpoints
local urudin_units = wesnoth.units.find_on_map({ side = 3, id = "Urudin" })[1]
if urudin_units and urudin_units.valid then
local max_hp, hp = urudin_units.max_hitpoints, urudin_units.hitpoints
local turn = wesnoth.current.turn
if (turn >= 5) or (hp < max_hp / 2) then
AH.movefull_stopunit(ai, urudin, 33, 8)
AH.movefull_stopunit(ai, urudin_units, 33, 8)
end
end
end

View file

@ -14,7 +14,7 @@ end
function ca_ogres_flee:execution()
local units = AH.get_units_with_moves { side = wesnoth.current.side }
local units_noMP = wesnoth.units.find_on_map { side = wesnoth.current.side,
local units_no_mp = wesnoth.units.find_on_map { side = wesnoth.current.side,
formula = 'movement_left = 0'
}
@ -22,7 +22,7 @@ function ca_ogres_flee:execution()
local enemies = wesnoth.units.find_on_map { { "filter_side", { {"enemy_of", {side = wesnoth.current.side} } } } }
local enemy_attack_map = BC.get_attack_map(enemies)
local max_rating, best_hex, best_unit = - math.huge
local max_rating, best_hex, best_unit = - math.huge, nil, nil
for i,u in ipairs(units) do
local reach = wesnoth.paths.find_reach(u)
for j,r in ipairs(reach) do
@ -42,15 +42,14 @@ function ca_ogres_flee:execution()
local rating = - dist
-- If we can reach the edge, we do so
if (dist == 0) then rating = rating + 1000 end
local enemy_weight = 0.5
local enemy_rating = - (enemy_attack_map.units:get(r[1], r[2]) or 0) * enemy_weight
if (dist == 0) then
rating = rating + 1000
end
local enemy_rating = 0
for k,e in ipairs(enemies) do
local dist = M.distance_between(r[1], r[2], e.x, e.y)
enemy_rating = enemy_rating + math.sqrt(dist)
local enemy_dist = M.distance_between(r[1], r[2], e.x, e.y)
enemy_rating = enemy_rating + math.sqrt(enemy_dist)
end
rating = rating + enemy_rating
@ -58,9 +57,9 @@ function ca_ogres_flee:execution()
-- Also, maximize distance from own units that have already moved
local own_unit_weight = 0.5
local own_unit_rating = 0
for k,u_noMP in ipairs(units_noMP) do
local dist = M.distance_between(r[1], r[2], u_noMP.x, u_noMP.y)
own_unit_rating = own_unit_rating + math.sqrt(dist)
for k,u_no_mp in ipairs(units_no_mp) do
local no_mp_dist = M.distance_between(r[1], r[2], u_no_mp.x, u_no_mp.y)
own_unit_rating = own_unit_rating + math.sqrt(no_mp_dist)
end
rating = rating + own_unit_rating * own_unit_weight

View file

@ -52,14 +52,14 @@ function ca_transport:execution()
}
)
local max_rating, best_unit, best_hex, best_adj_tiles = - math.huge
local max_rating1, best_unit1, best_hex1, best_adj_tiles = - math.huge, nil, nil, nil
for i,u in ipairs(transports) do
local dst = { u.variables.destination_x, u.variables.destination_y }
if (not u.variables.landed) and (M.distance_between(u.x, u.y, dst[1], dst[2]) <= u.moves) then
local reach = wesnoth.paths.find_reach(u)
for i,r in ipairs(reach) do
for j,r in ipairs(reach) do
if landing_site_map:get(r[1], r[2]) and (not unit_map:get(r[1], r[2]))
then
-- Distance from destination is minor rating
@ -92,10 +92,10 @@ function ca_transport:execution()
end
end
if (rating > max_rating) then
max_rating = rating
best_unit = u
best_hex = r
if (rating > max_rating1) then
max_rating1 = rating
best_unit1 = u
best_hex1 = r
best_adj_tiles = adj_tiles
end
end
@ -103,13 +103,13 @@ function ca_transport:execution()
end
end
if best_unit then
ai.move_full(best_unit, best_hex[1], best_hex[2])
if best_unit1 then
ai.move_full(best_unit1, best_hex1[1], best_hex1[2])
-- Also unload units
table.sort(best_adj_tiles, function(a, b) return a[3] > b[3] end)
local command_data = { x = best_unit.x, y = best_unit.y }
local command_data = { x = best_unit1.x, y = best_unit1.y }
for i = 1, math.min(#best_adj_tiles, 3) do
table.insert(command_data, T.dst { x = best_adj_tiles[i][1], y = best_adj_tiles[i][2]} )
end
@ -127,13 +127,13 @@ function ca_transport:execution()
}
)
local max_rating, best_unit, best_hex = - math.huge
local max_rating2, best_unit2, best_hex2 = - math.huge, nil, nil
for i,u in ipairs(transports) do
local dst = { u.variables.destination_x, u.variables.destination_y }
local reach = wesnoth.paths.find_reach(u)
local max_rating_unit, best_hex_unit = - math.huge
for i,r in ipairs(reach) do
local max_rating_unit, best_hex_unit = - math.huge, nil
for j,r in ipairs(reach) do
if deep_water_map:get(r[1], r[2]) and (not blocked_hex_map:get(r[1], r[2])) then
local rating = -M.distance_between(r[1], r[2], dst[1], dst[2])
-- If possible, also move in a straight line
@ -154,16 +154,16 @@ function ca_transport:execution()
max_rating_unit = -1
end
if (max_rating_unit > max_rating) then
max_rating = max_rating_unit
best_unit = u
best_hex = best_hex_unit
if (max_rating_unit > max_rating2) then
max_rating2 = max_rating_unit
best_unit2 = u
best_hex2 = best_hex_unit
end
end
end
if best_unit then
ai.move_full(best_unit, best_hex[1], best_hex[2])
if best_unit2 then
ai.move_full(best_unit2, best_hex2[1], best_hex2[2])
else -- still need to make sure gamestate gets changed
ai.stopunit_moves(transports[1])
end

View file

@ -14,7 +14,7 @@ function ca_aggressive_attack_no_suicide:evaluation(cfg, data)
if (not attacks[1]) then return 0 end
-- Now find the best of the possible attacks
local max_rating, best_attack = - math.huge
local max_rating, best_attack = - math.huge, nil
for i, att in ipairs(attacks) do
local attacker = wesnoth.units.get(att.src.x, att.src.y)
local defender = wesnoth.units.get(att.target.x, att.target.y)

View file

@ -73,7 +73,7 @@ function muff_toras_move:execution()
local targets = AH.get_attackable_enemies { { "filter_adjacent", { id = muff_toras.id } } }
local max_rating, best_target, best_weapon = - math.huge
local max_rating, best_target, best_weapon = - math.huge, nil, nil
for _,target in ipairs(targets) do
for n_weapon,weapon in ipairs(muff_toras.attacks) do
local att_stats, def_stats = wesnoth.simulate_combat(muff_toras, n_weapon, target)

View file

@ -52,7 +52,7 @@ function wesnoth.wml_actions.wc2_store_carryover(cfg)
for side_num, side in ipairs(human_sides) do
player_gold = player_gold + side.gold
end
local player_gold = math.max(player_gold / #human_sides, 0)
player_gold = math.max(player_gold / #human_sides, 0)
wml.variables.wc2_carryover = math.ceil( (nvillages*turns_left + player_gold) * 0.15)
end

View file

@ -2,18 +2,18 @@ local _ = wesnoth.textdomain 'wesnoth-wc'
local dialog_wml = wml.load "campaigns/World_Conquest/gui/invest_dialog.cfg"
function wc2_show_invest_dialog_impl(args)
function wc2_show_invest_dialog_impl(dialog_args)
local side_num = wesnoth.current.side
local available_artifacts = args.items_available
local available_heroes = args.heroes_available
local available_deserters = args.deserters_available
local available_commanders = args.commanders_available
local available_training = args.trainings_available
local available_artifacts = dialog_args.items_available
local available_heroes = dialog_args.heroes_available
local available_deserters = dialog_args.deserters_available
local available_commanders = dialog_args.commanders_available
local available_training = dialog_args.trainings_available
local show_artifacts = args.items_available ~= nil
local show_heroes = args.heroes_available ~= nil
local show_training = args.trainings_available ~= nil
local show_other = args.gold_available
local show_artifacts = dialog_args.items_available ~= nil
local show_heroes = dialog_args.heroes_available ~= nil
local show_training = dialog_args.trainings_available ~= nil
local show_other = dialog_args.gold_available
local cati_items, cati_heroes, cati_training, cati_other
@ -33,20 +33,20 @@ function wc2_show_invest_dialog_impl(args)
return node
end
function gui.widget.add_invest_item(parent_node, args)
local node_type = args.desc and "item_desc" or "item"
local page_type = args.page_type or ""
function gui.widget.add_invest_item(parent_node, item_args)
local node_type = item_args.desc and "item_desc" or "item"
local page_type = item_args.page_type or ""
local node = parent_node:add_item_of_type(node_type)
local details_page = details:add_item_of_type(page_type)
node.image.label = args.icon
node.name.label = args.name
if args.desc then
node.desc.label = args.desc
node.image.label = item_args.icon
node.name.label = item_args.name
if item_args.desc then
node.desc.label = item_args.desc
end
index_map[table.concat(node.path, "_")] = { page_num = details.item_count, res = args.result }
index_map[table.concat(node.path, "_")] = { page_num = details.item_count, res = item_args.result }
return node, details_page
end

View file

@ -1,5 +1,5 @@
local _ = wesnoth.textdomain 'wesnoth-wc'
local dialog = wml.load "campaigns/World_Conquest/gui/help_dialog.cfg"
local dialog_wml = wml.load "campaigns/World_Conquest/gui/help_dialog.cfg"
local function make_caption(text)
return ("<big><b>%s</b></big>"):format(text)
@ -71,17 +71,17 @@ function wesnoth.wml_actions.wc2_show_wocopedia(cfg)
-- add general training topic.
if show_help_training then
local node, page = root_node:add_help_page {
local node, root_page = root_node:add_help_page {
title = str_cat_training
}
page.label_content.marked_up_text = str_des_training
root_page.label_content.marked_up_text = str_des_training
-- add specific training pages
for i = 1, #wc2_training.get_list() do
local current_level = wc2_training.get_level(current_side, i)
local trainer = wc2_training.get_trainer(i)
local subnode, page = node:add_help_page {
local subnode, sub_page = node:add_help_page {
title = trainer.name,
page_type = "training",
node_type = "subcategory",
@ -94,14 +94,14 @@ function wesnoth.wml_actions.wc2_show_wocopedia(cfg)
desc.message = "<span color='#00FF00'>" .. desc.message .. "</span>"
end
local page_element = page.treeview_details:add_item_of_type("training_details")
local page_element = sub_page.treeview_details:add_item_of_type("training_details")
page_element.training_caption.marked_up_text = desc.caption
page_element.training_description.marked_up_text = desc.message
end
set_description(1)
for j = 2, #trainer.grade - 1, 1 do
page.treeview_details:add_item_of_type("seperator")
sub_page.treeview_details:add_item_of_type("seperator")
set_description(j)
end
end
@ -119,16 +119,16 @@ function wesnoth.wml_actions.wc2_show_wocopedia(cfg)
---- add general factions topic ----
local era_wml = wesnoth.scenario.era
local node, page = root_node:add_help_page {
local node, root_page = root_node:add_help_page {
title = str_cat_era
}
page.label_content.marked_up_text = str_des_era
root_page.label_content.marked_up_text = str_des_era
for i, faction_info in ipairs(wc2_era.factions_wml) do
local faction_wml = wml.get_child(era_wml, "multiplayer_side", faction_info.id)
local subnode, page = node:add_help_page {
local subnode, sub_page = node:add_help_page {
title = faction_info.name,
page_type = "faction",
node_type = "subcategory",
@ -139,7 +139,7 @@ function wesnoth.wml_actions.wc2_show_wocopedia(cfg)
local ut1 = wesnoth.unit_types[p[1]] or error("invald unit type" .. tostring(p[1]))
local ut2 = wesnoth.unit_types[p[2]] or error("invald unit type" .. tostring(p[2]))
local page_element = page.treeview_recruits:add_item_of_type("recruit_pair")
local page_element = sub_page.treeview_recruits:add_item_of_type("recruit_pair")
page_element.label1.marked_up_text = ut1.name
page_element.image1.label = type_icon(ut1)
page_element.label2.marked_up_text = ut2.name
@ -147,20 +147,20 @@ function wesnoth.wml_actions.wc2_show_wocopedia(cfg)
end
page.label_deserters.marked_up_text = wesnoth.format_conjunct_list("", wc2_era.expand_hero_names(faction_info.deserters))
page.label_commanders.marked_up_text = wesnoth.format_conjunct_list("", wc2_era.expand_hero_names(faction_info.commanders))
page.label_heroes.marked_up_text = wesnoth.format_conjunct_list("", wc2_era.expand_hero_names(faction_info.heroes, true))
sub_page.label_deserters.marked_up_text = wesnoth.format_conjunct_list("", wc2_era.expand_hero_names(faction_info.deserters))
sub_page.label_commanders.marked_up_text = wesnoth.format_conjunct_list("", wc2_era.expand_hero_names(faction_info.commanders))
sub_page.label_heroes.marked_up_text = wesnoth.format_conjunct_list("", wc2_era.expand_hero_names(faction_info.heroes, true))
if faction_wml then
local random_leaders = {}
for i,v in ipairs(stringx.split(faction_wml.random_leader or "")) do
for j,v in ipairs(stringx.split(faction_wml.random_leader or "")) do
table.insert(random_leaders, wesnoth.unit_types[v].name)
end
random_leaders = wesnoth.format_conjunct_list("", random_leaders)
page.label_random_leaders.marked_up_text = random_leaders
sub_page.label_random_leaders.marked_up_text = random_leaders
else
page.title_random_leaders.visible = false
sub_page.title_random_leaders.visible = false
end
end
end
@ -228,8 +228,7 @@ function wesnoth.wml_actions.wc2_show_wocopedia(cfg)
end
end
local dialog_wml = wml.get_child(dialog, 'resolution')
gui.show_dialog(dialog_wml, preshow)
gui.show_dialog(wml.get_child(dialog_wml, 'resolution'), preshow)
end
wc2_utils.menu_item {

View file

@ -241,7 +241,6 @@ function default_generate_map(data)
local island_radius = 40 + ((max_coastal - orig_island_size) * 40) // max_coastal;
cfg.island_size = (island_radius * w * 2) // 100;
cfg.island_off_center = math.min(w, h);
else
end
for i = 1, 20 do
local status, map = pcall(function()

View file

@ -155,7 +155,7 @@ function world_conquest_tek_map_decoration_2a()
while #terrain_to_change > 0 and mathx.random(10) ~= 1 do
local loc = terrain_to_change[mathx.random(#terrain_to_change)]
map[loc] = "^Efm"
local terrain_to_change = wct_store_possible_flowers("G*^Fet")
terrain_to_change = wct_store_possible_flowers("G*^Fet")
end
-- extra coast
set_terrain { "Ww,Ww,Ww,Wwr",

View file

@ -143,8 +143,8 @@ function world_conquest_tek_map_decoration_2c()
))
mathx.shuffle(terrain_to_change)
-- base amount in map surface
local r = mathx.random_choice(tostring(total_tiles // 285) .. ".." .. tostring(total_tiles // 150))
for i = 1, math.min(r, #terrain_to_change) do
local r1 = mathx.random_choice(tostring(total_tiles // 285) .. ".." .. tostring(total_tiles // 150))
for i = 1, math.min(r1, #terrain_to_change) do
map[terrain_to_change[i]] = "Ai"
end
@ -153,9 +153,9 @@ function world_conquest_tek_map_decoration_2c()
f.adjacent(f.terrain("!,Wo,Ai"), nil, 0)
))
mathx.shuffle(icepack_candiates)
local r = mathx.random_choice(tostring(total_tiles // 250) .. ".." .. tostring(total_tiles // 150))
local r2 = mathx.random_choice(tostring(total_tiles // 250) .. ".." .. tostring(total_tiles // 150))
for i = 1, math.min(r, #icepack_candiates) do
for i = 1, math.min(r2, #icepack_candiates) do
local loc = icepack_candiates[i]
table.insert(prestart_event, wml.tag.item {
image = "scenery/icepack-1.png",

View file

@ -26,31 +26,31 @@ end
function world_conquest_tek_map_decoration_2d()
for i = 1, 2 do
local terrain_to_change = map:find(f.all(
local terrain_to_change1 = map:find(f.all(
f.terrain("Hh,Mm,Mm^Xm,Xu,*^F*"),
f.adjacent(f.terrain("D*^*,Hd*^*")),
wct_provinces_castle_separation()
))
wct_provinces_castle(terrain_to_change, "Cd")
wct_provinces_castle(terrain_to_change1, "Cd")
local terrain_to_change = map:find(f.all(
local terrain_to_change2 = map:find(f.all(
f.terrain("Hh^F*"),
wct_provinces_castle_separation()
))
wct_provinces_castle(terrain_to_change, "Cv^Fds")
wct_provinces_castle(terrain_to_change2, "Cv^Fds")
local terrain_to_change = map:find(f.all(
local terrain_to_change3 = map:find(f.all(
f.terrain("Hh"),
f.none(f.radius(2, f.terrain("D*^*,Hd*^*"))),
wct_provinces_castle_separation()
))
wct_provinces_castle(terrain_to_change, "Ce")
wct_provinces_castle(terrain_to_change3, "Ce")
local terrain_to_change = map:find(f.all(
local terrain_to_change4 = map:find(f.all(
f.terrain("Mm"),
wct_provinces_castle_separation()
))
wct_provinces_castle(terrain_to_change, "Co")
wct_provinces_castle(terrain_to_change4, "Co")
end
set_terrain { "*^Fds",

View file

@ -43,13 +43,6 @@ function world_conquest_tek_map_constructor_delta()
local d_y = math.max(0, y - y_end, y_start - y)
return d_x + d_y < max_dist
end
for x = 0, map.width - 1 do
for y = 0, map.height - 1 do
if is_in_octaegon(x, y) then
end
end
end
local water_tiles = map:find(f.terrain("W*"))
for i, loc in ipairs(water_tiles) do

View file

@ -187,13 +187,13 @@ function world_conquest_tek_map_repaint_4b()
}
-- create volcanos where possible and force one
local terrain_to_change = map:find(f.all(
local terrain_to_change1 = map:find(f.all(
f.terrain("Ql"),
f.adjacent(f.terrain("M*,M*^Xm"), "se,s,sw", 2),
f.adjacent(f.terrain("K*^*,C*^*,*^V"), "se,s,sw", 0)
))
if #terrain_to_change > 0 then
local loc = terrain_to_change[mathx.random(#terrain_to_change)]
if #terrain_to_change1 > 0 then
local loc = terrain_to_change1[mathx.random(#terrain_to_change1)]
set_terrain { "Md^Xm",
f.all(
f.none(f.terrain("M*^*")),
@ -207,10 +207,10 @@ function world_conquest_tek_map_repaint_4b()
f.adjacent(f.terrain("Md^Xm,Md"), "se,s,sw", 3)
),
}
local terrain_to_change = map:find(f.terrain("Mv"))
local terrain_to_change2 = map:find(f.terrain("Mv"))
for i, v in ipairs(terrain_to_change) do
local loc = terrain_to_change[i]
for i, v in ipairs(terrain_to_change2) do
local loc = terrain_to_change2[i]
table.insert(prestart_event, wml.tag.sound_source {
id = "volcano" .. tostring(i),
sounds = "rumble.ogg",
@ -276,12 +276,12 @@ function world_conquest_tek_map_repaint_4b()
}
-- mushrooms, base amount in map surface
local terrain_to_change = map:find(f.terrain("Hhd,Hhd^F^*"))
mathx.shuffle(terrain_to_change)
local r = mathx.random_choice(tostring(total_tiles // 600) .. ".." .. tostring(total_tiles // 300))
local terrain_to_change3 = map:find(f.terrain("Hhd,Hhd^F^*"))
mathx.shuffle(terrain_to_change3)
local r1 = mathx.random_choice(tostring(total_tiles // 600) .. ".." .. tostring(total_tiles // 300))
for mush_i = 1, math.min(r, #terrain_to_change) do
map[terrain_to_change[mush_i]] = "Hhd^Tf"
for mush_i = 1, math.min(r1, #terrain_to_change3) do
map[terrain_to_change3[mush_i]] = "Hhd^Tf"
end
-- chances of few orcish castles
wct_possible_map4_castle("Co", 2)
@ -401,10 +401,10 @@ function world_conquest_tek_map_repaint_4b()
}
local r = mathx.random(20)
if r == 1 then
local r2 = mathx.random(20)
if r2 == 1 then
wct_change_map_water("g")
elseif r == 2 then
elseif r2 == 2 then
wct_change_map_water("t")
end

View file

@ -363,9 +363,9 @@ function world_conquest_tek_map_repaint_4e()
layer = "overlay",
}
local r = "Gs^Fp,Gs^Fms,Gs^Fds,Gs^Ft,Gs^Ft,Gs^Ftp,Gs^Ftr,Gs^Ftd,Gs^Fet"
r = mathx.random_choice(r)
set_terrain { r,
local r1 = "Gs^Fp,Gs^Fms,Gs^Fds,Gs^Ft,Gs^Ft,Gs^Ftp,Gs^Ftr,Gs^Ftd,Gs^Fet"
r1 = mathx.random_choice(r1)
set_terrain { r1,
f.all(
f_west_half,
f.terrain("Gs^F*"),
@ -375,9 +375,9 @@ function world_conquest_tek_map_repaint_4e()
),
}
local r = "Gs^Fp,Gs^Fms,Gs^Fds,Gs^Ftp,Gs^Ft,Gs^Ftp,Gs^Ftr,Gs^Ftd,Gs^Fet,Gs^Fts,Gs^Fts,Gs^Ft,Gs^Ft,Gs^Ftd,Gs^Fp"
r = mathx.random_choice(r)
set_terrain { r,
local r2 = "Gs^Fp,Gs^Fms,Gs^Fds,Gs^Ftp,Gs^Ft,Gs^Ftp,Gs^Ftr,Gs^Ftd,Gs^Fet,Gs^Fts,Gs^Fts,Gs^Ft,Gs^Ft,Gs^Ftd,Gs^Fp"
r2 = mathx.random_choice(r2)
set_terrain { r2,
f.all(
f.terrain("Gs^F*,Hh^F*"),
f.none(

View file

@ -17,7 +17,7 @@ function connected_components(locs)
local todo = { loc }
l_set[loc_i] = color_i
while #todo ~= 0 do
for i, loc_ad in ipairs({wesnoth.map.get_adjacent_hexes(todo[1][1], todo[1][2])}) do
for j, loc_ad in ipairs({wesnoth.map.get_adjacent_hexes(todo[1][1], todo[1][2])}) do
local loc_ad_i = loc_to_index(loc_ad)
if l_set[loc_ad_i] then
if l_set[loc_ad_i] == true then

View file

@ -67,11 +67,11 @@ local function world_conquest_tek_map_decoration_6a()
}
-- stone roads, better ones near castle
local rad = mathx.random(4, 6)
local rad1 = mathx.random(4, 6)
set_terrain { "Rrc",
f.all(
f.terrain("Re"),
f.radius(rad, f.terrain("Ch"))
f.radius(rad1, f.terrain("Ch"))
),
}
set_terrain { "Rr",
@ -167,7 +167,7 @@ local function world_conquest_tek_map_decoration_6a()
}
-- add snow, base amount in map surface
local terrain_to_change = map:find(f.all(
local terrain_to_change1 = map:find(f.all(
f.terrain("!,Ss,D*^*,Hd,W*^*,Mm^Xm,Xu,Mv,Q*^*,U*^*"),
f.radius(3, f.all(
f.terrain("Gd^Fdf,Hh,Hh^Fdf"),
@ -175,11 +175,11 @@ local function world_conquest_tek_map_decoration_6a()
))
))
local r = mathx.random_choice(tostring(total_tiles // 930) .. ".." .. tostring(total_tiles // 210))
wct_storm(terrain_to_change, r + 2)
local rand_choice1 = mathx.random_choice(tostring(total_tiles // 930) .. ".." .. tostring(total_tiles // 210))
wct_storm(terrain_to_change1, rand_choice1 + 2)
wct_expand_snow()
wct_storm(terrain_to_change, r)
wct_storm(terrain_to_change1, rand_choice1)
-- snow can change adyacent forests
set_terrain { "Hh^Fmw",
f.all(
@ -268,15 +268,15 @@ local function world_conquest_tek_map_decoration_6a()
-- chances of few dwarven castles
local terrain_to_change = wct_store_possible_dwarven_castle()
while #terrain_to_change > 0 and mathx.random(2) == 1 do
local loc = terrain_to_change[mathx.random(#terrain_to_change)]
local terrain_to_change2 = wct_store_possible_dwarven_castle()
while #terrain_to_change2 > 0 and mathx.random(2) == 1 do
local loc = terrain_to_change2[mathx.random(#terrain_to_change2)]
map[loc] = "Cud"
terrain_to_change = wct_store_possible_dwarven_castle()
terrain_to_change2 = wct_store_possible_dwarven_castle()
end
-- decorative farmlands in base to log villages
local terrain_to_change = map:find(f.terrain("Gs^Vl"))
for i = 1, mathx.random(0, 2 * #terrain_to_change) do
local terrain_to_change3 = map:find(f.terrain("Gs^Vl"))
for i = 1, mathx.random(0, 2 * #terrain_to_change3) do
set_terrain { "Gg^Gvs",
f.all(
f.terrain("Gs,Gg"),
@ -350,17 +350,17 @@ local function world_conquest_tek_map_decoration_6a()
end
-- chances of stone walls and dark roads near darven castls
local rad = mathx.random(1, 4)
local rad2 = mathx.random(1, 4)
set_terrain { "Xos",
f.all(
f.terrain("Xu"),
f.radius(rad, f.terrain("Cud"))
f.radius(rad2, f.terrain("Cud"))
),
}
wct_map_cave_path_to("Re")
local r = mathx.random_choice("Ur,Urb")
set_terrain { r,
local rand_choice2 = mathx.random_choice("Ur,Urb")
set_terrain { rand_choice2,
f.all(
f.terrain("Re"),
f.radius(6, f.terrain("Cud"))

View file

@ -1,5 +1,5 @@
-- Industrial
-- TODO: this is somwwhta slow, maybe it because it used wct_iterate_road_to ?
-- TODO: this is somewhat slow, maybe it because it used wct_iterate_road_to ?
local function wct_conect_factory_rails()
local rails_conected = map:find(f.all(
f.terrain("*^Br*"),
@ -379,12 +379,12 @@ local function world_conquest_tek_map_decoration_6c()
),
layer = "base",
}
local terrain_to_change = map:find(f.all(
local terrain_to_change1 = map:find(f.all(
f.terrain("Sm^*"),
f.adjacent(f.terrain("Ww^*"))
))
for swamp_i, swamp_loc in ipairs(terrain_to_change) do
for swamp_i, swamp_loc in ipairs(terrain_to_change1) do
local r = mathx.random(3, map.width // 4)
set_terrain { "Sm",
f.all(
@ -396,12 +396,12 @@ local function world_conquest_tek_map_decoration_6c()
}
end
-- dirty rivers
local terrain_to_change = map:find(f.all(
local terrain_to_change2 = map:find(f.all(
f.terrain("Sm^*"),
f.adjacent(f.terrain("Ww^*"))
))
for water_i, water_loc in ipairs(terrain_to_change) do
for water_i, water_loc in ipairs(terrain_to_change2) do
local r = mathx.random(4, map.width // 6)
set_terrain { "Wwg",
f.all(

View file

@ -118,47 +118,31 @@ local function world_conquest_tek_map_repaint_6d()
set_terrain { "Khs",
f.terrain("Chs"),
}
if false then
-- this one was slow.
set_terrain { "Chs",
f.all(
f.terrain("!,W*,Ds,Ss,C*,K*,*^V*"),
f.adjacent(f.terrain("C*,K*"), nil, 0),
f.none(
f.radius(8, f.terrain("Re"))
),
f.radius(6, f.terrain("Khs"))
local r8_Re = map:find_in_radius(
map:find(f.terrain("Re")),
8,
wesnoth.map.filter(f.all())
)
local r6_Khs = map:find_in_radius(
map:find(f.terrain("Khs")),
6,
wesnoth.map.filter(f.all())
)
set_terrain { "Chs",
f.all(
f.terrain("!,W*,Ds,Ss,C*,K*,*^V*"),
f.adjacent(f.terrain("C*,K*"), nil, 0),
f.none(
f.find_in("r8_Re")
),
fraction = 40,
}
else
-- this is faster.
local r8_Re = map:find_in_radius(
map:find(f.terrain("Re")),
8,
wesnoth.map.filter(f.all())
)
local r6_Khs = map:find_in_radius(
map:find(f.terrain("Khs")),
6,
wesnoth.map.filter(f.all())
)
set_terrain { "Chs",
f.all(
f.terrain("!,W*,Ds,Ss,C*,K*,*^V*"),
f.adjacent(f.terrain("C*,K*"), nil, 0),
f.none(
f.find_in("r8_Re")
),
f.find_in("r6_Khs")
),
filter_extra = {
r6_Khs = r6_Khs,
r8_Re = r8_Re,
},
fraction = 40,
}
end
f.find_in("r6_Khs")
),
filter_extra = {
r6_Khs = r6_Khs,
r8_Re = r8_Re,
},
fraction = 40,
}
roads_to_feudal_castle(5)
-- rebuild cave
wct_reduce_wall_clusters("Uu")

View file

@ -5,9 +5,9 @@
---- place them ----
----------------------------------------------------------
function random_placement(locs, num_items, min_distance, command)
function random_placement(locs, orig_num_items, min_distance, command)
local distance = min_distance or 0
local num_items = num_items or 1
local num_items = orig_num_items or 1
local allow_less = true
local math_abs = math.abs
local size = #locs
@ -24,14 +24,13 @@ function random_placement(locs, num_items, min_distance, command)
local point = locs[index]
command(point, i)
if distance < 0 then
-- optimisation: nothing to do for distance < 0
elseif distance == 0 then
-- optimisation: nothing to do for distance < 0
if distance == 0 then
-- optimisation: for distance = 0 we just need to remove the element at index
-- optimisation: swapping elements and storing size in an extra variable is faster than table.remove(locs, j)
locs[index] = locs[size]
size = size - 1
else
elseif distance > 0 then
-- the default case and the main reason why this was implemented.
for j = size, 1, -1 do
local x1 = locs[j][1]
@ -285,18 +284,6 @@ function wct_bonus_chose_scenery(loc, theme, filter_extra)
scenery = "well_g,temple,tent2_g,tent1,village,monolith3,burial"
end
end
-- TODO: bring back?
if false then
if theme == "wild" then
if matches_location(
f.all(
f.find_in_wml("map_data.road_in_cave")
)) then
scenery = "altar,bones,rock_cairn,well,monolith2,monolith3,tent1"
end
end
end
if theme == "volcanic" then
if matches_location(
f.all(
@ -389,7 +376,6 @@ function wct_bonus_chose_scenery(loc, theme, filter_extra)
scenery = scenery .. "," .. "oak_dead,oak_dead,oak_dead,oak_dead,oak_dead2,oak_dead2,oak_dead2,oak_dead2"
end
::final_pick::
-- pick random scenery value from our list
local res = mathx.random_choice(scenery)
wesnoth.log("debug", "scenery:" .. res .. " from " .. scenery)

View file

@ -195,9 +195,9 @@ function convert_filter()
local terrain = change.terrain
local f = parse_wml_filter(wml.get_child(change, "filter"))
local extras = {}
for k, v in pairs(change) do
for k, val in pairs(change) do
if type(k) == "string" and k ~= "terrain" then
extras[k] = v
extras[k] = val
end
end

View file

@ -19,15 +19,13 @@ local ice = {
--replaces terrain fo the wct custom terrain mod.
local function wct_map_custom_ruin_village(loc)
local map = wesnoth.current.map
-- TODO: enable once https://github.com/wesnoth/wesnoth/issues/4894 is fixed.
if false then
if loc:matches{terrain = "*^Vh,*^Vha"} then
map[loc] = "^Vhr"
end
if loc:matches{terrain = "*^Vhc,*^Vhca"} then
map[loc] = "^Vhr"
end
end
-- TODO: uncomment once https://github.com/wesnoth/wesnoth/issues/4894 is fixed.
-- if loc:matches{terrain = "*^Vh,*^Vha"} then
-- map[loc] = "^Vhr"
-- end
-- if loc:matches{terrain = "*^Vhc,*^Vhca"} then
-- map[loc] = "^Vhr"
-- end
end
on_event("die", function(cx)
@ -106,12 +104,10 @@ on_event("die", function(cx)
if loc:matches{terrain = "Ch^V*"} then
map[loc] = "Chr^"
end
-- TODO: enable once https://github.com/wesnoth/wesnoth/issues/4894 is fixed.
if false then
if loc:matches{terrain = "*^Fda"} then
map[loc] = "^Fdw"
end
end
-- TODO: uncomment once https://github.com/wesnoth/wesnoth/issues/4894 is fixed.
-- if loc:matches{terrain = "*^Fda"} then
-- map[loc] = "^Fdw"
-- end
else
if loc:matches{terrain = "*^Vhh,*^Vhha"} then
map[loc] = "^Vhhr"

View file

@ -256,8 +256,7 @@ function converter.wml_to_lon(cfg, name)
end
for k,v in pairs(cfg) do
if type(k) == "number" then
else --string
if type(k) ~= "number" then
local conv = attrs[k] and schema.__attributes[attrs[k]]
if conv then
res[k] = conv.to_lon(v)

View file

@ -137,7 +137,7 @@ function callbacks.generate_map(params)
end
local path = wesnoth.paths.find_path(
v.start_x, v.start_y, v.dest_x, v.dest_y, calc, params.map_width, params.map_height)
for i, loc in ipairs(path) do
for j, loc in ipairs(path) do
local locs_set = LS.create()
build_chamber(loc[1], loc[2], locs_set, width, jagged)
for x,y in locs_set:stable_iter() do

View file

@ -38,9 +38,11 @@ if wesnoth.kernel_type() == "Game Lua Kernel" then
function wesnoth.get_side_variable(side, var)
return wesnoth.sides[side].variables[var]
end
function wesnoth.get_starting_location(side)
local side = side
if type(side) == 'number' then side = wesnoth.sides[side] end
function wesnoth.get_starting_location(side_num)
local side = side_num
if type(side) == 'number' then
side = wesnoth.sides[side]
end
return side.starting_location
end

View file

@ -53,7 +53,7 @@ function functional.choose(input, value)
value = function(v) return v[key] end
end
local max_value, best_input, best_key = -math.huge
local max_value, best_input, best_key = -math.huge, nil, nil
for k,v in ipairs(input) do
local v2 = value(v)
if v2 > max_value then
@ -75,7 +75,7 @@ function functional.choose_map(input, value)
value = function(k, v) return v[key] end
end
local max_value, best_input, best_key = -math.huge
local max_value, best_input, best_key = -math.huge, nil, nil
for k,v in pairs(input) do
local v2 = value(k, v)
if v2 > max_value then

View file

@ -325,12 +325,13 @@ function methods:to_wml_var(name, mode)
mode = mode or "always_clear"
local is_explicit_index = name[-1] == "]"
local i = 0
if is_explicit_index then
-- explicit indexes behave always like "replace"
elseif mode == "append" then
i = wml.variables[name .. ".length"]
elseif mode ~= "replace" then
wml.variables[name] = nil
-- explicit indexes behave always like "replace"
if not is_explicit_index then
if mode == "append" then
i = wml.variables[name .. ".length"]
elseif mode ~= "replace" then
wml.variables[name] = nil
end
end
self:stable_iter(function(x, y, v)
if wml.valid(v) then

View file

@ -346,7 +346,7 @@ function wml_actions.unit_overlay(cfg)
local img = cfg.image or wml.error( "[unit_overlay] missing required image= attribute" )
for i,u in ipairs(wesnoth.units.find_on_map(cfg)) do
local has_already = false
for i, w in ipairs(u.overlays) do
for j, w in ipairs(u.overlays) do
if w == img then has_already = true end
end
if has_already == false then
@ -366,7 +366,7 @@ function wml_actions.remove_unit_overlay(cfg)
local img = cfg.image or wml.error( "[remove_unit_overlay] missing required image= attribute" )
for i,u in ipairs(wesnoth.units.find_on_map(cfg)) do
local has_already = false
for i, w in ipairs(u.overlays) do
for j, w in ipairs(u.overlays) do
if w == img then has_already = true end
end
if has_already then

View file

@ -4,8 +4,8 @@ local utils = {vwriter = {}}
function utils.split(s)
return coroutine.wrap(function()
local split = s:split()
for _,s in ipairs(split) do
coroutine.yield(s)
for _,sp in ipairs(split) do
coroutine.yield(sp)
end
end)
end
@ -26,12 +26,13 @@ function utils.vwriter.init(cfg, default_variable)
local is_explicit_index = variable[-1] == "]"
local mode = cfg.mode or "always_clear"
local index = 0
if is_explicit_index then
-- explicit indexes behave always like "replace"
elseif mode == "append" then
index = wml.variables[variable .. ".length"]
elseif mode ~= "replace" then
wml.variables[variable] = nil
-- explicit indexes behave always like "replace"
if not is_explicit_index then
if mode == "append" then
index = wml.variables[variable .. ".length"]
elseif mode ~= "replace" then
wml.variables[variable] = nil
end
end
return {
variable = variable,

View file

@ -406,6 +406,7 @@ function wesnoth.wml_actions.message(cfg)
return
elseif cfg.highlight == false then
-- Nothing to do here
log("Nothing to highlight for [message]", "debug")
elseif speaker == "narrator" then
-- Narrator, so deselect units
wesnoth.interface.deselect_hex()

View file

@ -68,7 +68,7 @@ function wesnoth.wml_actions.move_unit(cfg)
local check_passability = cfg.check_passability
if check_passability == nil then check_passability = true end
cfg = wml.literal(cfg)
cfg.to_location, cfg.to_x, cfg.to_y, cfg.fire_event, cfg.clear_shroud = nil
cfg.to_location, cfg.to_x, cfg.to_y, cfg.fire_event, cfg.clear_shroud = nil, nil, nil, nil, nil
local units = wesnoth.units.find_on_map(cfg)
for current_unit_index, current_unit in ipairs(units) do

View file

@ -79,9 +79,7 @@ res.turns_over_advantage = function()
end
end
if #winning_sides == 0 then
-- every side either has no units or has a negative score
elseif #winning_sides == 1 then
if #winning_sides == 1 then
-- po: In the end-of-match summary, there's a single side that's won.
local comparison_text = _ "<span foreground='$side_color'>Side $side_number</span> has the advantage."
side_comparison = side_comparison .. "\n" .. comparison_text:vformat{side_number = winning_sides[1], side_color = winners_color}
@ -90,12 +88,14 @@ res.turns_over_advantage = function()
-- Separated from the three-or-more text in case a language differentiates "two sides" vs "three sides".
local comparison_text = _ "Sides $side_number and $other_side_number are tied."
side_comparison = side_comparison .. "\n" .. comparison_text:vformat{side_number = winning_sides[1], other_side_number = winning_sides[2]}
else
elseif #winning_sides ~= 0 then
local winners = stringx.format_conjunct_list("", winning_sides)
-- po: In the end-of-match summary, three or more teams have all tied for the best score. $winners contains the result of formatting the conjunct list.
local comparison_text = _ "Sides $winners are tied."
side_comparison = side_comparison .. "\n" .. comparison_text:vformat{winners = winners}
end
-- if #winning_sides==0, then every side either has no units or has a negative score
-- po: "Turns Over", meaning "turn limit reached" is the title of the end-of-match summary dialog
local a, b = gui.show_popup(_ "dialog^Turns Over", side_comparison)
end

View file

@ -11,8 +11,8 @@ local function plugin()
local events, context, info
local function find_test_game(info)
local g = info.game_list()
local function find_test_game(game_info)
local g = game_info.game_list()
if g then
local gamelist = wml.get_child(g, "gamelist")
if gamelist then