This commit is contained in:
Team3
2026-09-05 10:25:55 +02:00
parent 8b60164592
commit 124a55a03e
16 changed files with 659 additions and 92 deletions

View File

@@ -1,26 +1,27 @@
78098b89c88a74ebe8c20117b8754620
::res://::1788113016
anforderungen.md::TextFile::-1::1788204851::0::1::::<><><>0<>0<><>::
README.md::TextFile::-1::1788165734::0::1::::<><><>0<>0<><>::
::res://scenes/::1787989294
main.tscn::PackedScene::-1::1787989294::0::1::::<><><>0<>0<><>::res://scripts/main.gd
::res://scripts/::1788209300
bewohner.gd::GDScript::2125278938812678811::1788209097::0::1::::Bewohner<>Node3D<><>0<>0<><>::
dream_db.gd::GDScript::4217518896355437099::1788164505::0::1::::DreamDB<>RefCounted<><>0<>0<><>::
dream_world.gd::GDScript::8279158278942867258::1788164873::0::1::::DreamWorld<>Node3D<><>0<>0<><>::
earth_world.gd::GDScript::6086818627272428934::1788165412::0::1::::EarthWorld<>Node3D<><>0<>0<><>::
game.gd::GDScript::3600922541500868814::1788209816::0::1::::<>Node<><>0<>0<><>::
human_db.gd::GDScript::412604892032291296::1788208999::0::1::::HumanDB<>RefCounted<><>0<>0<><>::
main.gd::GDScript::1504009331368977934::1788209245::0::1::::<>Node3D<><>0<>0<><>::
netz.gd::GDScript::8422943321868648339::1788163667::0::1::::Netz<>RefCounted<><>0<>0<><>::
orte.gd::GDScript::5536340784294498671::1788209635::0::1::::Orte<>RefCounted<><>0<>0<><>::
player.gd::GDScript::8724108548430371398::1788039718::0::1::::Player<>CharacterBody3D<><>0<>0<><>::
prims.gd::GDScript::322632462553361584::1788039797::0::1::::Prims<>RefCounted<><>0<>0<><>::
technique_db.gd::GDScript::4543286561661639701::1788209343::0::1::::TechDB<>RefCounted<><>0<>0<><>::
ui.gd::GDScript::843471304695966286::1788209227::0::1::::UI<>CanvasLayer<><>0<>0<><>::
ursachen.gd::GDScript::7371116734724270900::1788208917::0::1::::Ursachen<>RefCounted<><>0<>0<><>::
::res://tests/::1788209571
shots.gd::GDScript::5999651346126871724::1788209816::0::1::::<>Node<><>0<>0<><>::
shots.tscn::PackedScene::-1::1787990528::0::1::::<><><>0<>0<><>::res://tests/shots.gd
verify.gd::GDScript::4392606218392155269::1788209816::0::1::::<>Node<><>0<>0<><>::
verify.tscn::PackedScene::-1::1787989983::0::1::::<><><>0<>0<><>::res://tests/verify.gd
::res://::1788260833
anforderungen.md::TextFile::-1::1788584851::0::1::::<><><>0<>0<><>::
README.md::TextFile::-1::1788471905::0::1::::<><><>0<>0<><>::
::res://scenes/::1788012512
main.tscn::PackedScene::-1::1788012512::0::1::::<><><>0<>0<><>::res://scripts/main.gd
::res://scripts/::1788584883
bewohner.gd::GDScript::2125278938812678811::1788463944::0::1::::Bewohner<>Node3D<><>0<>0<><>::
dream_db.gd::GDScript::4217518896355437099::1788260794::0::1::::DreamDB<>RefCounted<><>0<>0<><>::
dream_world.gd::GDScript::8279158278942867258::1788260794::0::1::::DreamWorld<>Node3D<><>0<>0<><>::
earth_world.gd::GDScript::6086818627272428934::1788260794::0::1::::EarthWorld<>Node3D<><>0<>0<><>::
game.gd::GDScript::3600922541500868814::1788468437::0::1::::<>Node<><>0<>0<><>::
human_db.gd::GDScript::412604892032291296::1788584883::0::1::::HumanDB<>RefCounted<><>0<>0<><>::
main.gd::GDScript::1504009331368977934::1788471754::0::1::::<>Node3D<><>0<>0<><>::
netz.gd::GDScript::8422943321868648339::1788260794::0::1::::Netz<>RefCounted<><>0<>0<><>::
orte.gd::GDScript::5536340784294498671::1788260833::0::1::::Orte<>RefCounted<><>0<>0<><>::
player.gd::GDScript::8724108548430371398::1788459499::0::1::::Player<>CharacterBody3D<><>0<>0<><>::
prims.gd::GDScript::322632462553361584::1788088940::0::1::::Prims<>RefCounted<><>0<>0<><>::
probleme.gd::GDScript::4928319609961045127::1788584883::0::1::::Probleme<>RefCounted<><>0<>0<><>::
technique_db.gd::GDScript::4543286561661639701::1788260833::0::1::::TechDB<>RefCounted<><>0<>0<><>::
ui.gd::GDScript::843471304695966286::1788471755::0::1::::UI<>CanvasLayer<><>0<>0<><>::
ursachen.gd::GDScript::7371116734724270900::1788260833::0::1::::Ursachen<>RefCounted<><>0<>0<><>::
::res://tests/::1788471701
shots.gd::GDScript::5999651346126871724::1788260833::0::1::::<>Node<><>0<>0<><>::
shots.tscn::PackedScene::-1::1788012512::0::1::::<><><>0<>0<><>::res://tests/shots.gd
verify.gd::GDScript::4392606218392155269::1788471838::0::1::::<>Node<><>0<>0<><>::
verify.tscn::PackedScene::-1::1788012512::0::1::::<><><>0<>0<><>::res://tests/verify.gd

View File

