This commit is contained in:
Team3
2026-09-05 11:07:43 +02:00
parent 124a55a03e
commit c62c6e551f
6 changed files with 176 additions and 247 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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:

View File

@@ -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

View File

@@ -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 = ""