class_name LuneBossIndicator extends PanelContainer ## The boss grotto and the Schlundkrone at a glance: BOSS VERFÜGBAR, BOSS UMKÄMPFT, BOSS ## EROBERT, EINSATZ NÄCHSTE WELLE, BOSS GREIFT AN, COOLDOWN – X RUNDEN. When a team owns the ## boss the card names target lane, deployment wave and the bounty the defenders earn; the ## player who steers the boss chooses its lane here. A click on the card moves the camera. signal focus_requested signal lane_chosen(lane: String) var data: Dictionary = {} var portrait: LunePortraitRect var _badge: LuneStatusBadge var _line: Label var _risk: Label var _bar: LuneHpBar var _choice: HBoxContainer var _lane_buttons: Dictionary = {} var _owner: LuneGlyph var _signature: String = "" var compact: bool = false var _own_team: int = 0 var _round: int = 0 var _planning: bool = true func _init() -> void: theme_type_variation = "HudPanelTight" mouse_filter = Control.MOUSE_FILTER_STOP mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND var row := HBoxContainer.new() row.add_theme_constant_override("separation", 10) row.mouse_filter = Control.MOUSE_FILTER_IGNORE add_child(row) portrait = LunePortraitRect.new() portrait.custom_minimum_size = Vector2(64, 64) portrait.size_flags_vertical = Control.SIZE_SHRINK_BEGIN row.add_child(portrait) _owner = LuneGlyph.make("emblem_2", LuneUiTheme.TEAM[2], 18.0, portrait) _owner.position = Vector2(2, 44) var column := VBoxContainer.new() column.add_theme_constant_override("separation", 3) column.size_flags_horizontal = Control.SIZE_EXPAND_FILL column.mouse_filter = Control.MOUSE_FILTER_IGNORE row.add_child(column) var head := HBoxContainer.new() head.add_theme_constant_override("separation", 6) head.mouse_filter = Control.MOUSE_FILTER_IGNORE column.add_child(head) LuneGlyph.make("grotto", LuneUiTheme.TEAM[2], 15.0, head) LuneUiTheme.label("BOSSGROTTE · G", "HudCaps", head) _badge = LuneStatusBadge.new() column.add_child(_badge) _badge.size_flags_horizontal = Control.SIZE_SHRINK_BEGIN _line = LuneUiTheme.label("", "HudText", column) _line.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART _risk = LuneUiTheme.label("", "HudMuted", column) _risk.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART _bar = LuneHpBar.new() _bar.custom_minimum_size = Vector2(0, 5) _bar.visible = false column.add_child(_bar) _choice = HBoxContainer.new() _choice.add_theme_constant_override("separation", 4) _choice.visible = false column.add_child(_choice) for lane: String in LuneMap.LANES: var button := LuneUiTheme.button(LuneMap.LANE_NAMES[lane].to_upper(), "HudToggle", _choice) button.toggle_mode = true button.size_flags_horizontal = Control.SIZE_EXPAND_FILL button.pressed.connect(func() -> void: lane_chosen.emit(lane)) _lane_buttons[lane] = button LuneTooltip.attach(self, _tip) ## Short form while the right column shows a selected unit: badge only. func set_compact(value: bool) -> void: if value == compact: return compact = value portrait.custom_minimum_size = Vector2(40, 40) if value else Vector2(64, 64) _signature = "" if not data.is_empty(): apply(data, _own_team, _round, _planning) func _gui_input(event: InputEvent) -> void: if event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT: focus_requested.emit() accept_event() func apply(boss: Dictionary, own_team: int, round_number: int, planning: bool) -> void: var signature: String = "%s|%d|%d|%s" % [str(boss), own_team, round_number, planning] if signature == _signature: return _signature = signature data = boss _own_team = own_team _round = round_number _planning = planning portrait.show_model("schlundkrone") var owner: int = int(boss.team) var own: bool = owner == own_team var lane_text: String = LuneMap.LANE_NAMES.get(str(boss.lane), "?").to_upper() var side: String = LuneUiTheme.team_name(owner) _owner.visible = owner >= 0 _owner.glyph = "emblem_%d" % clampi(owner, 0, 2) _owner.color = LuneUiTheme.team_color(owner) _bar.visible = false _choice.visible = false _risk.text = "" match str(boss.state): "available": _badge.set_state("BOSS VERFÜGBAR", LuneUiTheme.TEAM[2], "crown") _line.text = "Einheiten mit „Grotte“ entsenden. Wer den Boss besiegt, schickt ihn in der Folgewelle gegen den Gegner." "contested": _badge.set_state("BOSS UMKÄMPFT", LuneUiTheme.WARN, "melee") _line.text = "Expeditionen kämpfen in der Grotte; sie fehlen ihren Lanes bis Kampfende." "conquered": _badge.set_state("BOSS EROBERT · %s" % side.to_upper(), LuneUiTheme.team_color(owner), "crown", true) _line.text = "Einsatz in Welle %d für %s." % [int(boss.deploy_round), "dein Team" if own else side] "failed": _badge.set_state("EXPEDITION GESCHEITERT", LuneUiTheme.MUTED, "close") _line.text = "Der Boss hat überlebt; niemand erhält ihn." "deploy_next": _badge.set_state("EINSATZ NÄCHSTE WELLE", LuneUiTheme.team_color(owner) if own else LuneUiTheme.DANGER, "crown", true) if own: _line.text = "Deine Schlundkrone greift in Welle %d auf %s an." % [int(boss.deploy_round), lane_text] _risk.text = "Fällt sie, erhält %s %s Gold Kopfgeld." % [LuneUiTheme.team_name(1 - own_team), LuneUiTheme.number(boss.bounty)] else: _line.text = "%s: Schlundkrone greift in Welle %d auf %s an." % [side, int(boss.deploy_round), lane_text] _risk.text = "Besiegt ihr sie, erhält dein Team %s Gold Kopfgeld." % LuneUiTheme.number(boss.bounty) if bool(boss.chooser) and planning: _choice.visible = true for lane: String in _lane_buttons: (_lane_buttons[lane] as Button).set_pressed_no_signal(lane == str(boss.lane)) _risk.text += " Du wählst die Lane:" "deploying": _badge.set_state("BOSS GREIFT AN · %s" % lane_text, LuneUiTheme.team_color(owner) if own else LuneUiTheme.DANGER, "warning", true) _line.text = ("Deine Schlundkrone greift %s an." if own else "Gegnerische Schlundkrone auf %s!") % lane_text _risk.text = "Kopfgeld für die Verteidiger: %s Gold." % LuneUiTheme.number(boss.bounty) if boss.has("hp"): _bar.visible = true _bar.fraction = float(boss.hp) / maxf(1.0, float(boss.max_hp)) _bar.fill = LuneUiTheme.team_color(owner) "defeated": _badge.set_state("SCHLUNDKRONE BESIEGT", LuneUiTheme.GOOD if not own else LuneUiTheme.MUTED, "check") _line.text = "Das Kopfgeld von %s Gold geht an %s." % [LuneUiTheme.number(boss.bounty), "den Gegner" if own else "dein Team"] _: var left: int = int(boss.rounds_left) _badge.set_state("COOLDOWN – %d %s" % [left, "RUNDE" if left == 1 else "RUNDEN"], LuneUiTheme.MUTED, "clock") _line.text = "Grotte wieder offen ab Welle %d." % int(boss.next_round) _risk.visible = not _risk.text.is_empty() and not compact _line.visible = not compact _owner.visible = _owner.visible and not compact if compact: _choice.visible = false if LuneTooltip.current != null: LuneTooltip.current.refresh(self) ## Live boss HP during its attack, without rebuilding the texts. func set_boss_hp(fraction: float) -> void: if _bar.visible: _bar.fraction = fraction func _tip() -> Dictionary: return {"title": "Bossgrotte · Schlundkrone", "glyph": "crown", "glyph_color": LuneUiTheme.TEAM[2], "text": "Expeditionen kämpfen zuerst gegeneinander; der Boss erwacht, wenn höchstens ein Team übrig ist. Sieg: Der Boss greift in der Folgewelle für die Sieger an, die Verteidiger erhalten bei seinem Fall ein hohes Kopfgeld. Danach ist die Grotte %d Runden gesperrt." % LuneContent.BOSS_LOCK_ROUNDS, "note": "Klick oder G: Kamera zur Grotte"}