@@ -4,7 +4,7 @@ select_mode=0
[editor_metadata]
executable_path="/home/arbeit/bin/godot"
executable_path="/home/arbeit/.local/bin/godot"
[recent_files]

View File

@@ -72,6 +72,14 @@ list=[{
"path": "res://scripts/prims.gd"
}, {
"base": &"RefCounted",
"class": &"Probleme",
"icon": "",
"is_abstract": false,
"is_tool": false,
"language": &"GDScript",
"path": "res://scripts/probleme.gd"
}, {
"base": &"RefCounted",
"class": &"TechDB",
"icon": "",
"is_abstract": false,

Binary file not shown.

View File

@@ -34,6 +34,25 @@ Das Journal führt Buch — es lehrt und vergibt nichts.
gibt keine Wochentage; jeder Tag ist derselbe. Zu Beginn steht in jedem
Abschnitt nur ein Strich — der Tag ist leer, bis du dabei warst.
**Zwei Ebenen** — Gewohnheiten und Momente
Ein Mensch wird von zwei verschiedenen Dingen aufgehalten, und beide brauchen
eine andere Art zu spielen.
Gewohnheiten sitzen im Tagesablauf planend laufen ohne dich weiter
Probleme sitzen in Momenten reagierend du musst dabei sein
Eine Gewohnheit hat einen Platz im Tag: um zehn räumt sie auf, statt
anzufangen. Du findest den Platz, pflanzt eine Ersatzhandlung ein, und sie
läuft von allein. Ein psychisches Problem hat keinen Platz — es bricht in
**Situationen** auf, wann es will. Solange eine läuft, kommt der Traum nicht
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.
**Diagnose und Systeme** — der Kern des Spiels
Ein Traum scheitert an Ursachen: *kein Anfang*, *keine Zeit*, *keine Kraft*,
@@ -140,29 +159,31 @@ Abwehr. Am Ausgang ändert sich dadurch nichts, nur an der Wartezeit.
Technik nur, ob Thema und Moment passen — keine Zahl.
* Die Säule im Park bringt dich zurück in die Traumwelt.
## Erfolgschance
## Ob es gelingt
5 % + 9 % je Fertigkeitsstufe
+ 20 % wenn die Technik das Thema des Menschen trifft
+ 35 % wenn der Moment passt (z. B. Box-Atmung, während jemand angespannt ist)
− 30 % wenn der Mensch gerade abblockt
Ein System einzurichten ist kein Selbstläufer:
20 % + 13 % je Fertigkeitsstufe
− 25 % wenn der Mensch gerade abwehrt
begrenzt auf 5 … 95 %
Schlafende sind nicht erreichbar. Erfolg bringt Fortschritt und 2 EP, ein
Fehlversuch 1 EP, −14 % Fortschritt und 18 Sekunden Abwehr. Jeder Einsatz sperrt
die Technik für 30 Sekunden. Dieselbe Technik wirkt bei Wiederholung schwächer —
es lohnt sich, mehrere zu lernen. 100 % erfüllen den Traum.
Gelingt es, steht das System im Slot. Wie gut es trägt, entscheidet nicht der
Wurf, sondern die Passung: eine Ersatzhandlung mit **derselben Belohnung** wie
der Blocker — oder eine Technik, die ihm den Auslöser nimmt — hält deutlich
besser als eine, die nur den freien Platz füllt.
Im Moment einer Situation wird nicht gewürfelt. Entweder die Technik trifft das
Problem oder nicht. Jeder Einsatz sperrt die Technik für 30 Sekunden.
**Eine Technik wird nur besser, indem du sie anwendest.** Der Lehrort gibt sie
dir, mehr nicht: kein Üben, kein Trainieren, keine Währung, die man dagegen
eintauschen könnte. Wer eine Technik auf Stufe 5 will, muss sie draußen bei
Menschen einsetzen — auch Fehlversuche zählen.
eintauschen könnte. Ein Erfolg bringt 2 EP, ein Fehlversuch 1 — auch der zählt.
## Aufbau
project.godot Projekt, Autoload `Game`
scenes/main.tscn Einstieg
scripts/game.gd Zustand, Diagnose, Systeme, Tempo, Uhr (Autoload)
scripts/game.gd Zustand, Diagnose, Systeme, Momente, Tempo, Uhr (Autoload)
scripts/technique_db.gd die zwölf Techniken mit ihren Hinweisen
scripts/human_db.gd Bezirk: Arterien, Blöcke, roji, Parzellen, Menschen
scripts/dream_db.gd Traumdorf: wachsende Häuser, Wege, Bewohner, Lehrorte
@@ -170,10 +191,11 @@ Menschen einsetzen — auch Fehlversuche zählen.
scripts/orte.gd Orte, Türen, Wege, Tätigkeiten (beide Welten)
scripts/bewohner.gd Bewohner mit Tagesablauf und Slots
scripts/main.gd Weltenwechsel, Fokus, Interaktion
scripts/player.gd Läufer in der Traumwelt, Geist auf der Erde
scripts/player.gd Läufer in der Traumwelt, Geist auf der Erde, Verfolgung
scripts/dream_world.gd Insel mit Dorf
scripts/earth_world.gd Stadt mit Tag-Nacht-Wechsel
scripts/ursachen.gd Ursachen, blockierende Tätigkeiten, Belohnungen
scripts/probleme.gd Psychische Probleme und die Momente, in denen sie aufbrechen
scripts/ui.gd HUD, Journal, Tagesablauf, Hörsaal, Brett, Panels
scripts/prims.gd Bausteine aus Primitiven
@@ -186,7 +208,8 @@ Menschen einsetzen — auch Fehlversuche zählen.
Tagesabläufen, gewachsenes Dorf und erzeugter Bezirk,
Häuser betreten, Journal in beiden Welten, im Hörsaal lernen,
Verbessern allein durchs Anwenden, Mission am Schwarzen Brett annehmen,
Ursachen aufdecken, Systeme bauen, Tempo messen, zur Erde reisen,
Ursachen benennen, Systeme bauen, Momente abfangen, Probleme überwinden,
Tempo messen, zur Erde reisen,
Tagesabläufe über einen ganzen Tag, Wirkung der Technikwahl, Cooldown,
verdeckte Erfolgschance, keine Passungshinweise,
Tempo und Nachtsprung,

View File

@@ -5,7 +5,8 @@ Kern
Loops
- Träume erfüllen -> Welt vergrößeren -> Techniken entdecken
- Techniken entdecken -> Techniken lernen -> Missionen freischalten
- Menschen beobachten -> Probleme finden -> Techniken anwenden
- Menschen beobachten -> Tagesablauf herausfinden -> Gewohnheiten anpassen
- Menschen beobachten -> Probleme erkennen -> Techniken anwenden
Funktionen
- Bewegung: Bewegen, Springen, Geist, Anhängen

View File

@@ -148,6 +148,8 @@ func beschriftung() -> String:
if data.has("rolle"):
s += ", " + str(data["rolle"])
s += "\n" + Orte.text(activity)
if mit_mission and Game.situation_bei(str(data["id"])):
s += "\n» %s «" % Probleme.SITUATIONEN[Game.situation["key"]]["name"]
if resist_left > 0.0:
s += " (macht dicht)"
if mit_mission:

View File

@@ -13,7 +13,6 @@ const RESIST_SEKUNDEN := 18.0
## nicht der Faktor — Stufe 2 läuft dreifach, Stufe 3 siebenfach.
const TEMPO_FAKTOR := [1.0, 3.0, 7.0]
const TECHNIK_COOLDOWN := 30.0 # eine Technik braucht Luft, bevor sie wieder greift
const FEHLVERSUCH_VERLUST := 14.0 # ein Fehlschlag wirft den Traum zurück
# Der Verlust ist mit Absicht so hoch, dass sich nur eine Technik lohnt, die
# Thema UND Moment trifft. Wer eine Regel blind auf jede Tätigkeit hängt,
# verliert unterm Strich — die Wahl muss aus der Technik gelesen werden.
@@ -26,6 +25,11 @@ var systeme: Dictionary = {} # human_id -> {slot -> {tech, guete}}
var erkannt_slots: Dictionary = {} # human_id -> {slot -> true}
var gesehen: Dictionary = {} # human_id -> {slot -> true}, wo man dabei war
var notiz_sperre: float = 0.0 # nach einem Fehlgriff kurz gesperrt
var situation: Dictionary = {} # laufende Situation: mensch, key, rest
var situation_pause: float = 0.0 # bis die nächste kommen darf
var probleme_bekannt: Dictionary = {} # human_id -> {problem -> true}
var problem_stand: Dictionary = {} # "human:problem" -> gelungene Anwendungen
var ueberwunden: Dictionary = {} # human_id -> {problem -> true}
var completed: Array = []
var time_h: float = 7.0
var day: int = 1
@@ -344,6 +348,24 @@ func sehen(human_id: String, nr: int) -> void:
state_changed.emit()
## Der Zustand einer Stunde. HUD und Panel zeichnen denselben -- zwei
## Auslegungen würden mit der Zeit auseinanderlaufen.
enum Stunde { UNBEKANNT, GESEHEN, SCHLAF, UNGEKLAERT, BENANNT, GEBAUT }
func slot_zustand(human_id: String, nr: int) -> int:
if not gesehen_slot(human_id, nr):
return Stunde.UNBEKANNT
if not system_in(human_id, nr).is_empty():
return Stunde.GEBAUT
var grund := slot_grund(human_id, nr)
if Ursachen.ist_blocker(grund):
return Stunde.BENANNT if erkannt(human_id, nr) else Stunde.UNGEKLAERT
if grund == "schlaeft":
return Stunde.SCHLAF
return Stunde.GESEHEN
func slot_grund(human_id: String, nr: int) -> String:
var r := slots(human_id)
return str(r[nr][2]) if nr >= 0 and nr < r.size() else ""
@@ -501,6 +523,8 @@ func system_anzahl(human_id: String) -> int:
func traum_voranbringen(stunden: float) -> void:
if active_mission == "":
return
if situation_bei(active_mission):
return # im Moment geht nichts voran
var p: float = progress.get(active_mission, 0.0) \
+ traum_tempo(active_mission) * stunden / 24.0
progress[active_mission] = minf(p, MISSION_ZIEL)
@@ -514,6 +538,151 @@ func traum_voranbringen(stunden: float) -> void:
state_changed.emit()
# ------------------------------------------------------- Probleme und Momente
# Die zweite Ebene. Eine Gewohnheit sitzt im Tagesablauf und läuft ohne dich
# weiter, sobald ein System steht. Ein Problem sitzt in keiner Stunde -- es
# bricht in Situationen auf. Solange eine läuft, kommt der Traum nicht voran.
# Du kannst sie aussitzen oder mit der passenden Technik beenden.
const SITUATION_DAUER := 22.0 # so lange steht der Traum still
const SITUATION_PAUSE := 40.0 # Luft zwischen zwei Situationen
const PROBLEM_UEBERWINDEN := 3 # so oft muss eine Technik greifen
const SITUATION_GEWINN := 6.0 # Prozent, wenn sie früh beendet wird
func probleme_von(human_id: String) -> Array:
var h := HumanDB.by_id(human_id)
return h["probleme"] if h.has("probleme") else []
func problem_bekannt(human_id: String, problem: String) -> bool:
return probleme_bekannt.get(human_id, {}).has(problem)
func problem_ueberwunden(human_id: String, problem: String) -> bool:
return ueberwunden.get(human_id, {}).has(problem)
func problem_fortschritt(human_id: String, problem: String) -> int:
return int(problem_stand.get("%s:%s" % [human_id, problem], 0))
func situation_laeuft() -> bool:
return not situation.is_empty()
func situation_bei(human_id: String) -> bool:
return situation_laeuft() and str(situation["mensch"]) == human_id
func situation_problem() -> String:
return str(situation["problem"]) if situation_laeuft() else ""
## Läuft die Uhr weiter, kommt irgendwann die nächste Situation -- aber nur
## bei einem wachen Menschen, dem man gerade hilft.
func situationen_ticken(delta: float, wach: bool) -> void:
if situation_laeuft():
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),
Color(1, 0.75, 0.55))
situation = {}
situation_pause = SITUATION_PAUSE
state_changed.emit()
return
situation_pause = maxf(0.0, situation_pause - delta)
if active_mission == "" or not wach or situation_pause > 0.0:
return
_situation_starten()
func _situation_starten() -> void:
var offen: Array = []
for p in probleme_von(active_mission):
if not problem_ueberwunden(active_mission, str(p)):
offen.append(str(p))
if offen.is_empty():
situation_pause = SITUATION_PAUSE
return
var problem: String = str(offen[randi() % offen.size()])
var moeglich := Probleme.situationen_von(problem)
if moeglich.is_empty():
situation_pause = SITUATION_PAUSE
return
situation = {
"mensch": active_mission,
"key": str(moeglich[randi() % moeglich.size()]),
"problem": problem,
"rest": SITUATION_DAUER,
}
state_changed.emit()
## Dabeisein zeigt, welches Problem dahintersteckt.
func situation_sehen() -> void:
if not situation_laeuft():
return
var id := str(situation["mensch"])
var p := situation_problem()
if problem_bekannt(id, p):
return
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))
state_changed.emit()
## Eine Technik im Moment anwenden. Passt sie zum Problem, ist die Situation
## vorbei; oft genug, und das Problem kommt nicht wieder.
func situation_anwenden(tech_id: String) -> Dictionary:
var res := {"ok": false, "grund": "", "treffer": false, "ueberwunden": false}
if not situation_laeuft():
res["grund"] = "Gerade ist kein Moment offen."
return res
if not known.has(tech_id):
res["grund"] = "Diese Technik kennst du nicht."
return res
if not bereit(tech_id):
res["grund"] = "%s braucht noch %.0f s." % [TechDB.by_id(tech_id)["name"],
cooldown_rest(tech_id)]
return res
var id := str(situation["mensch"])
var problem := situation_problem()
cooldown[tech_id] = TECHNIK_COOLDOWN
res["ok"] = true
if not Probleme.hilft(tech_id, problem):
add_xp(tech_id, 1)
notified.emit("%s greift hier nicht." % TechDB.by_id(tech_id)["name"],
Color(1, 0.7, 0.5))
state_changed.emit()
return res
res["treffer"] = true
add_xp(tech_id, 2)
var schluessel := "%s:%s" % [id, problem]
problem_stand[schluessel] = problem_fortschritt(id, problem) + 1
situation_sehen()
situation = {}
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 %%)" %
[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))
state_changed.emit()
return res
# --------------------------------------------------- Erreichbarkeit
## Schlafende erreicht niemand.

