spaceship/tests/test_research_points_explainer.gd

160 lines
6.4 KiB
GDScript3
Raw Normal View History

extends SceneTree
# A player who is short of research data is told where it comes from.
#
# It is the one currency with a non-obvious source: ore and gas are visibly
# mined, but data comes off conquered worlds and nothing said so at the point
# it mattered. The skill tree refused the node in SILENCE, and the ship lab
# refused with "Research is already queued or complete" - which is not why it
# refused, and sends the player looking at the wrong thing.
#
# Covers:
# A. a doctrine that costs data the player has not got opens the explainer,
# naming what was wanted and what they hold
# B. the same from the ship lab, instead of blaming the queue
# C. with the data in hand, the research goes through and no popup appears
var game_state: Node
var scene: Node
var controller: Node
var popup: Control
var elapsed: float = 0.0
var stage: int = 0
func _initialize() -> void:
game_state = root.get_node("GameState")
game_state.buildings.clear()
game_state.extractors.clear()
game_state.reset_progression()
game_state.reset_new_game()
game_state.intro_active = false
game_state.reset_quests()
game_state.rocks = 5000
game_state.bank_inventory.set_amount(GameState.RESOURCE_GAS, 5000)
game_state.bank_inventory.set_amount(GameState.RESOURCE_ENERGY, 5000)
game_state.research_points = 0
game_state.unlocked = ["shipyards"]
scene = load("res://world/Main.tscn").instantiate()
root.add_child(scene)
current_scene = scene
controller = scene.get_node("BuildController")
popup = scene.get_node("UI/ResearchPointsMenu")
func _costly_doctrine() -> String:
for node in GameState.SKILL_TREE:
if int(node.get("research_points", 0)) > 0:
return String(node.id)
return ""
func _process(delta: float) -> bool:
elapsed += delta
if elapsed < 0.4:
return false
match stage:
0:
var doctrine: String = _costly_doctrine()
if doctrine == "":
return _fail("no doctrine costs research data, so this proves nothing")
# Everything but the data: the prerequisite met and the ore paid,
# so data is unambiguously the thing that is missing.
game_state.unlocked = ["shipyards"]
var requires: String = String(game_state.skill_node(doctrine).get("requires", ""))
if requires != "" and not game_state.is_unlocked(requires):
game_state.unlocked.append(requires)
game_state.research_points = 0
var mothership_id: int = game_state.add_building(
GameState.BUILDING_MOTHERSHIP, Vector2.ZERO)
controller.skill_menu.building_id = mothership_id
if popup.visible:
return _fail("the explainer was open before anything was refused")
controller._on_unlock_requested(doctrine)
if not popup.visible:
return _fail("a doctrine costing data was refused with no explanation")
if game_state.is_unlocked(doctrine):
return _fail("the doctrine was researched with no data at all")
var said: String = popup.have_label.text
if not said.contains("YOU HAVE 0"):
return _fail("the explainer does not say what the player holds: '%s'" % said)
if not popup.detail_label.text.to_lower().contains("scanner"):
return _fail("the explainer never mentions how to find a lab world")
print("skill tree: refused and explained - '%s'" % said)
popup.close_menu()
# --- C. with the data, it goes through, quietly ---------------
game_state.research_points = 20
controller._on_unlock_requested(doctrine)
if not game_state.is_unlocked(doctrine):
return _fail("the doctrine was refused with data in hand")
if popup.visible:
return _fail("the explainer opened on a research that succeeded")
print("with data in hand it goes through, and says nothing")
elapsed = 0.0
stage = 1
return false
1:
# --- B. the lab explains too, rather than blaming the queue ---
game_state.research_points = 0
var lab_id: int = game_state.add_building(GameState.BUILDING_SHIP_LAB,
Vector2(600.0, 0.0))
controller.lab_building_id = lab_id
controller.lab_vessel = GameState.VESSEL_INTERCEPTOR
controller.lab_choice = 0
var options: Array = controller._lab_options()
if options.is_empty():
return _fail("the lab offers nothing, so this proves nothing")
# Pick an option that actually costs data.
for i in range(options.size()):
if game_state.research_point_cost(String(options[i].id)) > 0:
controller.lab_choice = i
break
if game_state.research_point_cost(String(options[controller.lab_choice].id)) <= 0:
return _fail("no lab option costs research data, so this proves nothing")
# The lab panel is open when the player presses buy - that is what
# puts the explainer on top of another dialog, which is the whole
# point of case D below.
controller.lab_menu.open_menu()
controller._on_lab_buy()
if not popup.visible:
return _fail("the lab refused for want of data with no explanation")
if controller.lab_menu.status.text.contains("already queued"):
return _fail("the lab still blames the queue: '%s'" % controller.lab_menu.status.text)
print("ship lab: refused and explained, not blamed on the queue")
# --- D. and the player can get back out of it ----------------
# The explainer is the only dialog that opens ON TOP of another
# one, and IconButton refuses input to any button sitting behind
# an open panel. That used to include this popup's own close
# button, so the dialog could not be dismissed at all. Case B
# above left the ship lab open underneath, which is the real
# situation - assert that rather than arranging it.
if not controller.lab_menu.visible:
return _fail("the lab is not open underneath, so this proves nothing")
var close: Control = popup.get_node("CloseButton")
if close._blocked_by_modal():
return _fail("the explainer close button is blocked by the lab behind it - the dialog is inescapable")
close.pressed.emit()
if popup.visible:
return _fail("pressing close left the explainer open")
# The reverse must still hold: the lab's own buttons stay dead
# while a dialog covers them.
popup.open_for_shortfall(10, "anything")
var lab_close: Control = controller.lab_menu.get_node("CloseButton")
if not lab_close._blocked_by_modal():
return _fail("the lab buttons are live underneath an open dialog")
popup.close_menu()
print("close button works over the lab, and the lab stays blocked underneath")
print("TEST_RESEARCH_POINTS_EXPLAINER: PASS")
quit(0)
return true
return false
func _fail(message: String) -> bool:
print("TEST_RESEARCH_POINTS_EXPLAINER: FAIL (%s)" % message)
quit(1)
return true