update
This commit is contained in:
380
scripts/hud.gd
380
scripts/hud.gd
@@ -13,6 +13,7 @@ const DIM := Color(0.62, 0.64, 0.70)
|
||||
## Wette werden so gross gewählt, dass sie dort hineinpassen.
|
||||
const BID_BOX := Vector2(150.0, 108.0)
|
||||
const TIMER_W := 52.0 ## Breite der Zeitanzeige in der Ansage-Leiste
|
||||
const INFO_W := 280.0 ## Textbreite im Erklärfeld beim Überfahren
|
||||
const GRUEN := Color(0.55, 0.84, 0.55) ## überzähliger Würfel beim Aufdecken
|
||||
const ROT := Color(0.94, 0.55, 0.52) ## fehlender Würfel beim Aufdecken
|
||||
|
||||
@@ -47,6 +48,14 @@ var pause_hint: Label
|
||||
var boost_panel: PanelContainer
|
||||
var boost_cards: HBoxContainer
|
||||
var boost_title: Label
|
||||
var turn_label: Label
|
||||
var info_panel: PanelContainer
|
||||
var info_name: Label
|
||||
var info_desc: Label
|
||||
var info_stark: Label
|
||||
var wurf_slot: CenterContainer
|
||||
var wurf_icon: MuenzIcon
|
||||
var wurf_label: Label
|
||||
var timer_bid: Label
|
||||
var timer_boost: Label
|
||||
var target_row: HBoxContainer
|
||||
@@ -54,24 +63,44 @@ var target_row: HBoxContainer
|
||||
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
|
||||
## Gezeichnete Münze. Bilder als Dateien gibt es im Projekt nicht; alles wird
|
||||
## zur Laufzeit gemalt, so wie die Würfel auch. Vorn das Sinnbild der Wirkung
|
||||
## (Wappen), hinten die glatte Zahlseite.
|
||||
class MuenzIcon extends Control:
|
||||
const RAND := Color(0.40, 0.29, 0.11) ## Prägekante
|
||||
const FLAECHE := Color(0.78, 0.60, 0.26) ## Messing
|
||||
const GLANZ := Color(0.91, 0.75, 0.39) ## Lichtkante
|
||||
const GRAVUR := Color(0.19, 0.13, 0.04) ## eingeschlagenes Zeichen
|
||||
|
||||
func _init(karte: String, col: Color, px: float) -> void:
|
||||
id = karte
|
||||
farbe = col
|
||||
var id := ""
|
||||
var farbe := GRAVUR ## Zeichenfarbe, von den Zeichenhilfen benutzt
|
||||
var kind_col := Color.WHITE
|
||||
var seite := 0 ## 0 = Wappen (Sinnbild), 1 = Zahl
|
||||
|
||||
func _init(muenze: String, col: Color, px: float) -> void:
|
||||
id = muenze
|
||||
kind_col = col
|
||||
mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
custom_minimum_size = Vector2(px, px)
|
||||
size_flags_vertical = Control.SIZE_SHRINK_CENTER
|
||||
pivot_offset = Vector2(px, px) * 0.5
|
||||
|
||||
func _draw() -> void:
|
||||
var s := minf(size.x, size.y)
|
||||
var m := size * 0.5
|
||||
var r := s * 0.5
|
||||
draw_circle(m, r, RAND)
|
||||
draw_circle(m - Vector2(r, r) * 0.05, r * 0.95, GLANZ)
|
||||
draw_circle(m, r * 0.89, FLAECHE)
|
||||
# Der Farbring sagt, ob die Münze dir hilft oder den anderen schadet.
|
||||
draw_arc(m, r * 0.79, 0, TAU, 40, kind_col, maxf(1.0, s * 0.05))
|
||||
if seite == 1:
|
||||
draw_arc(m, r * 0.52, 0, TAU, 32, GRAVUR, maxf(1.0, s * 0.04))
|
||||
draw_circle(m, s * 0.09, GRAVUR)
|
||||
return
|
||||
_zeichen(m, s * 0.74)
|
||||
|
||||
func _zeichen(m: Vector2, s: float) -> void:
|
||||
match id:
|
||||
"reroll_all":
|
||||
_wuerfel(m + Vector2(-s * 0.16, -s * 0.06), s * 0.42, 5)
|
||||
@@ -115,7 +144,7 @@ class KartenIcon extends Control:
|
||||
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))
|
||||
draw_circle(mitte + p * weg, punkt, FLAECHE)
|
||||
|
||||
## Offener Kreisbogen mit Spitze - das Zeichen fürs Neuwerfen.
|
||||
func _bogen(mitte: Vector2, r: float) -> void:
|
||||
@@ -152,6 +181,8 @@ class KartenIcon extends Control:
|
||||
draw_circle(mitte, s * 0.11, farbe)
|
||||
|
||||
|
||||
## Ein gezeichnetes Würfelbild: Augen 1-6 oder ein Fragezeichen bei unbekanntem
|
||||
## Wert. Wird überall dort benutzt, wo früher Ziffern oder Sternchen standen.
|
||||
class DieIcon extends Control:
|
||||
const PIPS := {
|
||||
1: [Vector2(0, 0)],
|
||||
@@ -199,11 +230,24 @@ var _deadline := 0.0 ## lokaler Zeitstempel, 0 = keine Frist
|
||||
var _phase := ""
|
||||
var _my_turn := false
|
||||
var _pending_boost := ""
|
||||
var _letzter_wurf := 0 ## Nummer des zuletzt gezeigten Münzwurfs
|
||||
var _info_ctrl: Control ## worauf die Maus gerade liegt
|
||||
var _zug_box := StyleBoxFlat.new() ## Hinterlegung der Zeile, die dran ist
|
||||
var _leer_box := StyleBoxEmpty.new()
|
||||
var _hand_sig := "" ## Abbild des Vorrats, gegen unnötigen Neuaufbau
|
||||
var _mitte_sig := "" ## dasselbe für die Liste der gelegten Münzen
|
||||
var _wurf_tween: Tween
|
||||
var _my_values: Array = []
|
||||
var _my_seat := 0
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
_zug_box.bg_color = Color(0.30, 0.24, 0.07, 0.85)
|
||||
_zug_box.set_corner_radius_all(6)
|
||||
_zug_box.border_color = ACCENT
|
||||
_zug_box.set_border_width_all(1)
|
||||
_zug_box.set_content_margin_all(5)
|
||||
_leer_box.set_content_margin_all(5)
|
||||
layer = 1
|
||||
process_mode = Node.PROCESS_MODE_ALWAYS
|
||||
root = Control.new()
|
||||
@@ -300,6 +344,13 @@ func _build() -> void:
|
||||
_place(banner_label, 0, 0, 1, 0, edge, 20, -edge, 150)
|
||||
root.add_child(banner_label)
|
||||
|
||||
# --- Wer ist dran: direkt über der Ansageleiste, wo der Blick ohnehin liegt
|
||||
turn_label = _label("", 19, ACCENT)
|
||||
turn_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
turn_label.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
_place(turn_label, 0, 1, 1, 1, 16, -146, -16, -114)
|
||||
root.add_child(turn_label)
|
||||
|
||||
# --- Ansage: kompakte Leiste unten in der Mitte
|
||||
action_panel = _panel()
|
||||
_slot(0, 1, 1, 1, 16, -110, -16, -16).add_child(action_panel)
|
||||
@@ -376,20 +427,56 @@ func _build() -> void:
|
||||
timer_bid.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
|
||||
av.add_child(timer_bid)
|
||||
|
||||
# --- Handkarten unten links, über der Ansageleiste
|
||||
# --- Münzvorrat unten links, über der Ansageleiste
|
||||
hand_panel = _panel()
|
||||
_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)
|
||||
hand_panel.add_child(hv)
|
||||
hv.add_child(_label("Karten", 13, DIM))
|
||||
hv.add_child(_label("Münzen", 13, DIM))
|
||||
hand_box = HBoxContainer.new()
|
||||
hand_box.add_theme_constant_override("separation", 6)
|
||||
hv.add_child(hand_box)
|
||||
hand_panel.visible = false
|
||||
|
||||
# --- Booster-Overlay
|
||||
# --- Geworfene Münze, links unter der Liste der gelegten Münzen. Die
|
||||
# Tischmitte ist besetzt: dort stehen die Becher und das Gebot.
|
||||
wurf_slot = _slot(0, 0, 0, 0, 16, 100, 336, 300)
|
||||
wurf_slot.visible = false
|
||||
var wv := VBoxContainer.new()
|
||||
wv.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
wv.add_theme_constant_override("separation", 6)
|
||||
wurf_slot.add_child(wv)
|
||||
wurf_icon = MuenzIcon.new("", ACCENT, 104.0)
|
||||
wurf_icon.size_flags_horizontal = Control.SIZE_SHRINK_CENTER
|
||||
wv.add_child(wurf_icon)
|
||||
wurf_label = _label("", 16, ACCENT)
|
||||
wurf_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
wurf_label.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
wv.add_child(wurf_label)
|
||||
|
||||
# --- Erklärung beim Überfahren. Ein eigenes Feld statt Tooltip: das kommt
|
||||
# sofort und verschwindet nicht, wenn die Runde weiterläuft.
|
||||
info_panel = _panel(Color(0.05, 0.06, 0.09, 0.97))
|
||||
info_panel.visible = false
|
||||
info_panel.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
root.add_child(info_panel)
|
||||
var iv := VBoxContainer.new()
|
||||
iv.add_theme_constant_override("separation", 4)
|
||||
info_panel.add_child(iv)
|
||||
info_name = _label("", 16, ACCENT)
|
||||
iv.add_child(info_name)
|
||||
info_desc = _label("", 14, Color(0.82, 0.84, 0.90))
|
||||
info_desc.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||
info_desc.custom_minimum_size = Vector2(INFO_W, 0)
|
||||
iv.add_child(info_desc)
|
||||
info_stark = _label("", 14, ACCENT)
|
||||
info_stark.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||
info_stark.custom_minimum_size = Vector2(INFO_W, 0)
|
||||
iv.add_child(info_stark)
|
||||
|
||||
boost_slot = _slot(0, 0, 1, 1, 0, 0, 0, 0)
|
||||
boost_slot.visible = false
|
||||
boost_panel = _panel(Color(0.05, 0.06, 0.09, 0.97))
|
||||
@@ -397,7 +484,7 @@ func _build() -> void:
|
||||
var bvv := VBoxContainer.new()
|
||||
bvv.add_theme_constant_override("separation", 12)
|
||||
boost_panel.add_child(bvv)
|
||||
boost_title = _label("Wähle einen Booster", 24, ACCENT)
|
||||
boost_title = _label("Wähle eine Münze", 24, ACCENT)
|
||||
boost_title.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
bvv.add_child(boost_title)
|
||||
timer_boost = _label("", 16, DIM)
|
||||
@@ -554,15 +641,20 @@ func update_state(st: Dictionary, my_seat: int) -> void:
|
||||
var s: Dictionary = st.seats[i]
|
||||
var turn: bool = st.phase == "bid" and i == st.turn
|
||||
var col := ACCENT if turn else (Color.WHITE if s.alive else DIM)
|
||||
# Wer dran ist, bekommt eine hinterlegte Zeile. Ein Pfeil und etwas
|
||||
# Farbe gehen in der Liste unter.
|
||||
var zeile := PanelContainer.new()
|
||||
zeile.add_theme_stylebox_override("panel", _zug_box if turn else _leer_box)
|
||||
players_box.add_child(zeile)
|
||||
var entry := VBoxContainer.new()
|
||||
entry.add_theme_constant_override("separation", 2)
|
||||
players_box.add_child(entry)
|
||||
zeile.add_child(entry)
|
||||
var nm := _label(("▸ " if turn else "") + _short(String(s.name)) + (" (KI)" if s.ai else ""), 14, col)
|
||||
nm.clip_text = true
|
||||
nm.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS
|
||||
entry.add_child(nm)
|
||||
if not s.alive:
|
||||
entry.add_child(_label(" ausgeschieden", 13, DIM))
|
||||
entry.add_child(_label("ausgeschieden", 13, DIM))
|
||||
continue
|
||||
var row := HBoxContainer.new()
|
||||
row.add_theme_constant_override("separation", 4)
|
||||
@@ -595,35 +687,24 @@ func update_state(st: Dictionary, my_seat: int) -> void:
|
||||
|
||||
_zeichne_hand(st)
|
||||
|
||||
_clear(boosts_box)
|
||||
var boosts: Array = st.get("boosts", [])
|
||||
var any := false
|
||||
for i in mini(boosts.size(), st.seats.size()):
|
||||
if String(boosts[i]) == "":
|
||||
continue
|
||||
any = true
|
||||
var b: Dictionary = BoosterDB.get_booster(String(boosts[i]))
|
||||
var line := HBoxContainer.new()
|
||||
line.add_theme_constant_override("separation", 5)
|
||||
boosts_box.add_child(line)
|
||||
line.add_child(_label(_short(String(st.seats[i].name)) + ":", 14,
|
||||
ACCENT if i == my_seat else Color(0.78, 0.80, 0.86)))
|
||||
var kind := Color(0.5, 0.9, 0.6) if b.kind == BoosterDB.Kind.BUFF else Color(0.95, 0.5, 0.5)
|
||||
line.add_child(_label(String(b.get("name", "")), 14, kind))
|
||||
if int(st.min_raise) > 1:
|
||||
boosts_box.add_child(_label("Störfeuer: mind. %d erhöhen" % st.min_raise, 14, ACCENT))
|
||||
any = true
|
||||
if st.must_bid:
|
||||
boosts_box.add_child(_label("Maulkorb: du musst bieten", 14, ACCENT))
|
||||
any = true
|
||||
if not any:
|
||||
boosts_box.add_child(_label("Keine Karte gespielt", 14, DIM))
|
||||
_zeichne_mitte(st, my_seat)
|
||||
|
||||
banner_label.text = st.banner
|
||||
|
||||
var my_turn: bool = st.phase == "bid" and st.turn == my_seat and st.seats[my_seat].alive
|
||||
var kam_dran := my_turn and not _my_turn
|
||||
_my_turn = my_turn
|
||||
if st.phase == "bid" and int(st.turn) < st.seats.size():
|
||||
var wer := "%s ist dran" % _short(String(st.seats[st.turn].name))
|
||||
if my_turn:
|
||||
turn_label.text = "Du bist dran"
|
||||
elif not st.seats[my_seat].alive:
|
||||
turn_label.text = "Du bist raus · " + wer
|
||||
else:
|
||||
turn_label.text = wer
|
||||
turn_label.add_theme_color_override("font_color", ACCENT if my_turn else DIM)
|
||||
else:
|
||||
turn_label.text = ""
|
||||
action_panel.modulate = Color(1, 1, 1, 1.0 if my_turn else 0.45)
|
||||
bid_btn.disabled = not my_turn
|
||||
_count_max = maxi(1, int(st.total))
|
||||
@@ -665,7 +746,7 @@ func _process(_delta: float) -> void:
|
||||
timer_bid.text = text if wants_bid else ""
|
||||
timer_bid.add_theme_color_override("font_color", col)
|
||||
# Läuft die Ansagezeit ab, während die Würfelauswahl offen steht, wird
|
||||
# automatisch angesagt - die Karte bleibt dann ungespielt auf der Hand.
|
||||
# automatisch angesagt - die Münze bleibt dann ungeworfen liegen.
|
||||
timer_boost.text = "Noch %s bis zur Ansage" % text if wants_boost else ""
|
||||
timer_boost.add_theme_color_override("font_color", col)
|
||||
|
||||
@@ -698,10 +779,10 @@ func _seat_dice(st: Dictionary, seat: int, my_seat: int) -> Array:
|
||||
for _k in int(st.seats[seat].count):
|
||||
out.append(-1)
|
||||
var peek: Dictionary = st.peek
|
||||
if peek.has(seat):
|
||||
var idx := int(peek[seat][0])
|
||||
for paar: Array in peek.get(seat, []):
|
||||
var idx := int(paar[0])
|
||||
if idx >= 0 and idx < out.size():
|
||||
out[idx] = int(peek[seat][1])
|
||||
out[idx] = int(paar[1])
|
||||
return out
|
||||
|
||||
|
||||
@@ -711,52 +792,215 @@ func set_banner(text: String) -> void:
|
||||
|
||||
# ---------------------------------------------------------------- Booster
|
||||
|
||||
## Die Hand liegt offen unten links. Ein Klick spielt die Karte sofort;
|
||||
## nur Karten mit eigenem Ziel fragen noch nach dem Würfel.
|
||||
## Der Vorrat liegt offen unten links. Ein Klick wirft die Münze sofort; nur
|
||||
## Münzen mit eigenem Ziel fragen noch nach dem Würfel. Die Wirkung steht im
|
||||
## Tooltip - auf eine Münze passt nur das Sinnbild.
|
||||
func _zeichne_hand(st: Dictionary) -> void:
|
||||
if hand_box == null:
|
||||
return
|
||||
var karten: Array = st.get("hand", [])
|
||||
hand_panel.visible = not karten.is_empty()
|
||||
_clear(hand_box)
|
||||
var muenzen: Array = st.get("hand", [])
|
||||
# Wer raus ist, schaut nur noch zu. Münzen, die er nie werfen kann,
|
||||
# stünden nur klickbar im Weg.
|
||||
var dabei: bool = _my_seat < st.seats.size() and st.seats[_my_seat].alive
|
||||
hand_panel.visible = dabei and not muenzen.is_empty()
|
||||
var spielbar: bool = st.phase == "bid"
|
||||
for id: String in karten:
|
||||
# Jeder Zustand kommt mehrmals an. Ein Neuaufbau würde die Münze unter dem
|
||||
# Zeiger wegreissen und die Erklärung mitnehmen.
|
||||
var sig := "%s|%s" % [muenzen, spielbar]
|
||||
if sig == _hand_sig:
|
||||
return
|
||||
_hand_sig = sig
|
||||
_clear(hand_box)
|
||||
for id: String in muenzen:
|
||||
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 col := _kind_col(b)
|
||||
|
||||
var btn := Button.new()
|
||||
btn.custom_minimum_size = Vector2(168, 132)
|
||||
btn.tooltip_text = String(b.desc)
|
||||
btn.custom_minimum_size = Vector2(104, 120)
|
||||
btn.disabled = not spielbar
|
||||
# Ein gesperrter Knopf meldet keine Maus mehr; die Erklärung soll aber
|
||||
# auch dann kommen, wenn gerade nicht geworfen werden darf.
|
||||
btn.mouse_filter = Control.MOUSE_FILTER_STOP
|
||||
btn.pressed.connect(_pick.bind(id))
|
||||
hand_box.add_child(btn)
|
||||
_info_an(btn, id, false, hand_panel)
|
||||
|
||||
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.offset_top = 8
|
||||
v.offset_bottom = -6
|
||||
v.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
v.add_theme_constant_override("separation", 2)
|
||||
v.add_theme_constant_override("separation", 4)
|
||||
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 ic := MuenzIcon.new(id, col, 72.0)
|
||||
ic.size_flags_horizontal = Control.SIZE_SHRINK_CENTER
|
||||
v.add_child(ic)
|
||||
|
||||
var name_l := _label(String(b.name), 15, col)
|
||||
var name_l := _label(String(b.name), 14, col)
|
||||
name_l.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
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)
|
||||
|
||||
|
||||
## Was liegt in der Mitte, plus die Wirkungen, die gerade auf einem liegen.
|
||||
## Auch hier gilt: nur neu bauen, wenn sich etwas geändert hat.
|
||||
func _zeichne_mitte(st: Dictionary, my_seat: int) -> void:
|
||||
var boosts: Array = st.get("boosts", [])
|
||||
# Der neueste Wurf muss bei jedem Zustand geprüft werden, auch ohne Neubau.
|
||||
var neu := {}
|
||||
for i in mini(boosts.size(), st.seats.size()):
|
||||
var m: Dictionary = boosts[i]
|
||||
if not m.is_empty() and int(m.get("nr", 0)) > int(neu.get("nr", 0)):
|
||||
neu = {"nr": m.get("nr", 0), "id": m.get("id", ""),
|
||||
"stark": m.get("stark", false), "seat": i}
|
||||
_pruefe_wurf(neu, st)
|
||||
|
||||
var sig := "%s|%s|%s" % [boosts, st.min_raise, st.must_bid]
|
||||
if sig == _mitte_sig:
|
||||
return
|
||||
_mitte_sig = sig
|
||||
_clear(boosts_box)
|
||||
|
||||
var any := false
|
||||
for i in mini(boosts.size(), st.seats.size()):
|
||||
var m: Dictionary = boosts[i]
|
||||
if m.is_empty():
|
||||
continue
|
||||
var id := String(m.get("id", ""))
|
||||
var b: Dictionary = BoosterDB.get_booster(id)
|
||||
if b.is_empty():
|
||||
continue
|
||||
any = true
|
||||
var line := HBoxContainer.new()
|
||||
line.add_theme_constant_override("separation", 5)
|
||||
# Der Container muss die Maus annehmen, sonst gibt es kein Überfahren.
|
||||
line.mouse_filter = Control.MOUSE_FILTER_STOP
|
||||
boosts_box.add_child(line)
|
||||
_info_an(line, id, true)
|
||||
line.add_child(MuenzIcon.new(id, _kind_col(b), 22.0))
|
||||
line.add_child(_label(_short(String(st.seats[i].name)) + ":", 14,
|
||||
ACCENT if i == my_seat else Color(0.78, 0.80, 0.86)))
|
||||
line.add_child(_label(String(b.get("name", "")), 14, _kind_col(b)))
|
||||
if bool(m.get("stark", false)):
|
||||
line.add_child(_label("· Wappen", 14, ACCENT))
|
||||
if int(st.min_raise) > 1:
|
||||
boosts_box.add_child(_label("Störfeuer: mind. %d erhöhen" % st.min_raise, 14, ACCENT))
|
||||
any = true
|
||||
if st.must_bid:
|
||||
boosts_box.add_child(_label("Maulkorb: du musst bieten", 14, ACCENT))
|
||||
any = true
|
||||
if not any:
|
||||
boosts_box.add_child(_label("Keine Münze in der Mitte", 14, DIM))
|
||||
|
||||
|
||||
## Erklärung zu einer Münze, sobald die Maus daraufliegt. `unter` legt sie
|
||||
## unter das Feld statt darüber - oben links wäre sonst kein Platz. `anker`
|
||||
## ist, woran sie sich ausrichtet: beim Vorrat das ganze Feld, sonst läge sie
|
||||
## halb über dessen Überschrift.
|
||||
func _info_an(ctrl: Control, id: String, unter: bool, anker: Control = null) -> void:
|
||||
var an: Control = anker if anker != null else ctrl
|
||||
ctrl.mouse_entered.connect(_info_zeigen.bind(ctrl, id, unter, an))
|
||||
ctrl.mouse_exited.connect(_info_weg.bind(ctrl))
|
||||
|
||||
|
||||
func _info_zeigen(ctrl: Control, id: String, unter: bool, anker: Control) -> void:
|
||||
var b: Dictionary = BoosterDB.get_booster(id)
|
||||
if b.is_empty():
|
||||
return
|
||||
_info_ctrl = ctrl
|
||||
info_panel.visible = false
|
||||
info_name.text = String(b.name)
|
||||
info_desc.text = String(b.desc)
|
||||
info_stark.text = "Wappen: %s" % b.get("stark", "")
|
||||
# Die Höhe steht erst nach dem Umbruch fest, deshalb ein Bild später
|
||||
# setzen. Bis dahin bleibt das Feld unsichtbar, sonst springt es.
|
||||
await get_tree().process_frame
|
||||
if _info_ctrl != ctrl or not is_instance_valid(ctrl) or not is_instance_valid(anker):
|
||||
return
|
||||
info_panel.reset_size()
|
||||
var gr := info_panel.size
|
||||
var r := anker.get_global_rect()
|
||||
var y: float = r.position.y + r.size.y + 8.0 if unter else r.position.y - gr.y - 8.0
|
||||
info_panel.position = Vector2(
|
||||
clampf(r.position.x, 8.0, maxf(8.0, root.size.x - gr.x - 8.0)),
|
||||
clampf(y, 8.0, maxf(8.0, root.size.y - gr.y - 8.0)))
|
||||
info_panel.visible = true
|
||||
|
||||
|
||||
func _info_weg(ctrl: Control) -> void:
|
||||
if _info_ctrl != ctrl:
|
||||
return
|
||||
_info_ctrl = null
|
||||
info_panel.visible = false
|
||||
|
||||
|
||||
func _kind_col(b: Dictionary) -> Color:
|
||||
return Color(0.5, 0.9, 0.6) if b.kind == BoosterDB.Kind.BUFF else Color(0.95, 0.5, 0.5)
|
||||
|
||||
|
||||
## Jeder Wurf hat eine laufende Nummer. Steigt sie, ist eine neue Münze
|
||||
## gefallen und wird gezeigt. Zu Rundenbeginn ist die Mitte leer, dann faengt
|
||||
## die Zählung wieder bei null an.
|
||||
func _pruefe_wurf(neu: Dictionary, st: Dictionary) -> void:
|
||||
var nr := int(neu.get("nr", 0))
|
||||
if nr == 0:
|
||||
_letzter_wurf = 0
|
||||
return
|
||||
if nr <= _letzter_wurf:
|
||||
return
|
||||
_letzter_wurf = nr
|
||||
var seat := int(neu.get("seat", 0))
|
||||
_zeig_wurf(String(neu.get("id", "")), bool(neu.get("stark", false)),
|
||||
_short(String(st.seats[seat].name)))
|
||||
|
||||
|
||||
## Der Ausgang steht schon fest - der Host hat ihn ausgewürfelt. Die Drehung
|
||||
## ist nur die Ansicht dazu und endet auf der richtigen Seite.
|
||||
func _zeig_wurf(id: String, stark: bool, wer: String) -> void:
|
||||
var b: Dictionary = BoosterDB.get_booster(id)
|
||||
if b.is_empty():
|
||||
return
|
||||
wurf_icon.id = id
|
||||
wurf_icon.kind_col = _kind_col(b)
|
||||
wurf_icon.seite = 0
|
||||
wurf_icon.scale = Vector2.ONE
|
||||
wurf_icon.queue_redraw()
|
||||
wurf_label.text = "%s wirft\n%s" % [wer, b.name]
|
||||
wurf_label.add_theme_color_override("font_color", DIM)
|
||||
wurf_slot.visible = true
|
||||
if _wurf_tween != null and _wurf_tween.is_valid():
|
||||
_wurf_tween.kill()
|
||||
_wurf_tween = create_tween()
|
||||
_wurf_tween.tween_method(_dreh, 0.0, TAU * 2.5, 0.8)
|
||||
_wurf_tween.tween_callback(_wurf_ende.bind(stark, b))
|
||||
_wurf_tween.tween_interval(1.6)
|
||||
_wurf_tween.tween_callback(func() -> void: wurf_slot.visible = false)
|
||||
|
||||
|
||||
## Die Münze wird waagerecht gestaucht; bei negativer Breite sieht man die
|
||||
## Rückseite. Das ist eine Drehung, ohne dass etwas in 3D stehen muss.
|
||||
func _dreh(winkel: float) -> void:
|
||||
var c := cos(winkel)
|
||||
wurf_icon.scale.x = maxf(0.06, absf(c))
|
||||
var seite := 0 if c >= 0.0 else 1
|
||||
if wurf_icon.seite != seite:
|
||||
wurf_icon.seite = seite
|
||||
wurf_icon.queue_redraw()
|
||||
|
||||
|
||||
func _wurf_ende(stark: bool, b: Dictionary) -> void:
|
||||
wurf_icon.scale.x = 1.0
|
||||
wurf_icon.seite = 0 if stark else 1
|
||||
wurf_icon.queue_redraw()
|
||||
if stark:
|
||||
wurf_label.text = "%s\nWappen - verstärkt" % b.name
|
||||
wurf_label.add_theme_color_override("font_color", ACCENT)
|
||||
else:
|
||||
wurf_label.text = "%s\nZahl - Grundwirkung" % b.name
|
||||
wurf_label.add_theme_color_override("font_color", DIM)
|
||||
|
||||
|
||||
func _pick(id: String) -> void:
|
||||
|
||||
Reference in New Issue
Block a user