Teach the crews and the berths the game now asks the player to keep

#216 and #219 turned two things into player work without saying so anywhere:
transporters are built and assigned by hand, and a berth in the fleet is a
structure that has to be supplied. Five quests now teach both.

For the hub: build a transporter at a crafter, then assign it. Two steps,
because they happen in different places and one quest covering both strands
whoever misses the second in front of a hub that does nothing. The closing
line warns that they wear out, since the alternative is finding out when a
route quietly stops.

For the fleet: research Berth Authority, build an office, PUT ORE IN IT, and
only then crew the berth. The stocking step comes before the vessel on
purpose - the other way to learn it is to watch a vessel you paid for be
destroyed.

And a campaign-breaking bug of my own: #219 moved capacity onto the office,
so "fly two vessels at once" - sixth in the chain, six quests before
anything that could hold a second - could not be finished at all. It sits
after the office now, and a new rule in the chain test refuses any quest
that asks for more hulls than the player can yet hold. Verified by putting
the bug back: it fails, naming both steps.

Also: the conquest quest still said "take every capture point", which #211
deleted from the game.

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 14:43:35 +02:00
commit aca04ad4cf
3 changed files with 136 additions and 12 deletions

View file

@ -3945,6 +3945,31 @@ func quest_progress(quest: Dictionary) -> Vector2i:
QUESTS.GOAL_GARRISONED:
var stationed: int = int(goal.get("count", 1))
return Vector2i(mini(garrisoned_vessel_count(), stationed), stationed)
QUESTS.GOAL_VESSEL_BUILT:
# Counted ANYWHERE, not just in the fleet: a transporter never
# joins one, and the step being taught here is "you built it".
var built: int = int(goal.get("count", 1))
return Vector2i(mini(vessel_census(String(goal.get("vessel", ""))), built), built)
QUESTS.GOAL_BUILDING_STOCK:
# The fullest one of its kind, not the total: the lesson is that
# a SINGLE office has to be stocked, and summing across three
# half-empty ones would credit it without teaching it.
var stocked: int = int(goal.get("amount", 1))
var resource_type: String = String(goal.get("resource", RESOURCE_ORE))
var wanted_type: String = String(goal.get("building", ""))
var fullest: int = 0
for building in buildings:
if String(building.get("type", "")) == wanted_type:
fullest = maxi(fullest, building_resource(int(building.id), resource_type))
return Vector2i(mini(fullest, stocked), stocked)
QUESTS.GOAL_STATION_CREW:
var crewed: int = int(goal.get("count", 1))
var capability: String = String(goal.get("capability", "transport_hub"))
var standing: int = 0
for building in buildings:
if building_has_capability(building, capability):
standing += station_crew(int(building.id))
return Vector2i(mini(standing, crewed), crewed)
QUESTS.GOAL_BANKED:
var banked: int = int(goal.get("amount", 1))
return Vector2i(mini(banked_resource(String(goal.get("resource",

View file

@ -50,6 +50,17 @@ const GOAL_BANKED: String = "banked"
# outpost holds nothing and the player has no reason to discover the hangar
# that fills it.
const GOAL_GARRISONED: String = "garrisoned"
# #216 made transporters and repair drones things the player builds and
# assigns, which is two steps nothing in the game explained. These are the
# goals that teach them: one vessel of a type existing ANYWHERE, and one
# actually standing at the structure that uses it.
const GOAL_VESSEL_BUILT: String = "vessel_built"
const GOAL_STATION_CREW: String = "station_crew"
# #219 made a berth in the fleet a structure that has to be SUPPLIED, and a
# player who learns that by watching a vessel destroyed has learned it the
# expensive way. This goal is "there are resources sitting in the thing",
# which is the step to teach before the berth is ever crewed.
const GOAL_BUILDING_STOCK: String = "building_stock"
# #167: which quests carry the STORY, marked `"important": true` below.
#
@ -129,14 +140,6 @@ const CHAIN: Array = [
"brief": "Now build a ship crafter. Ore goes in, ships come out. It is the only way this fleet grows past the one hull that came through the breach.",
"done": "The yard is running. We can build our own ships now.",
},
{
"id": "second_hull",
"title": "A SECOND HULL",
"objective": "Fly two vessels at once",
"goal": {"kind": GOAL_FLEET_VESSEL, "vessel": "interceptor", "count": 2},
"brief": "Order an interceptor at the yard and crew it. Two ships is not a fleet, but it is twice what we flew out of the breach with.",
"done": "Two ships in formation. It has been a long time since we flew with company.",
},
{
"id": "planetfall",
"title": "PLANETFALL",
@ -149,9 +152,9 @@ const CHAIN: Array = [
{
"id": "conquest",
"title": "GROUND HELD",
"objective": "Take every capture point on one planet",
"objective": "Destroy every defender on one planet",
"goal": {"kind": GOAL_CONQUERED, "count": 1},
"brief": "Something reached this surface before us, and it is still holding it. Take every capture point on the planet. What we pull out of their camps is worth more than the ore.",
"brief": "Something reached this surface before us, and it is still holding it. Kill what is defending it and the planet is ours. What we pull out of their camps is worth more than the ore.",
# Says out loud where research points come from, because nothing
# else in the game does.
"done": "The planet is ours. Their machines gave us research data, the first we have had. Every doctrine worth having will cost some.",
@ -169,6 +172,50 @@ const CHAIN: Array = [
"brief": "Each ship carries twenty units and no more, and we are going to need more than twenty. Fly what we have back to the mothership and unload it. What is stored there stays there.",
"done": "Sixty in the vault. A hold empties on the next trip out. A vault does not. Everything from here on depends on that.",
},
{
# #219 moved fleet capacity onto the Fleet Office, so a second hull
# became impossible until one is standing - this quest used to sit
# before the crafter and could not be finished at all. The three
# steps below it are the ones that make it reachable, in the order
# the player has to do them.
#
# The office is asked for AFTER banking is taught: it costs more ore
# than one hull can carry in a single trip.
"id": "berth_authority",
"title": "BERTH AUTHORITY",
"objective": "Research the Berth Authority doctrine",
"goal": {"kind": GOAL_RESEARCH, "node": "berth_authority"},
"brief": "We fly alone because we have nowhere to keep anyone else. Research Berth Authority - it costs ore and no research data - and we can build the offices that hold a berth.",
"done": "We can build Fleet Offices now. Each one is a berth, and each one has to be paid for.",
},
{
"id": "fleet_office",
"title": "A BERTH",
"objective": "Build a Fleet Office",
"goal": {"kind": GOAL_BUILDING, "building": "fleet_office"},
"brief": "Put up a Fleet Office. It buys room in the fleet for one more vessel - not the vessel, the room.",
"done": "One berth stands ready. It is empty, and it is already hungry.",
},
{
"id": "office_stocked",
"title": "PAID IN ADVANCE",
"objective": "Put 20 ore into the Fleet Office",
"goal": {"kind": GOAL_BUILDING_STOCK, "building": "fleet_office",
"resource": "ore", "amount": 20},
"brief": "A berth is not free to hold. The office spends resources on the vessel in it, over and over, and takes them from its OWN store - fly to it and transfer ore in before you crew it.",
# Said plainly, because the alternative way to learn it is to watch a
# vessel you paid for be destroyed.
"done": "The office has something to spend. Keep it that way: an office that runs dry loses the vessel it was keeping, and it will not be given back.",
"important": true,
},
{
"id": "second_hull",
"title": "A SECOND HULL",
"objective": "Fly two vessels at once",
"goal": {"kind": GOAL_FLEET_VESSEL, "vessel": "interceptor", "count": 2},
"brief": "The berth is open and stocked. Order an interceptor at the yard and crew it. Two ships is not a fleet, but it is twice what we flew out of the breach with.",
"done": "Two ships in formation. It has been a long time since we flew with company.",
},
{
"id": "extractor",
"title": "STANDING MINE",
@ -190,8 +237,32 @@ const CHAIN: Array = [
"title": "FREIGHT",
"objective": "Build a transport hub",
"goal": {"kind": GOAL_BUILDING, "building": "transport_hub"},
"brief": "Hauling every load ourselves is slow. Research Freight Handling and build a transport hub. Its transporters fly the routes without us.",
"done": "The hub runs its own traffic now. That frees us for other work.",
"brief": "Hauling every load ourselves is slow. Research Freight Handling and build a transport hub. It runs the routes for us - once there is something in it to fly them.",
"done": "The hub is up. It is empty, though: the vessels that fly its routes are ours to build.",
},
{
# #216 took the free transporters away, so the hub above arrives empty
# and the player has to be told what to do about it. Two steps, not
# one: building a vessel and assigning it are separate acts in
# separate places, and a single quest covering both leaves whoever
# missed the second one staring at a hub that does nothing.
"id": "transporter_built",
"title": "ROLLING STOCK",
"objective": "Build a transporter at a ship crafter",
"goal": {"kind": GOAL_VESSEL_BUILT, "vessel": "transporter", "count": 1},
"brief": "The hub has no vessels of its own. Order a transporter at a ship crafter - the hub being built is what puts it on the list - and it will fly to the mothership when it is done.",
"done": "A transporter is parked at the mothership. It is no use to anyone there.",
},
{
"id": "transporter_assigned",
"title": "PUT TO WORK",
"objective": "Assign a transporter to the transport hub",
"goal": {"kind": GOAL_STATION_CREW, "capability": "transport_hub", "count": 1},
"brief": "Open the hub and ask it for one transporter. It will fly out from the mothership on its own and start running the routes.",
# The wear is the part a player will not guess, and finding out by
# watching a route quietly stop is a bad way to learn it.
"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",