View File

@@ -391,6 +391,18 @@ static func _anker_setzen() -> void:
ANKER[key] = int(NETZ.andocken(tuer)["knoten"])
## Was diesen Menschen nicht im Tagesablauf aufhält, sondern in Momenten.
## Ein bis zwei Probleme -- die zweite Ebene neben den Ursachen.
static func probleme_von(i: int) -> Array:
var alle: Array = Probleme.LISTE.keys()
var out: Array = [str(alle[i % alle.size()])]
if i % 2 == 1:
var zweites: String = str(alle[(i + 2) % alle.size()])
if zweites != out[0]:
out.append(zweites)
return out
## Woran der Traum dieses Menschen scheitert. Zwei bis drei Ursachen, nie alle.
## Die erste hängt am Weg gleicher Nummer -- so ist der neueste Mensch immer
## mit dem neuesten Weg anzugehen.
@@ -462,6 +474,7 @@ static func _mensch(i: int) -> Dictionary:
"problem": str(anliegen["problem"]),
"tags": (anliegen["tags"] as Array).duplicate(),
"ursachen": ursachen_von(i),
"probleme": probleme_von(i),
"mission": true,
"heim": heim,
"farbe": Color.from_hsv(fmod(0.02 + float(i) * 0.191, 1.0), 0.5, 0.8),
@@ -495,15 +508,6 @@ static func _nachname(i: int) -> String:
return str(NACHNAMEN[(i / VORNAMEN.size() + i) % NACHNAMEN.size()])
## Die Tätigkeiten eines Menschen in der Reihenfolge seines Tages, ohne Dopplung.
static func aktivitaeten(id: String) -> Array:
var out: Array = []
for e in by_id(id)["routine"]:
if not out.has(e[2]):
out.append(e[2])
return out
static func by_id(id: String) -> Dictionary:
for h in LIST:
if h["id"] == id:

