- Clients now handle the host closing the arena: bank winnings if still alive (retire), reset the HUD, and return to the camp menu instead of being stranded in a dead world - Death in co-op offers Spectate when a teammate is still fighting: closes the results overlay and watches the run; the escape menu gains a "Back to Camp" option for dead spectators to leave later - Late joiners receive the current wave number on connect so their HUD doesn't sit on "Prepare..." until the next wave starts
163 lines
5.4 KiB
GDScript
163 lines
5.4 KiB
GDScript
extends Control
|
|
class_name RunResults
|
|
## End-of-run results screen for the gladiator arena.
|
|
## Shown by the HUD when the local player dies. Displays survival stats and
|
|
## the death settlement (keep 10% of total value, floored at the fresh-start
|
|
## default), then returns the player to the menu/camp.
|
|
|
|
var stats: Dictionary = {}
|
|
|
|
func setup(run_stats: Dictionary):
|
|
stats = run_stats
|
|
|
|
func _ready():
|
|
# Full-screen dark backdrop
|
|
set_anchors_preset(Control.PRESET_FULL_RECT)
|
|
mouse_filter = Control.MOUSE_FILTER_STOP
|
|
|
|
var backdrop = ColorRect.new()
|
|
backdrop.color = Color(0.0, 0.0, 0.0, 0.75)
|
|
backdrop.set_anchors_preset(Control.PRESET_FULL_RECT)
|
|
add_child(backdrop)
|
|
|
|
# Centered panel
|
|
var center = CenterContainer.new()
|
|
center.set_anchors_preset(Control.PRESET_FULL_RECT)
|
|
add_child(center)
|
|
|
|
var panel = PanelContainer.new()
|
|
panel.custom_minimum_size = Vector2(460, 0)
|
|
center.add_child(panel)
|
|
|
|
var margin = MarginContainer.new()
|
|
margin.add_theme_constant_override("margin_left", 30)
|
|
margin.add_theme_constant_override("margin_right", 30)
|
|
margin.add_theme_constant_override("margin_top", 24)
|
|
margin.add_theme_constant_override("margin_bottom", 24)
|
|
panel.add_child(margin)
|
|
|
|
var vbox = VBoxContainer.new()
|
|
vbox.add_theme_constant_override("separation", 8)
|
|
margin.add_child(vbox)
|
|
|
|
# Title
|
|
var title = Label.new()
|
|
title.text = "YOU HAVE FALLEN"
|
|
title.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
|
title.add_theme_font_size_override("font_size", 36)
|
|
title.add_theme_color_override("font_color", Color(0.9, 0.2, 0.2))
|
|
vbox.add_child(title)
|
|
|
|
var subtitle = Label.new()
|
|
subtitle.text = "The arena claims another gladiator"
|
|
subtitle.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
|
subtitle.add_theme_font_size_override("font_size", 16)
|
|
subtitle.add_theme_color_override("font_color", Color(0.7, 0.7, 0.7))
|
|
vbox.add_child(subtitle)
|
|
|
|
_add_spacer(vbox, 12)
|
|
|
|
# Survival stats
|
|
_add_header(vbox, "=== SURVIVAL ===")
|
|
_add_stat_row(vbox, "Waves Survived", str(int(stats.get("waves", 0))))
|
|
_add_stat_row(vbox, "Time in Arena", _format_time(stats.get("time", 0.0)))
|
|
_add_stat_row(vbox, "Kills", str(int(stats.get("kills", 0))))
|
|
|
|
_add_spacer(vbox, 12)
|
|
|
|
# Settlement
|
|
_add_header(vbox, "=== SETTLEMENT ===")
|
|
_add_stat_row(vbox, "Gold Earned This Run", str(int(stats.get("gold_earned", 0))))
|
|
_add_stat_row(vbox, "Total Value at Death", str(int(stats.get("total_value", 0))))
|
|
|
|
var kept = int(stats.get("kept", 0))
|
|
var kept_row = Label.new()
|
|
kept_row.text = "The arena takes its cut... you keep " + str(kept) + " gold"
|
|
kept_row.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
|
kept_row.add_theme_font_size_override("font_size", 18)
|
|
kept_row.add_theme_color_override("font_color", Color(1.0, 0.8, 0.0))
|
|
vbox.add_child(kept_row)
|
|
|
|
_add_spacer(vbox, 16)
|
|
|
|
# Spectate option - only when a teammate is still fighting
|
|
if _teammates_still_alive():
|
|
var spectate_button = Button.new()
|
|
spectate_button.text = "Spectate"
|
|
spectate_button.custom_minimum_size = Vector2(0, 44)
|
|
spectate_button.pressed.connect(_on_spectate_pressed)
|
|
vbox.add_child(spectate_button)
|
|
_add_spacer(vbox, 6)
|
|
|
|
# Return button
|
|
var return_button = Button.new()
|
|
return_button.text = "Return to Camp"
|
|
return_button.custom_minimum_size = Vector2(0, 44)
|
|
return_button.pressed.connect(_on_return_pressed)
|
|
vbox.add_child(return_button)
|
|
|
|
# Make sure the mouse is usable on the overlay
|
|
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
|
|
|
|
## Any other living player in the arena?
|
|
func _teammates_still_alive() -> bool:
|
|
if multiplayer.multiplayer_peer == null:
|
|
return false
|
|
var level = get_tree().get_current_scene()
|
|
if not level or not level.has_node("PlayersContainer"):
|
|
return false
|
|
var my_id = multiplayer.get_unique_id()
|
|
for p in level.get_node("PlayersContainer").get_children():
|
|
if p is Character and not p.is_dead and str(p.name).to_int() != my_id:
|
|
return true
|
|
return false
|
|
|
|
## Close the overlay and watch the run play out (escape menu can leave later).
|
|
## For the host this also keeps the server alive for everyone else.
|
|
func _on_spectate_pressed():
|
|
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
|
|
queue_free()
|
|
|
|
func _add_header(parent: Control, text: String):
|
|
var label = Label.new()
|
|
label.text = text
|
|
label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
|
label.add_theme_font_size_override("font_size", 16)
|
|
label.add_theme_color_override("font_color", Color(0.8, 0.8, 0.8))
|
|
parent.add_child(label)
|
|
|
|
func _add_stat_row(parent: Control, label_text: String, value_text: String):
|
|
var row = HBoxContainer.new()
|
|
var label = Label.new()
|
|
label.text = label_text
|
|
label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
|
label.add_theme_font_size_override("font_size", 16)
|
|
row.add_child(label)
|
|
|
|
var value = Label.new()
|
|
value.text = value_text
|
|
value.add_theme_font_size_override("font_size", 16)
|
|
value.add_theme_color_override("font_color", Color(1.0, 0.8, 0.0))
|
|
row.add_child(value)
|
|
parent.add_child(row)
|
|
|
|
func _add_spacer(parent: Control, height: int):
|
|
var spacer = Control.new()
|
|
spacer.custom_minimum_size = Vector2(0, height)
|
|
parent.add_child(spacer)
|
|
|
|
func _format_time(seconds: float) -> String:
|
|
var total = int(seconds)
|
|
return "%dm %02ds" % [total / 60, total % 60]
|
|
|
|
func _on_return_pressed():
|
|
# Tear down the multiplayer session and go back to the menu.
|
|
# (Host quitting ends the session for connected clients - acceptable for now.)
|
|
multiplayer.multiplayer_peer = null
|
|
Network.players.clear()
|
|
|
|
if has_node("/root/HUD"):
|
|
get_node("/root/HUD").reset()
|
|
|
|
get_tree().reload_current_scene()
|