Commit graph spaceship/world/IntroDirector.gd
Author SHA1 Message Date
Loïc Wisniewski
3fcc26c8bc Implement #160, #161, #162, #163, #164 and #165
#162 - a single tap bought a research node outright. One physical tap arrives
TWICE: Godot emulates a mouse button from every touch AND a touch from every
mouse button, both project settings are on, and the menu's dispatcher routes
InputEventScreenTouch and InputEventMouseButton alike to the tree. The second
arrival found the node already selected and took itself for the confirming
tap. Measured, not reasoned about - one tap produced two picks and two
confirms.

What is ignored is specifically the TWIN: same frame, same place, arriving
through the other input kind. Deduping on frame and position alone also
swallowed two genuine taps in one frame, which the test caught.

#164 - the build menu predicted a caption's height from the COLUMN WIDTH:
wide column, assume one line. Right for most names and wrong for the long
ones, so "Spacial Workshop" wrapped onto the price beneath it. Captions are
now measured against the font that draws them, and prices sized from
PriceTag.wanted_height(), which existed for exactly this and was not being
asked. Prices are set before anything is measured, because the old order laid
out first and priced afterwards.

The ship lab: its buy button is gone and a second tap on an option buys it,
the same rule as the research tree; the explanation drops into the room that
freed; research points move up into the resource table, where everything else
being spent already is; the second row of options is placed from the first
row's measured bottom rather than a constant; and the vessel strip is spaced
from the panel's own width, so the eighth vessel is no longer half off the
right edge.

#160 - the quest panel was drawn BEFORE the sticks and the pivot pair, so
they sat on top of it. Moved after them, under the narration banner. Its title
rule ran straight through the close button; the header band is now as tall as
that button.

#161 - the prologue widens the formation into a freight convoy by writing over
GameState.formation, and nothing put it back. The player flew the convoy's
600-unit spread for the rest of the game - a shape nobody chose, which reads
as the fleet having drifted apart.

#163 - a quest to station a vessel at the outpost, after the one that asks for
the outpost. Building one and crewing it are different acts, and an empty
outpost holds nothing.

#165 - the gas bomb's blast and a vessel arriving fast both damage a
structure. The blast used to stop politely at anything the player owned, which
made a bomb dropped on a besieged mothership a free way to sweep the attackers
off it.

Collisions are caught on ENTRY, not on the 0.7s strike tick: a vessel is only
moving fast for the instant it arrives, and a ship sent in at 900 did no
damage at all until this moved. Docking is free - the fleet sits on its own
mothership constantly to bank ore - and garrison vessels are exempt outright,
because they launch from their outpost and re-dock with it at speed. The suite
caught that one: the ram rule was destroying the garrison as it launched.

Suite 153/153. Four tests changed because what they pinned moved: the lab's
buy button, the intro's formation, the research tree's tap delivery, and the
build menu's own preview.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 02:27:44 +02:00
Loïc Wisniewski
ac4b96ef49 #139: the prologue's debris belt keeps off the screen too
The belt was laid out with its own arithmetic - a centre BELT_AHEAD in front
of the fleet, rocks spread BELT_DEPTH either side of it - so its near edge
reached back to within a screen of the convoy. At the aspect it was
eyeballed on that was just outside the view; at a wider one, or any zoom
out, rocks appeared in plain sight.

#126 already answered this question for the rest of the game, so the answer
is borrowed rather than restated: AsteroidField's keep-out rect and its
push-out-through-the-nearest-edge placement are public now, and the belt
runs through them. That also means the two cannot drift apart later.

The distance moves as well, 2200 to 2900. The clamp alone would work, but it
would work by pressing every stray rock onto the boundary line; with the
belt properly out in front, the clamp has almost nothing left to do and the
belt still looks laid out ahead rather than pinned to the edge of the
screen. Measured: nearest rock 1551 units out, against a keep-out that
reaches 1100.
2026-08-28 15:37:11 +02:00
Loïc Wisniewski
710dcbf230 #130, #135: a vessel's death takes a moment, and leaves an interceptor
#130 asked for the hull to break away from the fleet, drift a few metres,
and go up further off with something more explosive than a light animation.

The wreck is a separate node rather than the Ship staying alive to animate,
and that is the load-bearing part. A dying Ship still in the tree is still
an Area2D in the player_ships group with live weapon components - it would
keep firing, keep being fired at, keep counting as a target, and keep
colliding on the way out. So the ship's own lifecycle is untouched: it
leaves the fleet, emits destroyed, and is freed on exactly the frame it
always was. What is left behind is scenery, and the test pins that.

The explosion at the end was also the quieter of the two the game has.
Killing an enemy was made deliberately loud by #87 while losing one of your
own kept the base class's twelve-particle default - the reward louder than
the loss. It is now the bigger of the two.

#135 is the same scene from the other end: the prologue's convoy flies its
escorts on the corners of the box, which is the exposed part of it, and the
debris belt can take all four. With no interceptor left, the only hulls the
vortex could spare were holds, and the player flew out of the prologue in a
carrier. Two guards now: one interceptor is put back into the convoy at the
top of the vortex, where a vessel appearing among ten being thrown around a
black hole is not something anyone will catch; and the handover checks the
TYPES it hands over rather than only the count - one surviving carrier is
also a fleet of one, and it is not the fleet a new game starts with.
2026-08-28 15:05:02 +02:00
Loïc Wisniewski
1e89780bd7 #128: a dialog stops the game until it is acknowledged
While a line is on the banner the whole tree is paused, which freezes the
fleet, the enemies and GameState's own production and wave clocks, and stops
input reaching any node but the banner. So a press while a dialog is up
acknowledges it and does nothing else - it cannot also steer the fleet or
open a menu on the way through.

