diff --git a/scripts/hud.gd b/scripts/hud.gd index 7ab2047..7e540b7 100644 --- a/scripts/hud.gd +++ b/scripts/hud.gd @@ -56,6 +56,121 @@ var _face := 1 ## Ein gezeichnetes Würfelbild: Augen 1-6 oder ein Fragezeichen bei unbekanntem ## Wert. Wird überall dort benutzt, wo früher Ziffern oder Sternchen standen. +## Gezeichnetes Sinnbild je Karte. Bilder als Dateien gibt es im Projekt nicht; +## alles wird zur Laufzeit gemalt, so wie die Würfel auch. +class KartenIcon extends Control: + var id := "" + var farbe := Color.WHITE + + func _init(karte: String, col: Color, px: float) -> void: + id = karte + farbe = col + mouse_filter = Control.MOUSE_FILTER_IGNORE + custom_minimum_size = Vector2(px, px) + size_flags_vertical = Control.SIZE_SHRINK_CENTER + + func _draw() -> void: + var s := minf(size.x, size.y) + var m := size * 0.5 + match id: + "reroll_all": + _wuerfel(m + Vector2(-s * 0.16, -s * 0.06), s * 0.42, 5) + _wuerfel(m + Vector2(s * 0.18, s * 0.10), s * 0.42, 2) + "reroll_one": + _wuerfel(m + Vector2(0, s * 0.10), s * 0.38, 3) + _bogen(m + Vector2(0, s * 0.10), s * 0.34) + "set_six": + _wuerfel(m, s * 0.54, 6) + "gain_die": + _wuerfel(m + Vector2(-s * 0.10, 0), s * 0.46, 4) + _plus(m + Vector2(s * 0.26, -s * 0.20), s * 0.20) + "cancel": + draw_arc(m, s * 0.30, 0, TAU, 32, farbe, s * 0.08) + draw_line(m + Vector2(-s * 0.21, -s * 0.21), m + Vector2(s * 0.21, s * 0.21), + farbe, s * 0.08) + "peek": + _auge(m, s) + "bid_up": + _pfeil(m, s * 0.52, true) + "raise_min": + _pfeil(m + Vector2(-s * 0.14, 0), s * 0.44, true) + _pfeil(m + Vector2(s * 0.14, 0), s * 0.44, true) + "enemy_lower": + _pfeil(m, s * 0.52, false) + "fog": + draw_circle(m + Vector2(-s * 0.16, s * 0.06), s * 0.16, farbe) + draw_circle(m + Vector2(s * 0.16, s * 0.06), s * 0.16, farbe) + draw_circle(m + Vector2(0, -s * 0.06), s * 0.20, farbe) + "gag": + var r := Rect2(m - Vector2(s * 0.28, s * 0.16), Vector2(s * 0.56, s * 0.32)) + draw_rect(r, farbe, false, s * 0.07) + draw_line(m + Vector2(-s * 0.28, s * 0.22), m + Vector2(s * 0.28, -s * 0.22), + farbe, s * 0.08) + _: + draw_circle(m, s * 0.26, farbe) + + func _wuerfel(mitte: Vector2, kante: float, augen: int) -> void: + var r := Rect2(mitte - Vector2(kante, kante) * 0.5, Vector2(kante, kante)) + draw_rect(r, farbe, true) + var punkt := kante * 0.10 + var weg := kante * 0.26 + for p: Vector2 in DieIcon.PIPS[augen]: + draw_circle(mitte + p * weg, punkt, Color(0.08, 0.09, 0.12)) + + ## Offener Kreisbogen mit Spitze - das Zeichen fürs Neuwerfen. + func _bogen(mitte: Vector2, r: float) -> void: + draw_arc(mitte, r, PI * 0.85, TAU * 0.92, 28, farbe, maxf(1.5, r * 0.20)) + var spitze := mitte + Vector2(cos(TAU * 0.92), sin(TAU * 0.92)) * r + draw_colored_polygon([spitze + Vector2(-r * 0.30, -r * 0.10), + spitze + Vector2(r * 0.24, -r * 0.16), spitze + Vector2(r * 0.02, r * 0.28)], farbe) + + func _plus(mitte: Vector2, r: float) -> void: + draw_rect(Rect2(mitte - Vector2(r, r * 0.28), Vector2(r * 2, r * 0.56)), farbe, true) + draw_rect(Rect2(mitte - Vector2(r * 0.28, r), Vector2(r * 0.56, r * 2)), farbe, true) + + ## Der Schaft sitzt hinter der Spitze, sonst überlagern sich beide zu + ## einem Klecks. + func _pfeil(mitte: Vector2, h: float, hoch: bool) -> void: + var d := -1.0 if hoch else 1.0 + var schaft_y: float = mitte.y - d * h * 0.48 + var oben: float = minf(mitte.y, schaft_y) + draw_rect(Rect2(Vector2(mitte.x - h * 0.13, oben), + Vector2(h * 0.26, absf(mitte.y - schaft_y))), farbe, true) + draw_colored_polygon([mitte + Vector2(0, d * h * 0.50), + mitte + Vector2(-h * 0.34, d * h * 0.02), + mitte + Vector2(h * 0.34, d * h * 0.02)], farbe) + + func _auge(mitte: Vector2, s: float) -> void: + var punkte := PackedVector2Array() + for i in 17: + var t := -1.0 + 2.0 * i / 16.0 + punkte.append(mitte + Vector2(t * s * 0.34, -sqrt(maxf(0.0, 1.0 - t * t)) * s * 0.20)) + for i in 17: + var t := 1.0 - 2.0 * i / 16.0 + punkte.append(mitte + Vector2(t * s * 0.34, sqrt(maxf(0.0, 1.0 - t * t)) * s * 0.20)) + draw_polyline(punkte, farbe, s * 0.05, true) + draw_circle(mitte, s * 0.11, farbe) + + +## Kleines Zeichen für Buff oder Debuff: Dreieck hoch oder runter. +class ArtIcon extends Control: + var buff := true + + func _init(ist_buff: bool, px: float) -> void: + buff = ist_buff + mouse_filter = Control.MOUSE_FILTER_IGNORE + custom_minimum_size = Vector2(px, px) + size_flags_vertical = Control.SIZE_SHRINK_CENTER + + func _draw() -> void: + var s := minf(size.x, size.y) + var m := size * 0.5 + var col := Color(0.5, 0.9, 0.6) if buff else Color(0.95, 0.5, 0.5) + var d := -1.0 if buff else 1.0 + draw_colored_polygon([m + Vector2(0, d * s * 0.34), + m + Vector2(-s * 0.34, -d * s * 0.24), m + Vector2(s * 0.34, -d * s * 0.24)], col) + + class DieIcon extends Control: const PIPS := { 1: [Vector2(0, 0)], @@ -282,7 +397,7 @@ func _build() -> void: # --- Handkarten unten links, über der Ansageleiste hand_panel = _panel() - _place(hand_panel, 0, 1, 0, 1, 16, -190, 16, -124) + _place(hand_panel, 0, 1, 0, 1, 16, -300, 16, -124) root.add_child(hand_panel) var hv := VBoxContainer.new() hv.add_theme_constant_override("separation", 4) @@ -628,17 +743,45 @@ func _zeichne_hand(st: Dictionary) -> void: var b: Dictionary = BoosterDB.get_booster(id) if b.is_empty(): continue + var buff: bool = b.kind == BoosterDB.Kind.BUFF + var col := Color(0.5, 0.9, 0.6) if buff else Color(0.95, 0.5, 0.5) + var btn := Button.new() - btn.text = String(b.name) + btn.custom_minimum_size = Vector2(168, 132) btn.tooltip_text = String(b.desc) - btn.custom_minimum_size = Vector2(0, 40) btn.disabled = not spielbar - var col := Color(0.5, 0.9, 0.6) if b.kind == BoosterDB.Kind.BUFF else Color(0.95, 0.5, 0.5) - btn.add_theme_color_override("font_color", col) - btn.add_theme_color_override("font_hover_color", Color.WHITE) btn.pressed.connect(_pick.bind(id)) hand_box.add_child(btn) + var v := VBoxContainer.new() + v.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT) + v.offset_left = 9 + v.offset_top = 7 + v.offset_right = -9 + v.offset_bottom = -7 + v.mouse_filter = Control.MOUSE_FILTER_IGNORE + v.add_theme_constant_override("separation", 2) + btn.add_child(v) + + var kopf := HBoxContainer.new() + kopf.mouse_filter = Control.MOUSE_FILTER_IGNORE + v.add_child(kopf) + kopf.add_child(KartenIcon.new(id, col, 34.0)) + var luecke := Control.new() + luecke.size_flags_horizontal = Control.SIZE_EXPAND_FILL + luecke.mouse_filter = Control.MOUSE_FILTER_IGNORE + kopf.add_child(luecke) + kopf.add_child(ArtIcon.new(buff, 16.0)) + + var name_l := _label(String(b.name), 15, col) + name_l.mouse_filter = Control.MOUSE_FILTER_IGNORE + v.add_child(name_l) + var d := _label(String(b.desc), 11, Color(0.78, 0.80, 0.86)) + d.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART + d.mouse_filter = Control.MOUSE_FILTER_IGNORE + d.size_flags_vertical = Control.SIZE_EXPAND_FILL + v.add_child(d) + func _pick(id: String) -> void: if not BoosterDB.needs_target(id) or _my_values.is_empty():