diff --git a/GameState.gd b/GameState.gd index 235808c..d546073 100644 --- a/GameState.gd +++ b/GameState.gd @@ -1223,12 +1223,15 @@ func rotate_formation(radians: float) -> void: # hauler: ore becomes spendable only when a hub-stationed transporter picks # up a full load and physically delivers it to the mothership. Entries are # {"position", "planet_id", "planet_name", "resource_type", "inventory", "mining_progress"}. -# Ore per second. Halved alongside the planet-density change in WorldGen: with -# 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 -# from. The intent is more sites each worth less, so expanding is what grows -# the economy rather than one lucky early extractor carrying it. -const EXTRACTOR_RATE: float = 1.0 +# Ore per second, per extractor. +# +# Halved once alongside the planet-density change in WorldGen (roughly 2.5x as +# many planets to build on, so holding the rate would have multiplied passive +# income rather than moving where it comes from), and halved again because it +# 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 = [] diff --git a/Main.tscn b/Main.tscn index acd8fb2..43eba93 100644 --- a/Main.tscn +++ b/Main.tscn @@ -1211,9 +1211,9 @@ color = Color(0.03, 0.03, 0.08, 0.94) mouse_filter = 2 anchor_right = 1.0 offset_left = 24 -offset_top = 36 +offset_top = 20 offset_right = -200 -offset_bottom = 166 +offset_bottom = 82 text = "Ship Lab" horizontal_alignment = 1 @@ -1221,9 +1221,9 @@ horizontal_alignment = 1 mouse_filter = 2 anchor_right = 1.0 offset_left = 24 -offset_top = 172 +offset_top = 148 offset_right = -24 -offset_bottom = 308 +offset_bottom = 284 script = ExtResource("24") [node name="VesselA" type="Control" parent="UI/LabMenu"] @@ -1231,8 +1231,8 @@ anchor_left = 0.5 anchor_right = 0.5 offset_left = -300 offset_right = -240 -offset_top = 274 -offset_bottom = 394 +offset_top = 300 +offset_bottom = 420 script = ExtResource("10") icon = 2 glow_color = Color(0.25, 0.85, 1, 1) @@ -1242,8 +1242,8 @@ anchor_left = 0.5 anchor_right = 0.5 offset_left = -210 offset_right = -150 -offset_top = 274 -offset_bottom = 394 +offset_top = 300 +offset_bottom = 420 script = ExtResource("10") icon = 2 glow_color = Color(0.45, 0.8, 1, 1) @@ -1253,8 +1253,8 @@ anchor_left = 0.5 anchor_right = 0.5 offset_left = -120 offset_right = -60 -offset_top = 274 -offset_bottom = 394 +offset_top = 300 +offset_bottom = 420 script = ExtResource("10") icon = 31 glow_color = Color(0.96, 0.32, 0.78, 1) @@ -1264,8 +1264,8 @@ anchor_left = 0.5 anchor_right = 0.5 offset_left = -30 offset_right = 30 -offset_top = 274 -offset_bottom = 394 +offset_top = 300 +offset_bottom = 420 script = ExtResource("10") icon = 12 glow_color = Color(0.95, 0.55, 0.85, 1) @@ -1275,8 +1275,8 @@ anchor_left = 0.5 anchor_right = 0.5 offset_left = 60 offset_right = 120 -offset_top = 274 -offset_bottom = 394 +offset_top = 300 +offset_bottom = 420 script = ExtResource("10") icon = 34 glow_color = Color(1, 0.78, 0.3, 1) @@ -1286,8 +1286,8 @@ anchor_left = 0.5 anchor_right = 0.5 offset_left = 150 offset_right = 210 -offset_top = 274 -offset_bottom = 394 +offset_top = 300 +offset_bottom = 420 script = ExtResource("10") icon = 35 glow_color = Color(0.3, 0.9, 1, 1) @@ -1297,8 +1297,8 @@ anchor_left = 0.5 anchor_right = 0.5 offset_left = 240 offset_right = 300 -offset_top = 274 -offset_bottom = 394 +offset_top = 300 +offset_bottom = 420 script = ExtResource("10") icon = 37 glow_color = Color(0.7, 0.3, 1, 1) @@ -1308,9 +1308,9 @@ visible = false mouse_filter = 2 anchor_right = 1.0 offset_left = 24 -offset_top = 402 +offset_top = 424 offset_right = -24 -offset_bottom = 460 +offset_bottom = 482 theme_override_font_sizes/font_size = 34 horizontal_alignment = 1 text = "" @@ -1321,8 +1321,8 @@ anchor_left = 0.5 anchor_right = 0.5 offset_left = -310 offset_right = -230 -offset_top = 400 -offset_bottom = 472 +offset_top = 424 +offset_bottom = 496 theme_override_font_sizes/font_size = 15 autowrap_mode = 2 horizontal_alignment = 1 @@ -1334,8 +1334,8 @@ anchor_left = 0.5 anchor_right = 0.5 offset_left = -220 offset_right = -140 -offset_top = 400 -offset_bottom = 472 +offset_top = 424 +offset_bottom = 496 theme_override_font_sizes/font_size = 15 autowrap_mode = 2 horizontal_alignment = 1 @@ -1347,8 +1347,8 @@ anchor_left = 0.5 anchor_right = 0.5 offset_left = -130 offset_right = -50 -offset_top = 400 -offset_bottom = 472 +offset_top = 424 +offset_bottom = 496 theme_override_font_sizes/font_size = 15 autowrap_mode = 2 horizontal_alignment = 1 @@ -1360,8 +1360,8 @@ anchor_left = 0.5 anchor_right = 0.5 offset_left = -40 offset_right = 40 -offset_top = 400 -offset_bottom = 472 +offset_top = 424 +offset_bottom = 496 theme_override_font_sizes/font_size = 15 autowrap_mode = 2 horizontal_alignment = 1 @@ -1373,8 +1373,8 @@ anchor_left = 0.5 anchor_right = 0.5 offset_left = 50 offset_right = 130 -offset_top = 400 -offset_bottom = 472 +offset_top = 424 +offset_bottom = 496 theme_override_font_sizes/font_size = 15 autowrap_mode = 2 horizontal_alignment = 1 @@ -1386,8 +1386,8 @@ anchor_left = 0.5 anchor_right = 0.5 offset_left = 140 offset_right = 220 -offset_top = 400 -offset_bottom = 472 +offset_top = 424 +offset_bottom = 496 theme_override_font_sizes/font_size = 15 autowrap_mode = 2 horizontal_alignment = 1 @@ -1399,8 +1399,8 @@ anchor_left = 0.5 anchor_right = 0.5 offset_left = 230 offset_right = 310 -offset_top = 400 -offset_bottom = 472 +offset_top = 424 +offset_bottom = 496 theme_override_font_sizes/font_size = 15 autowrap_mode = 2 horizontal_alignment = 1 @@ -1410,9 +1410,9 @@ text = "Distorder" mouse_filter = 2 anchor_right = 1.0 offset_left = 48 -offset_top = 480 +offset_top = 502 offset_right = -48 -offset_bottom = 484 +offset_bottom = 506 color = Color(0.25, 0.85, 1, 0.6) [node name="UpgradeList" type="Label" parent="UI/LabMenu"] @@ -1421,9 +1421,9 @@ mouse_filter = 2 anchor_right = 1.0 anchor_bottom = 1.0 offset_left = 32 -offset_top = 488 +offset_top = 514 offset_right = -32 -offset_bottom = -470 +offset_bottom = -390 theme_override_font_sizes/font_size = 30 autowrap_mode = 2 text = "" @@ -1434,9 +1434,9 @@ anchor_right = 1.0 anchor_top = 1.0 anchor_bottom = 1.0 offset_left = 32 -offset_top = -460 +offset_top = -380 offset_right = -32 -offset_bottom = -330 +offset_bottom = -280 theme_override_font_sizes/font_size = 32 autowrap_mode = 2 horizontal_alignment = 1 @@ -1448,9 +1448,9 @@ anchor_right = 1.0 anchor_top = 1.0 anchor_bottom = 1.0 offset_left = 32 -offset_top = -324 +offset_top = -274 offset_right = -32 -offset_bottom = -256 +offset_bottom = -226 theme_override_font_sizes/font_size = 30 autowrap_mode = 2 horizontal_alignment = 1 @@ -1464,8 +1464,8 @@ anchor_right = 0.5 anchor_bottom = 1.0 offset_left = -230 offset_right = -110 -offset_top = -240 -offset_bottom = -120 +offset_top = -218 +offset_bottom = -108 script = ExtResource("10") icon = 6 glow_color = Color(0.55, 0.95, 0.9, 1) @@ -1477,8 +1477,8 @@ anchor_right = 0.5 anchor_bottom = 1.0 offset_left = 110 offset_right = 230 -offset_top = -240 -offset_bottom = -120 +offset_top = -218 +offset_bottom = -108 script = ExtResource("10") icon = 4 glow_color = Color(0.45, 0.9, 0.55, 1) @@ -1490,9 +1490,9 @@ anchor_right = 1.0 anchor_top = 1.0 anchor_bottom = 1.0 offset_left = 24 -offset_top = -110 +offset_top = -102 offset_right = -24 -offset_bottom = -20 +offset_bottom = -22 theme_override_font_sizes/font_size = 28 autowrap_mode = 2 horizontal_alignment = 1 @@ -1503,8 +1503,8 @@ anchor_left = 0.5 anchor_right = 0.5 offset_left = -240 offset_right = -120 -offset_top = 488 -offset_bottom = 598 +offset_top = 514 +offset_bottom = 624 script = ExtResource("10") icon = 13 glow_color = Color(0.25, 0.85, 1, 1) @@ -1515,8 +1515,8 @@ anchor_left = 0.5 anchor_right = 0.5 offset_left = -310 offset_right = -50 -offset_top = 603 -offset_bottom = 673 +offset_top = 628 +offset_bottom = 698 theme_override_font_sizes/font_size = 22 autowrap_mode = 2 horizontal_alignment = 1 @@ -1527,8 +1527,8 @@ anchor_left = 0.5 anchor_right = 0.5 offset_left = 120 offset_right = 240 -offset_top = 488 -offset_bottom = 598 +offset_top = 514 +offset_bottom = 624 script = ExtResource("10") icon = 13 glow_color = Color(0.25, 0.85, 1, 1) @@ -1539,8 +1539,8 @@ anchor_left = 0.5 anchor_right = 0.5 offset_left = 50 offset_right = 310 -offset_top = 603 -offset_bottom = 673 +offset_top = 628 +offset_bottom = 698 theme_override_font_sizes/font_size = 22 autowrap_mode = 2 horizontal_alignment = 1 @@ -1551,8 +1551,8 @@ anchor_left = 0.5 anchor_right = 0.5 offset_left = -240 offset_right = -120 -offset_top = 678 -offset_bottom = 783 +offset_top = 706 +offset_bottom = 816 script = ExtResource("10") icon = 13 glow_color = Color(0.25, 0.85, 1, 1) @@ -1563,8 +1563,8 @@ anchor_left = 0.5 anchor_right = 0.5 offset_left = -310 offset_right = -50 -offset_top = 788 -offset_bottom = 833 +offset_top = 820 +offset_bottom = 890 theme_override_font_sizes/font_size = 22 autowrap_mode = 2 horizontal_alignment = 1 @@ -1575,8 +1575,8 @@ anchor_left = 0.5 anchor_right = 0.5 offset_left = 120 offset_right = 240 -offset_top = 678 -offset_bottom = 783 +offset_top = 706 +offset_bottom = 816 script = ExtResource("10") icon = 13 glow_color = Color(0.25, 0.85, 1, 1) @@ -1587,8 +1587,8 @@ anchor_left = 0.5 anchor_right = 0.5 offset_left = 50 offset_right = 310 -offset_top = 788 -offset_bottom = 833 +offset_top = 820 +offset_bottom = 890 theme_override_font_sizes/font_size = 22 autowrap_mode = 2 horizontal_alignment = 1 @@ -1597,10 +1597,10 @@ text = "" [node name="CloseButton" type="Control" parent="UI/LabMenu"] anchor_left = 1.0 anchor_right = 1.0 -offset_left = -172 -offset_top = 24 +offset_left = -140 +offset_top = 20 offset_right = -24 -offset_bottom = 172 +offset_bottom = 136 script = ExtResource("10") icon = 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 anchor_right = 1.0 offset_left = 24 -offset_top = 36 +offset_top = 20 offset_right = -200 -offset_bottom = 166 +offset_bottom = 82 text = "Build a ship" horizontal_alignment = 1 [node name="Bar" type="Control" parent="UI/CraftMenu"] mouse_filter = 2 offset_left = 24 -offset_top = 172 +offset_top = 148 offset_right = 520 -offset_bottom = 308 +offset_bottom = 284 script = ExtResource("24") [node name="StatusLabel" type="Label" parent="UI/CraftMenu"] mouse_filter = 2 anchor_right = 1.0 offset_left = 24 -offset_top = 274 +offset_top = 300 offset_right = -200 -offset_bottom = 420 +offset_bottom = 446 theme_override_font_sizes/font_size = 36 autowrap_mode = 2 text = "" @@ -1899,10 +1899,10 @@ glow_color = Color(0.25, 0.85, 1, 1) [node name="CloseButton" type="Control" parent="UI/CraftMenu"] anchor_left = 1.0 anchor_right = 1.0 -offset_left = -172 +offset_left = -140 offset_right = -24 -offset_top = 24 -offset_bottom = 172 +offset_top = 20 +offset_bottom = 136 script = ExtResource("10") icon = 1 diff --git a/TouchJoystick.gd b/TouchJoystick.gd index 4c1cf2a..5685f91 100644 --- a/TouchJoystick.gd +++ b/TouchJoystick.gd @@ -9,6 +9,9 @@ extends Control # finger out to max_radius, and `direction` reports the offset normalised # 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 # through untouched, which is what keeps pinch-to-zoom working everywhere # else on screen. @@ -38,8 +41,15 @@ func _ready() -> void: _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: - base_pos = size / 2.0 + base_pos = home_pos() knob_pos = base_pos max_radius = minf(size.x, size.y) * RADIUS_RATIO queue_redraw() @@ -67,6 +77,11 @@ func handle_touch(event: InputEventScreenTouch) -> bool: if event.index != active_touch_index: return false 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 direction = Vector2.ZERO queue_redraw() diff --git a/tests/_lab_menu_preview.gd b/tests/_lab_menu_preview.gd index 80db449..636e240 100644 --- a/tests/_lab_menu_preview.gd +++ b/tests/_lab_menu_preview.gd @@ -1,29 +1,22 @@ extends Node2D -# Preview, not a test - #71's ship lab layout with all 7 vessels present, -# checking the vessel-name row no longer overlaps itself. +# Preview, not a test - the ship lab at the real 720x1280 viewport, with a +# vessel selected and its upgrades listed. # -# bash tests/screenshot.sh res://tests/_lab_menu_preview.tscn /tmp/lab.png 20 720x1280 - -var configured: bool = false +# bash tests/screenshot.sh res://tests/_lab_menu_preview.tscn /tmp/lab.png 25 720x1280 -func _process(_delta: float) -> void: - if configured: - return - configured = true +func _ready() -> void: GameState.buildings.clear() GameState.extractors.clear() - GameState.transporters.clear() - GameState.rocks = 500 - GameState.research_points = 5 + GameState.reset_progression() + GameState.bank_inventory.set_amount(GameState.RESOURCE_ORE, 310) + GameState.fleet_inventory.set_amount(GameState.RESOURCE_ORE, 47) + GameState.research_points = 4 var main: Node = load("res://Main.tscn").instantiate() add_child(main) main.get_node("EnemySpawner").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 lab_id: int = int(GameState.buildings[-1].id) - var bc: Node = main.get_node("BuildController") - bc.lab_building_id = lab_id - main.get_node("UI/LabMenu").visible = true - bc._refresh_lab() + var build: Node = main.get_node("BuildController") + build.lab_menu.visible = true + build._refresh_lab() diff --git a/tests/test_asteroid_mining.gd.uid b/tests/test_asteroid_mining.gd.uid new file mode 100644 index 0000000..150cb1b --- /dev/null +++ b/tests/test_asteroid_mining.gd.uid @@ -0,0 +1 @@ +uid://cx1x1mb4d614u diff --git a/tests/test_black_hole.gd b/tests/test_black_hole.gd index 6bfe495..52fbf7c 100644 --- a/tests/test_black_hole.gd +++ b/tests/test_black_hole.gd @@ -179,7 +179,13 @@ func _process(delta: float) -> bool: return false 2: # 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 var mined: int = game_state.extractor_resource(extractor_index, GameState.RESOURCE_DARK_MATTER) if mined <= 0: diff --git a/tests/test_joystick_recentres.gd b/tests/test_joystick_recentres.gd new file mode 100644 index 0000000..bd7a1e8 --- /dev/null +++ b/tests/test_joystick_recentres.gd @@ -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 diff --git a/tests/test_joystick_recentres.gd.uid b/tests/test_joystick_recentres.gd.uid new file mode 100644 index 0000000..307f322 --- /dev/null +++ b/tests/test_joystick_recentres.gd.uid @@ -0,0 +1 @@ +uid://bk2jy7bvfm51b