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:
parent
9fcd374722
commit
a84ce19982
8 changed files with 772 additions and 0 deletions
86
engine/scenes/menus/game_setup.gd
Normal file
86
engine/scenes/menus/game_setup.gd
Normal 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")
|
||||
177
engine/scenes/menus/game_setup.tscn
Normal file
177
engine/scenes/menus/game_setup.tscn
Normal 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"
|
||||
|
|
@ -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()
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
211
engine/scenes/menus/throne_room.gd
Normal file
211
engine/scenes/menus/throne_room.gd
Normal 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 (0–1) 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()
|
||||
105
engine/scenes/menus/throne_room.tscn
Normal file
105
engine/scenes/menus/throne_room.tscn
Normal 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
|
||||
66
engine/scenes/menus/throne_room_spoils.gd
Normal file
66
engine/scenes/menus/throne_room_spoils.gd
Normal 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()
|
||||
79
engine/scenes/menus/throne_room_spoils.tscn
Normal file
79
engine/scenes/menus/throne_room_spoils.tscn
Normal 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
|
||||
Loading…
Add table
Reference in a new issue