Teach where research data comes from, and say so when it runs out

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
This commit is contained in:
Loïc Wisniewski 2026-09-06 16:24:09 +02:00
commit 8462099068
8 changed files with 327 additions and 26 deletions

View file

@ -3052,6 +3052,12 @@ func register_planet_garrison(planet_key: String, enemy_count: int,
# re-registered on a second visit must not become payable again.
"research_point_reward": point_reward,
"research_awarded": bool(existing.get("research_awarded", false)),
# Which kind of world this was. A quest can then ask for a research
# lab specifically - "any planet" and "the one worth research data"
# are different lessons - and the record is the only place that
# survives leaving the surface.
"definition_id": definition_id if definition_id != "" \
else String(existing.get("definition_id", "")),
}
@ -3985,10 +3991,18 @@ func quest_progress(quest: Dictionary) -> Vector2i:
return Vector2i(mini(visited_planet_kinds.size(), kinds), kinds)
QUESTS.GOAL_CONQUERED:
var wanted: int = int(goal.get("count", 1))
# An optional kind: "take a planet" and "take a research lab" are
# different asks, and the second is how a player learns where
# research data comes from in quantity.
var of_kind: String = String(goal.get("definition", ""))
var held: int = 0
for key in planet_capture:
if bool(planet_capture[key].get("conquered", false)):
held += 1
var record: Dictionary = planet_capture[key]
if not bool(record.get("conquered", false)):
continue
if of_kind != "" and String(record.get("definition_id", "")) != of_kind:
continue
held += 1
return Vector2i(mini(held, wanted), wanted)
# An unknown goal kind must not be quietly "already done" - that would
# run the whole chain off in one frame.

View file

@ -264,14 +264,6 @@ const CHAIN: Array = [
"done": "The hub is working. That transporter will wear out after a run of trips, and the hub will not replace it - watch its condition and build another before it goes.",
"important": true,
},
{
"id": "burner",
"title": "POWER",
"objective": "Build a gas burner",
"goal": {"kind": GOAL_BUILDING, "building": "gas_burner"},
"brief": "Research Power Systems and build a gas burner. Gas in, energy out. The better weapons run on energy.",
"done": "The burner is lit. This fleet has power again for the first time since the breach.",
},
{
"id": "lab",
"title": "SHIP SCIENCE",
@ -280,6 +272,55 @@ const CHAIN: Array = [
"brief": "Research Vessel Science and build a ship lab. It makes the ships we fly better, and it opens designs we have never built.",
"done": "The lab is open.",
},
{
# Bombers hang off the transporter pair because they are the first
# thing the player builds for a REASON rather than because the chain
# said so - and the ship lab above is where a vessel is unlocked, so
# it has to come first.
"id": "bomber_research",
"title": "ORDNANCE",
"objective": "Unlock the Gas Bomber",
"goal": {"kind": GOAL_VESSEL_UNLOCKED, "vessel": "gas_bomber"},
"brief": "Interceptor fire is one hull at a time. Unlock the Gas Bomber at the ship lab - it costs gas and research data - and we can clear a whole camp at once.",
"done": "The bomber is on the crafter's list. It throws a charge that blooms where it lands.",
},
{
"id": "bomber_built",
"title": "A HEAVY HAND",
"objective": "Fly a Gas Bomber",
"goal": {"kind": GOAL_FLEET_VESSEL, "vessel": "gas_bomber", "count": 1},
"brief": "Order one at a crafter and crew it. Aim it by dragging from its button; the further you drag, the further it throws.",
"done": "We are carrying ordnance now. Ground that took a long fight before takes one throw.",
},
{
"id": "planet_scanner",
"title": "LISTENING POST",
"objective": "Build a planet scanner",
"goal": {"kind": GOAL_BUILDING, "building": "planet_scanner"},
"brief": "Blind searching is wasting our reach. Research Deep-Space Scanning at the mothership, then build a planet scanner. Give it a world signature and it will put the nearest match on our map.",
"done": "The scanner is listening. Now we can choose where the search goes next.",
},
{
# The scanner earns its place here: it is the only way to FIND a
# research lab world, and a lab world is the only thing that pays
# research data in quantity. Before the burner, because everything
# past it wants data the player has no reliable way to get yet.
"id": "lab_world",
"title": "SOMETHING WORTH TAKING",
"objective": "Find and take a research lab world",
"goal": {"kind": GOAL_CONQUERED, "definition": "research_lab", "count": 1},
"brief": "Scan for a research lab. Whatever was working there left its data behind, and taking one pays far better than an ordinary world - every doctrine worth having is waiting on it.",
"done": "Their lab is ours, and so is what they were working on. That is where research data comes from: take the worlds that have it.",
"important": true,
},
{
"id": "burner",
"title": "POWER",
"objective": "Build a gas burner",
"goal": {"kind": GOAL_BUILDING, "building": "gas_burner"},
"brief": "Research Power Systems and build a gas burner. Gas in, energy out. The better weapons run on energy.",
"done": "The burner is lit. This fleet has power again for the first time since the breach.",
},
{
"id": "shield",
"title": "A NEW HULL",
@ -304,14 +345,6 @@ const CHAIN: Array = [
"brief": "An empty outpost is only a building. Open its hangar and station a ship there. It will hold that ground whether we are there or not.",
"done": "The outpost has a crew. It watches that approach now, so we do not have to.",
},
{
"id": "planet_scanner",
"title": "LISTENING POST",
"objective": "Build a planet scanner",
"goal": {"kind": GOAL_BUILDING, "building": "planet_scanner"},
"brief": "Blind searching is wasting our reach. Research Deep-Space Scanning at the mothership, then build a planet scanner. Give it a world signature and it will put the nearest match on our map.",
"done": "The scanner is listening. Now we can choose where the search goes next.",
},
{
"id": "worlds",
"title": "THE SURVEY",