Booster-Phase raus, Karten auf die Hand

Die Boosterwahl kostete jede Runde eine eigene Phase mit 30 Sekunden Frist.
Zwischen Wurf und Ansage lag damit eine Wartezeit, die den Ablauf zerriss.

Jetzt gibt es Karten statt einer Phase:

* Wer einen Wuerfel abgibt, zieht eine Karte. Das ist der einzige Nachschub,
  also bekommt der etwas zurueck, der gerade hinten liegt.
* Gespielt wird jederzeit waehrend der Ansagen, nicht nur am eigenen Zug.
* Hoechstens drei Karten auf der Hand.
* Die Hand liegt offen unten links, ein Klick spielt. Nur Feinschliff und
  Gluecksgriff fragen noch nach dem Wuerfel.

Der Katalog ist angepasst, weil jede Karte jetzt sofort wirken muss:
neu sind Erhoehen (Ansage +1), Widerruf (hebt Nebel, Stoerfeuer und Maulkorb
auf dir auf) und Nachschub (ein Wuerfel dazu). Zwilling und Ruetteln sind
raus - beide brauchten den festen Zeitpunkt vor dem Wurf.

Bots spielen ihre Karten am eigenen Zug, bei voller Hand immer.

Zwei Karten gleichzeitig wuerden sich beim Wuerfeln in die Quere kommen,
deshalb wird immer nur eine aufgeloest.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
team3
2026-09-08 16:11:07 +02:00
parent 318f9f3159
commit 3f4532ad59
5 changed files with 219 additions and 240 deletions

View File

@@ -39,6 +39,8 @@ var bid_btn: Button
var challenge_btn: Button
var action_panel: PanelContainer
var hand_panel: PanelContainer
var hand_box: HBoxContainer
var boost_slot: CenterContainer
var pause_slot: Control
var pause_hint: Label
@@ -278,6 +280,19 @@ func _build() -> void:
timer_bid.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
av.add_child(timer_bid)
# --- Handkarten unten links, über der Ansageleiste
hand_panel = _panel()
_place(hand_panel, 0, 1, 0, 1, 16, -190, 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))
hand_box = HBoxContainer.new()
hand_box.add_theme_constant_override("separation", 6)
hv.add_child(hand_box)
hand_panel.visible = false
# --- Booster-Overlay
boost_slot = _slot(0, 0, 1, 1, 0, 0, 0, 0)
boost_slot.visible = false
@@ -482,6 +497,8 @@ func update_state(st: Dictionary, my_seat: int) -> void:
bg = ROT
bid_row.add_child(DieIcon.new(int(st.bid.face), px, bg))
_zeichne_hand(st)
_clear(boosts_box)
var boosts: Array = st.get("boosts", [])
var any := false
@@ -504,7 +521,7 @@ func update_state(st: Dictionary, my_seat: int) -> void:
boosts_box.add_child(_label("Maulkorb: du musst bieten", 14, ACCENT))
any = true
if not any:
boosts_box.add_child(_label("Keine Booster aktiv", 14, DIM))
boosts_box.add_child(_label("Keine Karte gespielt", 14, DIM))
banner_label.text = st.banner
@@ -551,7 +568,9 @@ func _process(_delta: float) -> void:
var col := Color(0.95, 0.45, 0.4) if left <= 10.0 else DIM
timer_bid.text = text if wants_bid else ""
timer_bid.add_theme_color_override("font_color", col)
timer_boost.text = "Noch %s - danach wird zufällig gewählt" % text if wants_boost else ""
# Läuft die Ansagezeit ab, während die Würfelauswahl offen steht, wird
# automatisch angesagt - die Karte bleibt dann ungespielt auf der Hand.
timer_boost.text = "Noch %s bis zur Ansage" % text if wants_boost else ""
timer_boost.add_theme_color_override("font_color", col)
@@ -596,32 +615,29 @@ func set_banner(text: String) -> void:
# ---------------------------------------------------------------- Booster
func show_booster_offer(ids: Array, values: Array) -> void:
_my_values = values
_pending_boost = ""
target_row.visible = false
boost_title.text = "Wähle einen Booster"
_clear(boost_cards)
for id: String in ids:
## Die Hand liegt offen unten links. Ein Klick spielt die Karte sofort;
## nur Karten mit eigenem Ziel fragen noch nach dem Würfel.
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 spielbar: bool = st.phase == "bid"
for id: String in karten:
var b: Dictionary = BoosterDB.get_booster(id)
var card := _panel(Color(0.10, 0.12, 0.17, 0.98))
card.custom_minimum_size = Vector2(210, 170)
var v := VBoxContainer.new()
v.add_theme_constant_override("separation", 6)
card.add_child(v)
var kind_col := Color(0.5, 0.9, 0.6) if b.kind == BoosterDB.Kind.BUFF else Color(0.95, 0.5, 0.5)
v.add_child(_label("BUFF" if b.kind == BoosterDB.Kind.BUFF else "DEBUFF", 12, kind_col))
v.add_child(_label(b.name, 20, ACCENT))
var d := _label(b.desc, 14, Color(0.8, 0.82, 0.88))
d.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
d.custom_minimum_size = Vector2(190, 60)
v.add_child(d)
if b.is_empty():
continue
var btn := Button.new()
btn.text = "Wählen"
btn.text = String(b.name)
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))
v.add_child(btn)
boost_cards.add_child(card)
boost_slot.visible = true
hand_box.add_child(btn)
func _pick(id: String) -> void:
@@ -633,6 +649,7 @@ func _pick(id: String) -> void:
boost_title.text = "%s - welchen Würfel?" % BoosterDB.get_booster(id).name
_clear(boost_cards)
_clear(target_row)
boost_slot.visible = true
for i in _my_values.size():
var b := Button.new()
b.custom_minimum_size = Vector2(56, 56)