Recentre a released stick, slow extractors again, and unbreak the lab layout

Both sticks float - the base jumps to wherever the finger lands, so a player
does not have to hit an exact spot on a screen they cannot feel. Releasing put
only the KNOB back onto the base and left the base parked wherever that touch
had been, so an idle stick sat off-centre in a different place every time and
read as a control still in use. Release now returns base and knob to the
middle of the rect.

Extractors produce at 0.5 ore per second, halved again: at 1.0 they still
outran the rest of the economy. An extractor now pays back its 25-ore cost in
fifty seconds rather than twelve.

The ship lab and the crafter were both overlapping themselves. Enlarging the
shared resource table to 136px (so it could breathe and show bigger type)
pushed its bottom edge 34px into the vessel row beneath it in one and the
status text in the other - my regression, visible immediately on a real
screen and not at all in any test. The lab's second row of upgrade cards was
also already running into the detail text below it, by 13px, before any of
this. Both menus are re-spaced end to end rather than nudged, since moving one
collision into another is how the second one got there.

Two tests carried waits tuned to an extraction rate that has now changed
twice. Both derive them from EXTRACTOR_RATE instead, so the next balance pass
does not report a broken extractor that is working perfectly - the same fix
test_extractor_income already needed one round ago, in the file next to it.

Suite 112/112.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Loïc Wisniewski 2026-08-21 13:31:46 +02:00
commit b999031e6a
8 changed files with 220 additions and 102 deletions

View file

@ -1223,12 +1223,15 @@ func rotate_formation(radians: float) -> void:
# hauler: ore becomes spendable only when a hub-stationed transporter picks # hauler: ore becomes spendable only when a hub-stationed transporter picks
# up a full load and physically delivers it to the mothership. Entries are # up a full load and physically delivers it to the mothership. Entries are
# {"position", "planet_id", "planet_name", "resource_type", "inventory", "mining_progress"}. # {"position", "planet_id", "planet_name", "resource_type", "inventory", "mining_progress"}.
# Ore per second. Halved alongside the planet-density change in WorldGen: with # Ore per second, per extractor.
# roughly 2.5x as many planets to put extractors on, holding the per-extractor #
# rate would have multiplied passive income rather than shifting where it comes # Halved once alongside the planet-density change in WorldGen (roughly 2.5x as
# from. The intent is more sites each worth less, so expanding is what grows # many planets to build on, so holding the rate would have multiplied passive
# the economy rather than one lucky early extractor carrying it. # income rather than moving where it comes from), and halved again because it
const EXTRACTOR_RATE: float = 1.0 # still outran the rest of the economy. At 0.5 an extractor pays back its own
# 25-ore cost in fifty seconds and yields 30 a minute after that, so a
# single lucky early site cannot carry a game and expanding is what grows one.
const EXTRACTOR_RATE: float = 0.5
var extractors: Array = [] var extractors: Array = []

152
Main.tscn
View file