View File

@@ -73,6 +73,7 @@ func _process(delta: float) -> void:
ui.setze_hinweis("")
return
Game.notiz_sperre = maxf(0.0, Game.notiz_sperre - delta)
Game.situationen_ticken(dt, auf_erde and not Game.schlaeft_ziel())
_fokus_suchen()
_dabeisein()
_hinweis_setzen()
@@ -131,6 +132,9 @@ func _notiz_hinweis(mensch: Bewohner) -> String:
var tat := Orte.text(mensch.activity)
if str(mensch.data["id"]) != Game.active_mission:
return tat
if Game.situation_bei(str(mensch.data["id"])):
return "%s · [E] jetzt eine 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)):
@@ -181,6 +185,8 @@ func _dabeisein() -> void:
var id: String = str(_fokus_mensch.data["id"])
if id == Game.active_mission:
Game.sehen(id, int(_fokus_mensch.slot))
if Game.situation_bei(id):
Game.situation_sehen()
## Den Moment benennen: hier läuft etwas schief. Das ist der Kern des
@@ -227,7 +233,11 @@ func _verfolgen() -> void:
func _interagieren() -> void:
if _fokus_mensch != null:
ui.anwenden_panel(_fokus_mensch)
# Der offene Moment geht vor: er ist gleich wieder vorbei
if Game.situation_bei(str(_fokus_mensch.data["id"])):
ui.situation_panel(_fokus_mensch)
else:
ui.anwenden_panel(_fokus_mensch)
return
if _fokus == null:
return

