633 lines
21 KiB
GDScript
633 lines
21 KiB
GDScript
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()
|