160 lines
7.5 KiB
GDScript
160 lines
7.5 KiB
GDScript
extends SceneTree
|
|
|
|
# Headless test: run with
|
|
# godot --headless -s res://tests/test_dev_mode.gd
|
|
# A "Dev Mode" start for play-testing: one of every planet type next to the
|
|
# spawn, every resource banked, and research points to spend. Offered by the
|
|
# main menu only when the game is run from Godot, alongside the map editor.
|
|
#
|
|
# The same change took the training wheels off a NORMAL game: no 500 free
|
|
# ore, and no gas giant guaranteed in the origin chunk. Both of those were
|
|
# play-testing conveniences that had become part of the real game, so this
|
|
# test covers both sides - what dev mode hands you, and what a normal game
|
|
# no longer does.
|
|
#
|
|
# Covers:
|
|
# A. a dev game banks every resource type and research points
|
|
# B. a dev game is a normal game PLUS that, not a separate definition
|
|
# C. one of each planet type sits within a chunk or two of the spawn
|
|
# D. none of that leaks into a normal game, and starting one clears it
|
|
# E. a normal game starts with an empty bank
|
|
# F. the menu gates dev mode and the map editor on the same rule
|
|
|
|
var game_state: Node
|
|
var menu: Node
|
|
var stage: int = 0
|
|
var elapsed: float = 0.0
|
|
|
|
|
|
func _initialize() -> void:
|
|
game_state = root.get_node("GameState")
|
|
|
|
|
|
func _process(delta: float) -> bool:
|
|
elapsed += delta
|
|
match stage:
|
|
0:
|
|
# --- E. a normal game hands over nothing ----------------------
|
|
game_state.reset_new_game()
|
|
# #108: reset_new_game() also arms the prologue. Nothing below is
|
|
# about it, and this test never builds a scene for it to run in.
|
|
game_state.intro_active = false
|
|
if game_state.rocks != 0:
|
|
return _fail("a normal game started with %d ore banked" % game_state.rocks)
|
|
for resource_type in game_state.resource_types():
|
|
if game_state.banked_resource(resource_type) != 0:
|
|
return _fail("a normal game started with %s banked" % resource_type)
|
|
if game_state.research_points != 0:
|
|
return _fail("a normal game started with research points")
|
|
if game_state.dev_mode:
|
|
return _fail("a normal game started in dev mode")
|
|
print("normal game starts with an empty bank and no research points")
|
|
|
|
# --- D. no dev planets in a normal game -----------------------
|
|
# The dev arrangement must not survive into a normal world. Noise
|
|
# could coincidentally place a planet in one of these chunks, so
|
|
# what is asserted is that the ARRANGEMENT is not reproduced, not
|
|
# that each chunk is empty.
|
|
var reproduced: bool = true
|
|
for chunk in WorldGen.DEV_PLANET_CHUNKS:
|
|
var expected: String = String(WorldGen.DEV_PLANET_CHUNKS[chunk])
|
|
var data: Dictionary = WorldGen.planet_data_at_chunk(chunk)
|
|
if not WorldGen.has_planet_at_chunk(chunk) or String(data.get("definition_id", "")) != expected:
|
|
reproduced = false
|
|
if Vector2(data.get("local_pos", Vector2.ZERO)) == WorldGen.DEV_PLANET_LOCAL_POS:
|
|
return _fail("a normal game placed a planet at dev mode's fixed in-chunk position, in chunk %s" % chunk)
|
|
if reproduced:
|
|
return _fail("a normal game reproduced dev mode's whole planet arrangement")
|
|
print("normal game does not carry dev mode's planets")
|
|
|
|
# --- A + B. what a dev game hands over ------------------------
|
|
game_state.add_building(GameState.BUILDING_MOTHERSHIP, Vector2.ZERO)
|
|
game_state.planet_capture["chunk:9:9"] = {"captured": [true], "conquered": true}
|
|
game_state.start_dev_game()
|
|
if not game_state.dev_mode:
|
|
return _fail("start_dev_game() did not set dev_mode")
|
|
if game_state.intro_active:
|
|
return _fail("dev mode still starts at the prologue instead of after it")
|
|
for resource_type in game_state.resource_types():
|
|
var banked: int = game_state.banked_resource(resource_type)
|
|
if banked != GameState.DEV_RESOURCE_AMOUNT:
|
|
return _fail("dev game banked %d of %s, expected %d" \
|
|
% [banked, resource_type, GameState.DEV_RESOURCE_AMOUNT])
|
|
if game_state.research_points != GameState.DEV_RESEARCH_POINTS:
|
|
return _fail("dev game granted %d research points, expected %d" \
|
|
% [game_state.research_points, GameState.DEV_RESEARCH_POINTS])
|
|
# B: it still went through reset_new_game, so a dirty run is gone.
|
|
if not game_state.buildings.is_empty() or not game_state.planet_capture.is_empty():
|
|
return _fail("a dev game did not reset the previous run - it must be a fresh game plus a stock")
|
|
print("dev game banks %d of each resource and %d research points, from a clean slate" \
|
|
% [GameState.DEV_RESOURCE_AMOUNT, GameState.DEV_RESEARCH_POINTS])
|
|
|
|
# --- C. one of each planet type, close by ---------------------
|
|
var found: Dictionary = {}
|
|
for chunk in WorldGen.DEV_PLANET_CHUNKS:
|
|
if not WorldGen.has_planet_at_chunk(chunk):
|
|
return _fail("dev mode chunk %s holds no planet" % chunk)
|
|
var data: Dictionary = WorldGen.planet_data_at_chunk(chunk)
|
|
var definition_id: String = String(data.get("definition_id", ""))
|
|
if definition_id != String(WorldGen.DEV_PLANET_CHUNKS[chunk]):
|
|
return _fail("dev mode chunk %s holds a %s, expected a %s" \
|
|
% [chunk, definition_id, WorldGen.DEV_PLANET_CHUNKS[chunk]])
|
|
found[definition_id] = true
|
|
# "Near the start" is the whole point - a play-tester should
|
|
# reach any of them in seconds, not go exploring.
|
|
var world_pos: Vector2 = WorldGen.chunk_origin(chunk) + Vector2(data.local_pos)
|
|
if world_pos.length() > WorldGen.CHUNK_SIZE * 2.5:
|
|
return _fail("dev mode's %s spawned %.0f units away, too far to be 'near the start'" \
|
|
% [definition_id, world_pos.length()])
|
|
for definition_id in [PlanetDefinitions.ROCKY_ID, PlanetDefinitions.GAS_GIANT_ID,
|
|
PlanetDefinitions.BLACK_HOLE_ID, PlanetDefinitions.RESEARCH_LAB_ID,
|
|
PlanetDefinitions.BOSS_ID]:
|
|
if not found.has(definition_id):
|
|
return _fail("dev mode is missing a %s - it must plant one of EVERY planet type" % definition_id)
|
|
print("dev mode plants all %d planet types within %.0f units of the spawn" \
|
|
% [found.size(), WorldGen.CHUNK_SIZE * 2.5])
|
|
|
|
# --- D. starting a normal game clears it ----------------------
|
|
game_state.reset_new_game()
|
|
if game_state.dev_mode:
|
|
return _fail("starting a normal game after a dev one left dev_mode set")
|
|
if game_state.dev_unlimited_resources:
|
|
return _fail("starting a normal game kept unlimited resources enabled")
|
|
if game_state.rocks != 0 or game_state.research_points != 0:
|
|
return _fail("starting a normal game after a dev one kept the dev stock")
|
|
print("starting a normal game afterwards clears dev mode entirely")
|
|
|
|
menu = load("res://ui/MainMenu.tscn").instantiate()
|
|
root.add_child(menu)
|
|
current_scene = menu
|
|
elapsed = 0.0
|
|
stage = 1
|
|
return false
|
|
1:
|
|
# --- F. the menu gates both on the same rule ------------------
|
|
if elapsed < 0.1:
|
|
return false
|
|
var developing: bool = menu.is_developer_build()
|
|
if menu.dev_button.visible != developing:
|
|
return _fail("the dev mode button's visibility did not follow is_developer_build()")
|
|
if menu.editor_button.visible != developing:
|
|
return _fail("the map editor button's visibility did not follow is_developer_build()")
|
|
if not menu.play_button.visible:
|
|
return _fail("gating the development entries also hid Play")
|
|
# Hiding is presentation; pressing it anyway must still be refused.
|
|
if not developing:
|
|
menu._on_dev_mode_pressed()
|
|
if game_state.dev_mode:
|
|
return _fail("dev mode started outside a developer build")
|
|
print("dev mode and the map editor are both gated on is_developer_build() (%s here)" % developing)
|
|
|
|
print("TEST_DEV_MODE: PASS")
|
|
quit(0)
|
|
return true
|
|
return false
|
|
|
|
|
|
func _fail(message: String) -> bool:
|
|
print("TEST_DEV_MODE: FAIL (%s)" % message)
|
|
quit(1)
|
|
return true
|