102
scripts/probleme.gd Normal file
View File

@@ -0,0 +1,102 @@
class_name Probleme
## Die zweite Ebene: was einen Menschen nicht im Tagesablauf aufhält, sondern
## in einzelnen Momenten. Eine Gewohnheit hat einen Platz im Tag -- ein
## psychisches Problem hat keinen. Es zeigt sich in Situationen, und die
## kommen, wann sie wollen.
##
## Darum die andere Mechanik: Gewohnheiten pflanzt man ein und sie laufen ohne
## dich weiter. Bei einer Situation musst du dabei sein und im Moment die
## Technik wählen, die zu diesem Problem passt.
static var LISTE: Dictionary = {
"angst": {
"name": "Angst", "kurz": "der Körper macht dicht, bevor der Kopf mitredet",
},
"selbstzweifel": {
"name": "Selbstzweifel", "kurz": "die innere Stimme redet es klein",
},
"stress": {
"name": "Stress", "kurz": "alles gleichzeitig, nichts zu Ende",
},
"ueberforderung": {
"name": "Überforderung", "kurz": "der Berg ist zu groß zum Ansehen",
},
"erschoepfung": {
"name": "Erschöpfung", "kurz": "der Akku ist leer, bevor der Tag anfängt",
},
"einsamkeit": {
"name": "Einsamkeit", "kurz": "hängt allein an dem, was zu zweit ginge",
},
}
## Situationen: was im Moment sichtbar wird. Jede gehört zu einem Problem.
static var SITUATIONEN: Dictionary = {
"blackout": {
"name": "wird starr", "was": "Ihr wird schwarz vor Augen.",
"problem": "angst",
},
"aufschieben_angst": {
"name": "meldet sich ab", "was": "Sie sagt den Termin wieder ab.",
"problem": "angst",
},
"kleinreden": {
"name": "redet es klein", "was": "»Das kann doch jeder besser.«",
"problem": "selbstzweifel",
},
"vergleich": {
"name": "vergleicht sich", "was": "Sie sieht, was andere schaffen.",
"problem": "selbstzweifel",
},
"alles_gleichzeitig": {
"name": "fängt drei Dinge an", "was": "Alles gleichzeitig, nichts zu Ende.",
"problem": "stress",
},
"noch_ein_ja": {
"name": "sagt schon wieder ja", "was": "Noch eine Bitte, noch ein Ja.",
"problem": "stress",
},
"erstarrt": {
"name": "erstarrt vor dem Berg", "was": "Sie sieht die Aufgabe und macht nichts.",
"problem": "ueberforderung",
},
"ausgebrannt": {
"name": "sackt zusammen", "was": "Sie sitzt da und starrt.",
"problem": "erschoepfung",
},
"allein": {
"name": "hängt allein fest", "was": "Sie kommt nicht weiter und fragt niemanden.",
"problem": "einsamkeit",
},
}
static func problem_da(schluessel: String) -> bool:
return LISTE.has(schluessel)
static func name_von(schluessel: String) -> String:
return str(LISTE[schluessel]["name"]) if LISTE.has(schluessel) else schluessel
## Alle Situationen, in denen sich dieses Problem zeigt.
static func situationen_von(problem: String) -> Array:
var out: Array = []
for key in SITUATIONEN:
if SITUATIONEN[key]["problem"] == problem:
out.append(key)
return out
## Techniken, die gegen dieses Problem etwas ausrichten -- erkennbar am Feld
## `tags` der Technik.
static func techniken_gegen(problem: String) -> Array:
var out: Array = []
for t in TechDB.LIST:
if (t["tags"] as Array).has(problem):
out.append(str(t["id"]))
return out
static func hilft(tech_id: String, problem: String) -> bool:
var t := TechDB.by_id(tech_id)
return not t.is_empty() and (t["tags"] as Array).has(problem)

1
scripts/probleme.gd.uid Normal file
View File

@@ -0,0 +1 @@
uid://cchkx60v1a0e2

View File

