0.4.0: map (N) that fills in as you explore and a compass (closes #1); Old Tam's seam and Cove tips (voiced); the journey and sea fish in the guide; trailer with the tunnel and the Cove; protocol 16
This commit is contained in:
@@ -9,7 +9,7 @@ if [ ! -f .godot/global_script_class_cache.cfg ]; then
|
||||
echo "Importing the project first (fresh copy)..."
|
||||
godot --headless --path . --import >/dev/null 2>&1
|
||||
fi
|
||||
for t in test_survival_core test_survival_stats test_save_load test_weather_building test_creatures_combat test_wolves test_alpha test_bear test_thieves test_barrow test_boss test_den_sites test_fishing_diet test_food test_hazards test_iron test_stone test_net_lobby test_net_world test_net_shared test_net_life test_net_boss test_net_rules test_host test_tutorial test_tutorial_full test_hints test_updates test_audio test_items_more test_worldlets test_worldlet_pick test_water_bodies test_cove test_tunnel test_terrain_edges test_boundary; do
|
||||
for t in test_survival_core test_survival_stats test_save_load test_weather_building test_creatures_combat test_wolves test_alpha test_bear test_thieves test_barrow test_boss test_den_sites test_fishing_diet test_food test_hazards test_iron test_stone test_net_lobby test_net_world test_net_shared test_net_life test_net_boss test_net_rules test_host test_tutorial test_tutorial_full test_hints test_updates test_audio test_items_more test_worldlets test_worldlet_pick test_water_bodies test_cove test_tunnel test_map test_terrain_edges test_boundary; do
|
||||
extra=""
|
||||
[ "$t" = "test_boundary" ] && extra="--fixed-fps 30"
|
||||
# A suite that waits on a world that failed to load would hang forever,
|
||||
|
||||
@@ -75,7 +75,7 @@ func _for(secs: float) -> void:
|
||||
|
||||
func _body() -> void:
|
||||
print("the tips")
|
||||
var kinds := ["event", "status", "weather", "has", "night", "stamina_low", "wolf_moon", "hard_winter"]
|
||||
var kinds := ["event", "status", "weather", "has", "night", "stamina_low", "wolf_moon", "hard_winter", "worldlet", "seam"]
|
||||
var bad: Array = []
|
||||
for h in H.hints:
|
||||
if not String(h.when).get_slice(":", 0) in kinds or String(h.title).is_empty() or String(h.text).is_empty():
|
||||
|
||||
139
tests/test_map.gd
Normal file
139
tests/test_map.gd
Normal file
@@ -0,0 +1,139 @@
|
||||
extends SceneTree
|
||||
## The map and compass (Gitea issue #1). The map starts blank and fills in
|
||||
## around you as you go; places are marked once you've seen them (the den,
|
||||
## the barrow, the stones, the tunnel's seam, the Cove's pier and sea cave,
|
||||
## your beds and buildings); you're a dot, and the compass says which way
|
||||
## you're facing. What you've seen is saved with each worldlet.
|
||||
## Run: godot --headless --path . --script res://tests/test_map.gd
|
||||
|
||||
var _fails := 0
|
||||
var _finished := false
|
||||
var S: Node
|
||||
var DB: Node
|
||||
|
||||
func check(cond: bool, what: String) -> void:
|
||||
print((" ok " if cond else " FAIL ") + what)
|
||||
if not cond:
|
||||
_fails += 1
|
||||
|
||||
func _initialize() -> void:
|
||||
_run.call_deferred()
|
||||
|
||||
func _run() -> void:
|
||||
S = root.get_node("Saves")
|
||||
DB = root.get_node("ItemDB")
|
||||
S.root_dir = "user://test_map_worlds"
|
||||
for w in S.list_worlds():
|
||||
S.delete_world(w.id)
|
||||
await _body()
|
||||
check(_finished, "test ran to the end (no script errors)")
|
||||
for w in S.list_worlds():
|
||||
S.delete_world(w.id)
|
||||
DirAccess.remove_absolute(S.root_dir)
|
||||
print("RESULT: %s (%d failures)" % ["PASS" if _fails == 0 else "FAIL", _fails])
|
||||
quit(1 if _fails > 0 else 0)
|
||||
|
||||
func _load_world() -> Node3D:
|
||||
var w: Node3D = load("res://scenes/world.tscn").instantiate()
|
||||
root.add_child(w)
|
||||
for _i in range(8):
|
||||
await physics_frame
|
||||
w.creatures.enabled = false
|
||||
w.player.set_physics_process(false)
|
||||
return w
|
||||
|
||||
func _count(w: Node3D) -> int:
|
||||
var n := 0
|
||||
for b in w.explored:
|
||||
n += 1 if b != 0 else 0
|
||||
return n
|
||||
|
||||
func _body() -> void:
|
||||
S.current_id = S.create_world("Mapped", 1337)
|
||||
var w: Node3D = await _load_world()
|
||||
var player: Node3D = w.player
|
||||
print("filling in")
|
||||
await create_timer(0.7).timeout
|
||||
var start := _count(w)
|
||||
var all: int = w.MAP_CELLS * w.MAP_CELLS
|
||||
check(start > 0 and start < all / 8, "at first, only the ground around you (%d of %d cells)" % [start, all])
|
||||
check(w.seen(player.global_position.x, player.global_position.z), "(including where you stand)")
|
||||
check(w.den.found and not w.seen(w.den.global_position.x, w.den.global_position.z), "the den isn't on it yet")
|
||||
check(not w.map_marks().any(func(m): return m.kind == "den"), "(nor marked)")
|
||||
player.global_position = w.den.global_position + Vector3(6, 1, 0)
|
||||
w.explore(player.global_position)
|
||||
check(w.map_marks().any(func(m): return m.kind == "den" and m.label == "Wolf den"), "go near it and it's marked")
|
||||
check(_count(w) > start, "and the map's filled in on the way")
|
||||
w.explore(w.tunnel.seam_at)
|
||||
w.explore(w.barrow.global_position)
|
||||
w.explore(w.stones.global_position)
|
||||
var kinds: Array = w.map_marks().map(func(m): return m.kind)
|
||||
check("seam" in kinds and "barrow" in kinds and "stones" in kinds, "the cracked seam, the barrow and the stones, once seen (%s)" % [kinds])
|
||||
var bed: Node3D = w.spawn_piece(DB.get_item("bed"), Transform3D(Basis(), w._spawn + Vector3(4, 0, 2)))
|
||||
var floor_def: Dictionary = DB.get_item("wood_floor")
|
||||
if not floor_def.is_empty():
|
||||
w.spawn_piece(floor_def, Transform3D(Basis(), w._spawn + Vector3(-4, 0, 2)))
|
||||
w.explore(w._spawn)
|
||||
kinds = w.map_marks().map(func(m): return m.kind)
|
||||
check("bed" in kinds, "your bed")
|
||||
check(floor_def.is_empty() or "build" in kinds, "and your buildings")
|
||||
var below: Vector3 = w.tunnel.ORIGIN
|
||||
var before := _count(w)
|
||||
w.explore(below)
|
||||
check(_count(w) == before, "(nothing fills in down the tunnel)")
|
||||
|
||||
print("the screen")
|
||||
var MS: Script = load("res://scripts/ui/map_screen.gd")
|
||||
var img: Image = MS.render(w)
|
||||
check(img.get_width() == MS.RES, "the map image (%d px)" % img.get_width())
|
||||
var far := Vector2i(2, 2)
|
||||
var near: Vector2i = Vector2i(((w._spawn.x + w.terrain.size * 0.5) / w.terrain.size * MS.RES), ((w._spawn.z + w.terrain.size * 0.5) / w.terrain.size * MS.RES))
|
||||
check(img.get_pixelv(far).is_equal_approx(img.get_pixelv(Vector2i(4, 2))) or img.get_pixelv(far).v < 0.25, "blank where you haven't been")
|
||||
check(img.get_pixelv(near).v > 0.25, "drawn where you have")
|
||||
var lake: Vector2 = w.terrain.lake_center
|
||||
check(MS.ground_colour(w.terrain, lake.x, lake.y).b > MS.ground_colour(w.terrain, lake.x, lake.y).g, "water is blue")
|
||||
var screen: Control = MS.new()
|
||||
root.add_child(screen)
|
||||
screen.setup(w, player)
|
||||
screen.open()
|
||||
await process_frame
|
||||
await process_frame
|
||||
check(screen.is_open() and player.ui_open and screen._title.text == "The Valley", "N opens it: the Valley")
|
||||
check(screen._facing.text.begins_with("Facing "), "with which way you face (%s)" % screen._facing.text)
|
||||
screen.close()
|
||||
check(not screen.is_open() and not player.ui_open, "and closes it")
|
||||
screen.queue_free()
|
||||
|
||||
print("the compass")
|
||||
var C: Script = load("res://scripts/ui/compass.gd")
|
||||
player.rotation = Vector3.ZERO # (facing -Z)
|
||||
await process_frame
|
||||
check(absf(C.heading(player)) < 1.0 or absf(C.heading(player) - 360.0) < 1.0, "facing -Z is north (%.0f)" % C.heading(player))
|
||||
player.rotation = Vector3(0, -PI * 0.5, 0) # (facing +X)
|
||||
await process_frame
|
||||
check(absf(C.heading(player) - 90.0) < 1.0, "facing +X is east (%.0f)" % C.heading(player))
|
||||
|
||||
print("saved")
|
||||
var seen_n := _count(w)
|
||||
w.save_now()
|
||||
w.queue_free()
|
||||
for _i in range(3):
|
||||
await process_frame
|
||||
w = await _load_world()
|
||||
check(_count(w) >= seen_n, "what you've seen is still on the map after a reload (%d cells)" % _count(w))
|
||||
check(w.map_marks().any(func(m): return m.kind == "den"), "(the den too)")
|
||||
w.queue_free()
|
||||
for _i in range(3):
|
||||
await process_frame
|
||||
print("the Cove")
|
||||
S.current_id = S.create_world("Cove map", 1337, {"worldlet": "cove"})
|
||||
w = await _load_world()
|
||||
await create_timer(0.7).timeout
|
||||
check(_count(w) < start * 2, "a map of its own: only the ground round the start so far (%d cells)" % _count(w))
|
||||
w.explore(w.pier.end)
|
||||
w.explore(w.sea_cave.global_position)
|
||||
kinds = w.map_marks().map(func(m): return m.kind)
|
||||
check("pier" in kinds and "cave" in kinds, "the Cove's map: the pier and the sea cave (%s)" % [kinds])
|
||||
w.queue_free()
|
||||
await process_frame
|
||||
_finished = true
|
||||
1
tests/test_map.gd.uid
Normal file
1
tests/test_map.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://i5xx2lpb66s7
|
||||
Reference in New Issue
Block a user