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:
parent
254716e41e
commit
370d03ccb7
79 changed files with 455 additions and 477 deletions
1
.github/workflows/ci-scripts/docker.sh
vendored
1
.github/workflows/ci-scripts/docker.sh
vendored
|
@ -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
17
.luacheckrc
Normal 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"}
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 = {}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 } } }
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 }
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 } }
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"))
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
4
join.lua
4
join.lua
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue