extends CanvasLayer const _GOLD := Color(1.00, 0.78, 0.22) const _CREAM := Color(0.88, 0.83, 0.72) const _MUTED := Color(0.65, 0.60, 0.48) const _BG := Color(0.06, 0.04, 0.02, 0.78) const _BADGE := Color(0.16, 0.10, 0.03, 0.90) const _BORDER := Color(0.65, 0.48, 0.15, 0.55) const ROUND_DURATION := 60.0 var _controls_visible: bool = true var _timer_remaining: float = ROUND_DURATION var _score: int = 0 var _round_active: bool = true var _controls_panel: PanelContainer var _timer_label: Label var _score_label: Label var _toggle_btn: Button var _game_over_panel: Control var _final_score_label: Label var _spawner: Node func _ready() -> void: layer = 11 process_mode = Node.PROCESS_MODE_ALWAYS _build() _find_spawner.call_deferred() func _find_spawner() -> void: var spawners := get_tree().get_nodes_in_group(&"matador_spawn") if not spawners.is_empty(): _spawner = spawners[0] _spawner.matador_killed.connect(_on_matador_killed) func _process(delta: float) -> void: if not _round_active: return _timer_remaining = maxf(0.0, _timer_remaining - delta) _update_timer_display() if _timer_remaining <= 0.0: _end_round() func _unhandled_input(event: InputEvent) -> void: if event is InputEventKey and event.pressed and not event.echo: if event.physical_keycode == KEY_H: _toggle_controls() func _toggle_controls() -> void: _controls_visible = not _controls_visible _controls_panel.visible = _controls_visible _toggle_btn.text = "Hide controls" if _controls_visible else "Show controls" func _on_matador_killed() -> void: if _round_active: _score += 1 _update_score_display() func _end_round() -> void: _round_active = false _final_score_label.text = "You killed %d matadors!" % _score _game_over_panel.visible = true get_tree().paused = true func _on_continue_pressed() -> void: _on_reset_pressed() func _on_reset_pressed() -> void: if get_tree().paused: get_tree().paused = false _game_over_panel.visible = false _timer_remaining = ROUND_DURATION _score = 0 _round_active = true _update_timer_display() _update_score_display() if _spawner: _spawner.reset_spawn() func _update_timer_display() -> void: var s := int(_timer_remaining) _timer_label.text = "%d:%02d" % [s / 60, s % 60] func _update_score_display() -> void: _score_label.text = "Kills: %d" % _score func _build() -> void: _build_controls_panel() _build_score_panel() _build_game_over_overlay() func _build_controls_panel() -> void: _controls_panel = PanelContainer.new() var bg := StyleBoxFlat.new() bg.bg_color = _BG bg.corner_radius_top_left = 7 bg.corner_radius_top_right = 7 bg.corner_radius_bottom_left = 7 bg.corner_radius_bottom_right = 7 bg.border_width_left = 1 bg.border_width_right = 1 bg.border_width_top = 1 bg.border_width_bottom = 1 bg.border_color = _BORDER bg.content_margin_left = 14.0 bg.content_margin_right = 14.0 bg.content_margin_top = 10.0 bg.content_margin_bottom = 10.0 _controls_panel.add_theme_stylebox_override("panel", bg) _controls_panel.anchor_left = 0.0 _controls_panel.anchor_top = 1.0 _controls_panel.anchor_right = 0.0 _controls_panel.anchor_bottom = 1.0 _controls_panel.grow_vertical = Control.GROW_DIRECTION_BEGIN _controls_panel.offset_left = 20.0 _controls_panel.offset_bottom = -20.0 add_child(_controls_panel) var vbox := VBoxContainer.new() vbox.add_theme_constant_override("separation", 5) _controls_panel.add_child(vbox) _row(vbox, "WASD / Arrows", "Move (not intended)", _MUTED) _row(vbox, "LMB (hold)", "Right horn", _CREAM) _row(vbox, "RMB (hold)", "Left horn", _CREAM) _row(vbox, "LMB + RMB", "Bull charge", _CREAM) _row(vbox, "Scroll", "Zoom", _CREAM) _row(vbox, "R", "Respawn matadors (cooldown)", _MUTED) _row(vbox, "H", "Toggle controls", _MUTED) func _build_score_panel() -> void: var panel := PanelContainer.new() var bg := StyleBoxFlat.new() bg.bg_color = _BG bg.corner_radius_top_left = 7 bg.corner_radius_top_right = 7 bg.corner_radius_bottom_left = 7 bg.corner_radius_bottom_right = 7 bg.border_width_left = 1 bg.border_width_right = 1 bg.border_width_top = 1 bg.border_width_bottom = 1 bg.border_color = _BORDER bg.content_margin_left = 16.0 bg.content_margin_right = 16.0 bg.content_margin_top = 12.0 bg.content_margin_bottom = 12.0 panel.add_theme_stylebox_override("panel", bg) panel.anchor_left = 1.0 panel.anchor_top = 0.0 panel.anchor_right = 1.0 panel.anchor_bottom = 0.0 panel.grow_horizontal = Control.GROW_DIRECTION_BEGIN panel.grow_vertical = Control.GROW_DIRECTION_END panel.offset_right = -20.0 panel.offset_top = 20.0 add_child(panel) var vbox := VBoxContainer.new() vbox.add_theme_constant_override("separation", 8) panel.add_child(vbox) _timer_label = Label.new() _timer_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER _timer_label.add_theme_color_override("font_color", _GOLD) _timer_label.add_theme_font_size_override("font_size", 32) vbox.add_child(_timer_label) _score_label = Label.new() _score_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER _score_label.add_theme_color_override("font_color", _CREAM) _score_label.add_theme_font_size_override("font_size", 16) vbox.add_child(_score_label) var sep := HSeparator.new() var sep_style := StyleBoxFlat.new() sep_style.bg_color = Color(0.65, 0.48, 0.15, 0.30) sep_style.content_margin_top = 2.0 sep_style.content_margin_bottom = 2.0 sep.add_theme_stylebox_override("separator", sep_style) vbox.add_child(sep) var hbox := HBoxContainer.new() hbox.add_theme_constant_override("separation", 8) vbox.add_child(hbox) _toggle_btn = _make_button("Hide controls") _toggle_btn.pressed.connect(_toggle_controls) hbox.add_child(_toggle_btn) var reset_btn := _make_button("Reset") reset_btn.pressed.connect(_on_reset_pressed) hbox.add_child(reset_btn) _update_timer_display() _update_score_display() func _build_game_over_overlay() -> void: _game_over_panel = Control.new() _game_over_panel.set_anchors_preset(Control.PRESET_FULL_RECT) _game_over_panel.visible = false _game_over_panel.process_mode = Node.PROCESS_MODE_ALWAYS add_child(_game_over_panel) var backdrop := ColorRect.new() backdrop.set_anchors_preset(Control.PRESET_FULL_RECT) backdrop.color = Color(0.0, 0.0, 0.0, 0.65) _game_over_panel.add_child(backdrop) var card := PanelContainer.new() var card_bg := StyleBoxFlat.new() card_bg.bg_color = Color(0.08, 0.05, 0.02, 0.95) card_bg.corner_radius_top_left = 12 card_bg.corner_radius_top_right = 12 card_bg.corner_radius_bottom_left = 12 card_bg.corner_radius_bottom_right = 12 card_bg.border_width_left = 2 card_bg.border_width_right = 2 card_bg.border_width_top = 2 card_bg.border_width_bottom = 2 card_bg.border_color = _GOLD card_bg.content_margin_left = 48.0 card_bg.content_margin_right = 48.0 card_bg.content_margin_top = 36.0 card_bg.content_margin_bottom = 36.0 card.add_theme_stylebox_override("panel", card_bg) card.anchor_left = 0.5 card.anchor_top = 0.5 card.anchor_right = 0.5 card.anchor_bottom = 0.5 card.grow_horizontal = Control.GROW_DIRECTION_BOTH card.grow_vertical = Control.GROW_DIRECTION_BOTH _game_over_panel.add_child(card) var vbox := VBoxContainer.new() vbox.add_theme_constant_override("separation", 18) vbox.alignment = BoxContainer.ALIGNMENT_CENTER card.add_child(vbox) var title := Label.new() title.text = "TIME'S UP!" title.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER title.add_theme_color_override("font_color", _GOLD) title.add_theme_font_size_override("font_size", 48) vbox.add_child(title) _final_score_label = Label.new() _final_score_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER _final_score_label.add_theme_color_override("font_color", _CREAM) _final_score_label.add_theme_font_size_override("font_size", 24) vbox.add_child(_final_score_label) var continue_btn := _make_button("Continue") continue_btn.custom_minimum_size = Vector2(160.0, 44.0) continue_btn.process_mode = Node.PROCESS_MODE_ALWAYS continue_btn.pressed.connect(_on_continue_pressed) vbox.add_child(continue_btn) func _make_button(label_text: String) -> Button: var btn := Button.new() btn.text = label_text btn.process_mode = Node.PROCESS_MODE_ALWAYS var normal := StyleBoxFlat.new() normal.bg_color = Color(0.18, 0.12, 0.04, 0.90) normal.corner_radius_top_left = 5 normal.corner_radius_top_right = 5 normal.corner_radius_bottom_left = 5 normal.corner_radius_bottom_right = 5 normal.border_width_left = 1 normal.border_width_right = 1 normal.border_width_top = 1 normal.border_width_bottom = 1 normal.border_color = _BORDER normal.content_margin_left = 12.0 normal.content_margin_right = 12.0 normal.content_margin_top = 6.0 normal.content_margin_bottom = 6.0 var hover := StyleBoxFlat.new() hover.bg_color = Color(0.30, 0.20, 0.06, 0.95) hover.corner_radius_top_left = 5 hover.corner_radius_top_right = 5 hover.corner_radius_bottom_left = 5 hover.corner_radius_bottom_right = 5 hover.border_width_left = 1 hover.border_width_right = 1 hover.border_width_top = 1 hover.border_width_bottom = 1 hover.border_color = _GOLD hover.content_margin_left = 12.0 hover.content_margin_right = 12.0 hover.content_margin_top = 6.0 hover.content_margin_bottom = 6.0 btn.add_theme_stylebox_override("normal", normal) btn.add_theme_stylebox_override("hover", hover) btn.add_theme_stylebox_override("pressed", hover) btn.add_theme_color_override("font_color", _GOLD) btn.add_theme_color_override("font_hover_color", _GOLD) btn.add_theme_font_size_override("font_size", 12) return btn func _row(parent: VBoxContainer, key: String, desc: String, desc_color: Color) -> void: var row := HBoxContainer.new() row.add_theme_constant_override("separation", 10) parent.add_child(row) var badge := PanelContainer.new() var bs := StyleBoxFlat.new() bs.bg_color = _BADGE bs.corner_radius_top_left = 3 bs.corner_radius_top_right = 3 bs.corner_radius_bottom_left = 3 bs.corner_radius_bottom_right = 3 bs.content_margin_left = 6.0 bs.content_margin_right = 6.0 bs.content_margin_top = 2.0 bs.content_margin_bottom = 2.0 badge.add_theme_stylebox_override("panel", bs) badge.custom_minimum_size = Vector2(100.0, 0.0) row.add_child(badge) var key_lbl := Label.new() key_lbl.text = key key_lbl.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER key_lbl.vertical_alignment = VERTICAL_ALIGNMENT_CENTER key_lbl.add_theme_color_override("font_color", _GOLD) key_lbl.add_theme_font_size_override("font_size", 12) badge.add_child(key_lbl) var desc_lbl := Label.new() desc_lbl.text = desc desc_lbl.vertical_alignment = VERTICAL_ALIGNMENT_CENTER desc_lbl.add_theme_color_override("font_color", desc_color) desc_lbl.add_theme_font_size_override("font_size", 12) row.add_child(desc_lbl)