Transport Hub building
Forgejo #18, part 5 of #12. The building only - the vessels that do the hauling are #19. Placeable, costed at 30, gated behind a new "Freight Handling" research node hanging off Logistics, with its own info popup, build-menu glyph and map marker. Drawn as an octagonal dock ring with berth arms and a squared-off freight core: deliberately radial-but-flat so it does not read as a small mothership, which is the only structure with swept arms. Its stationed transports are NeonPiece children of one rotating holder, per #10 - the geometry is rasterised once and only the holder's rotation changes, so the traffic costs no redraws. Building._draw()'s match has a catch-all that renders anything unrecognised as a ship crafter, so a missing case is silent and looks almost right. The test checks for the hub's own _hub_traffic holder rather than trusting that something plausible appeared - which caught exactly that: a _ready() patch had silently not applied and the hub was rendering through the crafter branch. The build menu grew a third row. Every button, label and price moved: the old row occupied 332px against a 372px pitch, and three of those do not fit above a 1280px screen. Rows are now shorter (128px buttons, 40px price digits) at a 290px pitch, ending at y=1176. Rendered and looked at - the first attempt tightened the pitch alone and left every price overlapping the row beneath it, which no headless test would have seen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
ff162faef5
commit
823828f3b3
10 changed files with 400 additions and 52 deletions
|
|
@ -27,6 +27,7 @@ extends Node2D
|
||||||
@onready var build_close_button: IconButton = get_node("../UI/BuildMenu/CloseButton")
|
@onready var build_close_button: IconButton = get_node("../UI/BuildMenu/CloseButton")
|
||||||
@onready var build_status: Label = get_node("../UI/BuildMenu/StatusLabel")
|
@onready var build_status: Label = get_node("../UI/BuildMenu/StatusLabel")
|
||||||
@onready var build_extractor_button: IconButton = get_node("../UI/BuildMenu/ExtractorButton")
|
@onready var build_extractor_button: IconButton = get_node("../UI/BuildMenu/ExtractorButton")
|
||||||
|
@onready var build_hub_button: IconButton = get_node("../UI/BuildMenu/TransportHubButton")
|
||||||
@onready var planet_field: Node2D = get_node("../PlanetField")
|
@onready var planet_field: Node2D = get_node("../PlanetField")
|
||||||
@onready var info_popup: Control = get_node("../UI/BuildMenu/InfoPopup")
|
@onready var info_popup: Control = get_node("../UI/BuildMenu/InfoPopup")
|
||||||
@onready var info_title: Label = get_node("../UI/BuildMenu/InfoPopup/Panel/TitleLabel")
|
@onready var info_title: Label = get_node("../UI/BuildMenu/InfoPopup/Panel/TitleLabel")
|
||||||
|
|
@ -76,6 +77,10 @@ const BUILDING_INFO: Dictionary = {
|
||||||
"title": "Command Center",
|
"title": "Command Center",
|
||||||
"body": "Fly the fleet onto it to drag your fleet into a new formation. Rebuilt fleets keep it.",
|
"body": "Fly the fleet onto it to drag your fleet into a new formation. Rebuilt fleets keep it.",
|
||||||
},
|
},
|
||||||
|
GameState.BUILDING_TRANSPORT_HUB: {
|
||||||
|
"title": "Transport Hub",
|
||||||
|
"body": "Stations transport vessels. They fetch ore from your mothership and deliver it to whichever building is waiting on it.",
|
||||||
|
},
|
||||||
GameState.BUILDING_EXTRACTOR: {
|
GameState.BUILDING_EXTRACTOR: {
|
||||||
"title": "Extractor",
|
"title": "Extractor",
|
||||||
"body": "Mines a planet and runs a hauler to your mothership. It keeps earning while you are away.",
|
"body": "Mines a planet and runs a hauler to your mothership. It keeps earning while you are away.",
|
||||||
|
|
@ -100,6 +105,7 @@ func _ready() -> void:
|
||||||
build_crafter_button.pressed.connect(_on_place_crafter)
|
build_crafter_button.pressed.connect(_on_place_crafter)
|
||||||
build_command_button.pressed.connect(_on_place_command_center)
|
build_command_button.pressed.connect(_on_place_command_center)
|
||||||
build_extractor_button.pressed.connect(_on_place_extractor)
|
build_extractor_button.pressed.connect(_on_place_extractor)
|
||||||
|
build_hub_button.pressed.connect(_on_place_transport_hub)
|
||||||
info_close_button.pressed.connect(_close_info)
|
info_close_button.pressed.connect(_close_info)
|
||||||
info_build_button.pressed.connect(_confirm_build)
|
info_build_button.pressed.connect(_confirm_build)
|
||||||
|
|
||||||
|
|
@ -194,6 +200,8 @@ func _action_icon_for(type: String) -> int:
|
||||||
match type:
|
match type:
|
||||||
GameState.BUILDING_SHIP_CRAFTER:
|
GameState.BUILDING_SHIP_CRAFTER:
|
||||||
return IconButton.Icon.SHIP
|
return IconButton.Icon.SHIP
|
||||||
|
GameState.BUILDING_TRANSPORT_HUB:
|
||||||
|
return IconButton.Icon.TRANSPORT_HUB
|
||||||
GameState.BUILDING_MOTHERSHIP:
|
GameState.BUILDING_MOTHERSHIP:
|
||||||
return IconButton.Icon.MOTHERSHIP
|
return IconButton.Icon.MOTHERSHIP
|
||||||
_:
|
_:
|
||||||
|
|
@ -243,6 +251,7 @@ func _refresh_build_status() -> void:
|
||||||
# explain itself in the info popup.
|
# explain itself in the info popup.
|
||||||
build_crafter_button.enabled = GameState.is_building_unlocked(GameState.BUILDING_SHIP_CRAFTER)
|
build_crafter_button.enabled = GameState.is_building_unlocked(GameState.BUILDING_SHIP_CRAFTER)
|
||||||
build_command_button.enabled = GameState.is_building_unlocked(GameState.BUILDING_COMMAND_CENTER)
|
build_command_button.enabled = GameState.is_building_unlocked(GameState.BUILDING_COMMAND_CENTER)
|
||||||
|
build_hub_button.enabled = GameState.is_building_unlocked(GameState.BUILDING_TRANSPORT_HUB)
|
||||||
build_extractor_button.enabled = _planet_under_fleet() != null \
|
build_extractor_button.enabled = _planet_under_fleet() != null \
|
||||||
and GameState.is_building_unlocked(GameState.BUILDING_EXTRACTOR)
|
and GameState.is_building_unlocked(GameState.BUILDING_EXTRACTOR)
|
||||||
|
|
||||||
|
|
@ -266,6 +275,10 @@ func _on_place_command_center() -> void:
|
||||||
_show_building_info(GameState.BUILDING_COMMAND_CENTER)
|
_show_building_info(GameState.BUILDING_COMMAND_CENTER)
|
||||||
|
|
||||||
|
|
||||||
|
func _on_place_transport_hub() -> void:
|
||||||
|
_show_building_info(GameState.BUILDING_TRANSPORT_HUB)
|
||||||
|
|
||||||
|
|
||||||
func _on_place_extractor() -> void:
|
func _on_place_extractor() -> void:
|
||||||
# The option stays pressable while greyed, so this is also how a
|
# The option stays pressable while greyed, so this is also how a
|
||||||
# not-over-a-planet extractor explains itself.
|
# not-over-a-planet extractor explains itself.
|
||||||
|
|
@ -274,6 +287,8 @@ func _on_place_extractor() -> void:
|
||||||
|
|
||||||
func cost_of(type: String) -> int:
|
func cost_of(type: String) -> int:
|
||||||
match type:
|
match type:
|
||||||
|
GameState.BUILDING_TRANSPORT_HUB:
|
||||||
|
return GameState.TRANSPORT_HUB_COST
|
||||||
GameState.BUILDING_MOTHERSHIP:
|
GameState.BUILDING_MOTHERSHIP:
|
||||||
return GameState.MOTHERSHIP_COST
|
return GameState.MOTHERSHIP_COST
|
||||||
GameState.BUILDING_SHIP_CRAFTER:
|
GameState.BUILDING_SHIP_CRAFTER:
|
||||||
|
|
|
||||||
65
Building.gd
65
Building.gd
|
|
@ -28,6 +28,19 @@ extends Node2D
|
||||||
const MOTHERSHIP_COLOR: Color = Color(0.45, 0.9, 0.55)
|
const MOTHERSHIP_COLOR: Color = Color(0.45, 0.9, 0.55)
|
||||||
const CRAFTER_COLOR: Color = Color(1.0, 0.72, 0.25)
|
const CRAFTER_COLOR: Color = Color(1.0, 0.72, 0.25)
|
||||||
const COMMAND_COLOR: Color = Color(0.55, 0.6, 1.0)
|
const COMMAND_COLOR: Color = Color(0.55, 0.6, 1.0)
|
||||||
|
const TRANSPORT_HUB_COLOR: Color = Color(0.95, 0.55, 0.85)
|
||||||
|
|
||||||
|
# Transport hub: an octagonal dock ring with berths around it and a freight
|
||||||
|
# core in the middle. Deliberately radial-but-flat, so it does not read as a
|
||||||
|
# small mothership - the mothership is the only thing with swept arms.
|
||||||
|
const HUB_RING_RADIUS: float = 74.0
|
||||||
|
const HUB_DECK_RADIUS: float = 54.0
|
||||||
|
const HUB_CORE_RADIUS: float = 22.0
|
||||||
|
const HUB_BERTH_COUNT: int = 8
|
||||||
|
const HUB_BERTH_LENGTH: float = 20.0
|
||||||
|
const HUB_DOCKED_COUNT: int = 3
|
||||||
|
const HUB_DOCKED_ORBIT: float = 96.0
|
||||||
|
const HUB_SPIN_SPEED: float = 0.22
|
||||||
# The vessel on the assembly line is drawn in the fleet's own colour, so it
|
# The vessel on the assembly line is drawn in the fleet's own colour, so it
|
||||||
# reads as "one of yours being built" rather than as shipyard machinery.
|
# reads as "one of yours being built" rather than as shipyard machinery.
|
||||||
const HULL_COLOR: Color = Color(0.25, 0.85, 1.0)
|
const HULL_COLOR: Color = Color(0.25, 0.85, 1.0)
|
||||||
|
|
@ -85,6 +98,8 @@ var _hoist: NeonPiece = null
|
||||||
var _sparks: Node2D = null
|
var _sparks: Node2D = null
|
||||||
var _hull_holder: Node2D = null
|
var _hull_holder: Node2D = null
|
||||||
var _hull_pieces: Array = []
|
var _hull_pieces: Array = []
|
||||||
|
# Rotating holder for the transports stationed at a transport hub (#18).
|
||||||
|
var _hub_traffic: Node2D = null
|
||||||
var _flash_ring: NeonPiece = null
|
var _flash_ring: NeonPiece = null
|
||||||
var _wash: NeonPiece = null
|
var _wash: NeonPiece = null
|
||||||
|
|
||||||
|
|
@ -103,6 +118,8 @@ func _ready() -> void:
|
||||||
_build_crafter_pieces()
|
_build_crafter_pieces()
|
||||||
elif building_type == GameState.BUILDING_MOTHERSHIP:
|
elif building_type == GameState.BUILDING_MOTHERSHIP:
|
||||||
_build_mothership_pieces()
|
_build_mothership_pieces()
|
||||||
|
elif building_type == GameState.BUILDING_TRANSPORT_HUB:
|
||||||
|
_build_hub_pieces()
|
||||||
queue_redraw()
|
queue_redraw()
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -121,6 +138,8 @@ func apply_animation() -> void:
|
||||||
_animate_mothership()
|
_animate_mothership()
|
||||||
GameState.BUILDING_SHIP_CRAFTER:
|
GameState.BUILDING_SHIP_CRAFTER:
|
||||||
_animate_crafter()
|
_animate_crafter()
|
||||||
|
GameState.BUILDING_TRANSPORT_HUB:
|
||||||
|
_animate_transport_hub()
|
||||||
|
|
||||||
|
|
||||||
# Where the satellites are, and how open the reactor core is. Both are read
|
# Where the satellites are, and how open the reactor core is. Both are read
|
||||||
|
|
@ -161,6 +180,8 @@ func _draw() -> void:
|
||||||
_draw_command_center()
|
_draw_command_center()
|
||||||
GameState.BUILDING_MOTHERSHIP:
|
GameState.BUILDING_MOTHERSHIP:
|
||||||
_draw_mothership_static(self)
|
_draw_mothership_static(self)
|
||||||
|
GameState.BUILDING_TRANSPORT_HUB:
|
||||||
|
_draw_transport_hub_static(self)
|
||||||
_:
|
_:
|
||||||
_draw_crafter_static(self)
|
_draw_crafter_static(self)
|
||||||
|
|
||||||
|
|
@ -203,6 +224,50 @@ const CMD_TOKEN_RADIUS: float = 9.0
|
||||||
const CMD_STUD_RADIUS: float = 7.0
|
const CMD_STUD_RADIUS: float = 7.0
|
||||||
|
|
||||||
|
|
||||||
|
# --- transport hub --------------------------------------------------------
|
||||||
|
|
||||||
|
func _draw_transport_hub_static(target: CanvasItem) -> void:
|
||||||
|
var c: Color = TRANSPORT_HUB_COLOR
|
||||||
|
|
||||||
|
# Dock ring and the deck nested inside it.
|
||||||
|
NeonDraw.draw_glowing_polygon(target, _ring(Vector2.ZERO, HUB_RING_RADIUS, HUB_BERTH_COUNT, PI / 8.0), c, 1.0)
|
||||||
|
NeonDraw.draw_glowing_polygon(target, _ring(Vector2.ZERO, HUB_DECK_RADIUS, HUB_BERTH_COUNT, PI / 8.0), c, 0.45, NeonDraw.DEFAULT_CORE, 0.7)
|
||||||
|
|
||||||
|
# Freight core: a squared-off hold rather than a reactor, so it reads as
|
||||||
|
# storage and not as another power plant.
|
||||||
|
NeonDraw.draw_glowing_polygon(target, _ring(Vector2.ZERO, HUB_CORE_RADIUS, 4, PI / 4.0), c, 0.95)
|
||||||
|
|
||||||
|
for i in range(HUB_BERTH_COUNT):
|
||||||
|
var a: float = (float(i) / HUB_BERTH_COUNT) * TAU + PI / 8.0
|
||||||
|
var dir: Vector2 = Vector2(cos(a), sin(a))
|
||||||
|
NeonDraw.draw_glowing_line(target, dir * HUB_CORE_RADIUS, dir * HUB_DECK_RADIUS, c, 0.5, 0.32)
|
||||||
|
# Berth arm standing off the ring, where a transporter parks.
|
||||||
|
NeonDraw.draw_glowing_line(target, dir * HUB_RING_RADIUS,
|
||||||
|
dir * (HUB_RING_RADIUS + HUB_BERTH_LENGTH), c, 0.75, 0.38)
|
||||||
|
|
||||||
|
|
||||||
|
func _build_hub_pieces() -> void:
|
||||||
|
# Stationed transports, as NeonPiece children of one holder that turns.
|
||||||
|
# Per #10 the geometry is rasterised once and only the holder's rotation
|
||||||
|
# changes, so the traffic costs no redraws at all.
|
||||||
|
_hub_traffic = Node2D.new()
|
||||||
|
add_child(_hub_traffic)
|
||||||
|
for i in range(HUB_DOCKED_COUNT):
|
||||||
|
var a: float = (float(i) / HUB_DOCKED_COUNT) * TAU
|
||||||
|
var at: Vector2 = Vector2(cos(a), sin(a)) * HUB_DOCKED_ORBIT
|
||||||
|
var piece: NeonPiece = NeonPiece.create(_hub_traffic, at, TRANSPORT_HUB_COLOR)
|
||||||
|
# A stubby freighter: blunt, boxy, nothing like the fleet's darts.
|
||||||
|
piece.add_polygon(PackedVector2Array([
|
||||||
|
Vector2(-9, -5), Vector2(9, -5), Vector2(12, 0), Vector2(9, 5), Vector2(-9, 5),
|
||||||
|
]))
|
||||||
|
piece.rotation = a + PI / 2.0
|
||||||
|
piece.queue_redraw()
|
||||||
|
|
||||||
|
|
||||||
|
func _animate_transport_hub() -> void:
|
||||||
|
_hub_traffic.rotation = phase_time * HUB_SPIN_SPEED
|
||||||
|
|
||||||
|
|
||||||
func _diamond(centre: Vector2, r: float) -> PackedVector2Array:
|
func _diamond(centre: Vector2, r: float) -> PackedVector2Array:
|
||||||
return PackedVector2Array([
|
return PackedVector2Array([
|
||||||
centre + Vector2(0, -r), centre + Vector2(r, 0),
|
centre + Vector2(0, -r), centre + Vector2(r, 0),
|
||||||
|
|
|
||||||
|
|
@ -101,9 +101,13 @@ const BUILDING_COMMAND_CENTER: String = "command_center"
|
||||||
# Extractors are not placed in space like the others - they are built ON a
|
# Extractors are not placed in space like the others - they are built ON a
|
||||||
# planet's surface and tracked separately (see `extractors`).
|
# planet's surface and tracked separately (see `extractors`).
|
||||||
const BUILDING_EXTRACTOR: String = "extractor"
|
const BUILDING_EXTRACTOR: String = "extractor"
|
||||||
|
# Hosts the transport vessels that supply other buildings (#18). Built in
|
||||||
|
# space like the rest; it is the transporters (#19) that do the moving.
|
||||||
|
const BUILDING_TRANSPORT_HUB: String = "transport_hub"
|
||||||
|
|
||||||
const COMMAND_CENTER_COST: int = 15
|
const COMMAND_CENTER_COST: int = 15
|
||||||
const EXTRACTOR_COST: int = 25
|
const EXTRACTOR_COST: int = 25
|
||||||
|
const TRANSPORT_HUB_COST: int = 30
|
||||||
|
|
||||||
var buildings: Array = []
|
var buildings: Array = []
|
||||||
|
|
||||||
|
|
@ -136,6 +140,11 @@ const SKILL_TREE: Array = [
|
||||||
"x": 0.82, "unlocks": BUILDING_COMMAND_CENTER,
|
"x": 0.82, "unlocks": BUILDING_COMMAND_CENTER,
|
||||||
"desc": "Build command centers, where the fleet formation is arranged.",
|
"desc": "Build command centers, where the fleet formation is arranged.",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "freight", "name": "Freight Handling", "cost": 40, "requires": "logistics",
|
||||||
|
"x": 0.18, "unlocks": BUILDING_TRANSPORT_HUB,
|
||||||
|
"desc": "Build transport hubs, which supply your other buildings with ore.",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "wing", "name": "Wing Doctrine", "cost": 30, "requires": "coordination",
|
"id": "wing", "name": "Wing Doctrine", "cost": 30, "requires": "coordination",
|
||||||
"x": 0.82, "fleet_bonus": 1,
|
"x": 0.82, "fleet_bonus": 1,
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ enum Icon {
|
||||||
# build menu used to pick from the generic set, which left the mothership
|
# build menu used to pick from the generic set, which left the mothership
|
||||||
# and the command centre sharing a folded-map glyph and neither of them
|
# and the command centre sharing a folded-map glyph and neither of them
|
||||||
# looking anything like the structure they build.
|
# looking anything like the structure they build.
|
||||||
MOTHERSHIP, CRAFTER, COMMAND_CENTER, EXTRACTOR,
|
MOTHERSHIP, CRAFTER, COMMAND_CENTER, EXTRACTOR, TRANSPORT_HUB,
|
||||||
}
|
}
|
||||||
|
|
||||||
# Size the glyphs were originally drawn against. Every glyph dimension is
|
# Size the glyphs were originally drawn against. Every glyph dimension is
|
||||||
|
|
@ -119,6 +119,8 @@ func _draw() -> void:
|
||||||
_draw_command_icon(center, pulse, s)
|
_draw_command_icon(center, pulse, s)
|
||||||
Icon.EXTRACTOR:
|
Icon.EXTRACTOR:
|
||||||
_draw_extractor_icon(center, pulse, s)
|
_draw_extractor_icon(center, pulse, s)
|
||||||
|
Icon.TRANSPORT_HUB:
|
||||||
|
_draw_transport_hub_icon(center, pulse, s)
|
||||||
|
|
||||||
|
|
||||||
func _draw_close(center: Vector2, pulse: float, s: float) -> void:
|
func _draw_close(center: Vector2, pulse: float, s: float) -> void:
|
||||||
|
|
@ -204,6 +206,32 @@ func _draw_mothership_icon(center: Vector2, pulse: float, s: float) -> void:
|
||||||
NeonDraw.draw_glowing_polygon(self, ring, _active_color(), pulse, core_color)
|
NeonDraw.draw_glowing_polygon(self, ring, _active_color(), pulse, core_color)
|
||||||
|
|
||||||
|
|
||||||
|
func _draw_transport_hub_icon(center: Vector2, pulse: float, s: float) -> void:
|
||||||
|
# A ring of docking cradles with a freight box in the middle: reads as
|
||||||
|
# "things are stationed here and go out from here", which is what the hub
|
||||||
|
# does, and shares no silhouette with the crafter's open cradle.
|
||||||
|
var ring_r: float = 11.0 * s
|
||||||
|
var ring: PackedVector2Array = PackedVector2Array()
|
||||||
|
for i in range(8):
|
||||||
|
var a: float = (float(i) / 8.0) * TAU + PI / 8.0
|
||||||
|
ring.append(center + Vector2(cos(a), sin(a)) * ring_r)
|
||||||
|
NeonDraw.draw_glowing_polygon(self, ring, _active_color(), pulse, core_color)
|
||||||
|
|
||||||
|
var box: float = 4.2 * s
|
||||||
|
NeonDraw.draw_glowing_polygon(self, PackedVector2Array([
|
||||||
|
center + Vector2(-box, -box), center + Vector2(box, -box),
|
||||||
|
center + Vector2(box, box), center + Vector2(-box, box),
|
||||||
|
]), _active_color(), pulse, core_color)
|
||||||
|
|
||||||
|
# Three stubby berths, so the ring reads as occupied rather than as a
|
||||||
|
# plain octagon.
|
||||||
|
for i in range(3):
|
||||||
|
var a: float = (float(i) / 3.0) * TAU - PI / 2.0
|
||||||
|
var dir: Vector2 = Vector2(cos(a), sin(a))
|
||||||
|
NeonDraw.draw_glowing_line(self, center + dir * (box * 1.5),
|
||||||
|
center + dir * (ring_r - 1.5 * s), _active_color(), pulse, 0.35 * s, core_color)
|
||||||
|
|
||||||
|
|
||||||
func _draw_crafter_icon(center: Vector2, pulse: float, s: float) -> void:
|
func _draw_crafter_icon(center: Vector2, pulse: float, s: float) -> void:
|
||||||
# Reactor core, truss spine, and an open cradle holding a hull.
|
# Reactor core, truss spine, and an open cradle holding a hull.
|
||||||
var core_centre: Vector2 = center + Vector2(-11, 0) * s
|
var core_centre: Vector2 = center + Vector2(-11, 0) * s
|
||||||
|
|
|
||||||
138
Main.tscn
138
Main.tscn
|
|
@ -270,10 +270,10 @@ anchor_left = 0.5
|
||||||
anchor_right = 0.5
|
anchor_right = 0.5
|
||||||
anchor_top = 0.5
|
anchor_top = 0.5
|
||||||
anchor_bottom = 0.5
|
anchor_bottom = 0.5
|
||||||
offset_left = -214
|
offset_left = -204
|
||||||
offset_right = -66
|
offset_right = -76
|
||||||
offset_top = -254
|
offset_top = -300
|
||||||
offset_bottom = -106
|
offset_bottom = -172
|
||||||
script = ExtResource("10")
|
script = ExtResource("10")
|
||||||
icon = 8
|
icon = 8
|
||||||
glow_color = Color(0.45, 0.9, 0.55, 1)
|
glow_color = Color(0.45, 0.9, 0.55, 1)
|
||||||
|
|
@ -286,9 +286,9 @@ anchor_top = 0.5
|
||||||
anchor_bottom = 0.5
|
anchor_bottom = 0.5
|
||||||
offset_left = -290
|
offset_left = -290
|
||||||
offset_right = 10
|
offset_right = 10
|
||||||
offset_top = -96
|
offset_top = -166
|
||||||
offset_bottom = 4
|
offset_bottom = -100
|
||||||
theme_override_font_sizes/font_size = 36
|
theme_override_font_sizes/font_size = 32
|
||||||
autowrap_mode = 2
|
autowrap_mode = 2
|
||||||
text = "Mothership"
|
text = "Mothership"
|
||||||
horizontal_alignment = 1
|
horizontal_alignment = 1
|
||||||
|
|
@ -299,23 +299,23 @@ anchor_left = 0.5
|
||||||
anchor_right = 0.5
|
anchor_right = 0.5
|
||||||
anchor_top = 0.5
|
anchor_top = 0.5
|
||||||
anchor_bottom = 0.5
|
anchor_bottom = 0.5
|
||||||
offset_left = -204
|
offset_left = -200
|
||||||
offset_right = -64
|
offset_right = -80
|
||||||
offset_top = 14
|
offset_top = -96
|
||||||
offset_bottom = 78
|
offset_bottom = -44
|
||||||
script = ExtResource("19")
|
script = ExtResource("19")
|
||||||
amount = 20
|
amount = 20
|
||||||
digit_height = 52.0
|
digit_height = 40.0
|
||||||
|
|
||||||
[node name="CrafterButton" type="Control" parent="UI/BuildMenu"]
|
[node name="CrafterButton" type="Control" parent="UI/BuildMenu"]
|
||||||
anchor_left = 0.5
|
anchor_left = 0.5
|
||||||
anchor_right = 0.5
|
anchor_right = 0.5
|
||||||
anchor_top = 0.5
|
anchor_top = 0.5
|
||||||
anchor_bottom = 0.5
|
anchor_bottom = 0.5
|
||||||
offset_left = 66
|
offset_left = 76
|
||||||
offset_right = 214
|
offset_right = 204
|
||||||
offset_top = -254
|
offset_top = -300
|
||||||
offset_bottom = -106
|
offset_bottom = -172
|
||||||
script = ExtResource("10")
|
script = ExtResource("10")
|
||||||
icon = 9
|
icon = 9
|
||||||
glow_color = Color(1, 0.72, 0.25, 1)
|
glow_color = Color(1, 0.72, 0.25, 1)
|
||||||
|
|
@ -328,9 +328,9 @@ anchor_top = 0.5
|
||||||
anchor_bottom = 0.5
|
anchor_bottom = 0.5
|
||||||
offset_left = -10
|
offset_left = -10
|
||||||
offset_right = 290
|
offset_right = 290
|
||||||
offset_top = -96
|
offset_top = -166
|
||||||
offset_bottom = 4
|
offset_bottom = -100
|
||||||
theme_override_font_sizes/font_size = 36
|
theme_override_font_sizes/font_size = 32
|
||||||
autowrap_mode = 2
|
autowrap_mode = 2
|
||||||
text = "Ship Crafter"
|
text = "Ship Crafter"
|
||||||
horizontal_alignment = 1
|
horizontal_alignment = 1
|
||||||
|
|
@ -341,23 +341,23 @@ anchor_left = 0.5
|
||||||
anchor_right = 0.5
|
anchor_right = 0.5
|
||||||
anchor_top = 0.5
|
anchor_top = 0.5
|
||||||
anchor_bottom = 0.5
|
anchor_bottom = 0.5
|
||||||
offset_left = 76
|
offset_left = 80
|
||||||
offset_right = 216
|
offset_right = 200
|
||||||
offset_top = 14
|
offset_top = -96
|
||||||
offset_bottom = 78
|
offset_bottom = -44
|
||||||
script = ExtResource("19")
|
script = ExtResource("19")
|
||||||
amount = 12
|
amount = 12
|
||||||
digit_height = 52.0
|
digit_height = 40.0
|
||||||
|
|
||||||
[node name="CommandButton" type="Control" parent="UI/BuildMenu"]
|
[node name="CommandButton" type="Control" parent="UI/BuildMenu"]
|
||||||
anchor_left = 0.5
|
anchor_left = 0.5
|
||||||
anchor_right = 0.5
|
anchor_right = 0.5
|
||||||
anchor_top = 0.5
|
anchor_top = 0.5
|
||||||
anchor_bottom = 0.5
|
anchor_bottom = 0.5
|
||||||
offset_left = -214
|
offset_left = -204
|
||||||
offset_right = -66
|
offset_right = -76
|
||||||
offset_top = 118
|
offset_top = -10
|
||||||
offset_bottom = 266
|
offset_bottom = 118
|
||||||
script = ExtResource("10")
|
script = ExtResource("10")
|
||||||
icon = 10
|
icon = 10
|
||||||
glow_color = Color(0.55, 0.6, 1, 1)
|
glow_color = Color(0.55, 0.6, 1, 1)
|
||||||
|
|
@ -370,9 +370,9 @@ anchor_top = 0.5
|
||||||
anchor_bottom = 0.5
|
anchor_bottom = 0.5
|
||||||
offset_left = -290
|
offset_left = -290
|
||||||
offset_right = 10
|
offset_right = 10
|
||||||
offset_top = 276
|
offset_top = 124
|
||||||
offset_bottom = 376
|
offset_bottom = 190
|
||||||
theme_override_font_sizes/font_size = 36
|
theme_override_font_sizes/font_size = 32
|
||||||
autowrap_mode = 2
|
autowrap_mode = 2
|
||||||
text = "Command Center"
|
text = "Command Center"
|
||||||
horizontal_alignment = 1
|
horizontal_alignment = 1
|
||||||
|
|
@ -383,23 +383,23 @@ anchor_left = 0.5
|
||||||
anchor_right = 0.5
|
anchor_right = 0.5
|
||||||
anchor_top = 0.5
|
anchor_top = 0.5
|
||||||
anchor_bottom = 0.5
|
anchor_bottom = 0.5
|
||||||
offset_left = -204
|
offset_left = -200
|
||||||
offset_right = -64
|
offset_right = -80
|
||||||
offset_top = 386
|
offset_top = 194
|
||||||
offset_bottom = 450
|
offset_bottom = 246
|
||||||
script = ExtResource("19")
|
script = ExtResource("19")
|
||||||
amount = 15
|
amount = 15
|
||||||
digit_height = 52.0
|
digit_height = 40.0
|
||||||
|
|
||||||
[node name="ExtractorButton" type="Control" parent="UI/BuildMenu"]
|
[node name="ExtractorButton" type="Control" parent="UI/BuildMenu"]
|
||||||
anchor_left = 0.5
|
anchor_left = 0.5
|
||||||
anchor_right = 0.5
|
anchor_right = 0.5
|
||||||
anchor_top = 0.5
|
anchor_top = 0.5
|
||||||
anchor_bottom = 0.5
|
anchor_bottom = 0.5
|
||||||
offset_left = 66
|
offset_left = 76
|
||||||
offset_right = 214
|
offset_right = 204
|
||||||
offset_top = 118
|
offset_top = -10
|
||||||
offset_bottom = 266
|
offset_bottom = 118
|
||||||
script = ExtResource("10")
|
script = ExtResource("10")
|
||||||
icon = 11
|
icon = 11
|
||||||
glow_color = Color(0, 0.62, 0.7, 1)
|
glow_color = Color(0, 0.62, 0.7, 1)
|
||||||
|
|
@ -412,9 +412,9 @@ anchor_top = 0.5
|
||||||
anchor_bottom = 0.5
|
anchor_bottom = 0.5
|
||||||
offset_left = -10
|
offset_left = -10
|
||||||
offset_right = 290
|
offset_right = 290
|
||||||
offset_top = 276
|
offset_top = 124
|
||||||
offset_bottom = 376
|
offset_bottom = 190
|
||||||
theme_override_font_sizes/font_size = 36
|
theme_override_font_sizes/font_size = 32
|
||||||
autowrap_mode = 2
|
autowrap_mode = 2
|
||||||
text = "Extractor"
|
text = "Extractor"
|
||||||
horizontal_alignment = 1
|
horizontal_alignment = 1
|
||||||
|
|
@ -425,13 +425,55 @@ anchor_left = 0.5
|
||||||
anchor_right = 0.5
|
anchor_right = 0.5
|
||||||
anchor_top = 0.5
|
anchor_top = 0.5
|
||||||
anchor_bottom = 0.5
|
anchor_bottom = 0.5
|
||||||
offset_left = 76
|
offset_left = 80
|
||||||
offset_right = 216
|
offset_right = 200
|
||||||
offset_top = 386
|
offset_top = 194
|
||||||
offset_bottom = 450
|
offset_bottom = 246
|
||||||
script = ExtResource("19")
|
script = ExtResource("19")
|
||||||
amount = 25
|
amount = 25
|
||||||
digit_height = 52.0
|
digit_height = 40.0
|
||||||
|
|
||||||
|
[node name="TransportHubButton" type="Control" parent="UI/BuildMenu"]
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
offset_left = -64
|
||||||
|
offset_right = 64
|
||||||
|
offset_top = 280
|
||||||
|
offset_bottom = 408
|
||||||
|
script = ExtResource("10")
|
||||||
|
icon = 12
|
||||||
|
glow_color = Color(0.95, 0.55, 0.85, 1)
|
||||||
|
|
||||||
|
[node name="TransportHubLabel" type="Label" parent="UI/BuildMenu"]
|
||||||
|
mouse_filter = 2
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
offset_left = -150
|
||||||
|
offset_right = 150
|
||||||
|
offset_top = 414
|
||||||
|
offset_bottom = 480
|
||||||
|
theme_override_font_sizes/font_size = 32
|
||||||
|
autowrap_mode = 2
|
||||||
|
text = "Transport Hub"
|
||||||
|
horizontal_alignment = 1
|
||||||
|
|
||||||
|
[node name="TransportHubCost" type="Control" parent="UI/BuildMenu"]
|
||||||
|
mouse_filter = 2
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
offset_left = -60
|
||||||
|
offset_right = 60
|
||||||
|
offset_top = 484
|
||||||
|
offset_bottom = 536
|
||||||
|
script = ExtResource("19")
|
||||||
|
amount = 30
|
||||||
|
digit_height = 40.0
|
||||||
|
|
||||||
[node name="CloseButton" type="Control" parent="UI/BuildMenu"]
|
[node name="CloseButton" type="Control" parent="UI/BuildMenu"]
|
||||||
anchor_left = 1.0
|
anchor_left = 1.0
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ const WORLD_TO_LOCAL: float = 0.04
|
||||||
const MOTHERSHIP_MARKER_COLOR: Color = Color(0.45, 0.9, 0.55)
|
const MOTHERSHIP_MARKER_COLOR: Color = Color(0.45, 0.9, 0.55)
|
||||||
const CRAFTER_MARKER_COLOR: Color = Color(1.0, 0.72, 0.25)
|
const CRAFTER_MARKER_COLOR: Color = Color(1.0, 0.72, 0.25)
|
||||||
const COMMAND_MARKER_COLOR: Color = Color(0.55, 0.6, 1.0)
|
const COMMAND_MARKER_COLOR: Color = Color(0.55, 0.6, 1.0)
|
||||||
|
const TRANSPORT_HUB_MARKER_COLOR: Color = Color(0.95, 0.55, 0.85)
|
||||||
|
|
||||||
# A structure built on a planet's surface (see GameState.extractors) is not
|
# A structure built on a planet's surface (see GameState.extractors) is not
|
||||||
# itself a map marker - it is a small badge on the existing planet marker,
|
# itself a map marker - it is a small badge on the existing planet marker,
|
||||||
|
|
@ -50,6 +51,8 @@ func _building_marker_color(type: String) -> Color:
|
||||||
return MOTHERSHIP_MARKER_COLOR
|
return MOTHERSHIP_MARKER_COLOR
|
||||||
GameState.BUILDING_SHIP_CRAFTER:
|
GameState.BUILDING_SHIP_CRAFTER:
|
||||||
return CRAFTER_MARKER_COLOR
|
return CRAFTER_MARKER_COLOR
|
||||||
|
GameState.BUILDING_TRANSPORT_HUB:
|
||||||
|
return TRANSPORT_HUB_MARKER_COLOR
|
||||||
_:
|
_:
|
||||||
return COMMAND_MARKER_COLOR
|
return COMMAND_MARKER_COLOR
|
||||||
|
|
||||||
|
|
@ -115,6 +118,8 @@ func _draw() -> void:
|
||||||
_draw_marker_polygon(_regular_polygon(marker.position, 8.0, 6, PI / 6.0), marker.color)
|
_draw_marker_polygon(_regular_polygon(marker.position, 8.0, 6, PI / 6.0), marker.color)
|
||||||
GameState.BUILDING_SHIP_CRAFTER:
|
GameState.BUILDING_SHIP_CRAFTER:
|
||||||
_draw_marker_polygon(_regular_polygon(marker.position, 7.0, 4, 0.0), marker.color)
|
_draw_marker_polygon(_regular_polygon(marker.position, 7.0, 4, 0.0), marker.color)
|
||||||
|
GameState.BUILDING_TRANSPORT_HUB:
|
||||||
|
_draw_marker_polygon(_regular_polygon(marker.position, 7.5, 8, PI / 8.0), marker.color)
|
||||||
_:
|
_:
|
||||||
_draw_marker_polygon(_regular_polygon(marker.position, 6.0, 4, PI / 4.0), marker.color)
|
_draw_marker_polygon(_regular_polygon(marker.position, 6.0, 4, PI / 4.0), marker.color)
|
||||||
|
|
||||||
|
|
|
||||||
20
tests/_build_menu_preview.gd
Normal file
20
tests/_build_menu_preview.gd
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
extends Node2D
|
||||||
|
|
||||||
|
# Preview, not a test. Opens the build menu itself, so the three-row layout
|
||||||
|
# added for the Transport Hub (#18) can be checked for fit on the real phone
|
||||||
|
# viewport - every button, label and price moved, and a bad offset is
|
||||||
|
# invisible to a headless test.
|
||||||
|
#
|
||||||
|
# bash tests/screenshot.sh res://tests/_build_menu_preview.tscn /tmp/menu.png 20 720x1280
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
GameState.buildings.clear()
|
||||||
|
GameState.extractors.clear()
|
||||||
|
GameState.rocks = 500
|
||||||
|
# Everything researched, so nothing is greyed out and the whole menu is
|
||||||
|
# legible at full strength.
|
||||||
|
GameState.unlocked = ["shipyards", "logistics", "freight", "coordination"]
|
||||||
|
var main: Node = load("res://Main.tscn").instantiate()
|
||||||
|
add_child(main)
|
||||||
|
main.get_node("UI/BuildMenu").visible = true
|
||||||
6
tests/_build_menu_preview.tscn
Normal file
6
tests/_build_menu_preview.tscn
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
[gd_scene load_steps=2 format=3]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://tests/_build_menu_preview.gd" id="1"]
|
||||||
|
|
||||||
|
[node name="BuildMenuPreview" type="Node2D"]
|
||||||
|
script = ExtResource("1")
|
||||||
|
|
@ -13,8 +13,9 @@ func _ready() -> void:
|
||||||
GameState.buildings.clear()
|
GameState.buildings.clear()
|
||||||
GameState.extractors.clear()
|
GameState.extractors.clear()
|
||||||
GameState.reset_formation()
|
GameState.reset_formation()
|
||||||
GameState.add_building(GameState.BUILDING_MOTHERSHIP, Vector2(-230.0, 0.0))
|
GameState.add_building(GameState.BUILDING_MOTHERSHIP, Vector2(-330.0, 0.0))
|
||||||
GameState.add_building(GameState.BUILDING_SHIP_CRAFTER, Vector2(240.0, 0.0))
|
GameState.add_building(GameState.BUILDING_SHIP_CRAFTER, Vector2(140.0, 0.0))
|
||||||
|
GameState.add_building(GameState.BUILDING_TRANSPORT_HUB, Vector2(480.0, 0.0))
|
||||||
|
|
||||||
var main: Node = load("res://Main.tscn").instantiate()
|
var main: Node = load("res://Main.tscn").instantiate()
|
||||||
add_child(main)
|
add_child(main)
|
||||||
|
|
@ -24,4 +25,4 @@ func _ready() -> void:
|
||||||
# far enough to see them whole.
|
# far enough to see them whole.
|
||||||
main.get_node("Fleet").move_to(Vector2(0.0, 210.0))
|
main.get_node("Fleet").move_to(Vector2(0.0, 210.0))
|
||||||
var cam: Camera2D = main.get_node("Camera2D")
|
var cam: Camera2D = main.get_node("Camera2D")
|
||||||
cam.zoom = Vector2(1.35, 1.35)
|
cam.zoom = Vector2(1.0, 1.0)
|
||||||
|
|
|
||||||
157
tests/test_transport_hub_building.gd
Normal file
157
tests/test_transport_hub_building.gd
Normal file
|
|
@ -0,0 +1,157 @@
|
||||||
|
extends SceneTree
|
||||||
|
|
||||||
|
# Headless gameplay test: run with
|
||||||
|
# godot --headless -s res://tests/test_transport_hub_building.gd
|
||||||
|
# Forgejo #18 (part 5 of #12): the Transport Hub is a placeable building of
|
||||||
|
# its own. Only the building here - the vessels that do the hauling are #19.
|
||||||
|
#
|
||||||
|
# Verifies:
|
||||||
|
# 1. it is gated behind its research node, like every other structure
|
||||||
|
# 2. researching it makes it buildable, and placing it charges its cost
|
||||||
|
# 3. it is drawn as ITSELF, not as the crafter - Building._draw()'s match
|
||||||
|
# has a catch-all that renders anything unrecognised as a ship crafter,
|
||||||
|
# so a missing case is silent and looks almost right
|
||||||
|
# 4. its geometry is rasterised ONCE however long it animates (#10), and
|
||||||
|
# its stationed transports really do move
|
||||||
|
# 5. it has its own build-menu icon and its own map marker rather than
|
||||||
|
# borrowing another building's - the menu was once unreadable because
|
||||||
|
# two buildings shared a glyph
|
||||||
|
|
||||||
|
var game_state: Node
|
||||||
|
var scene: Node
|
||||||
|
var field: Node
|
||||||
|
var controller: Node
|
||||||
|
var map_content: Node2D
|
||||||
|
var hub: Node2D
|
||||||
|
var stage: int = 0
|
||||||
|
var elapsed: float = 0.0
|
||||||
|
var spin_at_start: float = 0.0
|
||||||
|
|
||||||
|
const HUB_AT: Vector2 = Vector2(700.0, 0.0)
|
||||||
|
|
||||||
|
|
||||||
|
func _initialize() -> void:
|
||||||
|
game_state = root.get_node("GameState")
|
||||||
|
game_state.buildings.clear()
|
||||||
|
game_state.extractors.clear()
|
||||||
|
game_state.reset_progression()
|
||||||
|
game_state.rocks = 500
|
||||||
|
game_state.fleet_cargo = 0
|
||||||
|
scene = load("res://Main.tscn").instantiate()
|
||||||
|
root.add_child(scene)
|
||||||
|
field = scene.get_node("BuildingField")
|
||||||
|
controller = scene.get_node("BuildController")
|
||||||
|
map_content = scene.get_node("UI/WorldMap/MapContent")
|
||||||
|
|
||||||
|
|
||||||
|
func _process(delta: float) -> bool:
|
||||||
|
elapsed += delta
|
||||||
|
match stage:
|
||||||
|
0:
|
||||||
|
scene.get_node("AsteroidField").set_process(false)
|
||||||
|
scene.get_node("EnemySpawner").set_process(false)
|
||||||
|
|
||||||
|
# --- 1. locked until researched ------------------------------
|
||||||
|
if game_state.is_building_unlocked(GameState.BUILDING_TRANSPORT_HUB):
|
||||||
|
print("TEST_TRANSPORT_HUB_BUILDING: FAIL (buildable with no research at all)")
|
||||||
|
quit(1)
|
||||||
|
return true
|
||||||
|
var gate: String = game_state.research_for_building(GameState.BUILDING_TRANSPORT_HUB)
|
||||||
|
if gate == "":
|
||||||
|
print("TEST_TRANSPORT_HUB_BUILDING: FAIL (no research node gates it)")
|
||||||
|
quit(1)
|
||||||
|
return true
|
||||||
|
print("locked behind research: '%s'" % gate)
|
||||||
|
|
||||||
|
# --- 5. its own icon, distinct from every other building -----
|
||||||
|
var icons: Dictionary = {}
|
||||||
|
for type in [GameState.BUILDING_MOTHERSHIP, GameState.BUILDING_SHIP_CRAFTER,
|
||||||
|
GameState.BUILDING_COMMAND_CENTER, GameState.BUILDING_TRANSPORT_HUB]:
|
||||||
|
var icon: int = controller._action_icon_for(type)
|
||||||
|
if icons.has(icon):
|
||||||
|
print("TEST_TRANSPORT_HUB_BUILDING: FAIL (%s and %s share an icon)" % [type, icons[icon]])
|
||||||
|
quit(1)
|
||||||
|
return true
|
||||||
|
icons[icon] = type
|
||||||
|
print("action icons distinct across %d buildings" % icons.size())
|
||||||
|
|
||||||
|
# --- 2. research it, then build it ---------------------------
|
||||||
|
game_state.unlocked = ["shipyards", "logistics", "freight"]
|
||||||
|
if not game_state.is_building_unlocked(GameState.BUILDING_TRANSPORT_HUB):
|
||||||
|
print("TEST_TRANSPORT_HUB_BUILDING: FAIL (still locked after researching '%s')" % gate)
|
||||||
|
quit(1)
|
||||||
|
return true
|
||||||
|
var before: int = game_state.rocks
|
||||||
|
field.place(GameState.BUILDING_TRANSPORT_HUB, HUB_AT)
|
||||||
|
game_state.spend(controller.cost_of(GameState.BUILDING_TRANSPORT_HUB))
|
||||||
|
if game_state.rocks != before - GameState.TRANSPORT_HUB_COST:
|
||||||
|
print("TEST_TRANSPORT_HUB_BUILDING: FAIL (cost %d charged, expected %d)" % [
|
||||||
|
before - game_state.rocks, GameState.TRANSPORT_HUB_COST
|
||||||
|
])
|
||||||
|
quit(1)
|
||||||
|
return true
|
||||||
|
print("researched and placed for %d ore" % GameState.TRANSPORT_HUB_COST)
|
||||||
|
elapsed = 0.0
|
||||||
|
stage = 1
|
||||||
|
return false
|
||||||
|
1:
|
||||||
|
if elapsed < 0.3:
|
||||||
|
return false
|
||||||
|
for b in field.spawned:
|
||||||
|
if is_instance_valid(b) and b.building_type == GameState.BUILDING_TRANSPORT_HUB:
|
||||||
|
hub = b
|
||||||
|
if hub == null:
|
||||||
|
print("TEST_TRANSPORT_HUB_BUILDING: FAIL (never spawned)")
|
||||||
|
quit(1)
|
||||||
|
return true
|
||||||
|
|
||||||
|
# --- 3. drawn as itself, not via the crafter catch-all -------
|
||||||
|
# _hub_traffic only exists if _ready() took the transport-hub
|
||||||
|
# branch; a missing case falls through to the crafter and would
|
||||||
|
# leave it null while still rendering something plausible.
|
||||||
|
if hub._hub_traffic == null:
|
||||||
|
print("TEST_TRANSPORT_HUB_BUILDING: FAIL (rendered through the crafter catch-all, not as a hub)")
|
||||||
|
quit(1)
|
||||||
|
return true
|
||||||
|
|
||||||
|
# --- 5. its own map marker ----------------------------------
|
||||||
|
var markers: Array = map_content.building_markers()
|
||||||
|
var found: bool = false
|
||||||
|
for m in markers:
|
||||||
|
if m.type == GameState.BUILDING_TRANSPORT_HUB:
|
||||||
|
found = true
|
||||||
|
if m.color == map_content.CRAFTER_MARKER_COLOR \
|
||||||
|
or m.color == map_content.MOTHERSHIP_MARKER_COLOR \
|
||||||
|
or m.color == map_content.COMMAND_MARKER_COLOR:
|
||||||
|
print("TEST_TRANSPORT_HUB_BUILDING: FAIL (map marker reuses another building's colour)")
|
||||||
|
quit(1)
|
||||||
|
return true
|
||||||
|
if not found:
|
||||||
|
print("TEST_TRANSPORT_HUB_BUILDING: FAIL (no map marker - see #11)")
|
||||||
|
quit(1)
|
||||||
|
return true
|
||||||
|
print("has its own map marker")
|
||||||
|
|
||||||
|
spin_at_start = hub._hub_traffic.rotation
|
||||||
|
elapsed = 0.0
|
||||||
|
stage = 2
|
||||||
|
return false
|
||||||
|
2:
|
||||||
|
# --- 4. animates without ever redrawing (#10) ----------------
|
||||||
|
if elapsed < 2.0:
|
||||||
|
return false
|
||||||
|
print("rasterisations after %.1fs: %d" % [elapsed, hub.draw_count])
|
||||||
|
if hub.draw_count != 1:
|
||||||
|
print("TEST_TRANSPORT_HUB_BUILDING: FAIL (redrew its geometry %d times to animate)" % hub.draw_count)
|
||||||
|
quit(1)
|
||||||
|
return true
|
||||||
|
var spun: float = absf(hub._hub_traffic.rotation - spin_at_start)
|
||||||
|
print("stationed transports turned %.3f rad" % spun)
|
||||||
|
if spun < 0.05:
|
||||||
|
print("TEST_TRANSPORT_HUB_BUILDING: FAIL (nothing moved - a frozen hub trivially passes the redraw check)")
|
||||||
|
quit(1)
|
||||||
|
return true
|
||||||
|
print("TEST_TRANSPORT_HUB_BUILDING: PASS")
|
||||||
|
quit(0)
|
||||||
|
return true
|
||||||
|
return false
|
||||||
Loading…
Reference in a new issue