@@ -14,7 +14,6 @@ static var LIST: Array = [
"belohnung": "erfolg",
"ersatz": "arbeitet in Blöcken",
"tags": ["prokrastination", "fokus"],
"momente": ["arbeitet", "zoegert"],
"farbe": Color(0.95, 0.45, 0.30),
},
{
@@ -28,7 +27,6 @@ static var LIST: Array = [
"belohnung": "erfolg",
"ersatz": "fängt zwei Minuten an",
"tags": ["prokrastination", "ueberforderung"],
"momente": ["zoegert", "aufraeumen", "arbeitet"],
"farbe": Color(0.98, 0.72, 0.25),
},
{
@@ -42,7 +40,6 @@ static var LIST: Array = [
"belohnung": "ordnung",
"ersatz": "folgt dem Wenn-Dann-Plan",
"tags": ["gewohnheit", "prokrastination"],
"momente": ["morgenroutine", "pause"],
"farbe": Color(0.45, 0.80, 0.55),
},
{
@@ -56,7 +53,6 @@ static var LIST: Array = [
"belohnung": "ordnung",
"ersatz": "hängt es an die Routine",
"tags": ["gewohnheit"],
"momente": ["morgenroutine", "essen", "abendroutine"],
"farbe": Color(0.40, 0.70, 0.85),
},
{
@@ -70,7 +66,6 @@ static var LIST: Array = [
"belohnung": "ordnung",
"ersatz": "zerlegt die Aufgabe",
"tags": ["ueberforderung", "prokrastination", "ziel"],
"momente": ["gruebelt", "arbeitet"],
"farbe": Color(0.75, 0.55, 0.95),
},
{
@@ -84,7 +79,6 @@ static var LIST: Array = [
"belohnung": "",
"ersatz": "hat es sich leicht gemacht",
"tags": ["ablenkung", "gewohnheit"],
"momente": ["aufraeumen", "arbeitet", "ruht"],
"farbe": Color(0.55, 0.85, 0.40),
},
{
@@ -98,7 +92,6 @@ static var LIST: Array = [
"belohnung": "einordnung",
"ersatz": "deutet den Gedanken um",
"tags": ["selbstzweifel", "angst"],
"momente": ["gruebelt", "ruht", "angespannt"],
"farbe": Color(0.95, 0.55, 0.75),
},
{
@@ -112,7 +105,6 @@ static var LIST: Array = [
"belohnung": "abschalten",
"ersatz": "atmet sich ruhig",
"tags": ["angst", "stress"],
"momente": ["angespannt", "wartet", "pause"],
"farbe": Color(0.40, 0.85, 0.95),
},
{
@@ -126,7 +118,6 @@ static var LIST: Array = [
"belohnung": "verbundenheit",
"ersatz": "ist freundlich mit sich",
"tags": ["selbstzweifel", "rueckschlag"],
"momente": ["gruebelt", "ruht", "angespannt"],
"farbe": Color(1.0, 0.80, 0.60),
},
{
@@ -140,7 +131,6 @@ static var LIST: Array = [
"belohnung": "zeit_fuer_sich",
"ersatz": "hält das Schlaffenster",
"tags": ["erschoepfung", "gesundheit"],
"momente": ["abendroutine", "muede", "ruht"],
"farbe": Color(0.45, 0.50, 0.90),
},
{
@@ -154,7 +144,6 @@ static var LIST: Array = [
"belohnung": "anschluss",
"ersatz": "bittet um Hilfe",
"tags": ["einsamkeit", "ueberforderung"],
"momente": ["wartet", "pause", "unterwegs"],
"farbe": Color(0.90, 0.90, 0.45),
},
{
@@ -168,7 +157,6 @@ static var LIST: Array = [
"belohnung": "anerkennung",
"ersatz": "sagt Nein mit Alternative",
"tags": ["stress", "grenzen"],
"momente": ["arbeitet", "angespannt", "unterwegs"],
"farbe": Color(0.85, 0.35, 0.45),
},
]

View File

@@ -16,6 +16,8 @@ var _ablauf: HBoxContainer
var _ablauf_titel: Label
var _ablauf_jetzt: Label
var _ablauf_grund: ColorRect
var _probleme: RichTextLabel
var _probleme_grund: ColorRect
var _zellen: Array = []
var _ticks: Array = []
var _dim: ColorRect
@@ -27,7 +29,6 @@ var _apply_human: Node3D
var _journal_seite := "techniken"
var _scroll_wunsch := 0
var _scroll_frames := 0
var _on_travel: Callable
func _ready() -> void:
@@ -54,6 +55,7 @@ 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 · " + \
@@ -151,16 +153,17 @@ func _baue_ablauf() -> void:
## Farbe je Stunde: unbekannt, gesehen, ungeklärt, benannt, gebaut.
func _ablauf_farbe(human_id: String, nr: int) -> Color:
if not Game.gesehen_slot(human_id, nr):
return Color(0.22, 0.23, 0.30)
if not Game.system_in(human_id, nr).is_empty():
return Color(0.44, 0.78, 0.50)
var grund := Game.slot_grund(human_id, nr)
if Ursachen.ist_blocker(grund):
return Color(0.85, 0.66, 0.32) if not Game.erkannt(human_id, nr) \
else Color(0.84, 0.42, 0.35)
if grund == "schlaeft":
return Color(0.30, 0.33, 0.44)
match Game.slot_zustand(human_id, nr):
Game.Stunde.UNBEKANNT:
return Color(0.22, 0.23, 0.30)
Game.Stunde.GEBAUT:
return Color(0.44, 0.78, 0.50)
Game.Stunde.UNGEKLAERT:
return Color(0.85, 0.66, 0.32)
Game.Stunde.BENANNT:
return Color(0.84, 0.42, 0.35)
Game.Stunde.SCHLAF:
return Color(0.30, 0.33, 0.44)
return Color(0.46, 0.50, 0.62)
@@ -193,6 +196,60 @@ func _ablauf_aktualisieren() -> void:
_ablauf_jetzt.text = "%02d Uhr %s" % [jetzt, _stunden_text(id, nr_jetzt)]
## 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
var zeilen: Array = []
if Game.situation_laeuft() and 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"])])
else:
zeilen.append("[color=#8e93a8]Ihre Momente[/color]")
var bekannt: 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))
else:
bekannt.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)
func _baue_panel() -> void:
_dim = ColorRect.new()
_dim.color = Color(0, 0, 0, 0.62)
@@ -278,6 +335,7 @@ func _hud_aktualisieren() -> void:
zeilen.append("[color=#aaaaaa]Keine Mission. Schwarzes Brett am Dorfplatz.[/color]")
_hud.text = "\n".join(zeilen)
_ablauf_aktualisieren()
_probleme_aktualisieren()
func setze_hinweis(text: String) -> void:
@@ -531,18 +589,19 @@ func _tagesablauf(human_id: String) -> void:
func _stunden_text(human_id: String, nr: int) -> String:
if not Game.gesehen_slot(human_id, nr):
return "—"
var sys := Game.system_in(human_id, nr)
if not sys.is_empty():
return "%s ← %s" % [Game.slot_aktivitaet(human_id, nr),
TechDB.by_id(str(sys["tech"]))["name"]]
var grund := Game.slot_grund(human_id, nr)
if not Game.erkannt(human_id, nr):
return "?"
if Ursachen.ist_blocker(grund):
return "%s (%s)" % [Ursachen.BLOCKER[grund]["name"],
Ursachen.LISTE[Ursachen.BLOCKER[grund]["ursache"]]["name"]]
match Game.slot_zustand(human_id, nr):
Game.Stunde.UNBEKANNT:
return "—"
Game.Stunde.GEBAUT:
var sys := Game.system_in(human_id, nr)
return "%s ← %s" % [Game.slot_aktivitaet(human_id, nr),
TechDB.by_id(str(sys["tech"]))["name"]]
Game.Stunde.UNGEKLAERT:
return "?"
Game.Stunde.BENANNT:
return "%s (%s)" % [Ursachen.BLOCKER[grund]["name"],
Ursachen.LISTE[Ursachen.BLOCKER[grund]["ursache"]]["name"]]
return Orte.text(grund)
@@ -554,6 +613,49 @@ func _stunden_zeile(human_id: String, nr: int, von: int, bis: int, text: String)
func() -> void: slot_panel(human_id, nr), offen)
## Der offene Moment: hier zählt, welche Technik zu diesem Problem passt.
func situation_panel(mensch: Node3D) -> void:
_apply_human = mensch
var id: String = str(mensch.data["id"])
if not Game.situation_bei(id):
anwenden_panel(mensch)
return
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)
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)
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)
_trenner()
if Game.known.is_empty():
_text("[color=#ffcc66]Du kennst keine Technik.[/color]", 16)
_zeigen("situation")
return
for tech_id in TechDB.ids():
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)
_knopf(text, func() -> void:
Game.situation_anwenden(tech_id)
schliessen(), frei)
_trenner()
_zeigen("situation")
## Was soll in diesem Slot stehen?
func slot_panel(human_id: String, nr: int) -> void:
var h := HumanDB.by_id(human_id)
@@ -664,13 +766,14 @@ func brett_panel() -> void:
_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 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):
if not offen.has(id):
verdeckt += 1
continue
gezeigt += 1

View File

@@ -13,27 +13,22 @@ class_name Ursachen
static var LISTE: Dictionary = {
"anfang": {
"name": "Kein Anfang", "kurz": "kommt nie in Gang",
"symptom": "Sie setzt sich hin und tut dann etwas anderes.",
"faktor": 0.30,
},
"zeit": {
"name": "Keine Zeit", "kurz": "der Tag ist voll",
"symptom": "Der Tag ist voll mit dem, was andere wollen.",
"faktor": 0.30,
},
"kraft": {
"name": "Keine Kraft", "kurz": "abends ist nichts mehr übrig",
"symptom": "Am Abend reicht es nur noch für Berieselung.",
"faktor": 0.40,
},
"halt": {
"name": "Kein Halt", "kurz": "fängt an und hört wieder auf",
"symptom": "Angefangen wird oft, drangeblieben selten.",
"faktor": 0.50,
},
"grund": {
"name": "Kein Grund", "kurz": "glaubt nicht mehr daran",
"symptom": "Sie redet sich das Vorhaben selbst klein.",
"faktor": 0.40,
},
}

View File

@@ -40,6 +40,7 @@ func _ready() -> void:
await test_notieren_im_spiel()
await test_tagesablauf_anzeige()
await test_ablauf_im_hud()
await test_probleme_und_momente()
await test_systeme()
await test_tempo_des_traums()
await test_cooldown()
@@ -878,6 +879,165 @@ func test_diagnose() -> void:
## Gegen eine Ursache baut man ein System. Passt die Belohnung, hält es besser.
## Die zweite Ebene: Probleme hängen nicht an Stunden, sondern an Momenten.
## Gewohnheiten laufen ohne dich weiter -- hier musst du dabei sein.
func test_probleme_und_momente() -> void:
abschnitt("Probleme zeigen sich in Momenten")
var id := "mensch_0"
Game.active_mission = id
Game.situation = {}
Game.situation_pause = 0.0
Game.probleme_bekannt.clear()
Game.problem_stand.clear()
Game.ueberwunden.clear()
Game.cooldown.clear()
ui().schliessen()
var prob: Array = Game.probleme_von(id)
p(prob.size() >= 1 and prob.size() <= 2,
"%s trägt %d Problem(e): %s" % [HumanDB.by_id(id)["name"], prob.size(), str(prob)])
var alle_bekannt := true
for x in prob:
if not Probleme.problem_da(str(x)):
alle_bekannt = false
p(alle_bekannt, "Alle stehen im Katalog")
var ohne_situation: Array = []
for x in Probleme.LISTE:
if Probleme.situationen_von(str(x)).is_empty():
ohne_situation.append(str(x))
p(ohne_situation.is_empty(), "Jedes Problem zeigt sich in Situationen%s" %
("" if ohne_situation.is_empty() else " — außer " + ", ".join(ohne_situation)))
var ohne_technik: Array = []
for x in Probleme.LISTE:
if Probleme.techniken_gegen(str(x)).is_empty():
ohne_technik.append(str(x))
p(ohne_technik.is_empty(), "Und gegen jedes gibt es Techniken%s" %
("" if ohne_technik.is_empty() else " — außer " + ", ".join(ohne_technik)))
# Sie kommt von allein, aber nicht sofort
p(not Game.situation_laeuft(), "Erst läuft kein Moment")
Game.situationen_ticken(1.0, false)
p(not Game.situation_laeuft(), "Bei einem Schlafenden kommt keiner")
Game.situationen_ticken(1.0, true)
p(Game.situation_laeuft(), "Bei einem wachen Menschen bricht einer auf")
var problem := Game.situation_problem()
p(prob.has(problem), "Und gehört zu einem seiner Probleme: %s" % problem)
# Solange sie läuft, steht der Traum still
Game.progress[id] = 10.0
Game.traum_voranbringen(6.0)
p(is_equal_approx(Game.mission_progress(id), 10.0),
"Im Moment kommt der Traum nicht voran (%.1f %%)" % Game.mission_progress(id))
# Dabeisein zeigt, was dahintersteckt
p(not Game.problem_bekannt(id, problem), "Was dahintersteckt, ist noch unbekannt")
Game.situation_sehen()
p(Game.problem_bekannt(id, problem), "Dabeisein zeigt es: %s" %
Probleme.name_von(problem))
# Eine unpassende Technik greift nicht
var passend := ""
var unpassend := ""
for tid in TechDB.ids():
if Probleme.hilft(tid, problem) and passend == "":
passend = tid
elif not Probleme.hilft(tid, problem) and unpassend == "":
unpassend = tid
Game.known[passend] = 0
Game.known[unpassend] = 0
var res_falsch := Game.situation_anwenden(unpassend)
p(res_falsch["ok"] and not res_falsch["treffer"],
"%s greift bei %s nicht" % [TechDB.by_id(unpassend)["name"],
Probleme.name_von(problem)])
p(Game.situation_laeuft(), "Der Moment läuft weiter")
# Die passende beendet ihn
var vorher: float = Game.mission_progress(id)
var res := Game.situation_anwenden(passend)
p(res["treffer"], "%s trägt hindurch" % TechDB.by_id(passend)["name"])
p(not Game.situation_laeuft(), "Der Moment ist vorbei")
p(Game.mission_progress(id) > vorher, "Und bringt den Traum voran (%.0f → %.0f %%)" %
[vorher, Game.mission_progress(id)])
p(Game.problem_fortschritt(id, problem) == 1, "Einmal geschafft")
# Oft genug, und das Problem kommt nicht wieder
for i in range(Game.PROBLEM_UEBERWINDEN):
Game.situation = {"mensch": id, "key": Probleme.situationen_von(problem)[0],
"problem": problem, "rest": Game.SITUATION_DAUER}
Game.cooldown.clear()
Game.situation_anwenden(passend)
p(Game.problem_ueberwunden(id, problem),
"Nach %d Malen ist %s überwunden" % [Game.PROBLEM_UEBERWINDEN,
Probleme.name_von(problem)])
Game.situation = {}
Game.situation_pause = 0.0
var kommt_wieder := false
for i in range(200):
Game.situationen_ticken(1.0, true)
if Game.situation_laeuft() and Game.situation_problem() == problem:
kommt_wieder = true
break
p(not kommt_wieder, "Dieser Moment kommt nicht wieder")
# Beide Ebenen stehen nebeneinander im HUD
Game.situation = {}
ui()._hud_aktualisieren()
p(ui()._ablauf.visible and ui()._probleme.visible,
"Tagesablauf und Momente stehen beide im HUD")
p(ui()._probleme.text.contains(Probleme.name_von(problem)),
"Die Momente nennen das Problem: %s" % ui()._probleme.text.replace("\n", " / "))
Game.situation = {"mensch": id, "key": Probleme.situationen_von(problem)[0],
"problem": problem, "rest": 9.0}
ui()._hud_aktualisieren()
p(ui()._probleme.text.contains("Jetzt:"), "Der laufende Moment steht oben")
# Und er kündigt sich am Menschen selbst an, nicht nur im HUD
var wer: Bewohner = null
for mm in welt().humans:
if mm.data["id"] == id:
wer = mm
p(wer.beschriftung().contains(str(Probleme.SITUATIONEN[Game.situation["key"]]["name"])),
"Am Menschen steht, was gerade aufbricht: %s" %
wer.beschriftung().replace("\n", " / "))
Game.situation = {}
p(not wer.beschriftung().contains("»"), "Ohne Moment steht dort nichts davon")
# E führt in den Moment, sonst in den Tagesablauf -- die zwei Ebenen
# teilen sich eine Taste, ohne sich in die Quere zu kommen
var mensch: Bewohner = null
for mm in welt().humans:
if mm.data["id"] == id:
mensch = mm
main.player.set_mode(Player.Mode.GEIST)
main.player.folgt = null
main.player.global_position = mensch.global_position + Vector3(0, 1.5, 1.5)
Game.situation = {}
main._process(0.05)
main._interagieren()
p(ui()._kind == "anwenden", "Ohne Moment führt E in den Tagesablauf (%s)" % ui()._kind)
ui().schliessen()
Game.situation = {"mensch": id, "key": Probleme.situationen_von(problem)[0],
"problem": problem, "rest": 12.0}
main._process(0.05)
main._interagieren()
p(ui()._kind == "situation", "Im Moment führt dieselbe Taste dorthin (%s)" % ui()._kind)
p(_panel_text().contains(str(Probleme.SITUATIONEN[Game.situation["key"]]["was"])),
"Das Panel zeigt, was gerade passiert")
ui().schliessen()
# Die Gewohnheitsebene läuft davon unberührt weiter
Game.situation = {}
Game.progress[id] = 0.0
Game.traum_voranbringen(24.0)
p(Game.mission_progress(id) > 0.0,
"Ohne Moment liefert der Tagesablauf wieder sein Tempo (%.0f %%)" %
Game.mission_progress(id))
Game.situation = {}
Game.ueberwunden.clear()
Game.probleme_bekannt.clear()
Game.problem_stand.clear()
## Der Ablauf steht auch im HUD, ohne dass man ein Panel öffnen muss.
func test_ablauf_im_hud() -> void:
abschnitt("Der Ablauf steht im HUD")