@ -1211,9 +1211,9 @@ color = Color(0.03, 0.03, 0.08, 0.94)
mouse_filter = 2 mouse_filter = 2
anchor_right = 1.0 anchor_right = 1.0
offset_left = 24 offset_left = 24
offset_top = 36 offset_top = 20
offset_right = -200 offset_right = -200
offset_bottom = 166 offset_bottom = 82
text = "Ship Lab" text = "Ship Lab"
horizontal_alignment = 1 horizontal_alignment = 1
@ -1221,9 +1221,9 @@ horizontal_alignment = 1
mouse_filter = 2 mouse_filter = 2
anchor_right = 1.0 anchor_right = 1.0
offset_left = 24 offset_left = 24
offset_top = 172 offset_top = 148
offset_right = -24 offset_right = -24
offset_bottom = 308 offset_bottom = 284
script = ExtResource("24") script = ExtResource("24")
[node name="VesselA" type="Control" parent="UI/LabMenu"] [node name="VesselA" type="Control" parent="UI/LabMenu"]
@ -1231,8 +1231,8 @@ anchor_left = 0.5
anchor_right = 0.5 anchor_right = 0.5
offset_left = -300 offset_left = -300
offset_right = -240 offset_right = -240
offset_top = 274 offset_top = 300
offset_bottom = 394 offset_bottom = 420
script = ExtResource("10") script = ExtResource("10")
icon = 2 icon = 2
glow_color = Color(0.25, 0.85, 1, 1) glow_color = Color(0.25, 0.85, 1, 1)
@ -1242,8 +1242,8 @@ anchor_left = 0.5
anchor_right = 0.5 anchor_right = 0.5
offset_left = -210 offset_left = -210
offset_right = -150 offset_right = -150
offset_top = 274 offset_top = 300
offset_bottom = 394 offset_bottom = 420
script = ExtResource("10") script = ExtResource("10")
icon = 2 icon = 2
glow_color = Color(0.45, 0.8, 1, 1) glow_color = Color(0.45, 0.8, 1, 1)
@ -1253,8 +1253,8 @@ anchor_left = 0.5
anchor_right = 0.5 anchor_right = 0.5
offset_left = -120 offset_left = -120
offset_right = -60 offset_right = -60
offset_top = 274 offset_top = 300
offset_bottom = 394 offset_bottom = 420
script = ExtResource("10") script = ExtResource("10")
icon = 31 icon = 31
glow_color = Color(0.96, 0.32, 0.78, 1) glow_color = Color(0.96, 0.32, 0.78, 1)
@ -1264,8 +1264,8 @@ anchor_left = 0.5
anchor_right = 0.5 anchor_right = 0.5
offset_left = -30 offset_left = -30
offset_right = 30 offset_right = 30
offset_top = 274 offset_top = 300
offset_bottom = 394 offset_bottom = 420
script = ExtResource("10") script = ExtResource("10")
icon = 12 icon = 12
glow_color = Color(0.95, 0.55, 0.85, 1) glow_color = Color(0.95, 0.55, 0.85, 1)
@ -1275,8 +1275,8 @@ anchor_left = 0.5
anchor_right = 0.5 anchor_right = 0.5
offset_left = 60 offset_left = 60
offset_right = 120 offset_right = 120
offset_top = 274 offset_top = 300
offset_bottom = 394 offset_bottom = 420
script = ExtResource("10") script = ExtResource("10")
icon = 34 icon = 34
glow_color = Color(1, 0.78, 0.3, 1) glow_color = Color(1, 0.78, 0.3, 1)
@ -1286,8 +1286,8 @@ anchor_left = 0.5
anchor_right = 0.5 anchor_right = 0.5
offset_left = 150 offset_left = 150
offset_right = 210 offset_right = 210
offset_top = 274 offset_top = 300
offset_bottom = 394 offset_bottom = 420
script = ExtResource("10") script = ExtResource("10")
icon = 35 icon = 35
glow_color = Color(0.3, 0.9, 1, 1) glow_color = Color(0.3, 0.9, 1, 1)
@ -1297,8 +1297,8 @@ anchor_left = 0.5
anchor_right = 0.5 anchor_right = 0.5
offset_left = 240 offset_left = 240
offset_right = 300 offset_right = 300
offset_top = 274 offset_top = 300
offset_bottom = 394 offset_bottom = 420
script = ExtResource("10") script = ExtResource("10")
icon = 37 icon = 37
glow_color = Color(0.7, 0.3, 1, 1) glow_color = Color(0.7, 0.3, 1, 1)
@ -1308,9 +1308,9 @@ visible = false
mouse_filter = 2 mouse_filter = 2
anchor_right = 1.0 anchor_right = 1.0
offset_left = 24 offset_left = 24
offset_top = 402 offset_top = 424
offset_right = -24 offset_right = -24
offset_bottom = 460 offset_bottom = 482
theme_override_font_sizes/font_size = 34 theme_override_font_sizes/font_size = 34
horizontal_alignment = 1 horizontal_alignment = 1
text = "" text = ""
@ -1321,8 +1321,8 @@ anchor_left = 0.5
anchor_right = 0.5 anchor_right = 0.5
offset_left = -310 offset_left = -310
offset_right = -230 offset_right = -230
offset_top = 400 offset_top = 424
offset_bottom = 472 offset_bottom = 496
theme_override_font_sizes/font_size = 15 theme_override_font_sizes/font_size = 15
autowrap_mode = 2 autowrap_mode = 2
horizontal_alignment = 1 horizontal_alignment = 1
@ -1334,8 +1334,8 @@ anchor_left = 0.5
anchor_right = 0.5 anchor_right = 0.5
offset_left = -220 offset_left = -220
offset_right = -140 offset_right = -140
offset_top = 400 offset_top = 424
offset_bottom = 472 offset_bottom = 496
theme_override_font_sizes/font_size = 15 theme_override_font_sizes/font_size = 15
autowrap_mode = 2 autowrap_mode = 2
horizontal_alignment = 1 horizontal_alignment = 1
@ -1347,8 +1347,8 @@ anchor_left = 0.5
anchor_right = 0.5 anchor_right = 0.5
offset_left = -130 offset_left = -130
offset_right = -50 offset_right = -50
offset_top = 400 offset_top = 424
offset_bottom = 472 offset_bottom = 496
theme_override_font_sizes/font_size = 15 theme_override_font_sizes/font_size = 15
autowrap_mode = 2 autowrap_mode = 2
horizontal_alignment = 1 horizontal_alignment = 1
@ -1360,8 +1360,8 @@ anchor_left = 0.5
anchor_right = 0.5 anchor_right = 0.5
offset_left = -40 offset_left = -40
offset_right = 40 offset_right = 40
offset_top = 400 offset_top = 424
offset_bottom = 472 offset_bottom = 496
theme_override_font_sizes/font_size = 15 theme_override_font_sizes/font_size = 15
autowrap_mode = 2 autowrap_mode = 2
horizontal_alignment = 1 horizontal_alignment = 1
@ -1373,8 +1373,8 @@ anchor_left = 0.5
anchor_right = 0.5 anchor_right = 0.5
offset_left = 50 offset_left = 50
offset_right = 130 offset_right = 130
offset_top = 400 offset_top = 424
offset_bottom = 472 offset_bottom = 496
theme_override_font_sizes/font_size = 15 theme_override_font_sizes/font_size = 15
autowrap_mode = 2 autowrap_mode = 2
horizontal_alignment = 1 horizontal_alignment = 1
@ -1386,8 +1386,8 @@ anchor_left = 0.5
anchor_right = 0.5 anchor_right = 0.5
offset_left = 140 offset_left = 140
offset_right = 220 offset_right = 220
offset_top = 400 offset_top = 424
offset_bottom = 472 offset_bottom = 496
theme_override_font_sizes/font_size = 15 theme_override_font_sizes/font_size = 15
autowrap_mode = 2 autowrap_mode = 2
horizontal_alignment = 1 horizontal_alignment = 1
@ -1399,8 +1399,8 @@ anchor_left = 0.5
anchor_right = 0.5 anchor_right = 0.5
offset_left = 230 offset_left = 230
offset_right = 310 offset_right = 310
offset_top = 400 offset_top = 424
offset_bottom = 472 offset_bottom = 496
theme_override_font_sizes/font_size = 15 theme_override_font_sizes/font_size = 15
autowrap_mode = 2 autowrap_mode = 2
horizontal_alignment = 1 horizontal_alignment = 1
@ -1410,9 +1410,9 @@ text = "Distorder"
mouse_filter = 2 mouse_filter = 2
anchor_right = 1.0 anchor_right = 1.0
offset_left = 48 offset_left = 48
offset_top = 480 offset_top = 502
offset_right = -48 offset_right = -48
offset_bottom = 484 offset_bottom = 506
color = Color(0.25, 0.85, 1, 0.6) color = Color(0.25, 0.85, 1, 0.6)
[node name="UpgradeList" type="Label" parent="UI/LabMenu"] [node name="UpgradeList" type="Label" parent="UI/LabMenu"]
@ -1421,9 +1421,9 @@ mouse_filter = 2
anchor_right = 1.0 anchor_right = 1.0
anchor_bottom = 1.0 anchor_bottom = 1.0
offset_left = 32 offset_left = 32
offset_top = 488 offset_top = 514
offset_right = -32 offset_right = -32
offset_bottom = -470 offset_bottom = -390
theme_override_font_sizes/font_size = 30 theme_override_font_sizes/font_size = 30
autowrap_mode = 2 autowrap_mode = 2
text = "" text = ""
@ -1434,9 +1434,9 @@ anchor_right = 1.0
anchor_top = 1.0 anchor_top = 1.0
anchor_bottom = 1.0 anchor_bottom = 1.0
offset_left = 32 offset_left = 32
offset_top = -460 offset_top = -380
offset_right = -32 offset_right = -32
offset_bottom = -330 offset_bottom = -280
theme_override_font_sizes/font_size = 32 theme_override_font_sizes/font_size = 32
autowrap_mode = 2 autowrap_mode = 2
horizontal_alignment = 1 horizontal_alignment = 1
@ -1448,9 +1448,9 @@ anchor_right = 1.0
anchor_top = 1.0 anchor_top = 1.0
anchor_bottom = 1.0 anchor_bottom = 1.0
offset_left = 32 offset_left = 32
offset_top = -324 offset_top = -274
offset_right = -32 offset_right = -32
offset_bottom = -256 offset_bottom = -226
theme_override_font_sizes/font_size = 30 theme_override_font_sizes/font_size = 30
autowrap_mode = 2 autowrap_mode = 2
horizontal_alignment = 1 horizontal_alignment = 1
@ -1464,8 +1464,8 @@ anchor_right = 0.5
anchor_bottom = 1.0 anchor_bottom = 1.0
offset_left = -230 offset_left = -230
offset_right = -110 offset_right = -110
offset_top = -240 offset_top = -218
offset_bottom = -120 offset_bottom = -108
script = ExtResource("10") script = ExtResource("10")
icon = 6 icon = 6
glow_color = Color(0.55, 0.95, 0.9, 1) glow_color = Color(0.55, 0.95, 0.9, 1)
@ -1477,8 +1477,8 @@ anchor_right = 0.5
anchor_bottom = 1.0 anchor_bottom = 1.0
offset_left = 110 offset_left = 110
offset_right = 230 offset_right = 230
offset_top = -240 offset_top = -218
offset_bottom = -120 offset_bottom = -108
script = ExtResource("10") script = ExtResource("10")
icon = 4 icon = 4
glow_color = Color(0.45, 0.9, 0.55, 1) glow_color = Color(0.45, 0.9, 0.55, 1)
@ -1490,9 +1490,9 @@ anchor_right = 1.0
anchor_top = 1.0 anchor_top = 1.0
anchor_bottom = 1.0 anchor_bottom = 1.0
offset_left = 24 offset_left = 24
offset_top = -110 offset_top = -102
offset_right = -24 offset_right = -24
offset_bottom = -20 offset_bottom = -22
theme_override_font_sizes/font_size = 28 theme_override_font_sizes/font_size = 28
autowrap_mode = 2 autowrap_mode = 2
horizontal_alignment = 1 horizontal_alignment = 1
@ -1503,8 +1503,8 @@ anchor_left = 0.5
anchor_right = 0.5 anchor_right = 0.5
offset_left = -240 offset_left = -240
offset_right = -120 offset_right = -120
offset_top = 488 offset_top = 514
offset_bottom = 598 offset_bottom = 624
script = ExtResource("10") script = ExtResource("10")
icon = 13 icon = 13
glow_color = Color(0.25, 0.85, 1, 1) glow_color = Color(0.25, 0.85, 1, 1)
@ -1515,8 +1515,8 @@ anchor_left = 0.5
anchor_right = 0.5 anchor_right = 0.5
offset_left = -310 offset_left = -310
offset_right = -50 offset_right = -50
offset_top = 603 offset_top = 628
offset_bottom = 673 offset_bottom = 698
theme_override_font_sizes/font_size = 22 theme_override_font_sizes/font_size = 22
autowrap_mode = 2 autowrap_mode = 2
horizontal_alignment = 1 horizontal_alignment = 1
@ -1527,8 +1527,8 @@ anchor_left = 0.5
anchor_right = 0.5 anchor_right = 0.5
offset_left = 120 offset_left = 120
offset_right = 240 offset_right = 240
offset_top = 488 offset_top = 514
offset_bottom = 598 offset_bottom = 624
script = ExtResource("10") script = ExtResource("10")
icon = 13 icon = 13
glow_color = Color(0.25, 0.85, 1, 1) glow_color = Color(0.25, 0.85, 1, 1)
@ -1539,8 +1539,8 @@ anchor_left = 0.5
anchor_right = 0.5 anchor_right = 0.5
offset_left = 50 offset_left = 50
offset_right = 310 offset_right = 310
offset_top = 603 offset_top = 628
offset_bottom = 673 offset_bottom = 698
theme_override_font_sizes/font_size = 22 theme_override_font_sizes/font_size = 22
autowrap_mode = 2 autowrap_mode = 2
horizontal_alignment = 1 horizontal_alignment = 1
@ -1551,8 +1551,8 @@ anchor_left = 0.5
anchor_right = 0.5 anchor_right = 0.5
offset_left = -240 offset_left = -240
offset_right = -120 offset_right = -120
offset_top = 678 offset_top = 706
offset_bottom = 783 offset_bottom = 816
script = ExtResource("10") script = ExtResource("10")
icon = 13 icon = 13
glow_color = Color(0.25, 0.85, 1, 1) glow_color = Color(0.25, 0.85, 1, 1)
@ -1563,8 +1563,8 @@ anchor_left = 0.5
anchor_right = 0.5 anchor_right = 0.5
offset_left = -310 offset_left = -310
offset_right = -50 offset_right = -50
offset_top = 788 offset_top = 820
offset_bottom = 833 offset_bottom = 890
theme_override_font_sizes/font_size = 22 theme_override_font_sizes/font_size = 22
autowrap_mode = 2 autowrap_mode = 2
horizontal_alignment = 1 horizontal_alignment = 1
@ -1575,8 +1575,8 @@ anchor_left = 0.5
anchor_right = 0.5 anchor_right = 0.5
offset_left = 120 offset_left = 120
offset_right = 240 offset_right = 240
offset_top = 678 offset_top = 706
offset_bottom = 783 offset_bottom = 816
script = ExtResource("10") script = ExtResource("10")
icon = 13 icon = 13
glow_color = Color(0.25, 0.85, 1, 1) glow_color = Color(0.25, 0.85, 1, 1)
@ -1587,8 +1587,8 @@ anchor_left = 0.5
anchor_right = 0.5 anchor_right = 0.5
offset_left = 50 offset_left = 50
offset_right = 310 offset_right = 310
offset_top = 788 offset_top = 820
offset_bottom = 833 offset_bottom = 890
theme_override_font_sizes/font_size = 22 theme_override_font_sizes/font_size = 22
autowrap_mode = 2 autowrap_mode = 2
horizontal_alignment = 1 horizontal_alignment = 1
@ -1597,10 +1597,10 @@ text = ""
[node name="CloseButton" type="Control" parent="UI/LabMenu"] [node name="CloseButton" type="Control" parent="UI/LabMenu"]
anchor_left = 1.0 anchor_left = 1.0
anchor_right = 1.0 anchor_right = 1.0
offset_left = -172 offset_left = -140
offset_top = 24 offset_top = 20
offset_right = -24 offset_right = -24
offset_bottom = 172 offset_bottom = 136
script = ExtResource("10") script = ExtResource("10")
icon = 1 icon = 1
glow_color = Color(0.55, 0.95, 0.9, 1) glow_color = Color(0.55, 0.95, 0.9, 1)
@ -1619,27 +1619,27 @@ color = Color(0.03, 0.03, 0.08, 0.94)
mouse_filter = 2 mouse_filter = 2
anchor_right = 1.0 anchor_right = 1.0
offset_left = 24 offset_left = 24
offset_top = 36 offset_top = 20
offset_right = -200 offset_right = -200
offset_bottom = 166 offset_bottom = 82
text = "Build a ship" text = "Build a ship"
horizontal_alignment = 1 horizontal_alignment = 1
[node name="Bar" type="Control" parent="UI/CraftMenu"] [node name="Bar" type="Control" parent="UI/CraftMenu"]
mouse_filter = 2 mouse_filter = 2
offset_left = 24 offset_left = 24
offset_top = 172 offset_top = 148
offset_right = 520 offset_right = 520
offset_bottom = 308 offset_bottom = 284
script = ExtResource("24") script = ExtResource("24")
[node name="StatusLabel" type="Label" parent="UI/CraftMenu"] [node name="StatusLabel" type="Label" parent="UI/CraftMenu"]
mouse_filter = 2 mouse_filter = 2
anchor_right = 1.0 anchor_right = 1.0
offset_left = 24 offset_left = 24
offset_top = 274 offset_top = 300
offset_right = -200 offset_right = -200
offset_bottom = 420 offset_bottom = 446
theme_override_font_sizes/font_size = 36 theme_override_font_sizes/font_size = 36
autowrap_mode = 2 autowrap_mode = 2
text = "" text = ""
@ -1899,10 +1899,10 @@ glow_color = Color(0.25, 0.85, 1, 1)
[node name="CloseButton" type="Control" parent="UI/CraftMenu"] [node name="CloseButton" type="Control" parent="UI/CraftMenu"]
anchor_left = 1.0 anchor_left = 1.0
anchor_right = 1.0 anchor_right = 1.0
offset_left = -172 offset_left = -140
offset_right = -24 offset_right = -24
offset_top = 24 offset_top = 20
offset_bottom = 172 offset_bottom = 136
script = ExtResource("10") script = ExtResource("10")
icon = 1 icon = 1

