MultiplayerFighter
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

223 lines
6.8 KiB

extends Control
class_name CharacterSheet
## Character sheet / spellbook that displays player stats, weapons, and abilities
## Opens with Tab key
# References
@onready var stats_container: VBoxContainer = $Panel/MarginContainer/VBoxContainer/HBoxContainer/LeftPage/ScrollContainer/StatsContainer
@onready var weapons_container: VBoxContainer = $Panel/MarginContainer/VBoxContainer/HBoxContainer/RightPage/ScrollContainer/ContentContainer/WeaponsContainer
@onready var abilities_container: VBoxContainer = $Panel/MarginContainer/VBoxContainer/HBoxContainer/RightPage/ScrollContainer/ContentContainer/AbilitiesContainer
# Player reference
var player: Character = null
# Visibility
var is_visible: bool = false
func _ready():
# Start hidden
hide()
is_visible = false
func _input(event):
# Close on Escape press if open
if event.is_action_pressed("quit") and is_visible:
toggle_sheet()
get_viewport().set_input_as_handled()
return
# Toggle on Tab press
if event.is_action_pressed("toggle_character_sheet"):
toggle_sheet()
get_viewport().set_input_as_handled()
## Set the player reference and update display
func set_player(p: Character):
player = p
if player:
refresh_all()
## Toggle character sheet visibility
func toggle_sheet():
is_visible = !is_visible
if is_visible:
show()
refresh_all()
# Release mouse when opening sheet
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
else:
hide()
# Recapture mouse when closing sheet
if player and player.is_multiplayer_authority():
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
## Refresh all data in the sheet
func refresh_all():
if not player:
return
_refresh_stats()
_refresh_weapons()
_refresh_abilities()
## Refresh player stats
func _refresh_stats():
if not stats_container:
return
# Clear existing stats
for child in stats_container.get_children():
child.queue_free()
# Add title
var title = Label.new()
title.text = "CHARACTER STATS"
title.add_theme_font_size_override("font_size", 24)
title.add_theme_color_override("font_color", Color(1.0, 0.8, 0.0))
stats_container.add_child(title)
# Spacer
var spacer1 = Control.new()
spacer1.custom_minimum_size = Vector2(0, 10)
stats_container.add_child(spacer1)
# Get player name
var player_id = player.name.to_int()
var player_name = "Player"
if Network.players.has(player_id):
player_name = Network.players[player_id]["nick"]
_add_stat_label("Name: " + player_name)
_add_stat_label("Level: 1") # Hardcoded for now
_add_stat_label("")
# Health stats
_add_stat_label("=== HEALTH ===", Color(0.8, 0.8, 0.8))
_add_stat_label("Current HP: " + str(int(player.current_health)))
_add_stat_label("Max HP: " + str(int(player.max_health)))
_add_stat_label("Health: " + str(int(player.get_health_percent() * 100)) + "%")
_add_stat_label("")
# Movement stats
_add_stat_label("=== MOVEMENT ===", Color(0.8, 0.8, 0.8))
_add_stat_label("Walk Speed: " + str(player.NORMAL_SPEED))
_add_stat_label("Sprint Speed: " + str(player.SPRINT_SPEED))
_add_stat_label("Jump Power: " + str(player.JUMP_VELOCITY))
_add_stat_label("")
# Combat stats
_add_stat_label("=== COMBAT ===", Color(0.8, 0.8, 0.8))
_add_stat_label("Base Damage: " + str(player.attack_damage))
_add_stat_label("Attack Range: " + str(player.attack_range))
_add_stat_label("Attack Cooldown: " + str(player.attack_cooldown) + "s")
## Refresh equipped weapons
func _refresh_weapons():
if not weapons_container:
return
# Clear existing
for child in weapons_container.get_children():
child.queue_free()
# Add title
var title = Label.new()
title.text = "EQUIPPED WEAPONS"
title.add_theme_font_size_override("font_size", 20)
title.add_theme_color_override("font_color", Color(1.0, 0.8, 0.0))
weapons_container.add_child(title)
# Spacer
var spacer = Control.new()
spacer.custom_minimum_size = Vector2(0, 10)
weapons_container.add_child(spacer)
# Create horizontal container for weapon slots
var slots_container = HBoxContainer.new()
slots_container.add_theme_constant_override("separation", 15)
weapons_container.add_child(slots_container)
# Load weapon slot scene
var weapon_slot_scene = load("res://level/ui/scenes/weapon_slot.tscn")
if not weapon_slot_scene:
push_error("[CharacterSheet] Failed to load weapon_slot.tscn")
return
# Create main hand slot
var main_hand_slot = weapon_slot_scene.instantiate()
slots_container.add_child(main_hand_slot)
if player.equipped_weapon and player.equipped_weapon.weapon_data:
main_hand_slot.set_weapon(player.equipped_weapon.weapon_data, "Main Hand")
else:
main_hand_slot.clear_weapon()
# Create off-hand slot
var off_hand_slot = weapon_slot_scene.instantiate()
slots_container.add_child(off_hand_slot)
if player.equipped_offhand and player.equipped_offhand.weapon_data:
off_hand_slot.set_weapon(player.equipped_offhand.weapon_data, "Off-Hand")
else:
off_hand_slot.clear_weapon()
## Refresh abilities list
func _refresh_abilities():
if not abilities_container:
return
# Clear existing
for child in abilities_container.get_children():
child.queue_free()
# Add title
var title = Label.new()
title.text = "ABILITIES"
title.add_theme_font_size_override("font_size", 20)
title.add_theme_color_override("font_color", Color(1.0, 0.8, 0.0))
abilities_container.add_child(title)
# Spacer
var spacer = Control.new()
spacer.custom_minimum_size = Vector2(0, 10)
abilities_container.add_child(spacer)
# Dash ability
_add_stat_label("--- DASH (F) ---", Color(0.8, 0.8, 0.8))
_add_stat_label("Cooldown: " + str(player.dash_cooldown) + "s")
_add_stat_label("Duration: " + str(player.dash_duration) + "s")
_add_stat_label("Speed: " + str(player.dash_speed_multiplier) + "x")
_add_stat_label("Description: Dash in movement direction")
var dash_remaining = player._dash_cooldown_timer
if dash_remaining > 0:
_add_stat_label("Ready in: " + str(ceil(dash_remaining)) + "s", Color(1.0, 0.5, 0.5))
else:
_add_stat_label("Status: READY", Color(0.0, 1.0, 0.0))
# Spacer
var spacer2 = Control.new()
spacer2.custom_minimum_size = Vector2(0, 10)
abilities_container.add_child(spacer2)
# Jump ability
_add_stat_label("--- JUMP (Space) ---", Color(0.8, 0.8, 0.8))
_add_stat_label("Power: " + str(player.JUMP_VELOCITY))
_add_stat_label("Description: Jump into the air")
_add_stat_label("Status: ALWAYS READY", Color(0.0, 1.0, 0.0))
## Helper to add a stat label
func _add_stat_label(text: String, color: Color = Color.WHITE):
var label = Label.new()
label.text = text
label.add_theme_color_override("font_color", color)
label.add_theme_color_override("font_outline_color", Color.BLACK)
label.add_theme_constant_override("outline_size", 1)
label.add_theme_font_size_override("font_size", 16)
if stats_container:
stats_container.add_child(label)
elif weapons_container:
weapons_container.add_child(label)
elif abilities_container:
abilities_container.add_child(label)