Turn dev mode into sandbox menu
This commit is contained in:
parent
68985316e5
commit
c325501999
19 changed files with 651 additions and 54 deletions
|
|
@ -185,9 +185,12 @@ var research_points: int = 0
|
||||||
# generation is static and dependency-free by design. This stays the single
|
# generation is static and dependency-free by design. This stays the single
|
||||||
# place to set it - assigning dev_mode anywhere, tests included, reaches
|
# place to set it - assigning dev_mode anywhere, tests included, reaches
|
||||||
# world generation.
|
# world generation.
|
||||||
|
var dev_unlimited_resources: bool = false
|
||||||
var dev_mode: bool = false:
|
var dev_mode: bool = false:
|
||||||
set(value):
|
set(value):
|
||||||
dev_mode = value
|
dev_mode = value
|
||||||
|
if not value:
|
||||||
|
dev_unlimited_resources = false
|
||||||
WORLD_GEN.dev_planets_enabled = value
|
WORLD_GEN.dev_planets_enabled = value
|
||||||
|
|
||||||
# Explored-chunk history for the world map's fog-of-war reveal. Lives
|
# Explored-chunk history for the world map's fog-of-war reveal. Lives
|
||||||
|
|
@ -763,6 +766,7 @@ func reset_new_game() -> void:
|
||||||
_distorder_drain_progress = 0.0
|
_distorder_drain_progress = 0.0
|
||||||
boost_depleted_notice = false
|
boost_depleted_notice = false
|
||||||
research_points = 0
|
research_points = 0
|
||||||
|
dev_unlimited_resources = false
|
||||||
dev_mode = false
|
dev_mode = false
|
||||||
explored_chunks.clear()
|
explored_chunks.clear()
|
||||||
bank_inventory = INVENTORY.new()
|
bank_inventory = INVENTORY.new()
|
||||||
|
|
@ -786,12 +790,15 @@ func reset_new_game() -> void:
|
||||||
# the game immediately, without being so large that costs stop registering.
|
# the game immediately, without being so large that costs stop registering.
|
||||||
const DEV_RESOURCE_AMOUNT: int = 2000
|
const DEV_RESOURCE_AMOUNT: int = 2000
|
||||||
const DEV_RESEARCH_POINTS: int = 500
|
const DEV_RESEARCH_POINTS: int = 500
|
||||||
|
const DEV_UNLIMITED_AMOUNT: int = 999999
|
||||||
|
|
||||||
|
|
||||||
# A new game stocked for play-testing: every resource banked, research points
|
# A post-prologue game stocked for play-testing: every resource banked,
|
||||||
# to spend, and one of each planet type next to the spawn (WorldGen reads
|
# research points to spend, and one of each planet type next to the spawn
|
||||||
# dev_mode for that). Offered by the main menu only when running from Godot -
|
# (WorldGen reads dev_mode for that). Offered by the main menu only when
|
||||||
# see MainMenu.gd - so it cannot be reached in a shipped build.
|
# running from Godot - see MainMenu.gd - so it cannot be reached in a shipped
|
||||||
|
# build. Dev mode is for iterating on the game itself, not replaying the long
|
||||||
|
# scripted introduction before every check.
|
||||||
#
|
#
|
||||||
# Deliberately built ON TOP of reset_new_game() rather than beside it, so a
|
# Deliberately built ON TOP of reset_new_game() rather than beside it, so a
|
||||||
# dev game is a normal game plus a stock rather than a second, separately
|
# dev game is a normal game plus a stock rather than a second, separately
|
||||||
|
|
@ -799,12 +806,51 @@ const DEV_RESEARCH_POINTS: int = 500
|
||||||
func start_dev_game() -> void:
|
func start_dev_game() -> void:
|
||||||
reset_new_game()
|
reset_new_game()
|
||||||
dev_mode = true
|
dev_mode = true
|
||||||
|
intro_active = false
|
||||||
for resource_type in resource_types():
|
for resource_type in resource_types():
|
||||||
bank_inventory.set_amount(resource_type, DEV_RESOURCE_AMOUNT)
|
bank_inventory.set_amount(resource_type, DEV_RESOURCE_AMOUNT)
|
||||||
research_points = DEV_RESEARCH_POINTS
|
research_points = DEV_RESEARCH_POINTS
|
||||||
research_points_changed.emit(research_points)
|
research_points_changed.emit(research_points)
|
||||||
|
|
||||||
|
|
||||||
|
# Development toggles deliberately live beside the state they affect. The
|
||||||
|
# menu is only a front-end; scene swaps cannot turn an infinite bank off or
|
||||||
|
# forget which doctrines were exposed.
|
||||||
|
func set_dev_unlimited_resources(enabled: bool) -> bool:
|
||||||
|
if enabled and not dev_mode:
|
||||||
|
return false
|
||||||
|
dev_unlimited_resources = enabled
|
||||||
|
if enabled:
|
||||||
|
_refill_dev_resources()
|
||||||
|
return true
|
||||||
|
|
||||||
|
|
||||||
|
func _refill_dev_resources() -> void:
|
||||||
|
for resource_type in resource_types():
|
||||||
|
if bank_inventory.amount(resource_type) < DEV_UNLIMITED_AMOUNT:
|
||||||
|
bank_inventory.set_amount(resource_type, DEV_UNLIMITED_AMOUNT)
|
||||||
|
if research_points < DEV_UNLIMITED_AMOUNT:
|
||||||
|
research_points = DEV_UNLIMITED_AMOUNT
|
||||||
|
research_points_changed.emit(research_points)
|
||||||
|
|
||||||
|
|
||||||
|
func dev_unlock_all_skills() -> int:
|
||||||
|
if not dev_mode:
|
||||||
|
return 0
|
||||||
|
var added: int = 0
|
||||||
|
for node in SKILL_TREE:
|
||||||
|
var id: String = String(node.id)
|
||||||
|
if id in unlocked:
|
||||||
|
continue
|
||||||
|
unlocked.append(id)
|
||||||
|
added += 1
|
||||||
|
# These permanent doctrines affect structures which may already exist.
|
||||||
|
# Sync once after the batch instead of once per node.
|
||||||
|
_sync_hub_transporters()
|
||||||
|
_sync_workshop_drones()
|
||||||
|
return added
|
||||||
|
|
||||||
|
|
||||||
# --- building stock and production queue (#16) -----------------------------
|
# --- building stock and production queue (#16) -----------------------------
|
||||||
|
|
||||||
# Since #12, a building cannot just deduct from the bank at the moment of
|
# Since #12, a building cannot just deduct from the bank at the moment of
|
||||||
|
|
@ -2755,6 +2801,8 @@ func wave_cleared() -> void:
|
||||||
func _process(delta: float) -> void:
|
func _process(delta: float) -> void:
|
||||||
# Runs in the autoload, so mining and transport continue while the player
|
# Runs in the autoload, so mining and transport continue while the player
|
||||||
# is on a planet's surface or nowhere near either.
|
# is on a planet's surface or nowhere near either.
|
||||||
|
if dev_mode and dev_unlimited_resources:
|
||||||
|
_refill_dev_resources()
|
||||||
advance_waves(delta)
|
advance_waves(delta)
|
||||||
_advance_production(delta)
|
_advance_production(delta)
|
||||||
_advance_lab_research(delta)
|
_advance_lab_research(delta)
|
||||||
|
|
|
||||||
28
tests/_dev_menu_preview.gd
Normal file
28
tests/_dev_menu_preview.gd
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
extends Node2D
|
||||||
|
|
||||||
|
# Visual-only phone preview for the editor sandbox panel. It builds only the
|
||||||
|
# fleet and the menu; loading Main also schedules infinite-world population,
|
||||||
|
# which is wasted behind this opaque panel and painfully slow in softpipe.
|
||||||
|
#
|
||||||
|
# bash tests/screenshot.sh res://tests/_dev_menu_preview.tscn /tmp/dev_menu.png 4 720x1280
|
||||||
|
|
||||||
|
const FLEET = preload("res://vessels/Fleet.gd")
|
||||||
|
const DEV_MENU = preload("res://ui/menus/DevMenu.tscn")
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
GameState.start_dev_game()
|
||||||
|
GameState.dev_unlock_all_skills()
|
||||||
|
var fleet: Node = FLEET.new()
|
||||||
|
add_child(fleet)
|
||||||
|
fleet.spawn_ships(4, Vector2.ZERO, PackedStringArray([
|
||||||
|
GameState.VESSEL_INTERCEPTOR,
|
||||||
|
GameState.VESSEL_SHIELD,
|
||||||
|
GameState.VESSEL_GAS_BOMBER,
|
||||||
|
GameState.VESSEL_LASER,
|
||||||
|
]))
|
||||||
|
var layer := CanvasLayer.new()
|
||||||
|
add_child(layer)
|
||||||
|
var menu: Control = DEV_MENU.instantiate()
|
||||||
|
layer.add_child(menu)
|
||||||
|
menu.open_for(fleet)
|
||||||
1
tests/_dev_menu_preview.gd.uid
Normal file
1
tests/_dev_menu_preview.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://bxsf8yo6lyhf8
|
||||||
6
tests/_dev_menu_preview.tscn
Normal file
6
tests/_dev_menu_preview.tscn
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
[gd_scene load_steps=2 format=3]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://tests/_dev_menu_preview.gd" id="1"]
|
||||||
|
|
||||||
|
[node name="DevMenuPreview" type="Node2D"]
|
||||||
|
script = ExtResource("1")
|
||||||
95
tests/test_dev_menu.gd
Normal file
95
tests/test_dev_menu.gd
Normal file
|
|
@ -0,0 +1,95 @@
|
||||||
|
extends SceneTree
|
||||||
|
|
||||||
|
# The dev button is now a doorway rather than a one-off wave shortcut. This
|
||||||
|
# exercises the real Main scene so additions and removals prove they affect
|
||||||
|
# the live fleet, not only GameState bookkeeping.
|
||||||
|
|
||||||
|
const VESSEL_DEFINITIONS = preload("res://vessels/VesselDefinitions.gd")
|
||||||
|
|
||||||
|
var state: Node
|
||||||
|
var scene: Node
|
||||||
|
var fleet: Node
|
||||||
|
var dev_button: Control
|
||||||
|
var menu: Control
|
||||||
|
var stage: int = 0
|
||||||
|
var elapsed: float = 0.0
|
||||||
|
|
||||||
|
|
||||||
|
func _initialize() -> void:
|
||||||
|
state = root.get_node("GameState")
|
||||||
|
state.start_dev_game()
|
||||||
|
scene = load("res://world/Main.tscn").instantiate()
|
||||||
|
root.add_child(scene)
|
||||||
|
current_scene = scene
|
||||||
|
fleet = scene.get_node("Fleet")
|
||||||
|
dev_button = scene.get_node("UI/DevMenuButton")
|
||||||
|
menu = scene.get_node("UI/DevMenu")
|
||||||
|
|
||||||
|
|
||||||
|
func _process(delta: float) -> bool:
|
||||||
|
elapsed += delta
|
||||||
|
match stage:
|
||||||
|
0:
|
||||||
|
if elapsed < 0.2:
|
||||||
|
return false
|
||||||
|
if state.intro_active:
|
||||||
|
return _fail("the dev world opened inside the intro")
|
||||||
|
if fleet.ships.size() != GameState.STARTING_SHIP_COUNT:
|
||||||
|
return _fail("post-intro dev mode did not start with the normal fleet")
|
||||||
|
dev_button.button.pressed.emit()
|
||||||
|
if not menu.visible:
|
||||||
|
return _fail("the HUD dev button opened no menu")
|
||||||
|
|
||||||
|
menu.unlock_button.pressed.emit()
|
||||||
|
for skill in GameState.SKILL_TREE:
|
||||||
|
if not state.is_unlocked(String(skill.id)):
|
||||||
|
return _fail("unlock-all missed %s" % skill.id)
|
||||||
|
if state.max_fleet_size() != GameState.DEFAULT_FORMATION.size():
|
||||||
|
return _fail("unlock-all did not expose the complete fleet capacity")
|
||||||
|
|
||||||
|
for definition in VESSEL_DEFINITIONS.fleet():
|
||||||
|
menu.fleet_add_requested.emit(String(definition.definition_id))
|
||||||
|
for definition in VESSEL_DEFINITIONS.fleet():
|
||||||
|
if not fleet.has_vessel_type(String(definition.definition_id)):
|
||||||
|
return _fail("the menu could not add %s" % definition.display_name)
|
||||||
|
print("dev menu added every fleet-eligible vessel to the live fleet")
|
||||||
|
|
||||||
|
var before: int = fleet.ships.size()
|
||||||
|
menu.fleet_remove_requested.emit(GameState.VESSEL_GAS_BOMBER)
|
||||||
|
if fleet.ships.size() != before - 1:
|
||||||
|
return _fail("the dev menu did not remove a vessel")
|
||||||
|
|
||||||
|
menu.unlimited_button.pressed.emit()
|
||||||
|
if not state.dev_unlimited_resources:
|
||||||
|
return _fail("the unlimited-resources toggle did not turn on")
|
||||||
|
for resource_type in state.resource_types():
|
||||||
|
state.bank_inventory.withdraw(resource_type, GameState.DEV_UNLIMITED_AMOUNT)
|
||||||
|
state.research_points = 0
|
||||||
|
state._process(0.0)
|
||||||
|
for resource_type in state.resource_types():
|
||||||
|
if state.banked_resource(resource_type) != GameState.DEV_UNLIMITED_AMOUNT:
|
||||||
|
return _fail("unlimited mode did not replenish %s" % resource_type)
|
||||||
|
if state.research_points != GameState.DEV_UNLIMITED_AMOUNT:
|
||||||
|
return _fail("unlimited mode did not replenish research points")
|
||||||
|
print("skill unlock and unlimited resources operate on persistent GameState")
|
||||||
|
|
||||||
|
var wave_before: int = state.wave_number
|
||||||
|
menu.wave_button.pressed.emit()
|
||||||
|
if menu.visible:
|
||||||
|
return _fail("starting a wave left the dev menu over the action")
|
||||||
|
if state.wave_number != wave_before + 1 or not state.wave_pending:
|
||||||
|
return _fail("the dev menu did not retain the immediate wave tool")
|
||||||
|
|
||||||
|
state.reset_new_game()
|
||||||
|
if state.dev_mode or state.dev_unlimited_resources:
|
||||||
|
return _fail("dev cheats leaked into a normal new game")
|
||||||
|
print("TEST_DEV_MENU: PASS")
|
||||||
|
quit(0)
|
||||||
|
return true
|
||||||
|
return false
|
||||||
|
|
||||||
|
|
||||||
|
func _fail(message: String) -> bool:
|
||||||
|
print("TEST_DEV_MENU: FAIL (%s)" % message)
|
||||||
|
quit(1)
|
||||||
|
return true
|
||||||
1
tests/test_dev_menu.gd.uid
Normal file
1
tests/test_dev_menu.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://dws3sq74nik4v
|
||||||
|
|
@ -73,6 +73,8 @@ func _process(delta: float) -> bool:
|
||||||
game_state.start_dev_game()
|
game_state.start_dev_game()
|
||||||
if not game_state.dev_mode:
|
if not game_state.dev_mode:
|
||||||
return _fail("start_dev_game() did not set dev_mode")
|
return _fail("start_dev_game() did not set dev_mode")
|
||||||
|
if game_state.intro_active:
|
||||||
|
return _fail("dev mode still starts at the prologue instead of after it")
|
||||||
for resource_type in game_state.resource_types():
|
for resource_type in game_state.resource_types():
|
||||||
var banked: int = game_state.banked_resource(resource_type)
|
var banked: int = game_state.banked_resource(resource_type)
|
||||||
if banked != GameState.DEV_RESOURCE_AMOUNT:
|
if banked != GameState.DEV_RESOURCE_AMOUNT:
|
||||||
|
|
@ -116,6 +118,8 @@ func _process(delta: float) -> bool:
|
||||||
game_state.reset_new_game()
|
game_state.reset_new_game()
|
||||||
if game_state.dev_mode:
|
if game_state.dev_mode:
|
||||||
return _fail("starting a normal game after a dev one left dev_mode set")
|
return _fail("starting a normal game after a dev one left dev_mode set")
|
||||||
|
if game_state.dev_unlimited_resources:
|
||||||
|
return _fail("starting a normal game kept unlimited resources enabled")
|
||||||
if game_state.rocks != 0 or game_state.research_points != 0:
|
if game_state.rocks != 0 or game_state.research_points != 0:
|
||||||
return _fail("starting a normal game after a dev one kept the dev stock")
|
return _fail("starting a normal game after a dev one kept the dev stock")
|
||||||
print("starting a normal game afterwards clears dev mode entirely")
|
print("starting a normal game afterwards clears dev mode entirely")
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ extends SceneTree
|
||||||
|
|
||||||
const MENUS: Array[String] = [
|
const MENUS: Array[String] = [
|
||||||
"BuildMenu", "CraftMenu", "LabMenu", "TransferMenu", "HangarMenu",
|
"BuildMenu", "CraftMenu", "LabMenu", "TransferMenu", "HangarMenu",
|
||||||
"FormationMenu", "SkillMenu", "PlanningMenu", "GarrisonMenu",
|
"FormationMenu", "SkillMenu", "PlanningMenu", "GarrisonMenu", "DevMenu",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -434,7 +434,7 @@ func _process(delta: float) -> bool:
|
||||||
if elapsed < 0.3:
|
if elapsed < 0.3:
|
||||||
return false
|
return false
|
||||||
# #140: the objective lives behind a button next to the map's,
|
# #140: the objective lives behind a button next to the map's,
|
||||||
# not on the HUD - it used to sit on top of the wave button.
|
# not on the HUD - it used to sit on top of the dev button.
|
||||||
if panel.visible:
|
if panel.visible:
|
||||||
return _fail("the objective panel is open before anyone pressed anything")
|
return _fail("the objective panel is open before anyone pressed anything")
|
||||||
if not quest_button.visible:
|
if not quest_button.visible:
|
||||||
|
|
@ -442,9 +442,9 @@ func _process(delta: float) -> bool:
|
||||||
var map_button: Control = scene.get_node("UI/MapButton")
|
var map_button: Control = scene.get_node("UI/MapButton")
|
||||||
if quest_button.get_rect().intersects(map_button.get_rect()):
|
if quest_button.get_rect().intersects(map_button.get_rect()):
|
||||||
return _fail("the quest button is drawn on top of the map button")
|
return _fail("the quest button is drawn on top of the map button")
|
||||||
var wave_button: Control = scene.get_node("UI/DevWaveButton")
|
var dev_button: Control = scene.get_node("UI/DevMenuButton")
|
||||||
if quest_button.get_rect().intersects(wave_button.get_rect()):
|
if quest_button.get_rect().intersects(dev_button.get_rect()):
|
||||||
return _fail("the quest button is drawn on top of the wave button")
|
return _fail("the quest button is drawn on top of the dev button")
|
||||||
if absf(quest_button.get_rect().get_center().y - map_button.get_rect().get_center().y) > 1.0:
|
if absf(quest_button.get_rect().get_center().y - map_button.get_rect().get_center().y) > 1.0:
|
||||||
return _fail("the quest button does not sit beside the map button")
|
return _fail("the quest button does not sit beside the map button")
|
||||||
panel.open()
|
panel.open()
|
||||||
|
|
@ -458,7 +458,7 @@ func _process(delta: float) -> bool:
|
||||||
return _fail("the panel does not show the objective")
|
return _fail("the panel does not show the objective")
|
||||||
if panel.progress != Vector2i(0, 5):
|
if panel.progress != Vector2i(0, 5):
|
||||||
return _fail("the panel reads %s, expected 0 of 5" % panel.progress)
|
return _fail("the panel reads %s, expected 0 of 5" % panel.progress)
|
||||||
print("quest button beside the map, clear of the wave button; panel: \"%s\" - %s (%d/%d)" \
|
print("quest button beside the map, clear of the dev button; panel: \"%s\" - %s (%d/%d)" \
|
||||||
% [panel.quest_label.text, panel.objective_label.text,
|
% [panel.quest_label.text, panel.objective_label.text,
|
||||||
panel.progress.x, panel.progress.y])
|
panel.progress.x, panel.progress.y])
|
||||||
panel.close()
|
panel.close()
|
||||||
|
|
|
||||||
|
|
@ -224,20 +224,24 @@ func _process(delta: float) -> bool:
|
||||||
return _fail("killing the whole wave did not bring the quiet back")
|
return _fail("killing the whole wave did not bring the quiet back")
|
||||||
print("the wave died and the quiet came back")
|
print("the wave died and the quiet came back")
|
||||||
|
|
||||||
# --- G. the dev button ---------------------------------------
|
# --- G. the dev menu keeps the immediate wave tool -----------
|
||||||
var dev_button: Control = scene.get_node("UI/DevWaveButton")
|
var dev_button: Control = scene.get_node("UI/DevMenuButton")
|
||||||
|
var dev_menu: Control = scene.get_node("UI/DevMenu")
|
||||||
game_state.dev_mode = false
|
game_state.dev_mode = false
|
||||||
dev_button._process(0.0)
|
dev_button._process(0.0)
|
||||||
if dev_button.visible:
|
if dev_button.visible:
|
||||||
return _fail("the dev wave button is offered in a normal game")
|
return _fail("the dev menu button is offered in a normal game")
|
||||||
game_state.dev_mode = true
|
game_state.dev_mode = true
|
||||||
dev_button._process(0.0)
|
dev_button._process(0.0)
|
||||||
if not dev_button.visible:
|
if not dev_button.visible:
|
||||||
return _fail("the dev wave button is hidden in dev mode")
|
return _fail("the dev menu button is hidden in dev mode")
|
||||||
var number_before: int = game_state.wave_number
|
|
||||||
dev_button.button.pressed.emit()
|
dev_button.button.pressed.emit()
|
||||||
|
if not dev_menu.visible:
|
||||||
|
return _fail("the dev button did not open the dev menu")
|
||||||
|
var number_before: int = game_state.wave_number
|
||||||
|
dev_menu.wave_button.pressed.emit()
|
||||||
if game_state.wave_phase != GameState.WAVE_PHASE_ACTIVE:
|
if game_state.wave_phase != GameState.WAVE_PHASE_ACTIVE:
|
||||||
return _fail("the button left the wave in \"%s\"" % game_state.wave_phase)
|
return _fail("the menu's wave tool left the wave in \"%s\"" % game_state.wave_phase)
|
||||||
if not game_state.wave_pending:
|
if not game_state.wave_pending:
|
||||||
return _fail("the button turned the wave active without owing it to anyone")
|
return _fail("the button turned the wave active without owing it to anyone")
|
||||||
if game_state.wave_number != number_before + 1:
|
if game_state.wave_number != number_before + 1:
|
||||||
|
|
@ -249,7 +253,7 @@ func _process(delta: float) -> bool:
|
||||||
spawner._process(0.0)
|
spawner._process(0.0)
|
||||||
if _enemy_count() <= 0:
|
if _enemy_count() <= 0:
|
||||||
return _fail("the forced wave produced no enemies")
|
return _fail("the forced wave produced no enemies")
|
||||||
print("dev button: wave %d on the board at once, %d enemies" \
|
print("dev menu: wave %d on the board at once, %d enemies" \
|
||||||
% [game_state.wave_number, _enemy_count()])
|
% [game_state.wave_number, _enemy_count()])
|
||||||
game_state.dev_mode = false
|
game_state.dev_mode = false
|
||||||
|
|
||||||
|
|
|
||||||
75
ui/DevMenuButton.gd
Normal file
75
ui/DevMenuButton.gd
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
extends Control
|
||||||
|
|
||||||
|
# Editor-only entry into the live sandbox. The modal scene owns presentation;
|
||||||
|
# this small controller owns the boundary to the world nodes it manipulates.
|
||||||
|
|
||||||
|
@onready var button: IconButton = $Button
|
||||||
|
@onready var menu: Control = get_node("../DevMenu")
|
||||||
|
@onready var fleet: Node = get_node("../../Fleet")
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
button.pressed.connect(_on_pressed)
|
||||||
|
menu.fleet_add_requested.connect(_on_fleet_add_requested)
|
||||||
|
menu.fleet_remove_requested.connect(_on_fleet_remove_requested)
|
||||||
|
menu.unlock_skills_requested.connect(_on_unlock_skills_requested)
|
||||||
|
menu.unlimited_resources_requested.connect(_on_unlimited_resources_requested)
|
||||||
|
menu.wave_requested.connect(_on_wave_requested)
|
||||||
|
visible = false
|
||||||
|
|
||||||
|
|
||||||
|
func _process(_delta: float) -> void:
|
||||||
|
var show_it: bool = GameState.dev_mode and not GameState.intro_active
|
||||||
|
if show_it != visible:
|
||||||
|
visible = show_it
|
||||||
|
if not show_it and menu.visible:
|
||||||
|
menu.close_menu()
|
||||||
|
|
||||||
|
|
||||||
|
func _on_pressed() -> void:
|
||||||
|
if not GameState.dev_mode:
|
||||||
|
return
|
||||||
|
menu.open_for(fleet)
|
||||||
|
|
||||||
|
|
||||||
|
func _on_fleet_add_requested(vessel_type: String) -> void:
|
||||||
|
if fleet.add_ship(vessel_type):
|
||||||
|
menu.set_status("Added %s" % GameState.vessel_name(vessel_type))
|
||||||
|
else:
|
||||||
|
menu.set_status("Fleet is full — unlock all skills for up to %d slots" \
|
||||||
|
% GameState.DEFAULT_FORMATION.size())
|
||||||
|
|
||||||
|
|
||||||
|
func _on_fleet_remove_requested(vessel_type: String) -> void:
|
||||||
|
var index: int = -1
|
||||||
|
for i in range(fleet.ships.size()):
|
||||||
|
if is_instance_valid(fleet.ships[i]) \
|
||||||
|
and String(fleet.ships[i].vessel_type) == vessel_type:
|
||||||
|
index = i
|
||||||
|
break
|
||||||
|
if index < 0:
|
||||||
|
menu.set_status("No %s is currently deployed" % GameState.vessel_name(vessel_type))
|
||||||
|
return
|
||||||
|
if fleet.store_ship(index) == "":
|
||||||
|
menu.set_status("Keep at least one vessel in the fleet")
|
||||||
|
return
|
||||||
|
menu.set_status("Removed %s" % GameState.vessel_name(vessel_type))
|
||||||
|
|
||||||
|
|
||||||
|
func _on_unlock_skills_requested() -> void:
|
||||||
|
var unlocked_count: int = GameState.dev_unlock_all_skills()
|
||||||
|
if unlocked_count > 0:
|
||||||
|
menu.set_status("Unlocked all skills (%d new)" % unlocked_count)
|
||||||
|
else:
|
||||||
|
menu.set_status("All skills are already unlocked")
|
||||||
|
|
||||||
|
|
||||||
|
func _on_unlimited_resources_requested(enabled: bool) -> void:
|
||||||
|
if not GameState.set_dev_unlimited_resources(enabled):
|
||||||
|
return
|
||||||
|
menu.set_status("Unlimited resources %s" % ("enabled" if enabled else "disabled"))
|
||||||
|
|
||||||
|
|
||||||
|
func _on_wave_requested() -> void:
|
||||||
|
GameState.force_wave_now()
|
||||||
|
menu.close_menu()
|
||||||
1
ui/DevMenuButton.gd.uid
Normal file
1
ui/DevMenuButton.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://c52odygv78ilg
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
extends Control
|
|
||||||
|
|
||||||
# #110: a dev-only button that puts a wave on the board now.
|
|
||||||
#
|
|
||||||
# Waves are otherwise on a fifty-second clock, which makes anything that
|
|
||||||
# happens during one - the alert, the pathing, buildings taking damage, an
|
|
||||||
# outpost garrison actually earning its keep - slow to look at even once.
|
|
||||||
#
|
|
||||||
# Dev mode is the same gate the main menu already uses for the map editor:
|
|
||||||
# these are tools for building the game, and a player who installed a build
|
|
||||||
# has no use for them. The button does not exist outside it.
|
|
||||||
|
|
||||||
@onready var button: IconButton = get_node("Button")
|
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
button.pressed.connect(_on_pressed)
|
|
||||||
visible = false
|
|
||||||
|
|
||||||
|
|
||||||
func _process(_delta: float) -> void:
|
|
||||||
var show_it: bool = GameState.dev_mode and not GameState.intro_active
|
|
||||||
if show_it != visible:
|
|
||||||
visible = show_it
|
|
||||||
|
|
||||||
|
|
||||||
func _on_pressed() -> void:
|
|
||||||
GameState.force_wave_now()
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
uid://blhthsbawd7vg
|
|
||||||
|
|
@ -63,6 +63,9 @@ enum Icon {
|
||||||
QUEST,
|
QUEST,
|
||||||
# #179: a fleet-wide thrust burst, distinct from the Propulser vessel icon.
|
# #179: a fleet-wide thrust burst, distinct from the Propulser vessel icon.
|
||||||
DASH,
|
DASH,
|
||||||
|
# Development tools: three sliders, used only by the editor-only sandbox
|
||||||
|
# button. Appended to preserve every serialized icon number above.
|
||||||
|
DEV_TOOLS,
|
||||||
}
|
}
|
||||||
|
|
||||||
# Size the glyphs were originally drawn against. Every glyph dimension is
|
# Size the glyphs were originally drawn against. Every glyph dimension is
|
||||||
|
|
@ -323,6 +326,23 @@ func _draw() -> void:
|
||||||
_draw_quest_icon(center, pulse, s)
|
_draw_quest_icon(center, pulse, s)
|
||||||
Icon.DASH:
|
Icon.DASH:
|
||||||
_draw_dash_icon(center, pulse, s)
|
_draw_dash_icon(center, pulse, s)
|
||||||
|
Icon.DEV_TOOLS:
|
||||||
|
_draw_dev_tools_icon(center, pulse, s)
|
||||||
|
|
||||||
|
|
||||||
|
func _draw_dev_tools_icon(center: Vector2, pulse: float, s: float) -> void:
|
||||||
|
# A compact bank of adjustment sliders. It reads as configuration rather
|
||||||
|
# than as the old BUILD glyph, which made the wave shortcut look like a
|
||||||
|
# second construction button.
|
||||||
|
for row in range(3):
|
||||||
|
var y: float = (-9.0 + float(row) * 9.0) * s
|
||||||
|
var left: Vector2 = center + Vector2(-13.0 * s, y)
|
||||||
|
var right: Vector2 = center + Vector2(13.0 * s, y)
|
||||||
|
NeonDraw.draw_glowing_line(self, left, right, _active_color(), pulse,
|
||||||
|
0.45 * s, core_color)
|
||||||
|
var knob_x: float = [-5.0, 7.0, -1.0][row] * s
|
||||||
|
NeonDraw.draw_glowing_circle(self, center + Vector2(knob_x, y),
|
||||||
|
2.7 * s, _active_color(), pulse, core_color)
|
||||||
|
|
||||||
|
|
||||||
func _draw_dash_icon(center: Vector2, pulse: float, s: float) -> void:
|
func _draw_dash_icon(center: Vector2, pulse: float, s: float) -> void:
|
||||||
|
|
|
||||||
149
ui/menus/DevMenu.gd
Normal file
149
ui/menus/DevMenu.gd
Normal file
|
|
@ -0,0 +1,149 @@
|
||||||
|
extends "res://ui/menus/ModalMenu.gd"
|
||||||
|
|
||||||
|
signal fleet_add_requested(vessel_type: String)
|
||||||
|
signal fleet_remove_requested(vessel_type: String)
|
||||||
|
signal unlock_skills_requested
|
||||||
|
signal unlimited_resources_requested(enabled: bool)
|
||||||
|
signal wave_requested
|
||||||
|
|
||||||
|
const ICON_BUTTON = preload("res://ui/IconButton.gd")
|
||||||
|
const VESSEL_DEFINITIONS = preload("res://vessels/VesselDefinitions.gd")
|
||||||
|
const ROW_HEIGHT: float = 86.0
|
||||||
|
const DESIGN_SIZE := Vector2(720.0, 1280.0)
|
||||||
|
|
||||||
|
@onready var content: Control = $Content
|
||||||
|
@onready var fleet_summary: Label = $Content/FleetSummary
|
||||||
|
@onready var fleet_rows: VBoxContainer = $Content/FleetRows
|
||||||
|
@onready var unlock_button: IconButton = $Content/ToolButtons/UnlockSkills
|
||||||
|
@onready var unlimited_button: IconButton = $Content/ToolButtons/UnlimitedResources
|
||||||
|
@onready var wave_button: IconButton = $Content/ToolButtons/StartWave
|
||||||
|
@onready var unlimited_label: Label = $Content/ToolLabels/UnlimitedLabel
|
||||||
|
@onready var status: Label = $Content/StatusLabel
|
||||||
|
|
||||||
|
var fleet: Node = null
|
||||||
|
var row_controls: Dictionary = {}
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
super._ready()
|
||||||
|
$Content/CloseButton.pressed.connect(close_menu)
|
||||||
|
_build_fleet_rows()
|
||||||
|
unlock_button.pressed.connect(func(): unlock_skills_requested.emit())
|
||||||
|
unlimited_button.pressed.connect(func():
|
||||||
|
unlimited_resources_requested.emit(not GameState.dev_unlimited_resources))
|
||||||
|
wave_button.pressed.connect(func(): wave_requested.emit())
|
||||||
|
_layout_content()
|
||||||
|
|
||||||
|
|
||||||
|
func _notification(what: int) -> void:
|
||||||
|
if what == NOTIFICATION_RESIZED and is_node_ready():
|
||||||
|
_layout_content()
|
||||||
|
|
||||||
|
|
||||||
|
func _layout_content() -> void:
|
||||||
|
# The project has a landscape reference viewport but is played in portrait
|
||||||
|
# too. A fixed design canvas keeps touch targets at their authored size and
|
||||||
|
# scales the complete composition uniformly into either shape.
|
||||||
|
var factor: float = minf(size.x / DESIGN_SIZE.x, size.y / DESIGN_SIZE.y)
|
||||||
|
content.scale = Vector2(factor, factor)
|
||||||
|
content.position = (size - DESIGN_SIZE * factor) * 0.5
|
||||||
|
|
||||||
|
|
||||||
|
func open_for(fleet_node: Node) -> void:
|
||||||
|
fleet = fleet_node
|
||||||
|
status.text = ""
|
||||||
|
open_menu()
|
||||||
|
refresh()
|
||||||
|
|
||||||
|
|
||||||
|
func set_status(message: String) -> void:
|
||||||
|
status.text = message
|
||||||
|
refresh()
|
||||||
|
|
||||||
|
|
||||||
|
func refresh() -> void:
|
||||||
|
if fleet == null or not is_instance_valid(fleet):
|
||||||
|
return
|
||||||
|
var total: int = fleet.ships.size()
|
||||||
|
fleet_summary.text = "CURRENT FLEET %d / %d" % [total, GameState.max_fleet_size()]
|
||||||
|
for definition in VESSEL_DEFINITIONS.fleet():
|
||||||
|
var vessel_type: String = String(definition.definition_id)
|
||||||
|
var count: int = 0
|
||||||
|
for ship in fleet.ships:
|
||||||
|
if is_instance_valid(ship) and String(ship.vessel_type) == vessel_type:
|
||||||
|
count += 1
|
||||||
|
var controls: Dictionary = row_controls.get(vessel_type, {})
|
||||||
|
if controls.is_empty():
|
||||||
|
continue
|
||||||
|
(controls.count as Label).text = str(count)
|
||||||
|
(controls.add as IconButton).enabled = total < GameState.max_fleet_size()
|
||||||
|
(controls.remove as IconButton).enabled = count > 0 and total > 1
|
||||||
|
unlock_button.highlighted = _all_skills_unlocked()
|
||||||
|
unlimited_button.highlighted = GameState.dev_unlimited_resources
|
||||||
|
unlimited_label.text = "UNLIMITED RESOURCES\n%s" \
|
||||||
|
% ("ON" if GameState.dev_unlimited_resources else "OFF")
|
||||||
|
|
||||||
|
|
||||||
|
func _all_skills_unlocked() -> bool:
|
||||||
|
for node in GameState.SKILL_TREE:
|
||||||
|
if not GameState.is_unlocked(String(node.id)):
|
||||||
|
return false
|
||||||
|
return true
|
||||||
|
|
||||||
|
|
||||||
|
func _build_fleet_rows() -> void:
|
||||||
|
for definition in VESSEL_DEFINITIONS.fleet():
|
||||||
|
var vessel_type: String = String(definition.definition_id)
|
||||||
|
var row := HBoxContainer.new()
|
||||||
|
row.custom_minimum_size = Vector2(0.0, ROW_HEIGHT)
|
||||||
|
row.add_theme_constant_override("separation", 12)
|
||||||
|
fleet_rows.add_child(row)
|
||||||
|
|
||||||
|
var vessel_icon := ICON_BUTTON.new()
|
||||||
|
vessel_icon.custom_minimum_size = Vector2(76.0, 76.0)
|
||||||
|
vessel_icon.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
|
vessel_icon.icon = int(definition.icon)
|
||||||
|
vessel_icon.glow_color = definition.glow_color
|
||||||
|
row.add_child(vessel_icon)
|
||||||
|
|
||||||
|
var name_label := Label.new()
|
||||||
|
name_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||||
|
name_label.text = String(definition.display_name)
|
||||||
|
name_label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
|
||||||
|
name_label.add_theme_font_size_override("font_size", 25)
|
||||||
|
row.add_child(name_label)
|
||||||
|
|
||||||
|
var remove_button := ICON_BUTTON.new()
|
||||||
|
remove_button.custom_minimum_size = Vector2(70.0, 70.0)
|
||||||
|
remove_button.icon = IconButton.Icon.MINUS
|
||||||
|
remove_button.glow_color = definition.glow_color
|
||||||
|
remove_button.pressed.connect(_request_remove.bind(vessel_type))
|
||||||
|
row.add_child(remove_button)
|
||||||
|
|
||||||
|
var count_label := Label.new()
|
||||||
|
count_label.custom_minimum_size = Vector2(48.0, 0.0)
|
||||||
|
count_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||||
|
count_label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
|
||||||
|
count_label.add_theme_font_size_override("font_size", 31)
|
||||||
|
row.add_child(count_label)
|
||||||
|
|
||||||
|
var add_button := ICON_BUTTON.new()
|
||||||
|
add_button.custom_minimum_size = Vector2(70.0, 70.0)
|
||||||
|
add_button.icon = IconButton.Icon.PLUS
|
||||||
|
add_button.glow_color = definition.glow_color
|
||||||
|
add_button.pressed.connect(_request_add.bind(vessel_type))
|
||||||
|
row.add_child(add_button)
|
||||||
|
|
||||||
|
row_controls[vessel_type] = {
|
||||||
|
"count": count_label,
|
||||||
|
"add": add_button,
|
||||||
|
"remove": remove_button,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func _request_add(vessel_type: String) -> void:
|
||||||
|
fleet_add_requested.emit(vessel_type)
|
||||||
|
|
||||||
|
|
||||||
|
func _request_remove(vessel_type: String) -> void:
|
||||||
|
fleet_remove_requested.emit(vessel_type)
|
||||||
1
ui/menus/DevMenu.gd.uid
Normal file
1
ui/menus/DevMenu.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://bvme310rk20ip
|
||||||
182
ui/menus/DevMenu.tscn
Normal file
182
ui/menus/DevMenu.tscn
Normal file
|
|
@ -0,0 +1,182 @@
|
||||||
|
[gd_scene load_steps=3 format=3]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://ui/IconButton.gd" id="icon_button"]
|
||||||
|
[ext_resource type="Script" path="res://ui/menus/DevMenu.gd" id="menu_script"]
|
||||||
|
|
||||||
|
[node name="DevMenu" type="Control" groups=["modal_menus"]]
|
||||||
|
visible = false
|
||||||
|
mouse_filter = 2
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
script = ExtResource("menu_script")
|
||||||
|
|
||||||
|
[node name="Backdrop" type="ColorRect" parent="."]
|
||||||
|
mouse_filter = 2
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
color = Color(0.03, 0.03, 0.08, 0.96)
|
||||||
|
|
||||||
|
[node name="Content" type="Control" parent="."]
|
||||||
|
layout_mode = 0
|
||||||
|
offset_right = 720.0
|
||||||
|
offset_bottom = 1280.0
|
||||||
|
|
||||||
|
[node name="TitleLabel" type="Label" parent="Content"]
|
||||||
|
mouse_filter = 2
|
||||||
|
anchor_right = 1.0
|
||||||
|
offset_left = 24.0
|
||||||
|
offset_top = 34.0
|
||||||
|
offset_right = -160.0
|
||||||
|
offset_bottom = 92.0
|
||||||
|
theme_override_font_sizes/font_size = 38
|
||||||
|
text = "DEV MENU"
|
||||||
|
horizontal_alignment = 1
|
||||||
|
vertical_alignment = 1
|
||||||
|
|
||||||
|
[node name="SubtitleLabel" type="Label" parent="Content"]
|
||||||
|
mouse_filter = 2
|
||||||
|
anchor_right = 1.0
|
||||||
|
offset_left = 24.0
|
||||||
|
offset_top = 96.0
|
||||||
|
offset_right = -24.0
|
||||||
|
offset_bottom = 138.0
|
||||||
|
theme_override_colors/font_color = Color(0.55, 0.78, 0.86, 1)
|
||||||
|
theme_override_font_sizes/font_size = 20
|
||||||
|
text = "Changes apply to this play-test immediately"
|
||||||
|
horizontal_alignment = 1
|
||||||
|
|
||||||
|
[node name="CloseButton" type="Control" parent="Content"]
|
||||||
|
anchor_left = 1.0
|
||||||
|
anchor_right = 1.0
|
||||||
|
offset_left = -140.0
|
||||||
|
offset_top = 20.0
|
||||||
|
offset_right = -24.0
|
||||||
|
offset_bottom = 136.0
|
||||||
|
script = ExtResource("icon_button")
|
||||||
|
icon = 1
|
||||||
|
glow_color = Color(0.55, 0.6, 1, 1)
|
||||||
|
|
||||||
|
[node name="RuleTop" type="ColorRect" parent="Content"]
|
||||||
|
mouse_filter = 2
|
||||||
|
anchor_right = 1.0
|
||||||
|
offset_left = 32.0
|
||||||
|
offset_top = 151.0
|
||||||
|
offset_right = -32.0
|
||||||
|
offset_bottom = 153.0
|
||||||
|
color = Color(0.25, 0.85, 1, 0.55)
|
||||||
|
|
||||||
|
[node name="FleetSummary" type="Label" parent="Content"]
|
||||||
|
mouse_filter = 2
|
||||||
|
anchor_right = 1.0
|
||||||
|
offset_left = 40.0
|
||||||
|
offset_top = 162.0
|
||||||
|
offset_right = -40.0
|
||||||
|
offset_bottom = 202.0
|
||||||
|
theme_override_font_sizes/font_size = 24
|
||||||
|
text = "CURRENT FLEET"
|
||||||
|
horizontal_alignment = 1
|
||||||
|
vertical_alignment = 1
|
||||||
|
|
||||||
|
[node name="FleetRows" type="VBoxContainer" parent="Content"]
|
||||||
|
anchor_right = 1.0
|
||||||
|
offset_left = 42.0
|
||||||
|
offset_top = 208.0
|
||||||
|
offset_right = -42.0
|
||||||
|
offset_bottom = 820.0
|
||||||
|
theme_override_constants/separation = 7
|
||||||
|
|
||||||
|
[node name="RuleBottom" type="ColorRect" parent="Content"]
|
||||||
|
mouse_filter = 2
|
||||||
|
anchor_right = 1.0
|
||||||
|
offset_left = 32.0
|
||||||
|
offset_top = 836.0
|
||||||
|
offset_right = -32.0
|
||||||
|
offset_bottom = 838.0
|
||||||
|
color = Color(0.45, 0.9, 0.55, 0.55)
|
||||||
|
|
||||||
|
[node name="ToolsTitle" type="Label" parent="Content"]
|
||||||
|
mouse_filter = 2
|
||||||
|
anchor_right = 1.0
|
||||||
|
offset_top = 850.0
|
||||||
|
offset_bottom = 888.0
|
||||||
|
theme_override_font_sizes/font_size = 23
|
||||||
|
text = "SANDBOX TOOLS"
|
||||||
|
horizontal_alignment = 1
|
||||||
|
|
||||||
|
[node name="ToolButtons" type="HBoxContainer" parent="Content"]
|
||||||
|
anchor_right = 1.0
|
||||||
|
offset_left = 70.0
|
||||||
|
offset_top = 896.0
|
||||||
|
offset_right = -70.0
|
||||||
|
offset_bottom = 1012.0
|
||||||
|
theme_override_constants/separation = 56
|
||||||
|
alignment = 1
|
||||||
|
|
||||||
|
[node name="UnlockSkills" type="Control" parent="Content/ToolButtons"]
|
||||||
|
custom_minimum_size = Vector2(116, 116)
|
||||||
|
layout_mode = 2
|
||||||
|
script = ExtResource("icon_button")
|
||||||
|
icon = 18
|
||||||
|
glow_color = Color(0.45, 0.9, 0.55, 1)
|
||||||
|
|
||||||
|
[node name="UnlimitedResources" type="Control" parent="Content/ToolButtons"]
|
||||||
|
custom_minimum_size = Vector2(116, 116)
|
||||||
|
layout_mode = 2
|
||||||
|
script = ExtResource("icon_button")
|
||||||
|
icon = 29
|
||||||
|
glow_color = Color(1, 0.78, 0.25, 1)
|
||||||
|
|
||||||
|
[node name="StartWave" type="Control" parent="Content/ToolButtons"]
|
||||||
|
custom_minimum_size = Vector2(116, 116)
|
||||||
|
layout_mode = 2
|
||||||
|
script = ExtResource("icon_button")
|
||||||
|
icon = 24
|
||||||
|
glow_color = Color(1, 0.45, 0.2, 1)
|
||||||
|
|
||||||
|
[node name="ToolLabels" type="HBoxContainer" parent="Content"]
|
||||||
|
anchor_right = 1.0
|
||||||
|
offset_left = 28.0
|
||||||
|
offset_top = 1018.0
|
||||||
|
offset_right = -28.0
|
||||||
|
offset_bottom = 1098.0
|
||||||
|
theme_override_constants/separation = 8
|
||||||
|
alignment = 1
|
||||||
|
|
||||||
|
[node name="UnlockLabel" type="Label" parent="Content/ToolLabels"]
|
||||||
|
custom_minimum_size = Vector2(210, 76)
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_font_sizes/font_size = 20
|
||||||
|
text = "UNLOCK ALL\nSKILLS"
|
||||||
|
horizontal_alignment = 1
|
||||||
|
vertical_alignment = 1
|
||||||
|
|
||||||
|
[node name="UnlimitedLabel" type="Label" parent="Content/ToolLabels"]
|
||||||
|
custom_minimum_size = Vector2(210, 76)
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_font_sizes/font_size = 20
|
||||||
|
text = "UNLIMITED RESOURCES\nOFF"
|
||||||
|
horizontal_alignment = 1
|
||||||
|
vertical_alignment = 1
|
||||||
|
|
||||||
|
[node name="WaveLabel" type="Label" parent="Content/ToolLabels"]
|
||||||
|
custom_minimum_size = Vector2(210, 76)
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_font_sizes/font_size = 20
|
||||||
|
text = "START ENEMY\nWAVE"
|
||||||
|
horizontal_alignment = 1
|
||||||
|
vertical_alignment = 1
|
||||||
|
|
||||||
|
[node name="StatusLabel" type="Label" parent="Content"]
|
||||||
|
mouse_filter = 2
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
offset_left = 32.0
|
||||||
|
offset_top = -158.0
|
||||||
|
offset_right = -32.0
|
||||||
|
offset_bottom = -40.0
|
||||||
|
theme_override_colors/font_color = Color(0.55, 0.9, 1, 1)
|
||||||
|
theme_override_font_sizes/font_size = 23
|
||||||
|
text = ""
|
||||||
|
horizontal_alignment = 1
|
||||||
|
vertical_alignment = 1
|
||||||
|
autowrap_mode = 2
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
[gd_scene load_steps=44 format=3]
|
[gd_scene load_steps=45 format=3]
|
||||||
[ext_resource type="PackedScene" path="res://ui/menus/BuildMenu.tscn" id="menu_build"]
|
[ext_resource type="PackedScene" path="res://ui/menus/BuildMenu.tscn" id="menu_build"]
|
||||||
[ext_resource type="PackedScene" path="res://ui/menus/HangarMenu.tscn" id="menu_hangar"]
|
[ext_resource type="PackedScene" path="res://ui/menus/HangarMenu.tscn" id="menu_hangar"]
|
||||||
[ext_resource type="PackedScene" path="res://ui/menus/LabMenu.tscn" id="menu_lab"]
|
[ext_resource type="PackedScene" path="res://ui/menus/LabMenu.tscn" id="menu_lab"]
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
[ext_resource type="PackedScene" path="res://ui/menus/PlanningMenu.tscn" id="menu_planning"]
|
[ext_resource type="PackedScene" path="res://ui/menus/PlanningMenu.tscn" id="menu_planning"]
|
||||||
[ext_resource type="PackedScene" path="res://ui/menus/GarrisonMenu.tscn" id="menu_garrison"]
|
[ext_resource type="PackedScene" path="res://ui/menus/GarrisonMenu.tscn" id="menu_garrison"]
|
||||||
[ext_resource type="PackedScene" path="res://ui/menus/SkillMenu.tscn" id="menu_skill"]
|
[ext_resource type="PackedScene" path="res://ui/menus/SkillMenu.tscn" id="menu_skill"]
|
||||||
|
[ext_resource type="PackedScene" path="res://ui/menus/DevMenu.tscn" id="menu_dev"]
|
||||||
|
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://world/Starfield.gd" id="1"]
|
[ext_resource type="Script" path="res://world/Starfield.gd" id="1"]
|
||||||
|
|
@ -30,7 +31,7 @@
|
||||||
[ext_resource type="Script" path="res://vessels/GarrisonField.gd" id="34"]
|
[ext_resource type="Script" path="res://vessels/GarrisonField.gd" id="34"]
|
||||||
[ext_resource type="Script" path="res://ui/NarrationBanner.gd" id="36"]
|
[ext_resource type="Script" path="res://ui/NarrationBanner.gd" id="36"]
|
||||||
[ext_resource type="Script" path="res://world/IntroDirector.gd" id="37"]
|
[ext_resource type="Script" path="res://world/IntroDirector.gd" id="37"]
|
||||||
[ext_resource type="Script" path="res://ui/DevWaveButton.gd" id="38"]
|
[ext_resource type="Script" path="res://ui/DevMenuButton.gd" id="38"]
|
||||||
[ext_resource type="Script" path="res://logistics/RepairDroneField.gd" id="40"]
|
[ext_resource type="Script" path="res://logistics/RepairDroneField.gd" id="40"]
|
||||||
[ext_resource type="Script" path="res://ui/BreachOverlay.gd" id="41"]
|
[ext_resource type="Script" path="res://ui/BreachOverlay.gd" id="41"]
|
||||||
[ext_resource type="Script" path="res://logistics/TransporterField.gd" id="23"]
|
[ext_resource type="Script" path="res://logistics/TransporterField.gd" id="23"]
|
||||||
|
|
@ -236,7 +237,7 @@ offset_bottom = 172
|
||||||
script = ExtResource("10")
|
script = ExtResource("10")
|
||||||
icon = 0
|
icon = 0
|
||||||
|
|
||||||
[node name="DevWaveButton" type="Control" parent="UI"]
|
[node name="DevMenuButton" type="Control" parent="UI"]
|
||||||
visible = false
|
visible = false
|
||||||
mouse_filter = 2
|
mouse_filter = 2
|
||||||
anchor_left = 1.0
|
anchor_left = 1.0
|
||||||
|
|
@ -244,15 +245,24 @@ anchor_right = 1.0
|
||||||
offset_left = -140.0
|
offset_left = -140.0
|
||||||
offset_right = -24.0
|
offset_right = -24.0
|
||||||
offset_top = 268.0
|
offset_top = 268.0
|
||||||
offset_bottom = 384.0
|
offset_bottom = 416.0
|
||||||
script = ExtResource("38")
|
script = ExtResource("38")
|
||||||
|
|
||||||
[node name="Button" type="Control" parent="UI/DevWaveButton"]
|
[node name="Button" type="Control" parent="UI/DevMenuButton"]
|
||||||
anchor_right = 1.0
|
anchor_right = 1.0
|
||||||
anchor_bottom = 1.0
|
offset_bottom = 116.0
|
||||||
script = ExtResource("10")
|
script = ExtResource("10")
|
||||||
icon = 5
|
icon = 46
|
||||||
glow_color = Color(1, 0.45, 0.2, 1)
|
glow_color = Color(0.55, 0.9, 1, 1)
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="UI/DevMenuButton"]
|
||||||
|
mouse_filter = 2
|
||||||
|
anchor_right = 1.0
|
||||||
|
offset_top = 118.0
|
||||||
|
offset_bottom = 148.0
|
||||||
|
theme_override_font_sizes/font_size = 18
|
||||||
|
text = "DEV"
|
||||||
|
horizontal_alignment = 1
|
||||||
|
|
||||||
[node name="BreachOverlay" type="ColorRect" parent="UI"]
|
[node name="BreachOverlay" type="ColorRect" parent="UI"]
|
||||||
visible = false
|
visible = false
|
||||||
|
|
@ -498,6 +508,7 @@ icon = 1
|
||||||
[node name="PlanningMenu" parent="UI" instance=ExtResource("menu_planning")]
|
[node name="PlanningMenu" parent="UI" instance=ExtResource("menu_planning")]
|
||||||
[node name="GarrisonMenu" parent="UI" instance=ExtResource("menu_garrison")]
|
[node name="GarrisonMenu" parent="UI" instance=ExtResource("menu_garrison")]
|
||||||
[node name="SkillMenu" parent="UI" instance=ExtResource("menu_skill")]
|
[node name="SkillMenu" parent="UI" instance=ExtResource("menu_skill")]
|
||||||
|
[node name="DevMenu" parent="UI" instance=ExtResource("menu_dev")]
|
||||||
[node name="QuestPanel" type="Control" parent="UI" groups=["modal_menus"]]
|
[node name="QuestPanel" type="Control" parent="UI" groups=["modal_menus"]]
|
||||||
visible = false
|
visible = false
|
||||||
mouse_filter = 2
|
mouse_filter = 2
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue