diff --git a/README.md b/README.md index 2546d8c..4ea13ba 100644 --- a/README.md +++ b/README.md @@ -14,10 +14,12 @@ Steuerung: **WASD** bewegen · **Maus** umsehen · **E** interagieren · **F** folgen · **R** notieren · **J** Journal · **1/2/3** Tempo · **Esc** Maus freigeben. -Der Tagesablauf steht im **HUD**: 24 Felder, eines je Stunde, die laufende -hervorgehoben. Grau heißt unbekannt, gelb „hier stimmt etwas nicht, aber du -hast es noch nicht benannt", rot ein benannter Blocker, grün ein gebautes -System. Darunter steht, was gerade läuft. +Das **HUD** zeigt vier Zeilen: Zeit, die laufende Mission, den Tagesstreifen — +24 Felder, eines je Stunde, die laufende hervorgehoben — und darunter, was +gerade läuft. Grau heißt unbekannt, gelb „hier stimmt etwas nicht, aber du hast +es noch nicht benannt", rot ein benannter Blocker, grün ein gebautes System. +Bricht ein Moment auf, verdrängt er die Stundenzeile: er ist gleich vorbei. +Alles Weitere steht im Journal, nichts davon auf dem Schirm. In der Traumwelt springt **Leertaste**; auf der Erde steigt sie und **Umschalt** lässt sinken. @@ -50,8 +52,7 @@ voran; du kannst sie aussitzen oder mit der passenden Technik beenden. Dreimal die richtige Technik im richtigen Moment, und das Problem ist überwunden — dieser Moment kommt nicht wieder. Bis dahin umgehst du ihn jedes -Mal aufs Neue. Beides steht im HUD, bewusst verschieden gezeichnet: der Tag -als 24-Felder-Streifen, die Momente als Liste mit dem, was gerade aufbricht. +Mal aufs Neue. **Diagnose und Systeme** — der Kern des Spiels diff --git a/scripts/bewohner.gd b/scripts/bewohner.gd index 539577c..337ee37 100644 --- a/scripts/bewohner.gd +++ b/scripts/bewohner.gd @@ -155,8 +155,7 @@ func beschriftung() -> String: if mit_mission: if Game.completed.has(data["id"]): s += "\n★ Traum erfüllt" - elif Game.active_mission == data["id"]: - s += "\nTraum: %d %%" % int(Game.mission_progress(data["id"])) + return s diff --git a/scripts/game.gd b/scripts/game.gd index 638de9f..41ffc18 100644 --- a/scripts/game.gd +++ b/scripts/game.gd @@ -402,12 +402,10 @@ func notieren(human_id: String, nr: int) -> String: var grund := slot_grund(human_id, nr) if not Ursachen.ist_blocker(grund): notiz_sperre = NOTIZ_SPERRE - notified.emit("Hier läuft nichts schief — %s ist einfach ihr Tag." % - Orte.text(grund), Color(1, 0.75, 0.55)) + notified.emit("Nichts schief: %s" % Orte.text(grund), Color(1, 0.75, 0.55)) return "daneben" if erkannt(human_id, nr): - notified.emit("Das hast du schon notiert: %s." % Orte.text(grund), - Color(0.8, 0.85, 1)) + notified.emit("Schon notiert: %s" % Orte.text(grund), Color(0.8, 0.85, 1)) return "bekannt" if not erkannt_slots.has(human_id): erkannt_slots[human_id] = {} @@ -586,7 +584,7 @@ func situationen_ticken(delta: float, wach: bool) -> void: situation["rest"] = float(situation["rest"]) - delta if float(situation["rest"]) <= 0.0: var p := situation_problem() - notified.emit("Der Moment ist vorbei — %s bleibt." % Probleme.name_von(p), + notified.emit("Moment verpasst: %s" % Probleme.name_von(p), Color(1, 0.75, 0.55)) situation = {} situation_pause = SITUATION_PAUSE @@ -631,8 +629,7 @@ func situation_sehen() -> void: if not probleme_bekannt.has(id): probleme_bekannt[id] = {} probleme_bekannt[id][p] = true - notified.emit("Dahinter steckt: %s — %s" % - [Probleme.name_von(p), Probleme.LISTE[p]["kurz"]], Color(0.8, 0.95, 1)) + notified.emit("Erkannt: %s" % Probleme.name_von(p), Color(0.8, 0.95, 1)) state_changed.emit() @@ -670,15 +667,14 @@ func situation_anwenden(tech_id: String) -> Dictionary: situation_pause = SITUATION_PAUSE if id == active_mission: progress[id] = minf(mission_progress(id) + SITUATION_GEWINN, MISSION_ZIEL) - notified.emit("%s trägt durch den Moment. (+%d %%)" % + notified.emit("%s trägt durch +%d %%" % [TechDB.by_id(tech_id)["name"], int(SITUATION_GEWINN)], Color(0.6, 1, 0.7)) if problem_fortschritt(id, problem) >= PROBLEM_UEBERWINDEN: if not ueberwunden.has(id): ueberwunden[id] = {} ueberwunden[id][problem] = true res["ueberwunden"] = true - notified.emit("%s ist überwunden — dieser Moment kommt nicht wieder." % - Probleme.name_von(problem), Color(1, 0.85, 0.4)) + notified.emit("%s überwunden" % Probleme.name_von(problem), Color(1, 0.85, 0.4)) state_changed.emit() return res diff --git a/scripts/main.gd b/scripts/main.gd index 2bd6625..dc0e1ad 100644 --- a/scripts/main.gd +++ b/scripts/main.gd @@ -104,10 +104,10 @@ func _fokus_suchen() -> void: func _hinweis_setzen() -> void: if player.folgt != null and is_instance_valid(player.folgt): - ui.setze_hinweis("[F] loslassen · %s — %s" % + ui.setze_hinweis("%s · %s · [F] los" % [player.folgt.data["name"], _notiz_hinweis(player.folgt)]) elif _fokus_mensch != null: - ui.setze_hinweis("[F] folgen · %s — %s" % + ui.setze_hinweis("%s · %s · [F] folgen" % [_fokus_mensch.data["name"], _notiz_hinweis(_fokus_mensch)]) elif _fokus != null: var kind: String = _fokus.get_meta("kind") @@ -133,13 +133,13 @@ func _notiz_hinweis(mensch: Bewohner) -> String: if str(mensch.data["id"]) != Game.active_mission: return tat if Game.situation_bei(str(mensch.data["id"])): - return "%s · [E] jetzt eine Technik" % \ + return "%s · [E] Technik" % \ Probleme.SITUATIONEN[Game.situation["key"]]["name"] if Game.notiz_sperre > 0.0: return "%s (%.0f s)" % [tat, Game.notiz_sperre] if Game.erkannt(str(mensch.data["id"]), int(mensch.slot)): return "%s · [E] ansprechen" % tat - return "%s · [R] notieren, wenn hier etwas schiefläuft" % tat + return "%s · [R] notieren" % tat func _unhandled_input(event: InputEvent) -> void: diff --git a/scripts/ui.gd b/scripts/ui.gd index 0b3caa8..949db0d 100644 --- a/scripts/ui.gd +++ b/scripts/ui.gd @@ -13,11 +13,8 @@ var _hud: RichTextLabel var _hinweis: Label var _log: VBoxContainer var _ablauf: HBoxContainer -var _ablauf_titel: Label -var _ablauf_jetzt: Label +var _ablauf_jetzt: RichTextLabel var _ablauf_grund: ColorRect -var _probleme: RichTextLabel -var _probleme_grund: ColorRect var _zellen: Array = [] var _ticks: Array = [] var _dim: ColorRect @@ -55,17 +52,15 @@ func _baue_hud() -> void: add_child(_hud) _baue_ablauf() - _baue_probleme() var steuerung := Label.new() - steuerung.text = "WASD Bewegen · Maus Umsehen · E Interagieren · F Folgen · " + \ - "R Notieren · J Journal · 1/2/3 Tempo · Esc Maus frei" + steuerung.text = "J Journal · 1-3 Tempo · Esc" steuerung.set_anchors_preset(Control.PRESET_TOP_RIGHT) - steuerung.position = Vector2(-720, 16) - steuerung.size = Vector2(700, 24) + steuerung.position = Vector2(-260, 16) + steuerung.size = Vector2(240, 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.add_theme_color_override("font_color", Color(1, 1, 1, 0.4)) steuerung.mouse_filter = Control.MOUSE_FILTER_IGNORE add_child(steuerung) @@ -90,9 +85,10 @@ func _baue_hud() -> void: add_child(_log) -## Der Tagesablauf im HUD: 24 Felder, eines je Stunde, immer sichtbar. +## Der Tagesablauf im HUD: 24 Felder, eines je Stunde. Kein Titel, keine +## Erklärung -- der Streifen erklärt sich, sobald man eine Stunde gefüllt hat. const ABLAUF_X := 18.0 -const ABLAUF_Y := 126.0 +const ABLAUF_Y := 74.0 const ZELLE_BREIT := 14.0 const ZELLE_LUECKE := 2.0 @@ -100,54 +96,48 @@ func _baue_ablauf() -> void: var breite := 24.0 * (ZELLE_BREIT + ZELLE_LUECKE) - ZELLE_LUECKE _ablauf_grund = ColorRect.new() - _ablauf_grund.color = Color(0, 0, 0, 0.42) + _ablauf_grund.color = Color(0, 0, 0, 0.38) _ablauf_grund.set_anchors_preset(Control.PRESET_TOP_LEFT) _ablauf_grund.position = Vector2(ABLAUF_X - 8.0, ABLAUF_Y - 6.0) - _ablauf_grund.custom_minimum_size = Vector2(breite + 16.0, 88.0) - _ablauf_grund.size = _ablauf_grund.custom_minimum_size _ablauf_grund.mouse_filter = Control.MOUSE_FILTER_IGNORE add_child(_ablauf_grund) - _ablauf_titel = Label.new() - _ablauf_titel.set_anchors_preset(Control.PRESET_TOP_LEFT) - _ablauf_titel.position = Vector2(ABLAUF_X, ABLAUF_Y) - _ablauf_titel.add_theme_font_size_override("font_size", 14) - _ablauf_titel.add_theme_color_override("font_color", Color(1, 1, 1, 0.7)) - _ablauf_titel.mouse_filter = Control.MOUSE_FILTER_IGNORE - add_child(_ablauf_titel) - _ablauf = HBoxContainer.new() _ablauf.set_anchors_preset(Control.PRESET_TOP_LEFT) - _ablauf.position = Vector2(ABLAUF_X, ABLAUF_Y + 22.0) + _ablauf.position = Vector2(ABLAUF_X, ABLAUF_Y) _ablauf.add_theme_constant_override("separation", int(ZELLE_LUECKE)) _ablauf.mouse_filter = Control.MOUSE_FILTER_IGNORE add_child(_ablauf) for stunde in range(24): var zelle := ColorRect.new() - zelle.custom_minimum_size = Vector2(ZELLE_BREIT, 16) + zelle.custom_minimum_size = Vector2(ZELLE_BREIT, 14) zelle.mouse_filter = Control.MOUSE_FILTER_IGNORE _ablauf.add_child(zelle) _zellen.append(zelle) - # Stundenmarken unter dem Streifen for stunde in [0, 6, 12, 18]: var tick := Label.new() tick.text = "%d" % stunde tick.set_anchors_preset(Control.PRESET_TOP_LEFT) - tick.position = Vector2(ABLAUF_X + float(stunde) * (ZELLE_BREIT + ZELLE_LUECKE), - ABLAUF_Y + 42.0) - tick.add_theme_font_size_override("font_size", 11) - tick.add_theme_color_override("font_color", Color(1, 1, 1, 0.45)) + tick.position = Vector2(ABLAUF_X + float(stunde) * (ZELLE_BREIT + ZELLE_LUECKE) - 2.0, + ABLAUF_Y + 18.0) + tick.add_theme_font_size_override("font_size", 10) + tick.add_theme_color_override("font_color", Color(1, 1, 1, 0.35)) tick.mouse_filter = Control.MOUSE_FILTER_IGNORE add_child(tick) _ticks.append(tick) - _ablauf_jetzt = Label.new() + _ablauf_jetzt = RichTextLabel.new() + _ablauf_jetzt.bbcode_enabled = true + _ablauf_jetzt.fit_content = true + _ablauf_jetzt.scroll_active = false _ablauf_jetzt.set_anchors_preset(Control.PRESET_TOP_LEFT) - _ablauf_jetzt.position = Vector2(ABLAUF_X, ABLAUF_Y + 60.0) - _ablauf_jetzt.add_theme_font_size_override("font_size", 15) - _ablauf_jetzt.add_theme_color_override("font_color", Color(1, 0.95, 0.8)) + _ablauf_jetzt.position = Vector2(ABLAUF_X, ABLAUF_Y + 34.0) + _ablauf_jetzt.custom_minimum_size = Vector2(breite, 20) + _ablauf_jetzt.size = Vector2(breite, 20) _ablauf_jetzt.mouse_filter = Control.MOUSE_FILTER_IGNORE + _ablauf_jetzt.add_theme_font_size_override("normal_font_size", 14) + _ablauf_jetzt.add_theme_font_size_override("bold_font_size", 14) add_child(_ablauf_jetzt) @@ -171,7 +161,6 @@ func _ablauf_aktualisieren() -> void: var id := Game.active_mission var an := id != "" _ablauf.visible = an - _ablauf_titel.visible = an _ablauf_jetzt.visible = an _ablauf_grund.visible = an for t in _ticks: @@ -179,75 +168,36 @@ func _ablauf_aktualisieren() -> void: if not an: return var jetzt := int(Game.time_h) - var offen := 0 for stunde in range(24): - var nr := Game.slot_bei_stunde(id, stunde) - var f := _ablauf_farbe(id, nr) - if not Game.gesehen_slot(id, nr): - offen += 1 - if stunde == jetzt: - f = f.lightened(0.55) + var f := _ablauf_farbe(id, Game.slot_bei_stunde(id, stunde)) var zelle: ColorRect = _zellen[stunde] - zelle.color = f - zelle.custom_minimum_size.y = 20 if stunde == jetzt else 16 - _ablauf_titel.text = "Ihr Tag 0 – 23 Uhr%s" % \ - ("" if offen == 0 else " · %d Stunden unbekannt" % offen) - var nr_jetzt := Game.slot_bei_stunde(id, jetzt) - _ablauf_jetzt.text = "%02d Uhr %s" % [jetzt, _stunden_text(id, nr_jetzt)] + zelle.color = f.lightened(0.55) if stunde == jetzt else f + zelle.custom_minimum_size.y = 18 if stunde == jetzt else 14 - -## Die zweite Ebene im HUD: bekannte Probleme und der offene Moment. -## Bewusst anders gezeichnet als der Tagesstreifen -- sie hängt nicht an Stunden. -func _baue_probleme() -> void: - _probleme_grund = ColorRect.new() - _probleme_grund.color = Color(0, 0, 0, 0.42) - _probleme_grund.set_anchors_preset(Control.PRESET_TOP_LEFT) - _probleme_grund.position = Vector2(ABLAUF_X - 8.0, ABLAUF_Y + 88.0) - _probleme_grund.custom_minimum_size = Vector2(414.0, 74.0) - _probleme_grund.size = _probleme_grund.custom_minimum_size - _probleme_grund.mouse_filter = Control.MOUSE_FILTER_IGNORE - add_child(_probleme_grund) - - _probleme = RichTextLabel.new() - _probleme.bbcode_enabled = true - _probleme.fit_content = true - _probleme.scroll_active = false - _probleme.set_anchors_preset(Control.PRESET_TOP_LEFT) - _probleme.position = Vector2(ABLAUF_X, ABLAUF_Y + 94.0) - _probleme.custom_minimum_size = Vector2(400, 64) - _probleme.size = Vector2(400, 64) - _probleme.mouse_filter = Control.MOUSE_FILTER_IGNORE - _probleme.add_theme_font_size_override("normal_font_size", 14) - _probleme.add_theme_font_size_override("bold_font_size", 14) - add_child(_probleme) - - -func _probleme_aktualisieren() -> void: - var id := Game.active_mission - var an := id != "" - _probleme.visible = an - _probleme_grund.visible = an - if not an: - return + # Der offene Moment verdrängt die Stundenzeile -- er ist gleich vorbei var zeilen: Array = [] - if Game.situation_laeuft() and Game.situation_bei(id): + if Game.situation_bei(id): var s: Dictionary = Probleme.SITUATIONEN[Game.situation["key"]] - zeilen.append("[color=#ffcc66][b]Jetzt: %s[/b][/color] %s [b]%.0f s[/b]" % - [s["name"], s["was"], float(Game.situation["rest"])]) + zeilen.append("[color=#ffcc66][b]» %s «[/b][/color] [b]%.0f s[/b]" % + [s["name"], float(Game.situation["rest"])]) else: - zeilen.append("[color=#8e93a8]Ihre Momente[/color]") - var bekannt: Array = [] + zeilen.append("[color=#cfd6ff]%02d[/color] %s" % + [jetzt, _stunden_text(id, Game.slot_bei_stunde(id, jetzt))]) + var offen: Array = [] for p in Game.probleme_von(id): var key := str(p) if not Game.problem_bekannt(id, key): - bekannt.append("[color=#55596b]?[/color]") - elif Game.problem_ueberwunden(id, key): - bekannt.append("[color=#88ff99]%s ✓[/color]" % Probleme.name_von(key)) + continue + if Game.problem_ueberwunden(id, key): + offen.append("[color=#88ff99]%s ✓[/color]" % Probleme.name_von(key)) else: - bekannt.append("[color=#ffb0a0]%s %d/%d[/color]" % [Probleme.name_von(key), + offen.append("[color=#ffb0a0]%s %d/%d[/color]" % [Probleme.name_von(key), Game.problem_fortschritt(id, key), Game.PROBLEM_UEBERWINDEN]) - zeilen.append(" · ".join(bekannt)) - _probleme.text = "\n".join(zeilen) + if not offen.is_empty(): + zeilen.append(" ".join(offen)) + _ablauf_jetzt.text = "\n".join(zeilen) + var hoehe := 62.0 + (20.0 if zeilen.size() > 1 else 0.0) + _ablauf_grund.size = Vector2(24.0 * (ZELLE_BREIT + ZELLE_LUECKE) + 14.0, hoehe) func _baue_panel() -> void: @@ -290,11 +240,7 @@ func _baue_panel() -> void: _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: @@ -314,28 +260,22 @@ func _process(_delta: float) -> void: # ------------------------------------------------------------------ HUD func _hud_aktualisieren() -> void: - var zeilen: Array = [] - var takt := ("[color=#aaaaaa]Tempo %d (%d×)[/color]" - % [Game.tempo, int(Game.faktor_von(Game.tempo))]) + var kopf := "[b]%s[/b]" % Game.time_string() 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()]) + kopf += " [color=#9fb6ff]Tempo 3 (%d×) Nacht[/color]" % int(Game.zeit_faktor()) + elif Game.tempo != 1: + kopf += " [color=#9fb6ff]Tempo %d (%d×)[/color]" % [Game.tempo, int(Game.zeit_faktor())] if Game.active_mission != "": var h := HumanDB.by_id(Game.active_mission) - zeilen.append("Mission: [color=#ffdd77]%s[/color] — %d %% · %d %% je Tag" % + kopf += "\n[color=#ffdd77]%s[/color] %d %% [color=#8e93a8]+%d %%/Tag[/color]" % \ [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"]) + int(round(Game.traum_tempo(Game.active_mission)))] elif Game.completed.size() >= HumanDB.LIST.size(): - zeilen.append("[color=#88ff99]Alle Träume erfüllt.[/color]") + kopf += "\n[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) + kopf += "\n[color=#8e93a8]Keine Mission — Schwarzes Brett[/color]" + _hud.text = kopf _ablauf_aktualisieren() - _probleme_aktualisieren() func setze_hinweis(text: String) -> void: @@ -348,12 +288,12 @@ func _notiz(text: String, farbe: Color) -> void: 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_font_size_override("font_size", 14) 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: + while _log.get_child_count() > 3: var alt := _log.get_child(0) _log.remove_child(alt) alt.queue_free() @@ -390,8 +330,8 @@ 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) + b.custom_minimum_size = Vector2(0, 32) + b.add_theme_font_size_override("font_size", 16) _content.add_child(b) if aktiv: b.pressed.connect(cb) @@ -462,67 +402,65 @@ func _reiter() -> void: 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.add_theme_font_size_override("font_size", 16) 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) + _text("[color=#ffcc66]Noch nichts gelernt — Hörsaal der Wege.[/color]", 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() + _knopf("%s · Stufe %d · %s" % [t["name"], Game.skill_of(id), + Ursachen.LISTE[t["ursache"]]["name"]], + func() -> void: technik_panel(id)) + + +## Alles zu einer Technik -- nur, wenn man sie aufschlägt. +func technik_panel(tech_id: String) -> void: + var t := TechDB.by_id(tech_id) + _leeren(str(t["name"])) + _text("[color=#aaaaaa]Stufe %d (%s) · gegen [b]%s[/b][/color]" % + [Game.skill_of(tech_id), Game.xp_to_next(tech_id), + Ursachen.LISTE[t["ursache"]]["name"]], 15) + _trenner() + _text(_hinweis_block(t), 15) + _text("[color=#9fb6ff]Zu sehen an:[/color] %s" % t["woran"], 15) + var gegen: Array = [] + for tag in t["tags"]: + if Probleme.LISTE.has(str(tag)): + gegen.append(Probleme.name_von(str(tag))) + if not gegen.is_empty(): + _text("[color=#9fb6ff]Im Moment gegen:[/color] %s" % ", ".join(gegen), 15) + _trenner() + _knopf("Journal", func() -> void: journal_panel("techniken")) + _zeigen("technik") 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) + _text("[color=#ffcc66]Keine Mission — Schwarzes Brett am Dorfplatz.[/color]", 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) + var stand := "%d %%" % int(Game.mission_progress(id)) if Game.completed.has(id): - _text("[color=#88ff99]★ Der Traum ist erfüllt.[/color]", 15) + stand = "★ erfüllt" 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() + stand = "aktiv · %d %%" % int(Game.mission_progress(id)) + _knopf("%s · %s" % [h["name"], stand], + func() -> void: systeme_panel(id)) # ---------------------------------------------- Diagnose und Systeme @@ -534,9 +472,9 @@ 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) + _text("%d %% · +%d %% je Tag · [color=#aaaaaa]%s[/color]" % + [int(Game.mission_progress(human_id)), int(round(Game.traum_tempo(human_id))), + h["traum"]], 16) _trenner() _text("[b]Woran es scheitert[/b]", 17) @@ -551,16 +489,12 @@ func systeme_panel(human_id: String) -> void: 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, dann füllt sich ihr Tag. Und drücke [b]R[/b], " + - "wenn du meinst, dass eine Stunde den Traum aufhält.[/color]", 14) - _trenner() + _text("[b]%s[/b] %s" % [Ursachen.LISTE[name]["name"], stand], 15) + if offene > 0: _trenner() _tagesablauf(human_id) _trenner() - _knopf("Zurück zum Journal", func() -> void: journal_panel("missionen")) + _knopf("Journal", func() -> void: journal_panel("missionen")) _zeigen("systeme") _scroll_wunsch = scroll_alt _scroll_frames = 4 @@ -573,8 +507,8 @@ func _tagesablauf(human_id: String) -> void: for stunde in range(24): if not Game.gesehen_slot(human_id, Game.slot_bei_stunde(human_id, stunde)): offen += 1 - _text("[b]Ihr Tag[/b] [color=#8e93a8]0 – 23 Uhr, jeden Tag derselbe%s[/color]" % - ("" if offen == 0 else " · %d Stunden noch leer" % offen), 17) + _text("[b]Ihr Tag[/b]%s" % + ("" if offen == 0 else " [color=#8e93a8]%d Stunden leer[/color]" % offen), 17) # eine Zeile je Abschnitt des Tages -- auch wenn noch keiner bekannt ist, # steht der Tag vollständig da @@ -623,16 +557,14 @@ func situation_panel(mensch: Node3D) -> void: var s: Dictionary = Probleme.SITUATIONEN[Game.situation["key"]] var problem := Game.situation_problem() _leeren("%s — %s" % [mensch.data["name"], s["name"]]) - _text("[i]%s[/i]" % s["was"], 16) + var kopf := "[i]%s[/i]" % s["was"] if Game.problem_bekannt(id, problem): - _text("Dahinter steckt [b]%s[/b] — %s." % - [Probleme.name_von(problem), Probleme.LISTE[problem]["kurz"]], 15) - _text("[color=#aaaaaa]Überwunden nach %d von %d Malen.[/color]" % - [Game.problem_fortschritt(id, problem), Game.PROBLEM_UEBERWINDEN], 14) + kopf += " [color=#ffb0a0]%s %d/%d[/color]" % [Probleme.name_von(problem), + Game.problem_fortschritt(id, problem), Game.PROBLEM_UEBERWINDEN] else: - _text("[color=#ffcc66]Was dahintersteckt, weißt du noch nicht.[/color]", 15) - _text("[color=#aaaaaa]Noch %.0f Sekunden. Solange kommt ihr Traum nicht voran.[/color]" % - float(Game.situation["rest"]), 14) + kopf += " [color=#ffcc66]?[/color]" + kopf += " [b]%.0f s[/b]" % float(Game.situation["rest"]) + _text(kopf, 16) _trenner() if Game.known.is_empty(): _text("[color=#ffcc66]Du kennst keine Technik.[/color]", 16) @@ -642,17 +574,13 @@ func situation_panel(mensch: Node3D) -> void: if not Game.knows(tech_id): continue var t := TechDB.by_id(tech_id) - var wofuer: Array = [] - for tag in t["tags"]: - wofuer.append(Probleme.name_von(str(tag))) - _text("[b]%s[/b] · Stufe %d\n[color=#cccccc]%s[/color]\n[color=#9fb6ff]Hilft bei:[/color] %s" % - [t["name"], Game.skill_of(tech_id), t["wann"], ", ".join(wofuer)], 15) var frei := Game.bereit(tech_id) - var text := "Jetzt anwenden" if frei else "Noch %.0f s" % Game.cooldown_rest(tech_id) + var text := "%s · Stufe %d" % [t["name"], Game.skill_of(tech_id)] + if not frei: + text += " · %.0f s" % Game.cooldown_rest(tech_id) _knopf(text, func() -> void: Game.situation_anwenden(tech_id) schliessen(), frei) - _trenner() _zeigen("situation") @@ -666,8 +594,6 @@ func slot_panel(human_id: String, nr: int) -> void: 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() @@ -731,10 +657,7 @@ func lehre_panel(ort: String = "hoersaal") -> void: 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: + if not Game.knows(id): _knopf("Diesen Weg lernen", func() -> void: if Game.learn(id): lehre_panel(ort)) @@ -752,9 +675,8 @@ func _naechster_weg() -> void: _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) + _text("[color=#8e93a8]Noch unentdeckt: %s +%d[/color]" % + [naechste["name"], TechDB.LIST.size() - offen_zahl - 1], 14) # -------------------------------------------------------- Schwarzes Brett @@ -763,46 +685,55 @@ func _naechster_weg() -> void: 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 offen := Game.offene_missionen() + var offen_ids := Game.offene_missionen() var gezeigt := 0 var verdeckt := 0 for h in HumanDB.LIST: var id: String = h["id"] if Game.completed.has(id): continue - if not offen.has(id): + if not offen_ids.has(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) + var marke := "" 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() + marke = " · aktiv %d %%" % int(Game.mission_progress(id)) + elif Game.angenommen(id): + marke = " · %d %%" % int(Game.mission_progress(id)) + _knopf("%s · %s%s" % [h["name"], h["traum"], marke], + func() -> void: aushang_panel(id)) 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) + _text("[color=#ffcc66]Nichts passt — im Hörsaal einen Weg lernen.[/color]", 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) + _text("[color=#aaaaaa]%d verdeckt[/color]" % verdeckt, 14) _zeigen("brett") _scroll_wunsch = scroll_alt _scroll_frames = 4 +## Ein Aushang im Ganzen -- erst hier steht, was im Weg steht. +func aushang_panel(human_id: String) -> void: + var h := HumanDB.by_id(human_id) + _leeren(str(h["name"])) + _text("[color=#aaaaaa]%d — %s[/color]" % [h["alter"], h["beruf"]], 15) + _text("[b]Traum:[/b] %s" % h["traum"], 16) + _text("[b]Was im Weg steht:[/b] %s" % h["problem"], 15) + _trenner() + if Game.active_mission == human_id: + _text("[color=#ffdd77]Aktive Mission — %d %%[/color]" % + int(Game.mission_progress(human_id)), 15) + else: + if Game.angenommen(human_id): + _text("[color=#aaaaaa]Zurückgestellt — %d %%[/color]" % + int(Game.mission_progress(human_id)), 15) + _knopf("Mission annehmen", func() -> void: + Game.accept_mission(human_id) + brett_panel()) + _knopf("Zurück", func() -> void: brett_panel()) + _zeigen("aushang") + + # -------------------------------------------------------- Vor Ort ## Draußen am Menschen: hier greift man in den Slot ein, der gerade läuft. @@ -819,9 +750,7 @@ func anwenden_panel(mensch: Node3D) -> void: 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 notiert. " + - "Sieh ihr zu und drücke [b]R[/b], wenn du meinst, hier läuft etwas " + - "schief.[/color]", 16) + _text("[color=#ffcc66]Noch nicht notiert — [b]R[/b] im Moment.[/color]", 16) _zeigen("anwenden") return if Ursachen.ist_blocker(grund): @@ -833,7 +762,6 @@ func anwenden_panel(mensch: Node3D) -> void: _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 diff --git a/tests/verify.gd b/tests/verify.gd index 6475849..2de9d45 100644 --- a/tests/verify.gd +++ b/tests/verify.gd @@ -249,11 +249,11 @@ func test_journal() -> void: ui().journal_panel("techniken") p(ui().offen and ui()._kind == "journal", "Journal öffnet sich") - p(_journal_text().contains(str(TechDB.by_id(str(_basiswege()[0]))["name"])), + p(_knopf_texte().contains(str(TechDB.by_id(str(_basiswege()[0]))["name"])), "Das Journal führt den mitgebrachten Weg") p(not _knopf_da("Diesen Weg"), "Das Journal lehrt nicht selbst") ui().journal_panel("missionen") - p(_journal_text().contains("Schwarzen Brett"), + p(_journal_text().contains("Schwarze"), "Ohne Mission verweist das Journal auf das Schwarze Brett") p(not _knopf_da("Mission annehmen"), "Das Journal vergibt keine Missionen") ui().schliessen() @@ -275,8 +275,9 @@ func test_journal() -> void: ui().journal_panel("techniken") var buch := _journal_text() var alle_gelernten := true + var zeilen_buch := _knopf_texte() for id in Game.known: - if not buch.contains(str(TechDB.by_id(id)["name"])): + if not zeilen_buch.contains(str(TechDB.by_id(id)["name"])): alle_gelernten = false p(alle_gelernten, "Das Journal führt alle %d gelernten Techniken" % Game.known.size()) var fremde := 0 @@ -453,8 +454,6 @@ func test_hoersaal() -> void: for id in Game.known: xp_neu += int(Game.known[id]) p(xp_neu == xp_summe, "Der Besuch im Hörsaal bringt keine Erfahrung (%d)" % xp_neu) - p(_lehre_text().contains("anwendest"), - "Stattdessen verweist der Hörsaal aufs Anwenden") ui().schliessen() # Ausgangslage für die folgenden Prüfungen wiederherstellen @@ -482,7 +481,7 @@ func test_mission_annehmen() -> void: var alle_wege: Dictionary = Game.known.duplicate() Game.known = {str(_basiswege()[0]): 0} ui().brett_panel() - var aushang := _panel_text() + var aushang := _knopf_texte() var gezeigt := 0 var fehlend := 0 for h in HumanDB.LIST: @@ -498,7 +497,7 @@ func test_mission_annehmen() -> void: p(gezeigt > 0, "Mit einem Weg hängt mindestens ein Aushang (%d von %d)" % [gezeigt, HumanDB.LIST.size()]) p(fehlend > 0, "Und mindestens einer bleibt verdeckt (%d)" % fehlend) - p(aushang.contains("verdeckt"), "Das Brett sagt, dass etwas verdeckt bleibt") + p(_panel_text().contains("verdeckt"), "Das Brett sagt, dass etwas verdeckt bleibt") p(Game.offene_missionen().size() == gezeigt, "Brett und offene_missionen() sind sich einig (%d)" % gezeigt) @@ -513,6 +512,9 @@ func test_mission_annehmen() -> void: "Mehr Wege heißt mehr Aushänge (%d)" % Game.offene_missionen().size()) p(Game.active_mission == "", "Vorher keine Mission") + ui().aushang_panel("mensch_0") + p(_panel_text().contains(str(HumanDB.by_id("mensch_0")["problem"])), + "Der Aushang zeigt aufgeschlagen, was im Weg steht") var gedrueckt := _druecke("Mission annehmen") p(gedrueckt, "Ein Aushang lässt sich annehmen") p(Game.active_mission == "mensch_0", "Mission Lena ist aktiv (%s)" % Game.active_mission) @@ -521,7 +523,7 @@ func test_mission_annehmen() -> void: ui().journal_panel("missionen") var buch := _panel_text() - p(buch.contains(str(HumanDB.by_id("mensch_0")["name"])), + p(_knopf_texte().contains(str(HumanDB.by_id("mensch_0")["name"])), "Das Journal führt die angenommene Mission") p(not buch.contains(str(HumanDB.by_id("mensch_1")["name"])), "Nicht angenommene Menschen fehlen im Journal") @@ -1742,13 +1744,16 @@ func test_chance_verdeckt() -> void: ui().systeme_panel(id) p(not _knopf_texte().contains("%"), "Auch die Tageszeilen nennen keine Chance") - p(_panel_text().contains("Tempo"), "Das Panel nennt das Tempo des Traums") + p(_panel_text().contains("je Tag"), "Das Panel nennt das Tempo des Traums") ui().schliessen() ui().journal_panel("techniken") + p(_knopf_texte().contains(str(TechDB.LIST[0]["name"])), + "Das Journal listet die Technik als eine Zeile") + ui().technik_panel(str(TechDB.LIST[0]["id"])) var buch := _panel_text() p(buch.contains("Wann:") and buch.contains("Zu sehen an:"), - "Das Journal führt Was, Wann, Warum und Zu sehen an") + "Aufgeschlagen stehen Was, Wann, Warum und Zu sehen an da") ui().schliessen() @@ -1877,7 +1882,7 @@ func test_tempo() -> void: Game.accept_mission("mensch_0") Game.time_h = 2.0 ui()._hud_aktualisieren() - p(ui()._hud.text.contains("Nachtsprung"), "Und weist den Nachtsprung aus") + p(ui()._hud.text.contains("Nacht"), "Und weist den Nachtsprung aus") Game.tempo_setzen(1) Game.active_mission = ""