View file

@ -9,6 +9,9 @@ extends Control
# finger out to max_radius, and `direction` reports the offset normalised # finger out to max_radius, and `direction` reports the offset normalised
# against that radius (so magnitude is 0..1, usable for throttle later). # against that radius (so magnitude is 0..1, usable for throttle later).
# #
# Releasing puts BOTH the base and the knob back in the middle of the rect, so
# an idle stick always looks the same and always looks idle.
#
# Only claims touches that start inside its own rect - anything else falls # Only claims touches that start inside its own rect - anything else falls
# through untouched, which is what keeps pinch-to-zoom working everywhere # through untouched, which is what keeps pinch-to-zoom working everywhere
# else on screen. # else on screen.
@ -38,8 +41,15 @@ func _ready() -> void:
_relayout() _relayout()
# Where the stick sits when nobody is touching it: the middle of its own rect.
# The base only moves away from here while a finger is down (see handle_touch),
# and returns the moment it lifts.
func home_pos() -> Vector2:
return size / 2.0
func _relayout() -> void: func _relayout() -> void:
base_pos = size / 2.0 base_pos = home_pos()
knob_pos = base_pos knob_pos = base_pos
max_radius = minf(size.x, size.y) * RADIUS_RATIO max_radius = minf(size.x, size.y) * RADIUS_RATIO
queue_redraw() queue_redraw()
@ -67,6 +77,11 @@ func handle_touch(event: InputEventScreenTouch) -> bool:
if event.index != active_touch_index: if event.index != active_touch_index:
return false return false
active_touch_index = -1 active_touch_index = -1
# Back to the middle of the rect, BASE included. This used to reset the
# knob onto base_pos and leave the base wherever the finger had landed, so
# a released stick stayed parked off-centre - which reads as a control
# still in use, and left the ring somewhere different every time.
base_pos = home_pos()
knob_pos = base_pos knob_pos = base_pos
direction = Vector2.ZERO direction = Vector2.ZERO
queue_redraw() queue_redraw()

