Files
SurvivalOfTheSnippest/level/ui/scripts/weapon_slot.gd
T
Scottlg 1562b37563 Gladiator arena: gold economy, outfitting shop, permadeath runs
Turns the sandbox into a survival roguelike loop: outfit your gladiator
with banked gold, enter the arena, earn gold from kills and wave clears,
die, keep 10% of your total value (floored at the 500 fresh-start).

Economy (GameState autoload):
- banked_gold, owned items, and loadout persist to user://save.cfg
- Kill gold (basic 10g, armed 25g) credited server-side to the killer
- Wave-clear bonus (25 + 5/wave) for all players; wave synced to peers
- Death settlement liquidates gear, guarded against double-fire

Character creation / shop:
- Menu reframed: armory shop + live Character Sheet loadout preview
- Character Sheet gains preview mode (renders from loadout, no player)
- Buy/Equip with hand rules; two-handers and off-hands displace each
  other symmetrically (shop and in-game pickups)
- Chosen loadout auto-equips on spawn via existing RPC path

Combat feel:
- Attacks snap to camera facing and lock direction for the swing
- Dash commits to its direction for the full duration
- Weapon slots show name text when no icon is set
- Hitbox/hurtbox debug meshes hidden by default (H toggles)

Death is final: players no longer respawn; a results screen shows waves,
time, kills, and the settlement, then returns to camp. Armed enemies no
longer respawn (were an infinite gold farm and respawned invisible).
2026-07-01 23:38:59 +01:00

135 lines
3.9 KiB
GDScript

extends Control
class_name WeaponSlot
## Weapon slot that displays weapon icon and shows tooltip on hover
# References
@onready var icon_rect: TextureRect = $SlotPanel/MarginContainer/IconRect
var tooltip: PanelContainer = null
# Fallback name display for weapons without an icon texture
var _name_label: Label = null
# Weapon data
var weapon_data: WeaponData = null
var slot_name: String = "Main Hand"
func _ready():
# Create tooltip as a top-level CanvasLayer child so it's not clipped
_create_tooltip()
# Connect mouse events
mouse_entered.connect(_on_mouse_entered)
mouse_exited.connect(_on_mouse_exited)
## Create tooltip as a top-level node to avoid clipping
func _create_tooltip():
# Load tooltip scene template
var tooltip_scene = load("res://level/ui/scenes/weapon_tooltip.tscn")
if tooltip_scene:
tooltip = tooltip_scene.instantiate()
# Add to the root CanvasLayer (HUD) so it's not clipped
var hud = get_node_or_null("/root/HUD")
if hud:
hud.add_child(tooltip)
tooltip.hide()
else:
push_error("[WeaponSlot] Could not find HUD node")
else:
push_error("[WeaponSlot] Failed to load weapon_tooltip.tscn")
## Set weapon data and update display
func set_weapon(data: WeaponData, name: String = "Main Hand"):
weapon_data = data
slot_name = name
_update_display()
## Clear the weapon slot
func clear_weapon():
weapon_data = null
_update_display()
## Update the icon display
func _update_display():
if not icon_rect:
return
if weapon_data and weapon_data.icon:
icon_rect.texture = weapon_data.icon
icon_rect.modulate = Color.WHITE
_set_name_fallback("")
elif weapon_data:
# No icon on this weapon - show its name in the slot instead
icon_rect.texture = null
icon_rect.modulate = Color.WHITE
_set_name_fallback(weapon_data.weapon_name)
else:
icon_rect.texture = null
icon_rect.modulate = Color(0.3, 0.3, 0.3, 0.5) # Dim empty slot
_set_name_fallback("")
## Show/hide the fallback name label ("" hides it)
func _set_name_fallback(text: String):
if text == "":
if _name_label:
_name_label.hide()
return
if not _name_label:
_name_label = Label.new()
_name_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
_name_label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
_name_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
_name_label.add_theme_font_size_override("font_size", 12)
_name_label.add_theme_color_override("font_color", Color(1.0, 0.85, 0.4))
_name_label.add_theme_color_override("font_outline_color", Color.BLACK)
_name_label.add_theme_constant_override("outline_size", 2)
_name_label.set_anchors_preset(Control.PRESET_FULL_RECT)
_name_label.mouse_filter = Control.MOUSE_FILTER_IGNORE
var container = get_node_or_null("SlotPanel/MarginContainer")
if container:
container.add_child(_name_label)
else:
add_child(_name_label)
_name_label.text = text
_name_label.show()
## Show tooltip on mouse enter
func _on_mouse_entered():
if weapon_data and tooltip:
_update_tooltip()
# Position tooltip to the right of the slot
var global_pos = global_position
tooltip.position = Vector2(global_pos.x + size.x + 10, global_pos.y)
tooltip.show()
## Hide tooltip on mouse exit
func _on_mouse_exited():
if tooltip:
tooltip.hide()
## Update tooltip content
func _update_tooltip():
if not tooltip or not weapon_data:
return
var tooltip_label = tooltip.get_node_or_null("MarginContainer/VBoxContainer/StatsLabel")
if not tooltip_label:
return
var text = ""
text += slot_name.to_upper() + "\n"
text += weapon_data.weapon_name + "\n"
text += "---\n"
text += "Damage: " + str(weapon_data.damage) + "\n"
text += "Range: " + str(weapon_data.attack_range) + "\n"
text += "Cooldown: " + str(weapon_data.attack_cooldown) + "s\n"
text += "Knockback: " + str(weapon_data.knockback_force) + "\n"
if weapon_data.can_block:
text += "Block: " + str(int(weapon_data.block_reduction * 100)) + "%\n"
if weapon_data.description:
text += "\n" + weapon_data.description
tooltip_label.text = text