Files
dreamer-game/scripts/ui.gd
2026-09-01 13:07:02 +02:00

633 lines
21 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
extends CanvasLayer
class_name UI
signal panel_opened
signal panel_closed
const BREITE := 900
var offen := false
var _kind := ""
var _hud: RichTextLabel
var _hinweis: Label
var _log: VBoxContainer
var _dim: ColorRect
var _panel: PanelContainer
var _titel: Label
var _content: VBoxContainer
var _scroll: ScrollContainer
var _apply_human: Node3D
var _journal_seite := "techniken"
var _scroll_wunsch := 0
var _scroll_frames := 0
var _on_travel: Callable
func _ready() -> void:
layer = 10
_baue_hud()
_baue_panel()
Game.notified.connect(_notiz)
Game.state_changed.connect(_hud_aktualisieren)
_hud_aktualisieren()
func _baue_hud() -> void:
_hud = RichTextLabel.new()
_hud.bbcode_enabled = true
_hud.fit_content = true
_hud.scroll_active = false
_hud.set_anchors_preset(Control.PRESET_TOP_LEFT)
_hud.position = Vector2(18, 14)
_hud.custom_minimum_size = Vector2(420, 130)
_hud.size = Vector2(420, 130)
_hud.mouse_filter = Control.MOUSE_FILTER_IGNORE
_hud.add_theme_font_size_override("normal_font_size", 17)
_hud.add_theme_font_size_override("bold_font_size", 17)
add_child(_hud)
var steuerung := Label.new()
steuerung.text = "WASD Bewegen · Maus Umsehen · E Interagieren · J Journal · 1/2/3 Tempo · Esc Maus frei"
steuerung.set_anchors_preset(Control.PRESET_TOP_RIGHT)
steuerung.position = Vector2(-640, 16)
steuerung.size = Vector2(620, 24)
steuerung.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT
steuerung.add_theme_font_size_override("font_size", 14)
steuerung.add_theme_color_override("font_color", Color(1, 1, 1, 0.65))
steuerung.mouse_filter = Control.MOUSE_FILTER_IGNORE
add_child(steuerung)
_hinweis = Label.new()
_hinweis.set_anchors_preset(Control.PRESET_CENTER_BOTTOM)
_hinweis.position = Vector2(-300, -110)
_hinweis.size = Vector2(600, 30)
_hinweis.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
_hinweis.add_theme_font_size_override("font_size", 19)
_hinweis.add_theme_color_override("font_color", Color(1, 0.95, 0.75))
_hinweis.add_theme_color_override("font_outline_color", Color(0, 0, 0, 0.9))
_hinweis.add_theme_constant_override("outline_size", 6)
_hinweis.mouse_filter = Control.MOUSE_FILTER_IGNORE
add_child(_hinweis)
_log = VBoxContainer.new()
_log.set_anchors_preset(Control.PRESET_BOTTOM_RIGHT)
_log.position = Vector2(-520, -230)
_log.size = Vector2(500, 200)
_log.alignment = BoxContainer.ALIGNMENT_END
_log.mouse_filter = Control.MOUSE_FILTER_IGNORE
add_child(_log)
func _baue_panel() -> void:
_dim = ColorRect.new()
_dim.color = Color(0, 0, 0, 0.62)
_dim.set_anchors_preset(Control.PRESET_FULL_RECT)
_dim.visible = false
add_child(_dim)
_panel = PanelContainer.new()
_panel.set_anchors_preset(Control.PRESET_CENTER)
_panel.custom_minimum_size = Vector2(BREITE, 200)
_panel.visible = false
var sb := StyleBoxFlat.new()
sb.bg_color = Color(0.10, 0.09, 0.16, 0.98)
sb.border_color = Color(0.55, 0.70, 1.0, 0.8)
sb.set_border_width_all(2)
sb.set_corner_radius_all(10)
sb.set_content_margin_all(22)
_panel.add_theme_stylebox_override("panel", sb)
add_child(_panel)
var vb := VBoxContainer.new()
vb.add_theme_constant_override("separation", 10)
_panel.add_child(vb)
_titel = Label.new()
_titel.add_theme_font_size_override("font_size", 26)
_titel.add_theme_color_override("font_color", Color(1, 0.93, 0.75))
vb.add_child(_titel)
_scroll = ScrollContainer.new()
_scroll.custom_minimum_size = Vector2(BREITE - 44, 140)
_scroll.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED
vb.add_child(_scroll)
var scroll := _scroll
_content = VBoxContainer.new()
_content.custom_minimum_size.x = BREITE - 70
_content.add_theme_constant_override("separation", 10)
scroll.add_child(_content)
var fuss := Label.new()
fuss.text = "Esc schließt"
fuss.add_theme_font_size_override("font_size", 14)
fuss.add_theme_color_override("font_color", Color(1, 1, 1, 0.5))
vb.add_child(fuss)
func _process(_delta: float) -> void:
if not offen:
_hud_aktualisieren()
else:
var wunsch := _content.get_combined_minimum_size().y
var platz := get_viewport().get_visible_rect().size.y - 220.0
_scroll.custom_minimum_size.y = clampf(wunsch, 120.0, platz)
_panel.reset_size() # sonst behält der Rahmen die Höhe des Panels davor
if _scroll_frames > 0:
_scroll.scroll_vertical = _scroll_wunsch
_scroll_frames -= 1
_panel.position = (get_viewport().get_visible_rect().size - _panel.size) * 0.5
# ------------------------------------------------------------------ HUD
func _hud_aktualisieren() -> void:
var zeilen: Array = []
var takt := ("[color=#aaaaaa]Tempo %d (%d×)[/color]"
% [Game.tempo, int(Game.faktor_von(Game.tempo))])
if Game.schlaeft_ziel():
takt = ("[color=#9fb6ff]Tempo 3 (%d×) · Nachtsprung[/color]"
% int(Game.faktor_von(3)))
zeilen.append("[b]%s[/b] %s" % [Game.time_string(), takt])
zeilen.append("Techniken: [b]%d[/b] gelernt · [b]%d[/b] entdeckt · %d im Spiel" %
[Game.known.size(), Game.offene_techniken(), TechDB.LIST.size()])
if Game.active_mission != "":
var h := HumanDB.by_id(Game.active_mission)
zeilen.append("Mission: [color=#ffdd77]%s[/color] — %d %% · %d %% je Tag" %
[h["name"], int(Game.mission_progress(Game.active_mission)),
int(round(Game.traum_tempo(Game.active_mission)))])
zeilen.append("[color=#aaaaaa]%s[/color]" % h["traum"])
elif Game.completed.size() >= HumanDB.LIST.size():
zeilen.append("[color=#88ff99]Alle Träume erfüllt.[/color]")
else:
zeilen.append("[color=#aaaaaa]Keine Mission. Schwarzes Brett am Dorfplatz.[/color]")
_hud.text = "\n".join(zeilen)
func setze_hinweis(text: String) -> void:
_hinweis.text = text
func _notiz(text: String, farbe: Color) -> void:
var l := Label.new()
l.text = text
l.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT
l.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
l.custom_minimum_size.x = 500
l.add_theme_font_size_override("font_size", 16)
l.add_theme_color_override("font_color", farbe)
l.add_theme_color_override("font_outline_color", Color(0, 0, 0, 0.9))
l.add_theme_constant_override("outline_size", 5)
_log.add_child(l)
while _log.get_child_count() > 6:
var alt := _log.get_child(0)
_log.remove_child(alt)
alt.queue_free()
var tw := l.create_tween()
tw.tween_interval(6.0)
tw.tween_property(l, "modulate:a", 0.0, 1.5)
tw.tween_callback(l.queue_free)
# ------------------------------------------------------------------ Panel
func _leeren(titel: String) -> void:
for c in _content.get_children():
_content.remove_child(c)
c.queue_free()
_titel.text = titel
func _text(bb: String, groesse: int = 17) -> RichTextLabel:
var r := RichTextLabel.new()
r.bbcode_enabled = true
r.fit_content = true
r.scroll_active = false
r.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
r.custom_minimum_size.x = BREITE - 80
r.text = bb
r.add_theme_font_size_override("normal_font_size", groesse)
r.add_theme_font_size_override("bold_font_size", groesse)
_content.add_child(r)
return r
func _knopf(beschriftung: String, cb: Callable, aktiv: bool = true) -> Button:
var b := Button.new()
b.text = beschriftung
b.disabled = not aktiv
b.custom_minimum_size = Vector2(0, 38)
b.add_theme_font_size_override("font_size", 17)
_content.add_child(b)
if aktiv:
b.pressed.connect(cb)
return b
func _trenner() -> void:
var s := HSeparator.new()
_content.add_child(s)
func _zeigen(kind: String) -> void:
_kind = kind
offen = true
_dim.visible = true
_panel.visible = true
_panel.reset_size()
panel_opened.emit()
func schliessen() -> void:
if not offen:
return
offen = false
_kind = ""
_apply_human = null
_dim.visible = false
_panel.visible = false
panel_closed.emit()
func _hinweis_block(t: Dictionary) -> String:
return ("[b]Was:[/b] %s\n[b]Wann:[/b] %s\n[b]Warum:[/b] %s\n" +
"[color=#9fb6ff][b]Zu sehen an:[/b] %s[/color]") % \
[t["was"], t["wann"], t["warum"], t["woran"]]
# -------------------------------------------------------- Journal
## Das Journal ist immer dabei und führt Buch: welche Techniken du gelernt hast
## und welche Missionen du angenommen hast. Gelehrt wird im Hörsaal,
## vergeben werden die Missionen am Schwarzen Brett.
func journal_panel(seite: String = "") -> void:
if seite != "":
_journal_seite = seite
var scroll_alt := _scroll.scroll_vertical if offen and _kind == "journal" else 0
_leeren("Journal")
_reiter()
if _journal_seite == "missionen":
_journal_missionen()
else:
_journal_techniken()
_zeigen("journal")
_scroll_wunsch = scroll_alt
_scroll_frames = 4
func _reiter() -> void:
var hb := HBoxContainer.new()
hb.add_theme_constant_override("separation", 8)
_content.add_child(hb)
var seiten := [
["techniken", "Techniken (%d)" % Game.known.size()],
["missionen", "Missionen (%d)" % Game.progress.size()],
]
for eintrag in seiten:
var b := Button.new()
b.text = eintrag[1]
b.custom_minimum_size = Vector2(0, 36)
b.size_flags_horizontal = Control.SIZE_EXPAND_FILL
b.add_theme_font_size_override("font_size", 17)
b.disabled = _journal_seite == eintrag[0]
if b.disabled:
b.add_theme_color_override("font_disabled_color", Color(1, 0.88, 0.55))
hb.add_child(b)
if not b.disabled:
b.pressed.connect(func() -> void: journal_panel(eintrag[0]))
var mission := "keine"
if Game.active_mission != "":
mission = "%s (%d %%)" % [HumanDB.by_id(Game.active_mission)["name"],
int(Game.mission_progress(Game.active_mission))]
_text("[color=#aaaaaa]Mission: %s[/color]" % mission, 15)
_trenner()
func _journal_techniken() -> void:
if Game.known.is_empty():
_text("[color=#ffcc66]Du hast noch keine Technik gelernt.[/color]\n" +
"Im [b]Hörsaal der Wege[/b] hinter dem Dorfplatz werden sie gelehrt.", 16)
return
_text("Was du gelernt hast. Besser wird eine Technik nur, indem du sie draußen " +
"anwendest — Üben lässt sie sich nicht.", 15)
_trenner()
for id in TechDB.ids():
if not Game.knows(id):
continue
var t := TechDB.by_id(id)
_text("[b][color=#ffe3a0]%s[/color][/b] · Stufe %d (%s)" %
[t["name"], Game.skill_of(id), Game.xp_to_next(id)], 18)
_text(_hinweis_block(t), 15)
_trenner()
func _journal_missionen() -> void:
if Game.progress.is_empty():
_text("[color=#ffcc66]Du hast noch keine Mission angenommen.[/color]\n" +
"Am [b]Schwarzen Brett[/b] am Dorfplatz hängen die Menschen aus, " +
"die nicht weiterkommen.", 16)
return
_text("Die Menschen, für die du dich entschieden hast.", 15)
_trenner()
for h in HumanDB.LIST:
var id: String = h["id"]
if not Game.angenommen(id):
continue
_text("[b][color=#ffe3a0]%s[/color][/b], %d — %s" %
[h["name"], h["alter"], h["beruf"]], 18)
_text("[b]Traum:[/b] %s" % h["traum"], 16)
_text("[b]Was im Weg steht:[/b] %s" % h["problem"], 15)
if Game.completed.has(id):
_text("[color=#88ff99]★ Der Traum ist erfüllt.[/color]", 15)
elif Game.active_mission == id:
_text("[color=#ffdd77]Aktive Mission — %d %%[/color]" %
int(Game.mission_progress(id)), 15)
else:
_text("[color=#aaaaaa]Zurückgestellt — %d %%[/color]" %
int(Game.mission_progress(id)), 15)
if not Game.completed.has(id):
_knopf("Tagesablauf — %d Systeme" % Game.system_anzahl(id),
func() -> void: systeme_panel(id))
_trenner()
# ---------------------------------------------- Diagnose und Systeme
## Der Traum scheitert an Ursachen. Die stehen nicht im Panel -- man findet sie,
## indem man dabeisteht. Gegen jede gefundene Ursache baut man ein System in
## den Tag. Je mehr abgedeckt ist, desto schneller kommt der Traum voran.
func systeme_panel(human_id: String) -> void:
var scroll_alt := _scroll.scroll_vertical if offen and _kind == "systeme" else 0
var h := HumanDB.by_id(human_id)
_leeren("%s — Tagesablauf" % h["name"])
_text("[b]Traum:[/b] %s" % h["traum"], 16)
_text("[b]Fortschritt:[/b] %d %% · [b]Tempo:[/b] %d %% je Tag" %
[int(Game.mission_progress(human_id)), int(round(Game.traum_tempo(human_id)))], 16)
_trenner()
_text("[b]Woran es scheitert[/b]", 17)
var offene := 0
for u in Game.ursachen_von(human_id):
var name: String = str(u)
if not Game.ursache_bekannt(human_id, name):
_text("[color=#8e93a8]? — noch nicht erkannt[/color]", 15)
offene += 1
continue
var g := Game.ursache_geloest(human_id, name)
var stand := "[color=#88ff99]gelöst[/color]" if g > 0.0 else \
"[color=#ff9977]offen · bremst auf %d %%[/color]" % \
int(float(Ursachen.LISTE[name]["faktor"]) * 100.0)
_text("[b]%s[/b] — %s %s" % [Ursachen.LISTE[name]["name"],
Ursachen.LISTE[name]["kurz"], stand], 15)
if offene > 0:
_text("[color=#aaaaaa]Steh dabei, wenn sie etwas tut, das du noch nicht " +
"kennst. Dann zeigt sich, warum.[/color]", 14)
_trenner()
_text("[b]Ihr Tag[/b]", 17)
for nr in range(Game.slots(human_id).size()):
_slot_zeile(human_id, nr)
_trenner()
_knopf("Zurück zum Journal", func() -> void: journal_panel("missionen"))
_zeigen("systeme")
_scroll_wunsch = scroll_alt
_scroll_frames = 4
func _slot_zeile(human_id: String, nr: int) -> void:
var slot: Array = Game.slots(human_id)[nr]
var stunde := "%02d:00" % int(slot[0])
var grund := Game.slot_grund(human_id, nr)
if grund == "schlaeft":
_knopf("%s schläft" % stunde, func() -> void: pass, false)
return
var sys := Game.system_in(human_id, nr)
if not sys.is_empty():
_knopf("%s %s ← %s" % [stunde, Game.slot_aktivitaet(human_id, nr),
TechDB.by_id(str(sys["tech"]))["name"]],
func() -> void: slot_panel(human_id, nr))
return
if not Game.erkannt(human_id, nr):
_knopf("%s ?" % stunde, func() -> void: pass, false)
return
var text := Orte.text(grund)
if Ursachen.ist_blocker(grund):
text = "%s (%s)" % [Ursachen.BLOCKER[grund]["name"],
Ursachen.LISTE[Ursachen.BLOCKER[grund]["ursache"]]["name"]]
_knopf("%s %s" % [stunde, text], func() -> void: slot_panel(human_id, nr))
## Was soll in diesem Slot stehen?
func slot_panel(human_id: String, nr: int) -> void:
var h := HumanDB.by_id(human_id)
var grund := Game.slot_grund(human_id, nr)
var stunde := "%02d:00" % int(Game.slots(human_id)[nr][0])
_leeren("%s um %s" % [h["name"], stunde])
if Ursachen.ist_blocker(grund):
var b: Dictionary = Ursachen.BLOCKER[grund]
_text("Sie %s.\n[b]Auslöser:[/b] %s\n[b]Belohnung:[/b] %s" %
[b["name"], b["ausloeser"], Ursachen.belohnung_text(str(b["belohnung"]))], 16)
_text("[color=#aaaaaa]Eine Ersatzhandlung muss dieselbe Belohnung liefern, " +
"sonst hält sie nicht.[/color]", 15)
else:
_text("Hier ist Platz. Ein neues System passt in diesen Slot.", 16)
_trenner()
var sys := Game.system_in(human_id, nr)
if not sys.is_empty():
_text("[color=#88ff99]Hier steht: %s[/color]" %
TechDB.by_id(str(sys["tech"]))["name"], 16)
_knopf("System wieder herausnehmen", func() -> void:
Game.system_entfernen(human_id, nr)
systeme_panel(human_id))
_trenner()
for id in TechDB.ids():
if not Game.knows(id):
continue
var pruef := Game.system_pruefen(human_id, nr, id)
var t := TechDB.by_id(id)
var beschriftung := "%s · Stufe %d" % [t["name"], Game.skill_of(id)]
if not pruef["geht"]:
beschriftung += " — " + str(pruef["grund"])
elif float(pruef["guete"]) > Game.GUETE_NEU:
beschriftung += " — passt genau"
_knopf(beschriftung, func() -> void: _system_setzen(human_id, nr, id),
bool(pruef["geht"]))
_trenner()
_knopf("Zurück", func() -> void: systeme_panel(human_id))
_zeigen("slot")
func _system_setzen(human_id: String, nr: int, tech_id: String) -> void:
var res := Game.system_setzen(human_id, nr, tech_id, false)
if not res["ok"]:
Game.notified.emit(str(res["grund"]), Color(1, 0.6, 0.4))
return
if not res["erfolg"]:
Game.notified.emit("%s greift diesmal nicht. Später noch einmal." %
TechDB.by_id(tech_id)["name"], Color(1, 0.6, 0.5))
systeme_panel(human_id)
# -------------------------------------------------------- Lehrorte
## Jeder Lehrort unterrichtet genau einen Weg: der Hörsaal den ersten, jedes
## Haus den, den sein Bewohner mitgebracht hat.
func lehre_panel(ort: String = "hoersaal") -> void:
if not DreamDB.PLACES.has(ort):
return
var scroll_alt := _scroll.scroll_vertical if offen and _kind == "lehre" else 0
var pl: Dictionary = DreamDB.PLACES[ort]
var ids: Array = DreamDB.techniken_von(ort)
_leeren(str(pl["name"]))
_text("[color=#aaaaaa]Gelernt: [b]%d[/b] von %d entdeckten Wegen · %d im Spiel[/color]" %
[Game.known.size(), Game.offene_techniken(), TechDB.LIST.size()], 15)
_trenner()
if ids.is_empty():
_text("[color=#ffcc66]Hier wird nichts gelehrt.[/color]", 16)
for id in ids:
var t := TechDB.by_id(id)
if Game.knows(id):
_text("[b][color=#ffe3a0]%s[/color][/b] · Stufe %d (%s)" %
[t["name"], Game.skill_of(id), Game.xp_to_next(id)], 18)
else:
_text("[b][color=#9aa0b8]%s[/color][/b] · noch nicht gelernt" % t["name"], 18)
_text(_hinweis_block(t), 15)
if Game.knows(id):
_text("[color=#88ff99]Gelernt. Stufe %d steigt nur, wenn du diesen Weg " %
Game.skill_of(id) + "draußen anwendest — hier ist nichts mehr zu holen.[/color]", 15)
else:
_knopf("Diesen Weg lernen", func() -> void:
if Game.learn(id):
lehre_panel(ort))
_trenner()
_naechster_weg()
_zeigen("lehre")
_scroll_wunsch = scroll_alt
_scroll_frames = 4
## Was als Nächstes ins Dorf käme.
func _naechster_weg() -> void:
var offen_zahl := Game.offene_techniken()
if offen_zahl >= TechDB.LIST.size():
_text("[color=#88ff99]Alle zwölf Wege sind entdeckt. Das Dorf wächst weiter.[/color]", 15)
return
var naechste: Dictionary = TechDB.LIST[offen_zahl]
_text("[color=#aaaaaa]Noch unentdeckt: [b]%s[/b] und %d weitere. Jeder erfüllte Traum " %
[naechste["name"], TechDB.LIST.size() - offen_zahl - 1] +
"bringt einen Bewohner ins Dorf, und er lehrt einen neuen Weg.[/color]", 15)
# -------------------------------------------------------- Schwarzes Brett
## Hier hängen die Menschen aus, deren Traum feststeckt.
func brett_panel() -> void:
var scroll_alt := _scroll.scroll_vertical if offen and _kind == "brett" else 0
_leeren("Schwarzes Brett")
_text("Ausgehängt wird nur, wem du mit dem, was du kannst, auch helfen kannst. " +
"Das Tor zur Erde öffnet sich nur mit einer Mission.", 15)
_trenner()
var gezeigt := 0
var verdeckt := 0
for h in HumanDB.LIST:
var id: String = h["id"]
if Game.completed.has(id):
continue
if Game.active_mission != id and not Game.machbar(id):
verdeckt += 1
continue
gezeigt += 1
_text("[b][color=#ffe3a0]%s[/color][/b], %d — %s" %
[h["name"], h["alter"], h["beruf"]], 18)
_text("[b]Traum:[/b] %s" % h["traum"], 16)
_text("[b]Was im Weg steht:[/b] %s" % h["problem"], 15)
if Game.active_mission == id:
_text("[color=#ffdd77]Aktive Mission — %d %%[/color]" %
int(Game.mission_progress(id)), 15)
else:
if Game.angenommen(id):
_text("[color=#aaaaaa]Schon einmal angenommen — %d %%[/color]" %
int(Game.mission_progress(id)), 15)
_knopf("Mission annehmen", func() -> void:
Game.accept_mission(id)
brett_panel())
_trenner()
if gezeigt == 0:
_text("[color=#ffcc66]Gerade hängt nichts aus, das zu deinen Wegen passt.[/color]\n" +
"Lerne im Hörsaal oder in einem Haus einen weiteren Weg.", 16)
if verdeckt > 0:
_text("[color=#aaaaaa]%d weitere Anliegen bleiben verdeckt. Keiner deiner Wege " %
verdeckt + "trifft ihr Thema in einem Moment ihres Tages.[/color]", 15)
_zeigen("brett")
_scroll_wunsch = scroll_alt
_scroll_frames = 4
# -------------------------------------------------------- Vor Ort
## Draußen am Menschen: hier greift man in den Slot ein, der gerade läuft.
func anwenden_panel(mensch: Node3D) -> void:
_apply_human = mensch
var h: Dictionary = mensch.data
var id: String = str(h["id"])
var nr: int = int(mensch.slot)
_leeren("%s — %s" % [h["name"], Orte.text(mensch.activity)])
_text("[b]Traum:[/b] %s" % h["traum"], 16)
if Game.active_mission != id:
_text("[color=#ffcc66]Keine aktive Mission für diesen Menschen.[/color]", 15)
_zeigen("anwenden")
return
var grund := Game.slot_grund(id, nr)
if not Game.erkannt(id, nr):
_text("[color=#ffcc66]Was hier läuft, hast du noch nicht gesehen. " +
"Bleib stehen und schau zu.[/color]", 16)
_zeigen("anwenden")
return
if Ursachen.ist_blocker(grund):
var b: Dictionary = Ursachen.BLOCKER[grund]
_text("Sie %s. [b]Auslöser:[/b] %s · [b]Belohnung:[/b] %s" %
[b["name"], b["ausloeser"], Ursachen.belohnung_text(str(b["belohnung"]))], 15)
_trenner()
if Game.known.is_empty():
_text("[color=#ffcc66]Du kennst keine Technik.[/color]")
_zeigen("anwenden")
return
_text("[color=#aaaaaa]Was eine Technik tut, steht im Journal.[/color]", 15)
for tid in TechDB.ids():
if not Game.knows(tid):
continue
var pruef := Game.system_pruefen(id, nr, tid)
var t := TechDB.by_id(tid)
var beschriftung := "%s · Stufe %d" % [t["name"], Game.skill_of(tid)]
if not pruef["geht"]:
beschriftung += " — " + str(pruef["grund"])
elif mensch.resist_left > 0.0:
beschriftung += " — macht gerade dicht"
_knopf(beschriftung, func() -> void: _vor_ort_setzen(tid), bool(pruef["geht"]))
_zeigen("anwenden")
func _vor_ort_setzen(tech_id: String) -> void:
if _apply_human == null or not is_instance_valid(_apply_human):
schliessen()
return
var mensch := _apply_human
var id: String = str(mensch.data["id"])
var res := Game.system_setzen(id, int(mensch.slot), tech_id, mensch.resist_left > 0.0)
schliessen()
if not res["ok"]:
Game.notified.emit(str(res["grund"]), Color(1, 0.6, 0.4))
return
var t := TechDB.by_id(tech_id)
if res["erfolg"]:
mensch.reagiere(true, "%s\nsteht" % t["name"])
else:
mensch.reagiere(false, "%s greift nicht" % t["name"])
func _unhandled_input(event: InputEvent) -> void:
if offen and event.is_action_pressed("ui_cancel"):
schliessen()
get_viewport().set_input_as_handled()