View file

@ -1,29 +1,22 @@
extends Node2D extends Node2D
# Preview, not a test - #71's ship lab layout with all 7 vessels present, # Preview, not a test - the ship lab at the real 720x1280 viewport, with a
# checking the vessel-name row no longer overlaps itself. # vessel selected and its upgrades listed.
# #
# bash tests/screenshot.sh res://tests/_lab_menu_preview.tscn /tmp/lab.png 20 720x1280 # bash tests/screenshot.sh res://tests/_lab_menu_preview.tscn /tmp/lab.png 25 720x1280
var configured: bool = false
func _process(_delta: float) -> void: func _ready() -> void:
if configured:
return
configured = true
GameState.buildings.clear() GameState.buildings.clear()
GameState.extractors.clear() GameState.extractors.clear()
GameState.transporters.clear() GameState.reset_progression()
GameState.rocks = 500 GameState.bank_inventory.set_amount(GameState.RESOURCE_ORE, 310)
GameState.research_points = 5 GameState.fleet_inventory.set_amount(GameState.RESOURCE_ORE, 47)
GameState.research_points = 4
var main: Node = load("res://Main.tscn").instantiate() var main: Node = load("res://Main.tscn").instantiate()
add_child(main) add_child(main)
main.get_node("EnemySpawner").set_process(false) main.get_node("EnemySpawner").set_process(false)
main.get_node("AsteroidField").set_process(false) main.get_node("AsteroidField").set_process(false)
main.get_node("BuildingField").place(GameState.BUILDING_SHIP_LAB, Vector2(400.0, 0.0)) var build: Node = main.get_node("BuildController")
var lab_id: int = int(GameState.buildings[-1].id) build.lab_menu.visible = true
var bc: Node = main.get_node("BuildController") build._refresh_lab()
bc.lab_building_id = lab_id
main.get_node("UI/LabMenu").visible = true
bc._refresh_lab()

