extends CanvasLayer ## Classic amber HUD, kept above touch sticks/buttons rather than over them. const AMBER := Color(1.0, 0.66, 0.16) const DANGER := Color(1.0, 0.22, 0.12) var health_value: Label var ammo_value: Label var ammo_state: Label var wave_value: Label var grenade_value: Label var help: Label var root: Control var boss_panel: VBoxContainer var boss_name: Label var boss_health: ProgressBar func _ready() -> void: layer = 2 root = Control.new() root.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT) root.mouse_filter = Control.MOUSE_FILTER_IGNORE add_child(root) var health := _panel("Health", false) _label(health, "+ VITA", 16, Vector2(16, 10)) health_value = _label(health, "100", 42, Vector2(16, 27)) var ammo := _panel("Ammo", true) _label(ammo, "CARICATORE", 16, Vector2(16, 10)) ammo_value = _label(ammo, "30 / 30", 36, Vector2(16, 30)) ammo_state = _label(ammo, "", 14, Vector2(16, 77)) wave_value = _label(root, "", 18, Vector2.ZERO) wave_value.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER wave_value.set_anchors_and_offsets_preset(Control.PRESET_CENTER_TOP) wave_value.offset_left = -160 wave_value.offset_right = 160 wave_value.offset_top = 15 wave_value.offset_bottom = 45 grenade_value = _label(root, "", 15, Vector2.ZERO) grenade_value.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER grenade_value.set_anchors_and_offsets_preset(Control.PRESET_CENTER_TOP) grenade_value.offset_left = -160 grenade_value.offset_right = 160 grenade_value.offset_top = 44 grenade_value.offset_bottom = 66 help = _label(root, "WASD: muovi | mouse: mira | R: ricarica | destro: granata", 15, Vector2.ZERO) help.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER help.set_anchors_and_offsets_preset(Control.PRESET_CENTER_BOTTOM) help.offset_left = -420 help.offset_right = 420 help.offset_top = -30 help.offset_bottom = -8 boss_panel = VBoxContainer.new() boss_panel.mouse_filter = Control.MOUSE_FILTER_IGNORE root.add_child(boss_panel) boss_panel.set_anchors_and_offsets_preset(Control.PRESET_CENTER_TOP) boss_panel.offset_left = -180 boss_panel.offset_right = 180 boss_panel.offset_top = 76 boss_name = _label(boss_panel, "ALIEN GRUNT", 17, Vector2.ZERO) boss_name.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER boss_health = ProgressBar.new() boss_health.mouse_filter = Control.MOUSE_FILTER_IGNORE boss_health.custom_minimum_size = Vector2(360, 18) boss_health.show_percentage = false boss_health.step = 0.0 # explosion falloff produces fractional health values boss_health.rounded = false var fill := StyleBoxFlat.new() fill.bg_color = Color(0.14, 0.85, 0.5) boss_health.add_theme_stylebox_override("fill", fill) var background := StyleBoxFlat.new() background.bg_color = Color(0.02, 0.05, 0.03, 0.9) background.border_color = AMBER background.set_border_width_all(1) boss_health.add_theme_stylebox_override("background", background) boss_panel.add_child(boss_health) boss_panel.hide() func _panel(label: String, right: bool) -> Panel: var panel := Panel.new() panel.name = label panel.mouse_filter = Control.MOUSE_FILTER_IGNORE var style := StyleBoxFlat.new() style.bg_color = Color(0.025, 0.02, 0.008, 0.8) style.border_color = Color(1.0, 0.66, 0.16, 0.45) style.set_border_width_all(1) style.set_corner_radius_all(4) panel.add_theme_stylebox_override("panel", style) root.add_child(panel) panel.set_anchors_and_offsets_preset(Control.PRESET_TOP_RIGHT if right else Control.PRESET_TOP_LEFT) panel.offset_left = -224 if right else 16 panel.offset_right = -16 if right else 224 panel.offset_top = 16 panel.offset_bottom = 116 return panel func _label(parent: Control, text: String, size: int, pos: Vector2) -> Label: var label := Label.new() label.text = text label.position = pos label.mouse_filter = Control.MOUSE_FILTER_IGNORE label.add_theme_color_override("font_color", AMBER) label.add_theme_color_override("font_shadow_color", Color.BLACK) label.add_theme_constant_override("shadow_offset_x", 1) label.add_theme_constant_override("shadow_offset_y", 1) label.add_theme_font_size_override("font_size", size) parent.add_child(label) return label func update_boss(boss: Node) -> void: boss_panel.visible = is_instance_valid(boss) and not boss.dead if not boss_panel.visible: return boss_name.text = "ALIEN GRUNT — GRADO %d%s" % [boss.rank, " — ARRIVO" if boss.entering else " | %d / %d" % [ceili(boss.hp), ceili(boss.max_hp)]] boss_health.max_value = boss.max_hp boss_health.value = boss.hp func update_status(player: Node, wave: int, score: int) -> void: health_value.text = str(maxi(0, ceili(player.hp))) health_value.add_theme_color_override("font_color", DANGER if player.hp <= 25 else AMBER) ammo_value.text = "%02d / 30" % player.ammo ammo_value.add_theme_color_override("font_color", DANGER if player.ammo <= 5 else AMBER) ammo_state.text = "RICARICA..." if player.reloading else "" wave_value.text = "ONDATA %d | PUNTI %d" % [wave, score] grenade_value.text = "GRANATA: " + ("PRONTA" if player.grenade_cooldown <= 0 else "%ds" % ceili(player.grenade_cooldown)) help.visible = not player.touch_mode