Add unit tests for movement and vision costs
Includes changing the terrain costs, and aliased terrains. Can be cleanly cherry-picked to 1.14.
This commit is contained in:
parent
e62982325a
commit
358f564301
3 changed files with 396 additions and 0 deletions
13
data/test/maps/test_movetype.map
Normal file
13
data/test/maps/test_movetype.map
Normal file
|
@ -0,0 +1,13 @@
|
|||
Xv, Xv, Xv, Xv, Xv, Xv, Xv
|
||||
Xv, Xv, Xv, Xv, Xv, Xv, Xv
|
||||
Xv, Xv, destination Ce, Wwf^Fpa, Cme, Xv, Xv
|
||||
Xv, Xv, Xv, Xv, Wwf, Xv, Xv
|
||||
Xv, Xv, Uh^Fda, Wo^Bw/r, Xv, Xv, Xv
|
||||
Xv, Xv, Gg^Fda, Xv, Xv, Xv, Xv
|
||||
Xv, Xv, Xv, Dd^Ftd, Uh, Xv, Xv
|
||||
Xv, Xv, Xv, Xv, Hh, Xv, Xv
|
||||
Xv, Xv, Xv, Hh^Fds, Xv, Xv, Xv
|
||||
Xv, Xv, Gg, Gg^Fds, Gg, Xv, Xv
|
||||
Xv, Xv, 1 Gg, Xv, 2 Gg, Xv, Xv
|
||||
Xv, Xv, Xv, Xv, Xv, Xv, Xv
|
||||
Xv, Xv, Xv, Xv, Xv, Xv, Xv
|
362
data/test/scenarios/test_movetype.cfg
Normal file
362
data/test/scenarios/test_movetype.cfg
Normal file
|
@ -0,0 +1,362 @@
|
|||
# This series of tests checks that the C++ movetype class handles changes to movetypes correctly.
|
||||
|
||||
# The map defines a location_id "destination", and from both start points the path to it is
|
||||
# Flat
|
||||
# Forest
|
||||
# Forest Hills
|
||||
# Hills
|
||||
# Cave Hills
|
||||
# Forest Sand
|
||||
# Flat Frozen Forest
|
||||
# Cave Hills Frozen Forest
|
||||
# bridge over deep water (best-of Flat and Deep Water)
|
||||
# ford (best-of Flat and Water)
|
||||
# aquatic encampment (best-of Castle and Coastal Reef)
|
||||
# ford snowy forest (Frozen, Forest, Flat, Shallow Water)
|
||||
# Keep
|
||||
#
|
||||
# Note: in 1.14 (and 1.15 at the time of writing), ford snowy forest's movement is
|
||||
# the worst of all four types, not the worst of (Frozen, Forest, Ford).
|
||||
#
|
||||
# 1, 1, 2, 2, 3, 2, 2, 3, 1, 1, 1, 3, 1 MP for an Elvish Archer
|
||||
# 1, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 3, 1 MP for an Orcish Grunt
|
||||
|
||||
# Bob is always an orc, his movement is checked in every test run to check that
|
||||
# any effect in ALICE_MODIFICATION hasn't affected his movement costs.
|
||||
#define ORC_COSTS
|
||||
1,2,2,1,2,2,2,2,1,1,1,3,1
|
||||
#enddef
|
||||
|
||||
#define MOVETYPE_MOVE_SCEN ID ALICE_TYPE ALICE_MOVE_COSTS BOB_MOVE_COSTS ALICE_MODIFICATION
|
||||
[test]
|
||||
name = "Unit Test {ID}"
|
||||
map_data = "{test/maps/test_movetype.map}"
|
||||
turns = 1
|
||||
id = {ID}
|
||||
random_start_time = no
|
||||
is_unit_test = yes
|
||||
|
||||
{DEFAULT_SCHEDULE}
|
||||
|
||||
[side]
|
||||
side=1
|
||||
controller=human
|
||||
name = "Alice"
|
||||
type = {ALICE_TYPE}
|
||||
id=alice
|
||||
fog=no
|
||||
shroud=no
|
||||
share_view=no
|
||||
[/side]
|
||||
[side]
|
||||
side=2
|
||||
controller=human
|
||||
name = "Bob"
|
||||
type = Orcish Grunt
|
||||
id=bob
|
||||
fog=no
|
||||
shroud=no
|
||||
share_view=no
|
||||
[/side]
|
||||
|
||||
[event]
|
||||
name = prestart
|
||||
[set_variables]
|
||||
name=travelers
|
||||
mode=replace
|
||||
[split]
|
||||
list="alice,bob"
|
||||
key=id
|
||||
separator=","
|
||||
[/split]
|
||||
[/set_variables]
|
||||
[set_variables]
|
||||
name=expected_movement_cost
|
||||
mode=replace
|
||||
[split]
|
||||
list={ALICE_MOVE_COSTS}
|
||||
key=alice
|
||||
separator=","
|
||||
[/split]
|
||||
[/set_variables]
|
||||
[set_variables]
|
||||
name=expected_movement_cost
|
||||
mode=merge
|
||||
[split]
|
||||
list={BOB_MOVE_COSTS}
|
||||
key=bob
|
||||
separator=","
|
||||
[/split]
|
||||
[/set_variables]
|
||||
{ASSERT {VARIABLE_CONDITIONAL expected_movement_cost.length equals 13}}
|
||||
[/event]
|
||||
|
||||
[event]
|
||||
name = side 1 turn 1
|
||||
|
||||
# This test uses [find_path] to get the movement costs of mixed terrains,
|
||||
# but if a path needs multiple turns then [find_path] will include the
|
||||
# cost of movement points that were left unused at the end of all turns
|
||||
# except the last. To avoid that, give the units enough MP.
|
||||
[modify_unit]
|
||||
[filter]
|
||||
[/filter]
|
||||
moves="$({UNREACHABLE} - 1)"
|
||||
max_moves="$({UNREACHABLE} - 1)"
|
||||
[/modify_unit]
|
||||
|
||||
{ALICE_MODIFICATION}
|
||||
|
||||
[foreach]
|
||||
array=travelers
|
||||
variable=traveler
|
||||
[do]
|
||||
[find_path]
|
||||
[traveler]
|
||||
id=$traveler.id
|
||||
[/traveler]
|
||||
[destination]
|
||||
location_id=destination
|
||||
[/destination]
|
||||
allow_multiple_turns=no
|
||||
variable=path
|
||||
[/find_path]
|
||||
# The path's steps include the starting hex, which is why there's
|
||||
# a +1 here and a +1 in the [for] loop.
|
||||
{ASSERT {VARIABLE_CONDITIONAL path.hexes not_equals 0}}
|
||||
{ASSERT {VARIABLE_CONDITIONAL path.step.length equals 14}}
|
||||
{VARIABLE expected_total 0}
|
||||
[for]
|
||||
array=expected_movement_cost
|
||||
[do]
|
||||
{VARIABLE i_plus_one "$($i + 1)"}
|
||||
[set_variable]
|
||||
name=expected_total
|
||||
add=$expected_movement_cost[$i].$traveler.id
|
||||
[/set_variable]
|
||||
{ASSERT {VARIABLE_CONDITIONAL path.step[$i_plus_one].movement_cost equals $expected_total}}
|
||||
[/do]
|
||||
[/for]
|
||||
[/do]
|
||||
[/foreach]
|
||||
|
||||
{SUCCEED}
|
||||
[/event]
|
||||
[/test]
|
||||
#enddef
|
||||
|
||||
# This test works by setting Alice's vision points, resetting the fog and then seeing how many hexes are visible.
|
||||
# The parameter ALICE_VISION_COSTS contains the values of each hex in the path from Alice to the destination,
|
||||
# so the same order as in the movement tests. Vision will also see the path towards Bob, for which this assumes that
|
||||
# the terrain adjacent to Bob's hex is the same as the terrain adjacent to Alice's.
|
||||
#
|
||||
# The vision cost of the location_id=destination hex will be ignored, as that hex becomes visible based on the cost
|
||||
# of the adjacent hex, however it's included in the macro argument for easier cut&paste from the MOVETYPE_MOVE_SCEN
|
||||
# tests.
|
||||
#define MOVETYPE_VISION_SCEN ID ALICE_TYPE ALICE_VISION_COSTS ALICE_MODIFICATION
|
||||
[test]
|
||||
name = "Unit Test {ID}"
|
||||
map_data = "{test/maps/test_movetype.map}"
|
||||
turns = 1
|
||||
id = {ID}
|
||||
random_start_time = no
|
||||
is_unit_test = yes
|
||||
|
||||
{DEFAULT_SCHEDULE}
|
||||
|
||||
[side]
|
||||
side=1
|
||||
controller=human
|
||||
name = "Alice"
|
||||
type = {ALICE_TYPE}
|
||||
id=alice
|
||||
fog=yes
|
||||
shroud=no
|
||||
share_view=no
|
||||
[/side]
|
||||
[side]
|
||||
side=2
|
||||
controller=human
|
||||
name = "Bob"
|
||||
type = Orcish Grunt
|
||||
id=bob
|
||||
fog=yes
|
||||
shroud=no
|
||||
share_view=no
|
||||
[/side]
|
||||
|
||||
[event]
|
||||
name = prestart
|
||||
[set_variables]
|
||||
name=expected_vision_costs
|
||||
mode=replace
|
||||
[split]
|
||||
list={ALICE_VISION_COSTS}
|
||||
key=alice
|
||||
separator=","
|
||||
[/split]
|
||||
[/set_variables]
|
||||
{ASSERT {VARIABLE_CONDITIONAL expected_vision_costs.length equals 13}}
|
||||
|
||||
# This could be counted with a location filter, but other assumptions about the
|
||||
# map already need to be hardcoded in the test.
|
||||
{VARIABLE walkable_hexes_on_map 10}
|
||||
[/event]
|
||||
|
||||
[event]
|
||||
name = side 1 turn 1
|
||||
|
||||
{ALICE_MODIFICATION}
|
||||
|
||||
{VARIABLE vision_points 0}
|
||||
{VARIABLE expected_visible_count 0}
|
||||
[while]
|
||||
{VARIABLE_CONDITIONAL expected_visible_count less_than $walkable_hexes_on_map}
|
||||
{VARIABLE_CONDITIONAL ended boolean_equals no} # this is set by ASSERT
|
||||
[do]
|
||||
[modify_unit]
|
||||
[filter]
|
||||
id=alice
|
||||
[/filter]
|
||||
vision=$vision_points
|
||||
[/modify_unit]
|
||||
[reset_fog]
|
||||
[filter_side]
|
||||
side=1
|
||||
[/filter_side]
|
||||
reset_view=true
|
||||
[/reset_fog]
|
||||
[redraw]
|
||||
side=1
|
||||
clear_shroud=true
|
||||
[/redraw]
|
||||
|
||||
# cumulative sum of the expected_vision_costs
|
||||
{VARIABLE expected_total 0}
|
||||
# We can always see the hex Alice is standing on and those adjacent to it,
|
||||
# for this test we ignore impassible hexes
|
||||
{VARIABLE expected_visible_count 2}
|
||||
# How many of the hexes towards the destination can we see?
|
||||
[for]
|
||||
array=expected_vision_costs
|
||||
[do]
|
||||
[set_variable]
|
||||
name=expected_total
|
||||
add=$expected_vision_costs[$i].alice
|
||||
[/set_variable]
|
||||
[if]
|
||||
{VARIABLE_CONDITIONAL vision_points greater_than_equal_to $expected_total}
|
||||
[then]
|
||||
[set_variable]
|
||||
name=expected_visible_count
|
||||
add=1
|
||||
[/set_variable]
|
||||
[/then]
|
||||
[/if]
|
||||
[/do]
|
||||
[/for]
|
||||
# Add hexes towards Bob
|
||||
[if]
|
||||
{VARIABLE_CONDITIONAL vision_points greater_than_equal_to
|
||||
"$($expected_vision_costs[0].alice + $expected_vision_costs[1].alice)"}
|
||||
[then]
|
||||
[set_variable]
|
||||
name=expected_visible_count
|
||||
add=1
|
||||
[/set_variable]
|
||||
[/then]
|
||||
[/if]
|
||||
[if]
|
||||
# Assume that the terrain adjacent to Bob's hex is the same as the terrain adjacent to Alice's.
|
||||
{VARIABLE_CONDITIONAL vision_points greater_than_equal_to
|
||||
"$(2 * $expected_vision_costs[0].alice + $expected_vision_costs[1].alice)"}
|
||||
[then]
|
||||
[set_variable]
|
||||
name=expected_visible_count
|
||||
add=1
|
||||
[/set_variable]
|
||||
[/then]
|
||||
[/if]
|
||||
|
||||
[store_locations]
|
||||
terrain=!,X*
|
||||
[filter_vision]
|
||||
side=1
|
||||
visible=yes
|
||||
respect_fog=yes
|
||||
[/filter_vision]
|
||||
variable=visible_hexes
|
||||
[/store_locations]
|
||||
{ASSERT {VARIABLE_CONDITIONAL visible_hexes.length equals $expected_visible_count}}
|
||||
|
||||
[set_variable]
|
||||
name=vision_points
|
||||
add=1
|
||||
[/set_variable]
|
||||
[/do]
|
||||
[/while]
|
||||
|
||||
{SUCCEED}
|
||||
[/event]
|
||||
[/test]
|
||||
#enddef
|
||||
|
||||
#define SET_MOVE_COSTS COSTS
|
||||
[modify_unit]
|
||||
[filter]
|
||||
id=alice
|
||||
[/filter]
|
||||
[effect]
|
||||
apply_to=movement_costs
|
||||
replace=yes
|
||||
[movement_costs]
|
||||
{COSTS}
|
||||
[/movement_costs]
|
||||
[/effect]
|
||||
[/modify_unit]
|
||||
#enddef
|
||||
|
||||
#define SET_VISION_COSTS COSTS
|
||||
[modify_unit]
|
||||
[filter]
|
||||
id=alice
|
||||
[/filter]
|
||||
[effect]
|
||||
apply_to=vision_costs
|
||||
replace=yes
|
||||
[vision_costs]
|
||||
{COSTS}
|
||||
[/vision_costs]
|
||||
[/effect]
|
||||
[/modify_unit]
|
||||
#enddef
|
||||
|
||||
{MOVETYPE_MOVE_SCEN test_elf_movement (Elvish Archer) (1,1,2,2,3,2,2,3,1,1,1,3,1) {ORC_COSTS} ()}
|
||||
{MOVETYPE_MOVE_SCEN test_orc_movement (Orcish Grunt) {ORC_COSTS} {ORC_COSTS} ()}
|
||||
{MOVETYPE_MOVE_SCEN test_elf_fast_cave_movement (Elvish Archer) (1,1,2,2,2,2,2,2,1,1,1,3,1) {ORC_COSTS} {SET_MOVE_COSTS cave=1}}
|
||||
{MOVETYPE_MOVE_SCEN test_elf_fast_hills_movement (Elvish Archer) (1,1,1,1,3,2,2,3,1,1,1,3,1) {ORC_COSTS} {SET_MOVE_COSTS hills=1}}
|
||||
{MOVETYPE_MOVE_SCEN test_elf_fast_cave_and_hills_movement (Elvish Archer) (1,1,1,1,1,2,2,2,1,1,1,3,1) {ORC_COSTS} ({SET_MOVE_COSTS cave=1}{SET_MOVE_COSTS hills=1})}
|
||||
{MOVETYPE_MOVE_SCEN test_orc_fast_cave_movement (Orcish Grunt) (1,2,2,1,1,2,2,2,1,1,1,3,1) {ORC_COSTS} {SET_MOVE_COSTS cave=1}}
|
||||
{MOVETYPE_MOVE_SCEN test_orc_fast_forest_movement (Orcish Grunt) (1,1,1,1,2,2,2,2,1,1,1,3,1) {ORC_COSTS} {SET_MOVE_COSTS forest=1}}
|
||||
{MOVETYPE_MOVE_SCEN test_elf_slow_cave_movement (Elvish Archer) (1,1,2,2,4,2,2,4,1,1,1,3,1) {ORC_COSTS} {SET_MOVE_COSTS cave=4}}
|
||||
|
||||
# changing the vision costs shouldn't affect the movement costs
|
||||
{MOVETYPE_MOVE_SCEN test_elf_longsighted_movement (Elvish Archer) (1,1,2,2,3,2,2,3,1,1,1,3,1) {ORC_COSTS} {SET_VISION_COSTS cave=1}}
|
||||
{MOVETYPE_MOVE_SCEN test_orc_longsighted_movement (Orcish Grunt) {ORC_COSTS} {ORC_COSTS} {SET_VISION_COSTS cave=1}}
|
||||
{MOVETYPE_MOVE_SCEN test_elf_longsighted_fast_cave_movement (Elvish Archer) (1,1,2,2,2,2,2,2,1,1,1,3,1) {ORC_COSTS} ({SET_VISION_COSTS hills=1}{SET_MOVE_COSTS cave=1})}
|
||||
{MOVETYPE_MOVE_SCEN test_elf_fast_cave_longsighted_movement (Elvish Archer) (1,1,2,2,2,2,2,2,1,1,1,3,1) {ORC_COSTS} ({SET_MOVE_COSTS cave=1}{SET_VISION_COSTS hills=1})}
|
||||
|
||||
{MOVETYPE_VISION_SCEN test_elf_vision (Elvish Archer) (1,1,2,2,3,2,2,3,1,1,1,3,1) ()}
|
||||
# vision should fall back to movement, so these should match the movement numbers
|
||||
{MOVETYPE_VISION_SCEN test_elf_fast_cave_vision (Elvish Archer) (1,1,2,2,2,2,2,2,1,1,1,3,1) {SET_MOVE_COSTS cave=1}}
|
||||
{MOVETYPE_VISION_SCEN test_elf_fast_hills_vision (Elvish Archer) (1,1,1,1,3,2,2,3,1,1,1,3,1) {SET_MOVE_COSTS hills=1}}
|
||||
|
||||
{MOVETYPE_VISION_SCEN test_elf_longsighted_cave_vision (Elvish Archer) (1,1,2,2,2,2,2,2,1,1,1,3,1) {SET_VISION_COSTS cave=1}}
|
||||
{MOVETYPE_VISION_SCEN test_elf_longsighted_cave_and_hills_vision (Elvish Archer) (1,1,1,1,1,2,2,2,1,1,1,3,1) ({SET_VISION_COSTS cave=1}{SET_VISION_COSTS hills=1})}
|
||||
{MOVETYPE_VISION_SCEN test_elf_longsighted_cave_slow_cave_vision (Elvish Archer) (1,1,2,2,2,2,2,2,1,1,1,3,1) ({SET_VISION_COSTS cave=1}{SET_MOVE_COSTS cave=4})}
|
||||
|
||||
#undef SET_VISION_COSTS
|
||||
#undef SET_MOVE_COSTS
|
||||
#undef MOVETYPE_VISION_SCEN
|
||||
#undef MOVETYPE_MOVE_SCEN
|
||||
#undef ORC_COSTS
|
|
@ -120,6 +120,27 @@
|
|||
0 characterize_pathfinding_reach_6
|
||||
0 characterize_pathfinding_reach_7
|
||||
#
|
||||
# Movement types, and modifying them
|
||||
#
|
||||
0 test_elf_movement
|
||||
0 test_orc_movement
|
||||
0 test_elf_fast_cave_movement
|
||||
0 test_elf_fast_hills_movement
|
||||
0 test_elf_fast_cave_and_hills_movement
|
||||
0 test_orc_fast_cave_movement
|
||||
0 test_orc_fast_forest_movement
|
||||
0 test_elf_slow_cave_movement
|
||||
0 test_elf_longsighted_movement
|
||||
0 test_orc_longsighted_movement
|
||||
0 test_elf_longsighted_fast_cave_movement
|
||||
0 test_elf_fast_cave_longsighted_movement
|
||||
0 test_elf_vision
|
||||
0 test_elf_fast_cave_vision
|
||||
0 test_elf_fast_hills_vision
|
||||
0 test_elf_longsighted_cave_vision
|
||||
0 test_elf_longsighted_cave_and_hills_vision
|
||||
0 test_elf_longsighted_cave_slow_cave_vision
|
||||
#
|
||||
# Attack calculations & codepath tests
|
||||
#
|
||||
0 alice_kills_bob
|
||||
|
|
Loading…
Add table
Reference in a new issue