View file

@ -0,0 +1 @@
uid://cx1x1mb4d614u

View file

@ -179,7 +179,13 @@ func _process(delta: float) -> bool:
return false return false
2: 2:
# Mining is local, exactly like ore - no black-hole-specific code. # Mining is local, exactly like ore - no black-hole-specific code.
if elapsed < 1.2: # DERIVED from the extraction rate, not a fixed 1.2s. That was
# long enough only while an extractor produced 2 a second; the
# rate has since been quartered, and a wait tuned to the old one
# reported a broken extractor that was working perfectly. What is
# under test is that dark matter accumulates LOCALLY rather than
# banking itself - not how quickly it arrives.
if elapsed < 1.0 / GameState.EXTRACTOR_RATE + 0.4:
return false return false
var mined: int = game_state.extractor_resource(extractor_index, GameState.RESOURCE_DARK_MATTER) var mined: int = game_state.extractor_resource(extractor_index, GameState.RESOURCE_DARK_MATTER)
if mined <= 0: if mined <= 0:

View file

@ -0,0 +1,99 @@
extends SceneTree
# Headless test: run with
# godot --headless -s res://tests/test_joystick_recentres.gd
# Both sticks float: the base jumps to wherever the finger lands, so a player
# does not have to hit an exact spot on a screen they cannot feel. Releasing
# used to put only the KNOB back onto the base, leaving the base parked
# wherever that touch had been - so an idle stick sat off-centre, in a
# different place every time, and read as a control still in use.
#
# Covers, for the movement stick AND the fire stick:
# A. an untouched stick sits in the middle of its own rect
# B. pressing off-centre moves the base there - the floating behaviour is
# still intact, which is the thing this must not break
# C. releasing puts base AND knob back in the middle
# D. releasing also clears the reported direction, so nothing keeps acting
# on a stick nobody is holding
const OFFSET := Vector2(-58.0, 41.0)
var main: Node
var stage: int = 0
var elapsed: float = 0.0
func _initialize() -> void:
main = load("res://Main.tscn").instantiate()
root.add_child(main)
current_scene = main
func _check(stick: Control, label: String) -> bool:
var home: Vector2 = stick.home_pos()
# --- A. idle means centred -------------------------------------------
if stick.base_pos.distance_to(home) > 0.01 or stick.knob_pos.distance_to(home) > 0.01:
return _fail("%s starts at base %s knob %s, expected both at %s" \
% [label, stick.base_pos, stick.knob_pos, home])
# --- B. it still floats to the finger ---------------------------------
var press := InputEventScreenTouch.new()
press.index = 2
press.pressed = true
press.position = stick.global_position + home + OFFSET
if not stick.handle_touch(press):
return _fail("%s refused a touch inside its own rect" % label)
if stick.base_pos.distance_to(home + OFFSET) > 0.01:
return _fail("%s did not float its base to the finger: base %s, expected %s" \
% [label, stick.base_pos, home + OFFSET])
var drag := InputEventScreenDrag.new()
drag.index = 2
drag.position = press.position + Vector2(stick.max_radius, 0.0)
stick.handle_drag(drag)
if stick.direction == Vector2.ZERO:
return _fail("%s reported no direction while pushed" % label)
if stick.knob_pos.distance_to(stick.base_pos) < stick.max_radius * 0.5:
return _fail("%s knob barely moved while pushed" % label)
# --- C/D. release recentres everything and stops reporting ------------
var release := InputEventScreenTouch.new()
release.index = 2
release.pressed = false
release.position = drag.position
stick.handle_touch(release)
if stick.base_pos.distance_to(home) > 0.01:
return _fail("%s left its base at %s after release, expected %s" \
% [label, stick.base_pos, home])
if stick.knob_pos.distance_to(home) > 0.01:
return _fail("%s left its knob at %s after release, expected %s" \
% [label, stick.knob_pos, home])
if stick.direction != Vector2.ZERO:
return _fail("%s still reports %s after release" % [label, stick.direction])
if stick.is_active():
return _fail("%s still claims to be held after release" % label)
print("%s: floats to the finger, and returns to centre on release" % label)
return true
func _process(delta: float) -> bool:
elapsed += delta
if stage != 0:
return false
if elapsed < 0.2:
return false
stage = 1
if not _check(main.get_node("UI/Joystick"), "movement stick"):
return true
if not _check(main.get_node("UI/FireStick"), "fire stick"):
return true
print("TEST_JOYSTICK_RECENTRES: PASS")
quit(0)
return true
func _fail(message: String) -> bool:
print("TEST_JOYSTICK_RECENTRES: FAIL (%s)" % message)
quit(1)
return false

View file

@ -0,0 +1 @@
uid://bk2jy7bvfm51b