The scanner quest moves ahead of the gas burner and gains the hunt it exists for: a research lab world, which pays several times what an ordinary planet does and is the only reliable source of research data. Finding one is what the scanner is FOR, so the conquest record now remembers which kind of world was taken and a quest can ask for that kind. Bombers get a pair of quests after the transporters. That pulled the ship lab up with them - a vessel is unlocked AT the lab, so asking for a bomber before one exists would have been unfinishable, the same trap second_hull fell into. And both research screens now explain a shortfall instead of hiding it. The skill tree refused a doctrine in silence; the ship lab said "already queued or complete", which is not why it refused and sends the player to look at the wrong thing. Both open an explainer naming what was wanted, what is held, and where data actually comes from. #192's rule - a tool is taught immediately before the quest that needs it - now points at the scanner's FIRST use rather than its only one, with the world survey still required to follow it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019AJMdB7iuHuLFZM1aBu3GD
132 lines
5 KiB
GDScript
132 lines
5 KiB
GDScript
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")
|
|
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")
|
|
|
|
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
|