The pause is owned by NarrationBanner rather than by its callers: the thing
that must not get out of step is "a line is showing" and "the game is
stopped", and the banner is the only code that knows the first. It releases
on the last line, on clear(), and on leaving the tree - a scene swapped out
mid-line must not leave the game stopped with nothing left to start it.

Two consequences worth naming. A beat's deadline in the prologue is now game
time, so it can no longer run out from under an unread line; it remains the
way past a beat the player will not finish. And "the prologue leaves you
movement and nothing else" was applied by _process on the first frame, which
no longer comes - the prologue opens ON a dialog - so BuildController and
WorldMap apply it at _ready too.
2026-08-28 14:40:46 +02:00
Loïc Wisniewski
902d6922e7 #127: dialogs wait for the reader, and say who is talking
A line now stays until it is DISMISSED - there is no timer under it at all.
A prologue whose lines expire on their own reads at the game's pace rather
than at the reader's, and that was most of what made the opening feel
rushed even after #125 slowed the beats down.

The beats that are about the guide talking already hold while the banner is
speaking, so dismissing a line is what advances the prologue. A player who
never clicks is still never stuck: each beat's own deadline is the way out,
and the test pins that the deadline sits past the floor.

A dismissed line eats the press, so clicking to continue does not also steer
the fleet on the way through.

The speaker's name sits in a notch cut out of the top border at the left,
the way a label is riveted to a panel - the frame is one polygon, so the
fill and the stroke cannot disagree about where that notch is. Everything up
to the breach is the convoy's controller; after it there is nobody left to
talk to, so the closing lines are the ship's own log, which is the point
being made.

The tick strip along the bottom is gone. It read as an underline attached to
the last line rather than as part of the frame. What replaces it is a
blinking caret at the bottom right - the one thing that says a click is what
moves this on.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-24 20:57:56 +02:00
Loïc Wisniewski
d455361328 #125: slow the prologue down, and give the breach a real black hole
Five things, all of them "this happens too fast or looks too thin".

PACING. Every beat had a completion test that could be satisfied while the
guide was still mid-sentence, which is why everything landed seconds after
the thing before it. Beats now have a FLOOR as well as a deadline - a
minimum length - and a beat whose point is the guide talking will not end
while a line is still on screen. One rule in one place rather than tuning
each condition. The run is 3400px instead of 1500, which at cruise was about
four seconds, and a held line is 6.5s instead of 4.5.

THE CONVOY. Escorts at the four corners of a box, holds packed in the middle
of it, roughly three times the spread of the fleet's own wedge - this is
freight under guard, not a fighting formation. CONVOY and CONVOY_FORMATION
pair index-for-index, which is all it takes for spawn_ships to seat the guns
on the outside, and the test pins that every hold sits further in than the
furthest-out escort.

THE DIALOG. Cut corners, brackets holding the short edges open, a tick strip
along the bottom and a caret in the corner - geometry rather than art, so it
scales with the banner and costs nothing.

THE BREACH. It was a few lines turning around a point. It is now two halves
driven by one number: DimensionalBreach, a growing black hole out in the
world built on BlackHoleVisual's idiom - empty core, counter-rotating arc
segments hotter toward the centre - with infalling streamers it does not
have, because a planet's disc is steady and this one has to say "now"; and
breach.gdshader over the top, bending the ACTUAL SCENE around it. Ships,
rocks and the starfield all get dragged in, which is most of what makes a
hole in space read as a hole rather than as a decal drawn on one.

Inside the horizon the shader samples nothing at all - the same decision
BlackHoleVisual makes, for the same reason: a black hole with something
visible in the middle stops being one.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-24 13:25:10 +02:00
Loïc Wisniewski
209169206b #108: the prologue - the convoy, the ambush, and the breach
Landed as one piece across #122, #123 and #124: the frame is useless without
a script, and the script has nowhere to run without the frame.

The director drives the REAL scene rather than being a scene of its own. It
wants the real fleet, the real enemies and the real asteroid field, and it
makes "then the game starts" cost nothing - the director stops steering,
clears the flag, and what is left running is the ordinary game.

The script is a list of beats, each with a deadline as well as its own
completion test, so a beat whose condition is never met - a player who
refuses to fly at the ambush - runs out rather than wedging the prologue.
skip() ends the whole thing at any point and lands in exactly the state
playing it through does, so the game has one way to start rather than two
that have to be kept in step. The test pins that equivalence.

"No action button available, only movements" is enforced where the buttons
are decided, not by the director reaching in: the ability controllers set
their own visibility every frame and would have put them straight back, and
the map button belongs to the map. The joystick, the pivot and the fader
stay.

The convoy is ten hulls where a new game's fleet is one, so it needs an
explicit fleet-size override - a plain number rather than a fake doctrine,
because nothing about the player's own progression should be bent to fit a
cutscene. It is carriers rather than transporters: transporters belong to
hubs and are not fleet-eligible, so a convoy of them would be silently
filtered down to its escorts.

The ambush is chasers and only chasers. "Easy enough" is the requirement,
and a sniper against a convoy the player cannot yet fight properly is
neither easy nor a good first impression.

The breach takes the wheel through one check in GameController, covering the
stick, the keyboard and the released-again path together - three separate
gates would be three chances for one of them to keep steering. The shake is
written to camera.offset, never to its position, because GameController owns
where the camera is and would smooth a shake away.

The vessel that survives is chosen as the interceptor rather than whichever
happened to be first in the list, and the prologue ends on exactly a new
game's opening position.

Also: PlanetAtmosphereController no longer spawns the opening fleet while
the prologue is arming, and the tests that are about what the GAME starts
from now say so by turning the prologue off.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 20:59:12 +02:00