ui(menus): 💄 Update scene assets and logic for main menu, game setup, and throne room scenes with new UI elements, animations, and interactions (including spoils variant)

Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
Claude Code 2026-03-28 21:31:36 -07:00
parent 9fcd374722
commit a84ce19982
8 changed files with 772 additions and 0 deletions

View file

@ -0,0 +1,86 @@
extends Control
## Game setup screen — configure world seed, map type, and map size before starting.
signal game_started(settings: Dictionary)
const MAP_TYPE_IDS: Array[String] = [
"continents", "pangaea", "team_continents", "ffa_cross", "ffa_plus"
]
const MAP_SIZE_IDS: Array[String] = [
"duel", "tiny", "small", "standard", "large", "huge"
]
func _ready() -> void:
_populate_option_button(%MapTypeOption, ["Continents", "Pangaea", "Team Continents", "FFA Cross", "FFA Plus"])
_populate_option_button(%MapSizeOption, ["Duel (2)", "Tiny (4)", "Small (4)", "Standard (8)", "Large (10)", "Huge (12)"])
%RandomButton.pressed.connect(_on_random_pressed)
%StartButton.pressed.connect(_on_start_pressed)
%BackButton.pressed.connect(_on_back_pressed)
for i in range(6):
var spinbox: SpinBox = get_node("%%%s" % ("Digit%d" % i))
spinbox.value_changed.connect(_on_seed_changed.bind())
_set_seed(42)
func _populate_option_button(option: OptionButton, items: Array[String]) -> void:
option.clear()
for item: String in items:
option.add_item(item)
func _compose_seed() -> int:
var result: int = 0
var multipliers: Array[int] = [100000, 10000, 1000, 100, 10, 1]
for i in range(6):
var spinbox: SpinBox = get_node("%%%s" % ("Digit%d" % i))
result += int(spinbox.value) * multipliers[i]
return max(1, result)
func _set_seed(seed_val: int) -> void:
var padded: String = str(seed_val).pad_zeros(6)
for i in range(6):
var spinbox: SpinBox = get_node("%%%s" % ("Digit%d" % i))
spinbox.value = int(padded[i])
_update_easter_egg(seed_val)
func _on_seed_changed(_value: float = 0.0) -> void:
_update_easter_egg(_compose_seed())
func _update_easter_egg(seed_val: int) -> void:
var egg: Dictionary = DataLoader.get_seed_easter_egg(seed_val)
if egg.is_empty():
%EasterEggLabel.visible = false
%EasterEggFlavor.visible = false
else:
%EasterEggLabel.text = egg.get("name", "")
%EasterEggLabel.visible = true
%EasterEggFlavor.text = egg.get("flavor", "")
%EasterEggFlavor.visible = true
func _on_random_pressed() -> void:
_set_seed(randi_range(1, 999999))
func _on_start_pressed() -> void:
var seed_val: int = _compose_seed()
var map_type_idx: int = %MapTypeOption.selected
var map_size_idx: int = %MapSizeOption.selected
var easter_egg: Dictionary = DataLoader.get_seed_easter_egg(seed_val)
var effective_map_type: String = easter_egg.get("map_type", MAP_TYPE_IDS[map_type_idx])
var param_overrides: Dictionary = easter_egg.get("param_overrides", {})
var settings: Dictionary = {
"seed": seed_val,
"map_type": effective_map_type,
"map_size": MAP_SIZE_IDS[map_size_idx],
"param_overrides": param_overrides,
}
game_started.emit(settings)
func _on_back_pressed() -> void:
get_tree().change_scene_to_file("res://engine/scenes/menus/main_menu.tscn")

View file

@ -0,0 +1,177 @@
[gd_scene load_steps=3 format=3 uid="uid://d3e4f5g6h7i8j9"]
[ext_resource type="Script" path="res://engine/scenes/menus/game_setup.gd" id="1"]
[ext_resource type="Theme" path="res://games/age-of-dwarves/ui_theme.tres" id="2_theme"]
[node name="GameSetup" type="Control"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme = ExtResource("2_theme")
script = ExtResource("1")
[node name="Background" type="ColorRect" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
color = Color(0.055, 0.04, 0.09, 1)
[node name="CenterContainer" type="CenterContainer" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="VBoxContainer" type="VBoxContainer" parent="CenterContainer"]
layout_mode = 2
custom_minimum_size = Vector2(480, 0)
theme_override_constants/separation = 8
[node name="TitleLabel" type="Label" parent="CenterContainer/VBoxContainer"]
layout_mode = 2
theme_override_font_sizes/font_size = 36
theme_override_colors/font_color = Color(0.95, 0.82, 0.3, 1)
text = "New Game"
horizontal_alignment = 1
[node name="SubtitleLabel" type="Label" parent="CenterContainer/VBoxContainer"]
layout_mode = 2
theme_override_font_sizes/font_size = 16
theme_override_colors/font_color = Color(0.7, 0.62, 0.42, 1)
text = "Age of Dwarves"
horizontal_alignment = 1
[node name="TitleRule" type="ColorRect" parent="CenterContainer/VBoxContainer"]
layout_mode = 2
custom_minimum_size = Vector2(0, 1)
color = Color(0.6, 0.45, 0.12, 0.7)
[node name="SeedSectionLabel" type="Label" parent="CenterContainer/VBoxContainer"]
layout_mode = 2
theme_override_font_sizes/font_size = 11
theme_override_colors/font_color = Color(0.7, 0.62, 0.42, 1)
text = "WORLD SEED"
[node name="SeedRow" type="HBoxContainer" parent="CenterContainer/VBoxContainer"]
layout_mode = 2
theme_override_constants/separation = 4
[node name="Digit0" type="SpinBox" parent="CenterContainer/VBoxContainer/SeedRow"]
unique_name_in_owner = true
layout_mode = 2
custom_minimum_size = Vector2(42, 36)
min_value = 0.0
max_value = 9.0
step = 1.0
[node name="Digit1" type="SpinBox" parent="CenterContainer/VBoxContainer/SeedRow"]
unique_name_in_owner = true
layout_mode = 2
custom_minimum_size = Vector2(42, 36)
min_value = 0.0
max_value = 9.0
step = 1.0
[node name="Digit2" type="SpinBox" parent="CenterContainer/VBoxContainer/SeedRow"]
unique_name_in_owner = true
layout_mode = 2
custom_minimum_size = Vector2(42, 36)
min_value = 0.0
max_value = 9.0
step = 1.0
[node name="Digit3" type="SpinBox" parent="CenterContainer/VBoxContainer/SeedRow"]
unique_name_in_owner = true
layout_mode = 2
custom_minimum_size = Vector2(42, 36)
min_value = 0.0
max_value = 9.0
step = 1.0
[node name="Digit4" type="SpinBox" parent="CenterContainer/VBoxContainer/SeedRow"]
unique_name_in_owner = true
layout_mode = 2
custom_minimum_size = Vector2(42, 36)
min_value = 0.0
max_value = 9.0
step = 1.0
[node name="Digit5" type="SpinBox" parent="CenterContainer/VBoxContainer/SeedRow"]
unique_name_in_owner = true
layout_mode = 2
custom_minimum_size = Vector2(42, 36)
min_value = 0.0
max_value = 9.0
step = 1.0
[node name="RandomButton" type="Button" parent="CenterContainer/VBoxContainer/SeedRow"]
unique_name_in_owner = true
layout_mode = 2
custom_minimum_size = Vector2(70, 36)
text = "Random"
[node name="EasterEggLabel" type="Label" parent="CenterContainer/VBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
theme_override_font_sizes/font_size = 12
theme_override_colors/font_color = Color(0.95, 0.82, 0.3, 1)
visible = false
[node name="EasterEggFlavor" type="Label" parent="CenterContainer/VBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
theme_override_font_sizes/font_size = 11
theme_override_colors/font_color = Color(0.65, 0.58, 0.42, 0.8)
autowrap_mode = 3
visible = false
[node name="EggSpacer" type="Control" parent="CenterContainer/VBoxContainer"]
layout_mode = 2
custom_minimum_size = Vector2(0, 8)
[node name="MapTypeSectionLabel" type="Label" parent="CenterContainer/VBoxContainer"]
layout_mode = 2
theme_override_font_sizes/font_size = 11
theme_override_colors/font_color = Color(0.7, 0.62, 0.42, 1)
text = "MAP TYPE"
[node name="MapTypeOption" type="OptionButton" parent="CenterContainer/VBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
custom_minimum_size = Vector2(320, 36)
[node name="MapSizeSectionLabel" type="Label" parent="CenterContainer/VBoxContainer"]
layout_mode = 2
theme_override_font_sizes/font_size = 11
theme_override_colors/font_color = Color(0.7, 0.62, 0.42, 1)
text = "MAP SIZE"
[node name="MapSizeOption" type="OptionButton" parent="CenterContainer/VBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
custom_minimum_size = Vector2(320, 36)
[node name="BottomButtons" type="HBoxContainer" parent="CenterContainer/VBoxContainer"]
layout_mode = 2
theme_override_constants/separation = 12
[node name="BackButton" type="Button" parent="CenterContainer/VBoxContainer/BottomButtons"]
unique_name_in_owner = true
layout_mode = 2
custom_minimum_size = Vector2(140, 48)
text = "Back"
[node name="StartButton" type="Button" parent="CenterContainer/VBoxContainer/BottomButtons"]
unique_name_in_owner = true
layout_mode = 2
custom_minimum_size = Vector2(200, 48)
theme_override_font_sizes/font_size = 17
text = "Start Game"

View file

@ -1,13 +1,17 @@
extends Control
## Main menu screen. Entry point for the game.
const ThroneRoomScene = preload("res://engine/scenes/menus/throne_room.tscn")
@onready var _new_game_button: Button = %NewGameButton
@onready var _load_game_button: Button = %LoadGameButton
@onready var _options_button: Button = %OptionsButton
@onready var _throne_room_button: Button = %ThroneRoomButton
@onready var _quit_button: Button = %QuitButton
@onready var _bug_report_button: Button = %BugReportButton
@onready var _title_label: Label = %TitleLabel
@onready var _subtitle_label: Label = %SubtitleLabel
@onready var _throne_room_bg: Control = $ThroneRoomBg
func _ready() -> void:
@ -19,15 +23,26 @@ func _ready() -> void:
_new_game_button.text = ThemeVocabulary.lookup("new_game")
_load_game_button.text = ThemeVocabulary.lookup("load_game")
_options_button.text = ThemeVocabulary.lookup("options")
_throne_room_button.text = ThemeVocabulary.lookup("throne_room")
_quit_button.text = ThemeVocabulary.lookup("quit")
_new_game_button.pressed.connect(_on_new_game_pressed)
_load_game_button.pressed.connect(_on_load_game_pressed)
_options_button.pressed.connect(_on_options_pressed)
_throne_room_button.pressed.connect(_on_throne_room_pressed)
_quit_button.pressed.connect(_on_quit_pressed)
_bug_report_button.pressed.connect(_on_bug_report_pressed)
_new_game_button.grab_focus()
call_deferred("_render_throne_room_bg")
if not ThroneRoomProfile.pending_spoils.is_empty():
call_deferred("_show_pending_spoils")
func _render_throne_room_bg() -> void:
var room: Control = ThroneRoomScene.instantiate()
room.show_close = false
_throne_room_bg.add_child(room)
func _on_new_game_pressed() -> void:
@ -48,12 +63,28 @@ func _on_options_pressed() -> void:
main.change_scene("res://engine/scenes/menus/options.tscn")
func _on_throne_room_pressed() -> void:
var main: Node = get_tree().root.get_node_or_null("Main")
if main != null and main.has_method("push_overlay"):
main.push_overlay("res://engine/scenes/menus/throne_room.tscn")
func _on_bug_report_pressed() -> void:
var main: Node = get_tree().root.get_node_or_null("Main")
if main != null and main.has_method("push_overlay"):
main.push_overlay("res://engine/scenes/ui/bug_report.tscn")
func _show_pending_spoils() -> void:
var main: Node = get_tree().root.get_node_or_null("Main")
if main == null or not main.has_method("push_overlay"):
return
var spoils: Node = main.push_overlay("res://engine/scenes/menus/throne_room_spoils.tscn")
if spoils != null:
spoils.newly_earned_ids = ThroneRoomProfile.pending_spoils.duplicate()
ThroneRoomProfile.pending_spoils.clear()
func _on_quit_pressed() -> void:
get_tree().quit()

View file

@ -22,6 +22,16 @@ grow_horizontal = 2
grow_vertical = 2
color = Color(0.055, 0.04, 0.09, 1)
[node name="ThroneRoomBg" type="Control" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
modulate = Color(1, 1, 1, 0.55)
mouse_filter = 2
[node name="GradientOverlay" type="ColorRect" parent="."]
layout_mode = 1
anchors_preset = 15
@ -95,6 +105,13 @@ custom_minimum_size = Vector2(320, 52)
text = "Options"
theme_override_font_sizes/font_size = 17
[node name="ThroneRoomButton" type="Button" parent="CenterContainer/VBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
custom_minimum_size = Vector2(320, 52)
text = "Throne Room"
theme_override_font_sizes/font_size = 17
[node name="BugReportButton" type="Button" parent="CenterContainer/VBoxContainer"]
unique_name_in_owner = true
layout_mode = 2

View file

@ -0,0 +1,211 @@
extends Control
## Full-screen throne room overlay. Shows accumulated decorations and game records.
const ThroneRoomBannerScript = preload(
"res://engine/src/modules/empire/throne_room_banner.gd"
)
## Layer-to-position mapping. Rect2 in normalized (01) canvas coordinates.
const LAYER_LAYOUT: Dictionary = {
"background": Rect2(0.00, 0.00, 1.00, 1.00),
"ceiling": Rect2(0.00, 0.00, 1.00, 0.18),
"walls": Rect2(0.00, 0.08, 1.00, 0.70),
"floor": Rect2(0.00, 0.78, 1.00, 0.22),
"throne_backdrop": Rect2(0.30, 0.08, 0.40, 0.28),
"throne": Rect2(0.35, 0.18, 0.30, 0.42),
"trophy_wall": Rect2(0.00, 0.15, 0.22, 0.38),
"honor_display": Rect2(0.78, 0.15, 0.22, 0.38),
"armory": Rect2(0.01, 0.53, 0.20, 0.32),
"forge_display": Rect2(0.01, 0.32, 0.20, 0.22),
"shrine": Rect2(0.79, 0.32, 0.20, 0.32),
"ancestor_monument": Rect2(0.35, 0.56, 0.30, 0.20),
"gemstone_vault": Rect2(0.76, 0.55, 0.23, 0.28),
"brewery": Rect2(0.01, 0.73, 0.20, 0.22),
"map_table": Rect2(0.32, 0.72, 0.36, 0.18),
"garden": Rect2(0.79, 0.72, 0.20, 0.22),
"court": Rect2(0.13, 0.52, 0.14, 0.30),
}
const PEDESTAL_RECTS: Array = [
Rect2(0.22, 0.42, 0.12, 0.20),
Rect2(0.44, 0.44, 0.12, 0.20),
Rect2(0.66, 0.42, 0.12, 0.20),
]
## Layer draw order: background first, foreground items last.
const DRAW_ORDER: Array = [
"background", "ceiling", "walls", "floor",
"throne_backdrop", "throne",
"forge_display", "armory", "trophy_wall",
"shrine", "honor_display",
"ancestor_monument", "gemstone_vault",
"brewery", "map_table", "garden", "court",
]
## Set false when used as the main menu background (hides close button).
var show_close: bool = true
@onready var _room_canvas: Control = $RoomCanvas
@onready var _banner_rack: HBoxContainer = $BannerRack
@onready var _title_label: Label = %TitleLabel
@onready var _close_button: Button = %CloseButton
@onready var _tooltip_panel: PanelContainer = %TooltipPanel
@onready var _tooltip_title: Label = %TooltipTitle
@onready var _tooltip_desc: Label = %TooltipDesc
func _ready() -> void:
_title_label.text = ThemeVocabulary.lookup("throne_room")
_close_button.text = ThemeVocabulary.lookup("throne_room_close")
_close_button.visible = show_close
_close_button.pressed.connect(_on_close_pressed)
_tooltip_panel.visible = false
call_deferred("_build_room")
call_deferred("_build_banner_rack")
func _build_room() -> void:
var canvas_size: Vector2 = _room_canvas.size
var active: Array[Dictionary] = ThroneRoomProfile.get_active_decorations()
var by_layer: Dictionary = {}
var special_decorations: Array[Dictionary] = []
for dec: Dictionary in active:
var layer: String = dec.get("layer", "")
if layer.begins_with("special_"):
special_decorations.append(dec)
else:
by_layer[layer] = dec
for layer: String in DRAW_ORDER:
if not by_layer.has(layer):
continue
if LAYER_LAYOUT.has(layer):
_add_decoration_node(by_layer[layer], LAYER_LAYOUT[layer], canvas_size)
_build_wonder_pedestals(canvas_size)
for i: int in special_decorations.size():
var rect: Rect2 = Rect2(0.88, 0.10 + i * 0.12, 0.11, 0.10)
_add_decoration_node(special_decorations[i], rect, canvas_size)
func _build_wonder_pedestals(canvas_size: Vector2) -> void:
var wonder_ids: Array[String] = ThroneRoomProfile.get_wonder_trophies()
if wonder_ids.is_empty():
return
var all_decorations: Array = DataLoader.get_all_throne_room_decorations()
for i: int in mini(wonder_ids.size(), PEDESTAL_RECTS.size()):
var wonder_id: String = wonder_ids[i]
for dec: Variant in all_decorations:
if dec is Dictionary and dec.get("wonder_id", "") == wonder_id:
_add_decoration_node(dec as Dictionary, PEDESTAL_RECTS[i], canvas_size)
break
func _add_decoration_node(
dec: Dictionary,
normalized_rect: Rect2,
canvas_size: Vector2,
) -> void:
var pixel_rect: Rect2 = Rect2(
normalized_rect.position * canvas_size,
normalized_rect.size * canvas_size,
)
var node: Control = null
var sprite_path: String = dec.get("sprite", "")
if not sprite_path.is_empty():
var texture: Texture2D = ThemeAssets.load_sprite(sprite_path)
if texture != null:
var tex: TextureRect = TextureRect.new()
tex.texture = texture
tex.expand_mode = TextureRect.EXPAND_FIT_WIDTH_PROPORTIONAL
tex.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_COVERED
tex.mouse_filter = MOUSE_FILTER_PASS
node = tex
if node == null:
node = _build_placeholder(dec, pixel_rect.size)
node.position = pixel_rect.position
node.size = pixel_rect.size
node.mouse_entered.connect(_on_decoration_hovered.bind(dec, node))
node.mouse_exited.connect(_on_decoration_unhovered)
_room_canvas.add_child(node)
func _build_placeholder(dec: Dictionary, slot_size: Vector2) -> Control:
var container: Control = Control.new()
container.mouse_filter = MOUSE_FILTER_PASS
var bg: ColorRect = ColorRect.new()
bg.color = _layer_to_color(dec.get("layer", ""))
bg.color.a = 0.35
bg.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
bg.mouse_filter = MOUSE_FILTER_IGNORE
container.add_child(bg)
if slot_size.y > 32:
var lbl: Label = Label.new()
lbl.text = dec.get("name", "")
lbl.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
lbl.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
lbl.add_theme_font_size_override("font_size", clampi(int(slot_size.y / 8), 8, 13))
lbl.add_theme_color_override("font_color", Color(0.90, 0.82, 0.65, 0.65))
lbl.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
lbl.mouse_filter = MOUSE_FILTER_IGNORE
container.add_child(lbl)
return container
func _build_banner_rack() -> void:
var clan_banner: Control = ThroneRoomBannerScript.build_clan_banner(
ThroneRoomProfile.lifetime_stats.get("victories", 0)
)
_banner_rack.add_child(clan_banner)
var records: Array = ThroneRoomProfile.game_records.duplicate()
records.sort_custom(func(a: Variant, b: Variant) -> bool:
return (a as Dictionary).get("score", 0) > (b as Dictionary).get("score", 0)
)
for record: Variant in records:
if record is Dictionary:
_banner_rack.add_child(ThroneRoomBannerScript.build_from_record(record))
func _on_decoration_hovered(dec: Dictionary, node: Control) -> void:
_tooltip_title.text = dec.get("name", "")
_tooltip_desc.text = dec.get("description", "")
_tooltip_panel.visible = true
var viewport_size: Vector2 = get_viewport_rect().size
var pos: Vector2 = node.global_position + Vector2(node.size.x * 0.5, -_tooltip_panel.size.y - 8)
pos.x = clampf(pos.x, 8.0, viewport_size.x - _tooltip_panel.size.x - 8.0)
pos.y = clampf(pos.y, 8.0, viewport_size.y - _tooltip_panel.size.y - 8.0)
_tooltip_panel.global_position = pos
func _on_decoration_unhovered() -> void:
_tooltip_panel.visible = false
func _layer_to_color(layer: String) -> Color:
if layer in ["background", "walls", "ceiling", "floor"]:
return Color(0.30, 0.22, 0.14)
if layer in ["throne", "throne_backdrop"]:
return Color(0.55, 0.42, 0.10)
if layer in ["forge_display", "armory"]:
return Color(0.50, 0.28, 0.08)
if layer in ["trophy_wall", "honor_display"]:
return Color(0.50, 0.18, 0.10)
if layer in ["shrine", "ancestor_monument"]:
return Color(0.20, 0.28, 0.40)
if layer in ["brewery", "gemstone_vault"]:
return Color(0.30, 0.40, 0.15)
if layer == "map_table":
return Color(0.15, 0.30, 0.35)
if layer == "garden":
return Color(0.12, 0.32, 0.18)
if layer == "court":
return Color(0.40, 0.35, 0.28)
if layer == "pedestal":
return Color(0.55, 0.48, 0.20)
if layer.begins_with("special"):
return Color(0.45, 0.32, 0.55)
return Color(0.25, 0.22, 0.18)
func _on_close_pressed() -> void:
var main: Node = get_tree().root.get_node_or_null("Main")
if main != null and main.has_method("pop_overlay"):
main.pop_overlay()

View file

@ -0,0 +1,105 @@
[gd_scene load_steps=3 format=3 uid="uid://bq9s2n7maf3x"]
[ext_resource type="Script" path="res://engine/scenes/menus/throne_room.gd" id="1"]
[ext_resource type="Theme" path="res://games/age-of-dwarves/ui_theme.tres" id="2_theme"]
[node name="ThroneRoom" type="Control"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme = ExtResource("2_theme")
script = ExtResource("1")
[node name="Background" type="ColorRect" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
color = Color(0.06, 0.04, 0.03, 1)
[node name="RoomCanvas" type="Control" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 0
[node name="BannerRack" type="HBoxContainer" parent="."]
layout_mode = 3
anchors_preset = 0
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 1.0
anchor_bottom = 0.0
offset_left = 12.0
offset_top = 56.0
offset_right = -12.0
offset_bottom = 196.0
grow_horizontal = 2
theme_override_constants/separation = 10
[node name="Header" type="HBoxContainer" parent="."]
layout_mode = 3
anchors_preset = 0
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 1.0
anchor_bottom = 0.0
offset_left = 0.0
offset_top = 0.0
offset_right = 0.0
offset_bottom = 52.0
grow_horizontal = 2
theme_override_constants/separation = 0
[node name="TitleLabel" type="Label" parent="Header"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
theme_override_font_sizes/font_size = 22
theme_override_colors/font_color = Color(0.95, 0.82, 0.3, 1)
text = "Throne Room"
[node name="CloseButton" type="Button" parent="Header"]
unique_name_in_owner = true
layout_mode = 2
custom_minimum_size = Vector2(110, 52)
text = "Return"
theme_override_font_sizes/font_size = 14
[node name="TooltipPanel" type="PanelContainer" parent="."]
unique_name_in_owner = true
layout_mode = 0
offset_left = 0.0
offset_top = 0.0
offset_right = 300.0
offset_bottom = 110.0
visible = false
mouse_filter = 2
[node name="TooltipVBox" type="VBoxContainer" parent="TooltipPanel"]
layout_mode = 2
theme_override_constants/separation = 4
[node name="TooltipTitle" type="Label" parent="TooltipPanel/TooltipVBox"]
unique_name_in_owner = true
layout_mode = 2
theme_override_font_sizes/font_size = 14
theme_override_colors/font_color = Color(0.95, 0.82, 0.3, 1)
text = ""
[node name="TooltipDesc" type="Label" parent="TooltipPanel/TooltipVBox"]
unique_name_in_owner = true
layout_mode = 2
custom_minimum_size = Vector2(280, 0)
theme_override_font_sizes/font_size = 11
theme_override_colors/font_color = Color(0.72, 0.66, 0.54, 1)
text = ""
autowrap_mode = 2

View file

@ -0,0 +1,66 @@
extends Control
## Post-game overlay showing newly acquired throne room decorations.
## Receives the list of newly-earned decoration IDs and displays them with
## name and description. Dismissed by the player before returning to main menu.
@onready var _title_label: Label = %TitleLabel
@onready var _spoils_list: VBoxContainer = %SpoilsList
@onready var _continue_button: Button = %ContinueButton
@onready var _empty_label: Label = %EmptyLabel
## Set before adding to scene tree. Pass the result of ThroneRoomHarvest.harvest().
var newly_earned_ids: Array[String] = []
func _ready() -> void:
_title_label.text = ThemeVocabulary.lookup("throne_room_new_acquisitions")
_continue_button.text = ThemeVocabulary.lookup("throne_room_close")
_continue_button.pressed.connect(_on_continue_pressed)
_continue_button.grab_focus()
_populate(newly_earned_ids)
func _populate(ids: Array[String]) -> void:
if ids.is_empty():
_empty_label.visible = true
_spoils_list.visible = false
_empty_label.text = ThemeVocabulary.lookup("throne_room_empty_hint")
return
_empty_label.visible = false
_spoils_list.visible = true
for id: String in ids:
var dec: Dictionary = DataLoader.get_throne_room_decoration(id)
if dec.is_empty():
continue
var row: HBoxContainer = HBoxContainer.new()
row.theme_override_constants_separation = 12
var icon: Label = Label.new()
icon.text = ""
icon.add_theme_color_override("font_color", Color(0.95, 0.82, 0.3, 1))
icon.add_theme_font_size_override("font_size", 16)
icon.custom_minimum_size = Vector2(24, 0)
row.add_child(icon)
var text_col: VBoxContainer = VBoxContainer.new()
text_col.size_flags_horizontal = Control.SIZE_EXPAND_FILL
row.add_child(text_col)
var name_label: Label = Label.new()
name_label.text = dec.get("name", id)
name_label.add_theme_font_size_override("font_size", 15)
name_label.add_theme_color_override("font_color", Color(0.92, 0.86, 0.70, 1))
text_col.add_child(name_label)
var desc_label: Label = Label.new()
desc_label.text = dec.get("description", "")
desc_label.add_theme_font_size_override("font_size", 11)
desc_label.add_theme_color_override("font_color", Color(0.68, 0.62, 0.50, 1))
desc_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
text_col.add_child(desc_label)
_spoils_list.add_child(row)
var separator: HSeparator = HSeparator.new()
separator.add_theme_constant_override("separation", 8)
_spoils_list.add_child(separator)
func _on_continue_pressed() -> void:
var main: Node = get_tree().root.get_node_or_null("Main")
if main != null and main.has_method("pop_overlay"):
main.pop_overlay()

View file

@ -0,0 +1,79 @@
[gd_scene load_steps=3 format=3 uid="uid://cr8t3p5lbe2m"]
[ext_resource type="Script" path="res://engine/scenes/menus/throne_room_spoils.gd" id="1"]
[ext_resource type="Theme" path="res://games/age-of-dwarves/ui_theme.tres" id="2_theme"]
[node name="ThroneRoomSpoils" type="Control"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme = ExtResource("2_theme")
script = ExtResource("1")
[node name="Backdrop" type="ColorRect" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
color = Color(0.0, 0.0, 0.0, 0.72)
mouse_filter = 2
[node name="CenterContainer" type="CenterContainer" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="Panel" type="PanelContainer" parent="CenterContainer"]
layout_mode = 2
custom_minimum_size = Vector2(540, 0)
[node name="VBox" type="VBoxContainer" parent="CenterContainer/Panel"]
layout_mode = 2
theme_override_constants/separation = 16
[node name="TitleLabel" type="Label" parent="CenterContainer/Panel/VBox"]
unique_name_in_owner = true
layout_mode = 2
theme_override_font_sizes/font_size = 26
theme_override_colors/font_color = Color(0.95, 0.82, 0.3, 1)
text = "New Acquisitions"
horizontal_alignment = 1
[node name="TitleRule" type="ColorRect" parent="CenterContainer/Panel/VBox"]
layout_mode = 2
custom_minimum_size = Vector2(0, 1)
color = Color(0.6, 0.45, 0.12, 0.7)
[node name="ScrollContainer" type="ScrollContainer" parent="CenterContainer/Panel/VBox"]
layout_mode = 2
custom_minimum_size = Vector2(0, 320)
[node name="SpoilsList" type="VBoxContainer" parent="CenterContainer/Panel/VBox/ScrollContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
theme_override_constants/separation = 8
[node name="EmptyLabel" type="Label" parent="CenterContainer/Panel/VBox"]
unique_name_in_owner = true
layout_mode = 2
theme_override_font_sizes/font_size = 13
theme_override_colors/font_color = Color(0.65, 0.60, 0.48, 0.8)
text = "Your hall awaits its first glory."
horizontal_alignment = 1
visible = false
[node name="ContinueButton" type="Button" parent="CenterContainer/Panel/VBox"]
unique_name_in_owner = true
layout_mode = 2
custom_minimum_size = Vector2(0, 48)
text = "Return"
theme_override_font_sizes/font_size = 16