update
This commit is contained in:
@@ -1,27 +1,26 @@
|
|||||||
78098b89c88a74ebe8c20117b8754620
|
78098b89c88a74ebe8c20117b8754620
|
||||||
::res://::1788113016
|
::res://::1788113016
|
||||||
anforderungen.md::TextFile::-1::1788165575::0::1::::<><><>0<>0<><>::
|
anforderungen.md::TextFile::-1::1788204851::0::1::::<><><>0<>0<><>::
|
||||||
README.md::TextFile::-1::1788165599::0::1::::<><><>0<>0<><>::
|
README.md::TextFile::-1::1788165734::0::1::::<><><>0<>0<><>::
|
||||||
::res://scenes/::1787989294
|
::res://scenes/::1787989294
|
||||||
main.tscn::PackedScene::-1::1787989294::0::1::::<><><>0<>0<><>::res://scripts/main.gd
|
main.tscn::PackedScene::-1::1787989294::0::1::::<><><>0<>0<><>::res://scripts/main.gd
|
||||||
::res://scripts/::1788163668
|
::res://scripts/::1788209300
|
||||||
bewohner.gd::GDScript::2125278938812678811::1788165374::0::1::::Bewohner<>Node3D<><>0<>0<><>::
|
bewohner.gd::GDScript::2125278938812678811::1788209097::0::1::::Bewohner<>Node3D<><>0<>0<><>::
|
||||||
dream_db.gd::GDScript::4217518896355437099::1788164505::0::1::::DreamDB<>RefCounted<><>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<><>::
|
dream_world.gd::GDScript::8279158278942867258::1788164873::0::1::::DreamWorld<>Node3D<><>0<>0<><>::
|
||||||
earth_world.gd::GDScript::6086818627272428934::1788165412::0::1::::EarthWorld<>Node3D<><>0<>0<><>::
|
earth_world.gd::GDScript::6086818627272428934::1788165412::0::1::::EarthWorld<>Node3D<><>0<>0<><>::
|
||||||
game.gd::GDScript::3600922541500868814::1788165125::0::1::::<>Node<><>0<>0<><>::
|
game.gd::GDScript::3600922541500868814::1788209816::0::1::::<>Node<><>0<>0<><>::
|
||||||
human_db.gd::GDScript::412604892032291296::1788165374::0::1::::HumanDB<>RefCounted<><>0<>0<><>::
|
human_db.gd::GDScript::412604892032291296::1788208999::0::1::::HumanDB<>RefCounted<><>0<>0<><>::
|
||||||
main.gd::GDScript::1504009331368977934::1788121650::0::1::::<>Node3D<><>0<>0<><>::
|
main.gd::GDScript::1504009331368977934::1788209245::0::1::::<>Node3D<><>0<>0<><>::
|
||||||
netz.gd::GDScript::8422943321868648339::1788163667::0::1::::Netz<>RefCounted<><>0<>0<><>::
|
netz.gd::GDScript::8422943321868648339::1788163667::0::1::::Netz<>RefCounted<><>0<>0<><>::
|
||||||
orte.gd::GDScript::5536340784294498671::1788163839::0::1::::Orte<>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<><>::
|
player.gd::GDScript::8724108548430371398::1788039718::0::1::::Player<>CharacterBody3D<><>0<>0<><>::
|
||||||
prims.gd::GDScript::322632462553361584::1788039797::0::1::::Prims<>RefCounted<><>0<>0<><>::
|
prims.gd::GDScript::322632462553361584::1788039797::0::1::::Prims<>RefCounted<><>0<>0<><>::
|
||||||
technique_db.gd::GDScript::4543286561661639701::1788120975::0::1::::TechDB<>RefCounted<><>0<>0<><>::
|
technique_db.gd::GDScript::4543286561661639701::1788209343::0::1::::TechDB<>RefCounted<><>0<>0<><>::
|
||||||
ui.gd::GDScript::843471304695966286::1788122559::0::1::::UI<>CanvasLayer<><>0<>0<><>::
|
ui.gd::GDScript::843471304695966286::1788209227::0::1::::UI<>CanvasLayer<><>0<>0<><>::
|
||||||
::res://tests/::1788164088
|
ursachen.gd::GDScript::7371116734724270900::1788208917::0::1::::Ursachen<>RefCounted<><>0<>0<><>::
|
||||||
probe.gd::GDScript::5788011518062194748::1788165350::0::1::::<>Node<><>0<>0<><>::
|
::res://tests/::1788209571
|
||||||
probe.tscn::PackedScene::-1::1788163874::0::1::::<><><>0<>0<><>::res://tests/probe.gd
|
shots.gd::GDScript::5999651346126871724::1788209816::0::1::::<>Node<><>0<>0<><>::
|
||||||
shots.gd::GDScript::5999651346126871724::1788118441::0::1::::<>Node<><>0<>0<><>::
|
|
||||||
shots.tscn::PackedScene::-1::1787990528::0::1::::<><><>0<>0<><>::res://tests/shots.gd
|
shots.tscn::PackedScene::-1::1787990528::0::1::::<><><>0<>0<><>::res://tests/shots.gd
|
||||||
verify.gd::GDScript::4392606218392155269::1788165669::0::1::::<>Node<><>0<>0<><>::
|
verify.gd::GDScript::4392606218392155269::1788209816::0::1::::<>Node<><>0<>0<><>::
|
||||||
verify.tscn::PackedScene::-1::1787989983::0::1::::<><><>0<>0<><>::res://tests/verify.gd
|
verify.tscn::PackedScene::-1::1787989983::0::1::::<><><>0<>0<><>::res://tests/verify.gd
|
||||||
|
|||||||
@@ -86,4 +86,12 @@ list=[{
|
|||||||
"is_tool": false,
|
"is_tool": false,
|
||||||
"language": &"GDScript",
|
"language": &"GDScript",
|
||||||
"path": "res://scripts/ui.gd"
|
"path": "res://scripts/ui.gd"
|
||||||
|
}, {
|
||||||
|
"base": &"RefCounted",
|
||||||
|
"class": &"Ursachen",
|
||||||
|
"icon": "",
|
||||||
|
"is_abstract": false,
|
||||||
|
"is_tool": false,
|
||||||
|
"language": &"GDScript",
|
||||||
|
"path": "res://scripts/ursachen.gd"
|
||||||
}]
|
}]
|
||||||
|
|||||||
Binary file not shown.
66
README.md
66
README.md
@@ -24,41 +24,50 @@ Das Journal führt Buch — es lehrt und vergibt nichts.
|
|||||||
* **Techniken** — was du gelernt hast, mit Stufe und Erfahrung. Besser werden
|
* **Techniken** — was du gelernt hast, mit Stufe und Erfahrung. Besser werden
|
||||||
sie nur draußen.
|
sie nur draußen.
|
||||||
* **Missionen** — die Menschen, für die du dich entschieden hast, jeweils mit
|
* **Missionen** — die Menschen, für die du dich entschieden hast, jeweils mit
|
||||||
ihrem **Regelwerk**.
|
ihrem **Tagesablauf**.
|
||||||
|
|
||||||
**Regelwerk** — der Kern des Spiels
|
**Diagnose und Systeme** — der Kern des Spiels
|
||||||
|
|
||||||
Jede Tätigkeit im Tag eines Menschen kann eine Technik auslösen: *wenn Lena
|
Ein Traum scheitert an Ursachen: *kein Anfang*, *keine Zeit*, *keine Kraft*,
|
||||||
zögert, dann Pomodoro*. Wechselt sie in die Tätigkeit, greift die Regel von
|
*kein Halt*, *kein Grund*. Jeder Mensch hat zwei bis drei davon, nie alle. Die
|
||||||
allein, solange du auf der Erde bist.
|
stehen nirgends — du findest sie nur, indem du dabeistehst.
|
||||||
|
|
||||||
**Ob eine Regel taugt, sagt dir niemand.** Keine Prozentzahl, kein „passt zum
|
Sichtbar wird eine Ursache an den Tätigkeiten, die sie hervorbringt. Wer nie in
|
||||||
Thema", keine Liste guter Momente. Du bekommst nur die Technik selbst: was sie
|
Gang kommt, räumt auf statt anzufangen, recherchiert oder schreibt Später-Listen.
|
||||||
tut, wann sie passt, warum sie hilft. Und den Menschen: seinen Traum und das,
|
Wer keine Kraft hat, schaut abends eine Serie und bleibt danach wach. Jede
|
||||||
was im Weg steht. Beides zusammenzubringen ist das Spiel.
|
dieser Tätigkeiten hat einen **Auslöser** und eine **Belohnung**.
|
||||||
|
|
||||||
Eine Technik darf an beliebig vielen Tätigkeiten hängen. Sie überall
|
Gegen eine erkannte Ursache baust du ein System in den Tag:
|
||||||
hinzuhängen ist trotzdem falsch: im falschen Moment greift sie kaum und wirft
|
|
||||||
den Traum um 14 % zurück. Nach jedem Einsatz braucht sie außerdem 30 Sekunden
|
Einführen Ein System, das fehlt — in einen freien Slot.
|
||||||
Ruhe — ein Fehlgriff verbrennt also den Platz, den ein guter Moment gehabt
|
Ändern Eine Tätigkeit, die schadet — mit gleicher Belohnung ersetzt.
|
||||||
hätte. Mehr Momente sauber abzudecken heißt, mehr Techniken zu kennen, und die
|
|
||||||
gibt es nur auf der gewachsenen Insel.
|
Liefert die Ersatzhandlung dieselbe Belohnung, hält sie besser. Das ist Duhiggs
|
||||||
|
goldene Regel: Auslöser und Belohnung bleiben, nur die Handlung dazwischen wird
|
||||||
|
getauscht. Manche Techniken ersetzen nichts, sie nehmen dem Verhalten den
|
||||||
|
Auslöser.
|
||||||
|
|
||||||
|
Der Fortschritt ist keine Kette von Einzeltreffern, sondern ein **Tempo**:
|
||||||
|
|
||||||
|
Tempo je Tag = Grundrate × Faktor je Ursache
|
||||||
|
|
||||||
|
nichts gelöst 4 % je Tag → der Traum steht praktisch still
|
||||||
|
eine gelöst 18 % je Tag → er kommt voran
|
||||||
|
alle gelöst 61 % je Tag → in gut zwei Tagen erfüllt
|
||||||
|
|
||||||
|
Ungelöste Ursachen bremsen multiplikativ. Zwei Bremsen sind viel schlimmer als
|
||||||
|
eine — deshalb lohnt es, alle zu finden.
|
||||||
|
|
||||||
So laufen die zwei Schleifen:
|
So laufen die zwei Schleifen:
|
||||||
|
|
||||||
Techniken lernen → Regelwerk anpassen → Probleme lösen
|
Techniken lernen → Systeme bauen → Traum läuft schneller
|
||||||
Träume erfüllen → Dorf wächst → neue Wege entdecken
|
Träume erfüllen → Dorf wächst → neue Wege entdecken
|
||||||
|
|
||||||
Eine Regel greift immer wieder, solange der Moment anhält — im Takt des
|
|
||||||
Cooldowns. Wie viel ein Tag einbringt, hängt also daran, wie lange ein Mensch
|
|
||||||
in der passenden Tätigkeit bleibt.
|
|
||||||
|
|
||||||
Ein erfüllter Traum bringt ein Wesen mit seinem Haus ins Dorf, und in diesem
|
Ein erfüllter Traum bringt ein Wesen mit seinem Haus ins Dorf, und in diesem
|
||||||
Haus wird ein neuer Weg gelehrt. Zu Beginn kennt das Dorf nur einen.
|
Haus wird ein neuer Weg gelehrt. Zu Beginn kennt das Dorf nur einen.
|
||||||
|
|
||||||
Schlafende sind unerreichbar, dieselbe Technik wirkt bei Wiederholung
|
Nach jedem Einsatz braucht eine Technik 30 Sekunden Ruhe. Ein Einbau gelingt
|
||||||
schwächer, ein Fehlversuch macht kurz dicht. Von Hand geht es weiter: nah
|
nicht immer — Übung entscheidet.
|
||||||
herangehen und **E** wirkt sofort.
|
|
||||||
|
|
||||||
**Traumwelt** — eine schwebende Insel mit einem Dorf, das wächst
|
**Traumwelt** — eine schwebende Insel mit einem Dorf, das wächst
|
||||||
|
|
||||||
@@ -133,18 +142,19 @@ Menschen einsetzen — auch Fehlversuche zählen.
|
|||||||
|
|
||||||
project.godot Projekt, Autoload `Game`
|
project.godot Projekt, Autoload `Game`
|
||||||
scenes/main.tscn Einstieg
|
scenes/main.tscn Einstieg
|
||||||
scripts/game.gd Zustand, Regelwerk, wachsende Welt, Uhr (Autoload)
|
scripts/game.gd Zustand, Diagnose, Systeme, Tempo, Uhr (Autoload)
|
||||||
scripts/technique_db.gd die zwölf Techniken mit ihren Hinweisen
|
scripts/technique_db.gd die zwölf Techniken mit ihren Hinweisen
|
||||||
scripts/human_db.gd Bezirk: Arterien, Blöcke, roji, Parzellen, Menschen
|
scripts/human_db.gd Bezirk: Arterien, Blöcke, roji, Parzellen, Menschen
|
||||||
scripts/dream_db.gd Traumdorf: wachsende Häuser, Wege, Bewohner, Lehrorte
|
scripts/dream_db.gd Traumdorf: wachsende Häuser, Wege, Bewohner, Lehrorte
|
||||||
scripts/netz.gd Wegenetz: Knoten, Kanten, Andocken, kürzester Weg
|
scripts/netz.gd Wegenetz: Knoten, Kanten, Andocken, kürzester Weg
|
||||||
scripts/orte.gd Orte, Türen, Wege, Tätigkeiten (beide Welten)
|
scripts/orte.gd Orte, Türen, Wege, Tätigkeiten (beide Welten)
|
||||||
scripts/bewohner.gd Bewohner mit Tagesablauf, löst Regeln aus
|
scripts/bewohner.gd Bewohner mit Tagesablauf und Slots
|
||||||
scripts/main.gd Weltenwechsel, Fokus, Interaktion
|
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
|
||||||
scripts/dream_world.gd Insel mit Dorf
|
scripts/dream_world.gd Insel mit Dorf
|
||||||
scripts/earth_world.gd Stadt mit Tag-Nacht-Wechsel
|
scripts/earth_world.gd Stadt mit Tag-Nacht-Wechsel
|
||||||
scripts/ui.gd HUD, Journal, Regelwerk, Hörsaal, Brett, Panels
|
scripts/ursachen.gd Ursachen, blockierende Tätigkeiten, Belohnungen
|
||||||
|
scripts/ui.gd HUD, Journal, Tagesablauf, Hörsaal, Brett, Panels
|
||||||
scripts/prims.gd Bausteine aus Primitiven
|
scripts/prims.gd Bausteine aus Primitiven
|
||||||
|
|
||||||
## Prüfen
|
## Prüfen
|
||||||
@@ -156,9 +166,9 @@ Menschen einsetzen — auch Fehlversuche zählen.
|
|||||||
Tagesabläufen, gewachsenes Dorf und erzeugter Bezirk,
|
Tagesabläufen, gewachsenes Dorf und erzeugter Bezirk,
|
||||||
Häuser betreten, Journal in beiden Welten, im Hörsaal lernen,
|
Häuser betreten, Journal in beiden Welten, im Hörsaal lernen,
|
||||||
Verbessern allein durchs Anwenden, Mission am Schwarzen Brett annehmen,
|
Verbessern allein durchs Anwenden, Mission am Schwarzen Brett annehmen,
|
||||||
Regelwerk bauen und einen Tag unbeaufsichtigt laufen lassen, zur Erde reisen,
|
Ursachen aufdecken, Systeme bauen, Tempo messen, zur Erde reisen,
|
||||||
Tagesabläufe über einen ganzen Tag, Wirkung der Technikwahl, Cooldown,
|
Tagesabläufe über einen ganzen Tag, Wirkung der Technikwahl, Cooldown,
|
||||||
verdeckte Erfolgschance, keine Passungshinweise, Mehrfachbelegung von Regeln,
|
verdeckte Erfolgschance, keine Passungshinweise,
|
||||||
Tempo und Nachtsprung,
|
Tempo und Nachtsprung,
|
||||||
nur lösbare Aushänge, Mission abschließen,
|
nur lösbare Aushänge, Mission abschließen,
|
||||||
Insel wachsen lassen, Tastensteuerung. Beendet sich mit Code 1, wenn etwas
|
Insel wachsen lassen, Tastensteuerung. Beendet sich mit Code 1, wenn etwas
|
||||||
|
|||||||
@@ -9,15 +9,8 @@ Loops
|
|||||||
Funktionen
|
Funktionen
|
||||||
- Bewegung: Bewegen, Springen, Geist
|
- Bewegung: Bewegen, Springen, Geist
|
||||||
- Journal: Gelernte Techniken, Akzetierte Missionen
|
- Journal: Gelernte Techniken, Akzetierte Missionen
|
||||||
- Techniken: Lernen am Lehrort, Verbessern durch Anwenden
|
- Techniken: Lernen, Verbessern
|
||||||
- Missionen: Pipeline, nur lösbare werden angeboten
|
- Missionen: Pipeline
|
||||||
- Techniken: Cooldown, Fehlschlag kostet Fortschritt
|
- Techniken: Cooldown, Fehlschlag
|
||||||
- Erfolgschance und Passung bleiben verdeckt
|
- Menschen: Tagesablauf, Tempo
|
||||||
- Eine Technik darf an mehreren Tätigkeiten hängen
|
- Prozedurale Generierung: Dorf, Stadt
|
||||||
- Menschen: Tagesablauf
|
|
||||||
- Tempo: Stufe 1, 2, 3 wie in Die Sims (1×, 3×, 7×)
|
|
||||||
- Im Schlaf des Menschen automatisch Stufe 3
|
|
||||||
- Prozedurale Generierung
|
|
||||||
- Dorf: wächst Haus für Haus, verwinkelte Wege, grün und gemütlich
|
|
||||||
- Erde: Stadtbezirk nach japanischem Vorbild, Arterien und roji
|
|
||||||
- Auf der Erde sind alle Menschen von Anfang an da
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ var _aura: MeshInstance3D
|
|||||||
var _strahl: MeshInstance3D
|
var _strahl: MeshInstance3D
|
||||||
var _path: Array = []
|
var _path: Array = []
|
||||||
var _letzte_aktivitaet: String = ""
|
var _letzte_aktivitaet: String = ""
|
||||||
var _seit_regel: float = 0.0
|
var slot: int = 0
|
||||||
var _bob: float = 0.0
|
var _bob: float = 0.0
|
||||||
var _offset: Vector3
|
var _offset: Vector3
|
||||||
|
|
||||||
@@ -70,13 +70,18 @@ func setup(d: Dictionary, index: int, orte: Dictionary,
|
|||||||
global_position = Orte.center(places, place) + _offset
|
global_position = Orte.center(places, place) + _offset
|
||||||
|
|
||||||
|
|
||||||
|
## [Ort, Tätigkeit, Slotnummer] zur Stunde h. Steht in dem Slot ein System,
|
||||||
|
## ist die Tätigkeit die Ersatzhandlung.
|
||||||
func _routine_at(h: float) -> Array:
|
func _routine_at(h: float) -> Array:
|
||||||
var r: Array = data["routine"]
|
var r: Array = data["routine"]
|
||||||
var cur: Array = r[r.size() - 1]
|
var nr := r.size() - 1
|
||||||
for eintrag in r:
|
for i in range(r.size()):
|
||||||
if h >= float(eintrag[0]):
|
if h >= float(r[i][0]):
|
||||||
cur = eintrag
|
nr = i
|
||||||
return [cur[1], cur[2]]
|
var akt: String = str(r[nr][2])
|
||||||
|
if mit_mission:
|
||||||
|
akt = Game.slot_aktivitaet(str(data["id"]), nr)
|
||||||
|
return [str(r[nr][1]), akt, nr]
|
||||||
|
|
||||||
|
|
||||||
func _process(roh: float) -> void:
|
func _process(roh: float) -> void:
|
||||||
@@ -84,6 +89,7 @@ func _process(roh: float) -> void:
|
|||||||
resist_left = maxf(0.0, resist_left - delta)
|
resist_left = maxf(0.0, resist_left - delta)
|
||||||
|
|
||||||
var soll := _routine_at(Game.time_h)
|
var soll := _routine_at(Game.time_h)
|
||||||
|
slot = int(soll[2])
|
||||||
if soll[0] != place:
|
if soll[0] != place:
|
||||||
var war_unterwegs := not _path.is_empty()
|
var war_unterwegs := not _path.is_empty()
|
||||||
_path = Orte.route(places, place, soll[0], _offset, netz, anker)
|
_path = Orte.route(places, place, soll[0], _offset, netz, anker)
|
||||||
@@ -117,16 +123,8 @@ func _process(roh: float) -> void:
|
|||||||
_visual.rotation.z = lerp_angle(_visual.rotation.z, PI * 0.5 if activity == "schlaeft" else 0.0,
|
_visual.rotation.z = lerp_angle(_visual.rotation.z, PI * 0.5 if activity == "schlaeft" else 0.0,
|
||||||
1.0 - pow(0.01, delta))
|
1.0 - pow(0.01, delta))
|
||||||
|
|
||||||
# Solange der Moment anhält, greift die Regel erneut, sobald ihre Technik
|
|
||||||
# wieder frei ist. Der Cooldown gibt damit den Takt vor.
|
|
||||||
_seit_regel += delta
|
|
||||||
if activity != _letzte_aktivitaet:
|
if activity != _letzte_aktivitaet:
|
||||||
_letzte_aktivitaet = activity
|
_letzte_aktivitaet = activity
|
||||||
_seit_regel = 0.0
|
|
||||||
_regel_pruefen()
|
|
||||||
elif _seit_regel >= 1.0:
|
|
||||||
_seit_regel = 0.0
|
|
||||||
_regel_pruefen()
|
|
||||||
|
|
||||||
var erledigt: bool = mit_mission and Game.completed.has(data["id"])
|
var erledigt: bool = mit_mission and Game.completed.has(data["id"])
|
||||||
var aktiv: bool = mit_mission and Game.active_mission == data["id"]
|
var aktiv: bool = mit_mission and Game.active_mission == data["id"]
|
||||||
@@ -158,20 +156,6 @@ func beschriftung() -> String:
|
|||||||
return s
|
return s
|
||||||
|
|
||||||
|
|
||||||
## Wechselt der Mensch die Tätigkeit, greift das Regelwerk der Mission von allein.
|
|
||||||
func _regel_pruefen() -> void:
|
|
||||||
if not mit_mission:
|
|
||||||
return
|
|
||||||
var res := Game.regel_ausloesen(data["id"], activity, resist_left > 0.0)
|
|
||||||
if res.is_empty():
|
|
||||||
return
|
|
||||||
var t := TechDB.by_id(str(res["tech"]))
|
|
||||||
if res["success"]:
|
|
||||||
reagiere(true, "%s\n+%d %%" % [t["name"], int(round(float(res["gain"])))])
|
|
||||||
else:
|
|
||||||
reagiere(false, "%s prallt ab" % t["name"])
|
|
||||||
|
|
||||||
|
|
||||||
## Sichtbare Reaktion auf eine angewandte Technik.
|
## Sichtbare Reaktion auf eine angewandte Technik.
|
||||||
func reagiere(success: bool, text: String) -> void:
|
func reagiere(success: bool, text: String) -> void:
|
||||||
var l := Prims.label(self, Vector3(0, 3.5, 0), text, 0.34,
|
var l := Prims.label(self, Vector3(0, 3.5, 0), text, 0.34,
|
||||||
|
|||||||
342
scripts/game.gd
342
scripts/game.gd
@@ -21,9 +21,10 @@ const FEHLVERSUCH_VERLUST := 14.0 # ein Fehlschlag wirft den Traum zurück
|
|||||||
var known: Dictionary = {} # tech_id -> xp
|
var known: Dictionary = {} # tech_id -> xp
|
||||||
var active_mission: String = "" # human_id oder ""
|
var active_mission: String = "" # human_id oder ""
|
||||||
var progress: Dictionary = {} # human_id -> 0..100
|
var progress: Dictionary = {} # human_id -> 0..100
|
||||||
var used: Dictionary = {} # "human:tech" -> Anzahl
|
|
||||||
var cooldown: Dictionary = {} # tech_id -> Restsekunden
|
var cooldown: Dictionary = {} # tech_id -> Restsekunden
|
||||||
var pipeline: Dictionary = {} # human_id -> {activity -> tech_id}
|
var systeme: Dictionary = {} # human_id -> {slot -> {tech, guete}}
|
||||||
|
var erkannt_slots: Dictionary = {} # human_id -> {slot -> true}
|
||||||
|
var beobachtung: Dictionary = {} # "human:slot" -> Sekunden
|
||||||
var completed: Array = []
|
var completed: Array = []
|
||||||
var time_h: float = 7.0
|
var time_h: float = 7.0
|
||||||
var day: int = 1
|
var day: int = 1
|
||||||
@@ -113,15 +114,6 @@ func advance_time(delta: float) -> void:
|
|||||||
while time_h >= 24.0:
|
while time_h >= 24.0:
|
||||||
time_h -= 24.0
|
time_h -= 24.0
|
||||||
day += 1
|
day += 1
|
||||||
_gewoehnung_klingt_ab()
|
|
||||||
|
|
||||||
|
|
||||||
## Abstand macht eine Technik wieder wirksam: über Nacht verfällt die Hälfte
|
|
||||||
## der Gewöhnung. Wer täglich denselben Weg geht, hält ihn brauchbar — wer ihn
|
|
||||||
## an einem Tag immer wieder auffährt, stumpft ihn ab.
|
|
||||||
func _gewoehnung_klingt_ab() -> void:
|
|
||||||
for key in used:
|
|
||||||
used[key] = int(used[key]) / 2
|
|
||||||
|
|
||||||
|
|
||||||
func time_string() -> String:
|
func time_string() -> String:
|
||||||
@@ -261,25 +253,12 @@ func angenommen(human_id: String) -> bool:
|
|||||||
return progress.has(human_id)
|
return progress.has(human_id)
|
||||||
|
|
||||||
|
|
||||||
## Eine Mission ist machbar, wenn mindestens eine gelernte Technik das Thema
|
## Eine Mission ist machbar, wenn mindestens eine ihrer Ursachen mit einer
|
||||||
## des Menschen trifft und in seinem Tag auch einen Moment dafür findet.
|
## gelernten Technik anzugehen ist. Die übrigen bremsen dann eben noch.
|
||||||
## Nur solche werden am Schwarzen Brett überhaupt ausgehängt.
|
|
||||||
func machbar(human_id: String) -> bool:
|
func machbar(human_id: String) -> bool:
|
||||||
var h := HumanDB.by_id(human_id)
|
for u in ursachen_von(human_id):
|
||||||
if h.is_empty():
|
|
||||||
return false
|
|
||||||
var tag_liste: Array = HumanDB.aktivitaeten(human_id)
|
|
||||||
for id in known:
|
for id in known:
|
||||||
var t := TechDB.by_id(id)
|
if str(TechDB.by_id(id)["ursache"]) == str(u):
|
||||||
var thema := false
|
|
||||||
for tag in t["tags"]:
|
|
||||||
if (h["tags"] as Array).has(tag):
|
|
||||||
thema = true
|
|
||||||
break
|
|
||||||
if not thema:
|
|
||||||
continue
|
|
||||||
for a in t["momente"]:
|
|
||||||
if tag_liste.has(a) and erreichbar(a):
|
|
||||||
return true
|
return true
|
||||||
return false
|
return false
|
||||||
|
|
||||||
@@ -317,161 +296,188 @@ func _insel_waechst() -> void:
|
|||||||
Color(0.75, 0.95, 1))
|
Color(0.75, 0.95, 1))
|
||||||
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------- Regelwerk
|
# --------------------------------------------------------------------- Systeme
|
||||||
# Eine Regel ist ein Wenn-Dann: tut der Mensch etwas Bestimmtes, greift die
|
# Ein Traum scheitert an Ursachen. Die sind verdeckt und zeigen sich nur im
|
||||||
# zugeordnete Technik von allein. Damit automatisiert der Spieler den Fortschritt.
|
# Tagesablauf. Wer sie gefunden hat, baut Systeme dagegen: in einen freien
|
||||||
|
# Slot ein neues, oder auf einen Blocker ein besseres. Je mehr Ursachen
|
||||||
|
# abgedeckt sind, desto schneller kommt der Traum voran.
|
||||||
|
|
||||||
func regeln(human_id: String) -> Dictionary:
|
const BASIS_TEMPO := 45.0 # Prozent je Tag, wenn nichts mehr bremst
|
||||||
return pipeline.get(human_id, {})
|
const GUETE_ERSATZ := 1.35 # Blocker mit gleicher Belohnung ersetzt
|
||||||
|
const GUETE_NEU := 1.0 # System in einen freien Slot gesetzt
|
||||||
|
const ERKENNEN_SEK := 3.0 # so lange muss man dabeistehen
|
||||||
|
|
||||||
|
|
||||||
func regel_fuer(human_id: String, activity: String) -> String:
|
func slots(human_id: String) -> Array:
|
||||||
return regeln(human_id).get(activity, "")
|
var h := HumanDB.by_id(human_id)
|
||||||
|
return h["routine"] if h.has("routine") else []
|
||||||
|
|
||||||
|
|
||||||
func regel_anzahl(human_id: String) -> int:
|
func slot_grund(human_id: String, nr: int) -> String:
|
||||||
return regeln(human_id).size()
|
var r := slots(human_id)
|
||||||
|
return str(r[nr][2]) if nr >= 0 and nr < r.size() else ""
|
||||||
|
|
||||||
|
|
||||||
## An welchen Tätigkeiten hängt diese Technik gerade?
|
## Was in diesem Slot wirklich passiert: die Ersatzhandlung, wenn ein System
|
||||||
func regel_momente(human_id: String, tech_id: String) -> Array:
|
## steht -- sonst das, was von Haus aus dort steht.
|
||||||
var out: Array = []
|
func slot_aktivitaet(human_id: String, nr: int) -> String:
|
||||||
for activity in regeln(human_id):
|
var sys := system_in(human_id, nr)
|
||||||
if regeln(human_id)[activity] == tech_id:
|
if not sys.is_empty():
|
||||||
out.append(activity)
|
return str(TechDB.by_id(str(sys["tech"]))["ersatz"])
|
||||||
return out
|
return slot_grund(human_id, nr)
|
||||||
|
|
||||||
|
|
||||||
## Leere tech_id löscht die Regel. Eine Technik darf an beliebig vielen
|
func system_in(human_id: String, nr: int) -> Dictionary:
|
||||||
## Tätigkeiten hängen — ob das klug ist, muss der Spieler aus ihr herauslesen.
|
return systeme.get(human_id, {}).get(nr, {})
|
||||||
func regel_setzen(human_id: String, activity: String, tech_id: String) -> void:
|
|
||||||
if not pipeline.has(human_id):
|
|
||||||
pipeline[human_id] = {}
|
# ------------------------------------------------------------------- Erkennen
|
||||||
var r: Dictionary = pipeline[human_id]
|
|
||||||
if tech_id == "":
|
func erkannt(human_id: String, nr: int) -> bool:
|
||||||
r.erase(activity)
|
if not Ursachen.ist_blocker(slot_grund(human_id, nr)):
|
||||||
else:
|
return true
|
||||||
r[activity] = tech_id
|
return erkannt_slots.get(human_id, {}).has(nr)
|
||||||
|
|
||||||
|
|
||||||
|
## Dabeistehen deckt auf, was dort wirklich läuft -- und damit die Ursache.
|
||||||
|
func beobachten(human_id: String, nr: int, delta: float) -> bool:
|
||||||
|
if erkannt(human_id, nr):
|
||||||
|
return false
|
||||||
|
var schluessel := "%s:%d" % [human_id, nr]
|
||||||
|
var stand: float = float(beobachtung.get(schluessel, 0.0)) + delta
|
||||||
|
beobachtung[schluessel] = stand
|
||||||
|
if stand < ERKENNEN_SEK:
|
||||||
|
return false
|
||||||
|
if not erkannt_slots.has(human_id):
|
||||||
|
erkannt_slots[human_id] = {}
|
||||||
|
erkannt_slots[human_id][nr] = true
|
||||||
|
var b := slot_grund(human_id, nr)
|
||||||
|
notified.emit("Erkannt: %s — %s" % [Ursachen.BLOCKER[b]["name"],
|
||||||
|
Ursachen.LISTE[Ursachen.ursache_von(b)]["name"]], Color(0.8, 0.95, 1))
|
||||||
|
state_changed.emit()
|
||||||
|
return true
|
||||||
|
|
||||||
|
|
||||||
|
## Eine Ursache gilt als erkannt, sobald eine ihrer Tätigkeiten aufgedeckt ist.
|
||||||
|
## Nur eine Quelle -- sonst driften Slot und Ursache auseinander.
|
||||||
|
func ursache_bekannt(human_id: String, ursache: String) -> bool:
|
||||||
|
for nr in erkannt_slots.get(human_id, {}):
|
||||||
|
if Ursachen.ursache_von(slot_grund(human_id, int(nr))) == ursache:
|
||||||
|
return true
|
||||||
|
return false
|
||||||
|
|
||||||
|
|
||||||
|
func ursachen_von(human_id: String) -> Array:
|
||||||
|
var h := HumanDB.by_id(human_id)
|
||||||
|
return h["ursachen"] if h.has("ursachen") else []
|
||||||
|
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------- Tempo
|
||||||
|
|
||||||
|
## Steht gegen diese Ursache ein System? Gibt die Güte zurück, sonst 0.
|
||||||
|
func ursache_geloest(human_id: String, ursache: String) -> float:
|
||||||
|
var beste := 0.0
|
||||||
|
for nr in systeme.get(human_id, {}):
|
||||||
|
var sys: Dictionary = systeme[human_id][nr]
|
||||||
|
if str(TechDB.by_id(str(sys["tech"]))["ursache"]) == ursache:
|
||||||
|
beste = maxf(beste, float(sys["guete"]))
|
||||||
|
return beste
|
||||||
|
|
||||||
|
|
||||||
|
## Wie schnell kommt der Traum voran? Jede ungelöste Ursache bremst.
|
||||||
|
func traum_tempo(human_id: String) -> float:
|
||||||
|
var t := BASIS_TEMPO
|
||||||
|
for u in ursachen_von(human_id):
|
||||||
|
var g := ursache_geloest(human_id, str(u))
|
||||||
|
t *= g if g > 0.0 else float(Ursachen.LISTE[u]["faktor"])
|
||||||
|
return t
|
||||||
|
|
||||||
|
|
||||||
|
# ------------------------------------------------------------- System setzen
|
||||||
|
|
||||||
|
## Passt diese Technik in diesen Slot? Gibt Güte und Grund zurück.
|
||||||
|
func system_pruefen(human_id: String, nr: int, tech_id: String) -> Dictionary:
|
||||||
|
var res := {"geht": false, "guete": 0.0, "grund": ""}
|
||||||
|
if not known.has(tech_id):
|
||||||
|
res["grund"] = "Diese Technik kennst du nicht."
|
||||||
|
return res
|
||||||
|
if not bereit(tech_id):
|
||||||
|
res["grund"] = "%s ist noch nicht wieder einsatzbereit." % TechDB.by_id(tech_id)["name"]
|
||||||
|
return res
|
||||||
|
var grund_akt := slot_grund(human_id, nr)
|
||||||
|
if grund_akt == "schlaeft":
|
||||||
|
res["grund"] = "Im Schlaf lässt sich nichts einrichten."
|
||||||
|
return res
|
||||||
|
if not erkannt(human_id, nr):
|
||||||
|
res["grund"] = "Was hier läuft, hast du noch nicht gesehen."
|
||||||
|
return res
|
||||||
|
var t := TechDB.by_id(tech_id)
|
||||||
|
if Ursachen.ist_blocker(grund_akt):
|
||||||
|
var b: Dictionary = Ursachen.BLOCKER[grund_akt]
|
||||||
|
if str(t["ursache"]) != str(b["ursache"]):
|
||||||
|
res["grund"] = "Das hier hat einen anderen Grund."
|
||||||
|
return res
|
||||||
|
res["geht"] = true
|
||||||
|
var gleich: bool = str(t["belohnung"]) == str(b["belohnung"])
|
||||||
|
res["guete"] = GUETE_ERSATZ if gleich or TechDB.entfernt_ausloeser(tech_id) else GUETE_NEU
|
||||||
|
return res
|
||||||
|
res["geht"] = true
|
||||||
|
res["guete"] = GUETE_NEU
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
## Richtet das System ein. Gelingt nicht immer -- Übung entscheidet.
|
||||||
|
func system_setzen(human_id: String, nr: int, tech_id: String, widerstand: bool) -> Dictionary:
|
||||||
|
var pruef := system_pruefen(human_id, nr, tech_id)
|
||||||
|
if not pruef["geht"]:
|
||||||
|
return {"ok": false, "grund": pruef["grund"]}
|
||||||
|
cooldown[tech_id] = TECHNIK_COOLDOWN
|
||||||
|
var chance := clampf(0.20 + 0.13 * float(skill_of(tech_id)) - (0.25 if widerstand else 0.0),
|
||||||
|
0.05, 0.95)
|
||||||
|
var erfolg := randf() < chance
|
||||||
|
if not erfolg:
|
||||||
|
add_xp(tech_id, 1)
|
||||||
|
state_changed.emit()
|
||||||
|
return {"ok": true, "erfolg": false, "guete": 0.0}
|
||||||
|
if not systeme.has(human_id):
|
||||||
|
systeme[human_id] = {}
|
||||||
|
systeme[human_id][nr] = {"tech": tech_id, "guete": float(pruef["guete"])}
|
||||||
|
add_xp(tech_id, 2)
|
||||||
|
notified.emit("System steht: %s um %02d:00" %
|
||||||
|
[TechDB.by_id(tech_id)["name"], int(slots(human_id)[nr][0])], Color(0.6, 1, 0.7))
|
||||||
|
state_changed.emit()
|
||||||
|
return {"ok": true, "erfolg": true, "guete": float(pruef["guete"])}
|
||||||
|
|
||||||
|
|
||||||
|
func system_entfernen(human_id: String, nr: int) -> void:
|
||||||
|
if systeme.has(human_id):
|
||||||
|
systeme[human_id].erase(nr)
|
||||||
state_changed.emit()
|
state_changed.emit()
|
||||||
|
|
||||||
|
|
||||||
## Greift für diese Tätigkeit eine Regel? Wird nicht nur beim Wechsel gefragt,
|
func system_anzahl(human_id: String) -> int:
|
||||||
## sondern immer wieder — solange der Moment anhält und die Technik frei ist.
|
return systeme.get(human_id, {}).size()
|
||||||
func regel_ausloesen(human_id: String, activity: String, resisting: bool) -> Dictionary:
|
|
||||||
if human_id != active_mission:
|
|
||||||
return {}
|
|
||||||
var tech_id := regel_fuer(human_id, activity)
|
|
||||||
if tech_id == "" or not known.has(tech_id):
|
|
||||||
return {}
|
|
||||||
if not bereit(tech_id):
|
|
||||||
return {} # still: die Technik greift wieder, sobald ihre Sperre fällt
|
|
||||||
var res := apply_technique(tech_id, human_id, activity, resisting)
|
|
||||||
if not res["ok"]:
|
|
||||||
return {}
|
|
||||||
res["tech"] = tech_id
|
|
||||||
var t := TechDB.by_id(tech_id)
|
|
||||||
if res["success"]:
|
|
||||||
notified.emit("Regel greift — %s bei »%s« (+%d %%)" %
|
|
||||||
[t["name"], Orte.text(activity), int(round(float(res["gain"])))],
|
|
||||||
Color(0.6, 1, 0.7))
|
|
||||||
else:
|
|
||||||
notified.emit("Regel läuft ins Leere — %s bei »%s« (−%d %%)" %
|
|
||||||
[t["name"], Orte.text(activity), int(round(float(res["verlust"])))],
|
|
||||||
Color(1, 0.7, 0.5))
|
|
||||||
return res
|
|
||||||
|
|
||||||
|
|
||||||
# ----------------------------------------------------- Technik auf Mensch anwenden
|
## Der Traum kommt voran, solange Systeme stehen.
|
||||||
|
func traum_voranbringen(stunden: float) -> void:
|
||||||
## Schlafende erreicht keine Technik — weder von Hand noch über eine Regel.
|
if active_mission == "":
|
||||||
func erreichbar(activity: String) -> bool:
|
return
|
||||||
return activity != "schlaeft"
|
var p: float = progress.get(active_mission, 0.0) \
|
||||||
|
+ traum_tempo(active_mission) * stunden / 24.0
|
||||||
|
progress[active_mission] = minf(p, MISSION_ZIEL)
|
||||||
## Bewertet eine Technik in genau dieser Situation, ohne sie anzuwenden.
|
if progress[active_mission] >= MISSION_ZIEL and not completed.has(active_mission):
|
||||||
func evaluate(tech_id: String, human_id: String, activity: String, resisting: bool) -> Dictionary:
|
var wer := active_mission
|
||||||
var t := TechDB.by_id(tech_id)
|
completed.append(wer)
|
||||||
var h := HumanDB.by_id(human_id)
|
|
||||||
var skill := skill_of(tech_id)
|
|
||||||
var res := {
|
|
||||||
"chance": 0.0, "tag": false, "moment": false, "blocked": false,
|
|
||||||
"grund": "", "skill": skill,
|
|
||||||
}
|
|
||||||
if not erreichbar(activity):
|
|
||||||
res["blocked"] = true
|
|
||||||
res["grund"] = "Sie oder er schläft. Techniken erreichen nur wache Menschen."
|
|
||||||
return res
|
|
||||||
if skill == 0:
|
|
||||||
res["blocked"] = true
|
|
||||||
res["grund"] = "Technik nicht gelernt."
|
|
||||||
return res
|
|
||||||
|
|
||||||
for tag in t["tags"]:
|
|
||||||
if h["tags"].has(tag):
|
|
||||||
res["tag"] = true
|
|
||||||
break
|
|
||||||
res["moment"] = t["momente"].has(activity)
|
|
||||||
|
|
||||||
# Der Moment wiegt am schwersten: eine Technik zur falschen Zeit greift kaum,
|
|
||||||
# egal wie gut sie zum Menschen passt. Genau das steht in ihrem "Wann".
|
|
||||||
var c := 0.05 + 0.09 * float(skill)
|
|
||||||
if res["tag"]:
|
|
||||||
c += 0.20
|
|
||||||
if res["moment"]:
|
|
||||||
c += 0.35
|
|
||||||
if resisting:
|
|
||||||
c -= 0.30
|
|
||||||
res["grund"] = "Der Mensch macht gerade dicht."
|
|
||||||
res["chance"] = clampf(c, 0.05, 0.95)
|
|
||||||
return res
|
|
||||||
|
|
||||||
|
|
||||||
## Wendet die Technik wirklich an: würfelt, verteilt EP und Fortschritt.
|
|
||||||
func apply_technique(tech_id: String, human_id: String, activity: String, resisting: bool) -> Dictionary:
|
|
||||||
if not bereit(tech_id):
|
|
||||||
return {"ok": false, "grund": "%s ist noch nicht wieder einsatzbereit." %
|
|
||||||
TechDB.by_id(tech_id)["name"]}
|
|
||||||
var ev := evaluate(tech_id, human_id, activity, resisting)
|
|
||||||
if ev["blocked"]:
|
|
||||||
return {"ok": false, "grund": ev["grund"]}
|
|
||||||
cooldown[tech_id] = TECHNIK_COOLDOWN
|
|
||||||
|
|
||||||
var roll := randf()
|
|
||||||
var success: bool = roll < float(ev["chance"])
|
|
||||||
var key := "%s:%s" % [human_id, tech_id]
|
|
||||||
var wiederholung: int = used.get(key, 0)
|
|
||||||
used[key] = wiederholung + 1
|
|
||||||
|
|
||||||
var gain := 0.0
|
|
||||||
var verlust := 0.0
|
|
||||||
if success:
|
|
||||||
var base := 8.0 + 2.0 * float(ev["skill"])
|
|
||||||
if ev["tag"]:
|
|
||||||
base += 5.0
|
|
||||||
if ev["moment"]:
|
|
||||||
base += 5.0
|
|
||||||
gain = base / (1.0 + 0.6 * float(wiederholung))
|
|
||||||
add_xp(tech_id, 2)
|
|
||||||
else:
|
|
||||||
verlust = FEHLVERSUCH_VERLUST
|
|
||||||
add_xp(tech_id, 1)
|
|
||||||
|
|
||||||
var done := false
|
|
||||||
if human_id == active_mission:
|
|
||||||
var p: float = progress.get(human_id, 0.0) + gain - verlust
|
|
||||||
progress[human_id] = clampf(p, 0.0, MISSION_ZIEL)
|
|
||||||
if progress[human_id] >= MISSION_ZIEL and not completed.has(human_id):
|
|
||||||
completed.append(human_id)
|
|
||||||
active_mission = ""
|
active_mission = ""
|
||||||
done = true
|
mission_done.emit(wer)
|
||||||
mission_done.emit(human_id)
|
notified.emit("%s hat es geschafft." % HumanDB.by_id(wer)["name"], Color(1, 0.85, 0.4))
|
||||||
notified.emit("%s hat es geschafft." % HumanDB.by_id(human_id)["name"],
|
|
||||||
Color(1, 0.85, 0.4))
|
|
||||||
_insel_waechst()
|
_insel_waechst()
|
||||||
state_changed.emit()
|
state_changed.emit()
|
||||||
|
|
||||||
return {
|
|
||||||
"ok": true, "success": success, "chance": ev["chance"], "gain": gain,
|
# --------------------------------------------------- Erreichbarkeit
|
||||||
"verlust": verlust, "wiederholung": wiederholung, "mission_done": done,
|
|
||||||
"tag": ev["tag"], "moment": ev["moment"],
|
## Schlafende erreicht niemand.
|
||||||
}
|
func erreichbar(activity: String) -> bool:
|
||||||
|
return activity != "schlaeft"
|
||||||
|
|||||||
@@ -101,32 +101,20 @@ static var ANLIEGEN: Array = [
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
## Tagesabläufe: Platzhalter werden durch Wohnung und Arbeitsplatz ersetzt.
|
## Der Grundtag. Blocker werden später in passende Fenster gesetzt.
|
||||||
## Tagesabläufe: Platzhalter werden durch Wohnung und Arbeitsplatz ersetzt.
|
## [Stunde, Ort, Tätigkeit, Fenster]
|
||||||
## Die Reihenfolge passt zu den Anliegen — wer aufschiebt, arbeitet zu Hause.
|
static var GRUNDTAG: Array = [
|
||||||
static var ABLAEUFE: Array = [
|
[0, "heim", "schlaeft", "nacht"],
|
||||||
[[0, "heim", "schlaeft"], [7, "heim", "zoegert"], [10, "heim", "arbeitet"],
|
[7, "heim", "morgenroutine", "morgen"],
|
||||||
[13, "park", "pause"], [15, "heim", "arbeitet"], [18, "cafe", "wartet"],
|
[9, "arbeit", "arbeitet", "tag"],
|
||||||
[20, "heim", "zoegert"], [22, "heim", "gruebelt"], [23, "heim", "abendroutine"]],
|
[12, "cafe", "essen", "tag"],
|
||||||
[[0, "heim", "schlaeft"], [4, "arbeit", "arbeitet"], [10, "cafe", "pause"],
|
[14, "arbeit", "arbeitet", "tag"],
|
||||||
[12, "heim", "essen"], [14, "heim", "ruht"], [16, "heim", "zoegert"],
|
[17, "park", "unterwegs", "abend"],
|
||||||
[18, "park", "unterwegs"], [20, "heim", "muede"], [22, "heim", "abendroutine"]],
|
[19, "heim", "ruht", "abend"],
|
||||||
[[0, "heim", "schlaeft"], [8, "heim", "morgenroutine"], [10, "arbeit", "arbeitet"],
|
[21, "heim", "ruht", "abend"],
|
||||||
[13, "cafe", "angespannt"], [15, "arbeit", "wartet"], [18, "heim", "gruebelt"],
|
[23, "heim", "abendroutine", "nacht"],
|
||||||
[20, "park", "unterwegs"], [22, "heim", "abendroutine"]],
|
|
||||||
[[0, "heim", "schlaeft"], [6, "heim", "morgenroutine"], [8, "arbeit", "arbeitet"],
|
|
||||||
[12, "cafe", "essen"], [14, "arbeit", "arbeitet"], [19, "arbeit", "angespannt"],
|
|
||||||
[21, "heim", "essen"], [23, "heim", "muede"]],
|
|
||||||
[[0, "heim", "schlaeft"], [7, "heim", "morgenroutine"], [9, "arbeit", "arbeitet"],
|
|
||||||
[12, "cafe", "essen"], [14, "arbeit", "arbeitet"], [17, "park", "unterwegs"],
|
|
||||||
[19, "heim", "aufraeumen"], [21, "heim", "gruebelt"], [23, "heim", "abendroutine"]],
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
## Zu jeder Technik ein Anliegen und ein Tagesablauf, bei dem sie greift:
|
|
||||||
## [Anliegen, Ablauf]. Mensch i bekommt den Eintrag zu Technik i — und Technik i
|
|
||||||
## ist genau dann entdeckt, wenn i Träume erfüllt sind. So hängt am Schwarzen
|
|
||||||
## Brett immer mindestens ein Mensch, dem mit dem Gelernten zu helfen ist.
|
|
||||||
static var PASSEND: Array = [
|
static var PASSEND: Array = [
|
||||||
[0, 0], # Pomodoro -> aufschieben, zögert
|
[0, 0], # Pomodoro -> aufschieben, zögert
|
||||||
[6, 4], # Zwei-Minuten -> Werkstatt, räumt auf
|
[6, 4], # Zwei-Minuten -> Werkstatt, räumt auf
|
||||||
@@ -403,25 +391,68 @@ static func _anker_setzen() -> void:
|
|||||||
ANKER[key] = int(NETZ.andocken(tuer)["knoten"])
|
ANKER[key] = int(NETZ.andocken(tuer)["knoten"])
|
||||||
|
|
||||||
|
|
||||||
static func _mensch(i: int) -> Dictionary:
|
## Woran der Traum dieses Menschen scheitert. Zwei bis drei Ursachen, nie alle.
|
||||||
# Bis alle Wege entdeckt sind, folgt jeder Mensch dem Weg gleicher Nummer.
|
## Die erste hängt am Weg gleicher Nummer -- so ist der neueste Mensch immer
|
||||||
# Danach mischt sich das Feld wieder.
|
## mit dem neuesten Weg anzugehen.
|
||||||
var a_nr: int = i % ANLIEGEN.size()
|
static func ursachen_von(i: int) -> Array:
|
||||||
var b_nr: int = i % ABLAEUFE.size()
|
var alle: Array = Ursachen.LISTE.keys()
|
||||||
if i < PASSEND.size():
|
var erste: String = str(alle[i % alle.size()])
|
||||||
a_nr = int(PASSEND[i][0])
|
if i < TechDB.LIST.size():
|
||||||
b_nr = int(PASSEND[i][1])
|
erste = str(TechDB.LIST[i]["ursache"])
|
||||||
var anliegen: Dictionary = ANLIEGEN[a_nr]
|
var out: Array = [erste]
|
||||||
var heim := heim_key(i)
|
var zweite: String = str(alle[(alle.find(erste) + 1 + i % 3) % alle.size()])
|
||||||
var arbeit := _naechster_arbeitsplatz(heim, i)
|
if zweite != erste:
|
||||||
var ablauf: Array = []
|
out.append(zweite)
|
||||||
for e in ABLAEUFE[b_nr]:
|
if i % 3 == 2:
|
||||||
|
var dritte: String = str(alle[(alle.find(erste) + 3) % alle.size()])
|
||||||
|
if not out.has(dritte):
|
||||||
|
out.append(dritte)
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
## Der Tagesablauf: Grundtag, in den je Ursache ein Blocker gesetzt wird.
|
||||||
|
static func _tagesablauf(i: int, heim: String, arbeit: String) -> Array:
|
||||||
|
var slots: Array = []
|
||||||
|
for e in GRUNDTAG:
|
||||||
var ort: String = str(e[1])
|
var ort: String = str(e[1])
|
||||||
if ort == "heim":
|
if ort == "heim":
|
||||||
ort = heim
|
ort = heim
|
||||||
elif ort == "arbeit":
|
elif ort == "arbeit":
|
||||||
ort = arbeit
|
ort = arbeit
|
||||||
ablauf.append([e[0], ort, e[2]])
|
slots.append([int(e[0]), ort, str(e[2]), str(e[3])])
|
||||||
|
var belegt: Dictionary = {}
|
||||||
|
var nr := 0
|
||||||
|
for u in ursachen_von(i):
|
||||||
|
for fenster in ["tag", "abend", "morgen", "nacht"]:
|
||||||
|
var kandidaten: Array = Ursachen.blocker_fuer(str(u), fenster)
|
||||||
|
if kandidaten.is_empty():
|
||||||
|
continue
|
||||||
|
var blocker: String = str(kandidaten[(i + nr) % kandidaten.size()])
|
||||||
|
var gesetzt := false
|
||||||
|
for k in range(slots.size()):
|
||||||
|
if belegt.has(k) or str(slots[k][2]) == "schlaeft":
|
||||||
|
continue
|
||||||
|
if str(slots[k][3]) != fenster:
|
||||||
|
continue
|
||||||
|
slots[k][2] = blocker
|
||||||
|
belegt[k] = true
|
||||||
|
gesetzt = true
|
||||||
|
break
|
||||||
|
if gesetzt:
|
||||||
|
break
|
||||||
|
nr += 1
|
||||||
|
var out: Array = []
|
||||||
|
for e in slots:
|
||||||
|
out.append([e[0], e[1], e[2]])
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
static func _mensch(i: int) -> Dictionary:
|
||||||
|
var anliegen: Dictionary = ANLIEGEN[i % ANLIEGEN.size()]
|
||||||
|
if i < PASSEND.size():
|
||||||
|
anliegen = ANLIEGEN[int(PASSEND[i][0])]
|
||||||
|
var heim := heim_key(i)
|
||||||
|
var arbeit := _naechster_arbeitsplatz(heim, i)
|
||||||
return {
|
return {
|
||||||
"id": "mensch_%d" % i,
|
"id": "mensch_%d" % i,
|
||||||
"name": "%s %s" % [_vorname(i), _nachname(i)],
|
"name": "%s %s" % [_vorname(i), _nachname(i)],
|
||||||
@@ -430,10 +461,11 @@ static func _mensch(i: int) -> Dictionary:
|
|||||||
"traum": str(anliegen["traum"]),
|
"traum": str(anliegen["traum"]),
|
||||||
"problem": str(anliegen["problem"]),
|
"problem": str(anliegen["problem"]),
|
||||||
"tags": (anliegen["tags"] as Array).duplicate(),
|
"tags": (anliegen["tags"] as Array).duplicate(),
|
||||||
|
"ursachen": ursachen_von(i),
|
||||||
"mission": true,
|
"mission": true,
|
||||||
"heim": heim,
|
"heim": heim,
|
||||||
"farbe": Color.from_hsv(fmod(0.02 + float(i) * 0.191, 1.0), 0.5, 0.8),
|
"farbe": Color.from_hsv(fmod(0.02 + float(i) * 0.191, 1.0), 0.5, 0.8),
|
||||||
"routine": ablauf,
|
"routine": _tagesablauf(i, heim, arbeit),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -65,15 +65,28 @@ func _setze_welt(neu: Node3D) -> void:
|
|||||||
|
|
||||||
|
|
||||||
func _process(delta: float) -> void:
|
func _process(delta: float) -> void:
|
||||||
Game.advance_time(delta * Game.zeit_faktor())
|
var dt := delta * Game.zeit_faktor()
|
||||||
|
Game.advance_time(dt)
|
||||||
|
Game.traum_voranbringen(dt * 24.0 / Game.DAY_SECONDS)
|
||||||
Game.teleport_lock = maxf(0.0, Game.teleport_lock - delta)
|
Game.teleport_lock = maxf(0.0, Game.teleport_lock - delta)
|
||||||
if ui.offen:
|
if ui.offen:
|
||||||
ui.setze_hinweis("")
|
ui.setze_hinweis("")
|
||||||
return
|
return
|
||||||
_fokus_suchen()
|
_fokus_suchen()
|
||||||
|
_beobachten(dt)
|
||||||
_hinweis_setzen()
|
_hinweis_setzen()
|
||||||
|
|
||||||
|
|
||||||
|
## Dabeistehen deckt auf, was der Mensch gerade wirklich tut.
|
||||||
|
func _beobachten(dt: float) -> void:
|
||||||
|
if _fokus_mensch == null or not auf_erde:
|
||||||
|
return
|
||||||
|
var id: String = str(_fokus_mensch.data["id"])
|
||||||
|
if id != Game.active_mission:
|
||||||
|
return
|
||||||
|
Game.beobachten(id, int(_fokus_mensch.slot), dt)
|
||||||
|
|
||||||
|
|
||||||
func _fokus_suchen() -> void:
|
func _fokus_suchen() -> void:
|
||||||
_fokus = null
|
_fokus = null
|
||||||
_fokus_mensch = null
|
_fokus_mensch = null
|
||||||
@@ -99,8 +112,13 @@ func _fokus_suchen() -> void:
|
|||||||
|
|
||||||
func _hinweis_setzen() -> void:
|
func _hinweis_setzen() -> void:
|
||||||
if _fokus_mensch != null:
|
if _fokus_mensch != null:
|
||||||
ui.setze_hinweis("[E] %s ansprechen — %s" %
|
var mid: String = str(_fokus_mensch.data["name"])
|
||||||
[_fokus_mensch.data["name"], Orte.text(_fokus_mensch.activity)])
|
var mnr: int = int(_fokus_mensch.slot)
|
||||||
|
var mkey: String = str(_fokus_mensch.data["id"])
|
||||||
|
if mkey == Game.active_mission and not Game.erkannt(mkey, mnr):
|
||||||
|
ui.setze_hinweis("%s — schau zu, was sie hier tut …" % mid)
|
||||||
|
else:
|
||||||
|
ui.setze_hinweis("[E] %s — %s" % [mid, Orte.text(_fokus_mensch.activity)])
|
||||||
elif _fokus != null:
|
elif _fokus != null:
|
||||||
var kind: String = _fokus.get_meta("kind")
|
var kind: String = _fokus.get_meta("kind")
|
||||||
var titel: String = _fokus.get_meta("titel")
|
var titel: String = _fokus.get_meta("titel")
|
||||||
|
|||||||
@@ -37,8 +37,15 @@ static var ACTIVITY_TEXT: Dictionary = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
## Blocker tragen ihren Namen im Ursachen-Katalog, alles andere hier.
|
||||||
static func text(a: String) -> String:
|
static func text(a: String) -> String:
|
||||||
return ACTIVITY_TEXT.get(a, a)
|
if Ursachen.ist_blocker(a):
|
||||||
|
return str(Ursachen.BLOCKER[a]["name"])
|
||||||
|
return str(ACTIVITY_TEXT.get(a, a))
|
||||||
|
|
||||||
|
|
||||||
|
static func kennt(a: String) -> bool:
|
||||||
|
return ACTIVITY_TEXT.has(a) or Ursachen.ist_blocker(a)
|
||||||
|
|
||||||
|
|
||||||
static func center(places: Dictionary, key: String) -> Vector3:
|
static func center(places: Dictionary, key: String) -> Vector3:
|
||||||
|
|||||||
@@ -9,7 +9,10 @@ static var LIST: Array = [
|
|||||||
"was": "25 Minuten am Stück an einer Sache arbeiten, dann 5 Minuten Pause. Nach vier Runden eine lange Pause.",
|
"was": "25 Minuten am Stück an einer Sache arbeiten, dann 5 Minuten Pause. Nach vier Runden eine lange Pause.",
|
||||||
"wann": "Wenn eine Aufgabe zu groß wirkt und der Anfang immer wieder verschoben wird.",
|
"wann": "Wenn eine Aufgabe zu groß wirkt und der Anfang immer wieder verschoben wird.",
|
||||||
"warum": "Ein klar begrenzter Zeitraum senkt die Einstiegshürde. Der Kopf muss nur 25 Minuten durchhalten, nicht den ganzen Tag.",
|
"warum": "Ein klar begrenzter Zeitraum senkt die Einstiegshürde. Der Kopf muss nur 25 Minuten durchhalten, nicht den ganzen Tag.",
|
||||||
"woran": "jemandem, der zögert — oder der arbeitet und trotzdem nicht vorankommt.",
|
"woran": "jemandem, der aufräumt oder recherchiert, statt endlich anzufangen.",
|
||||||
|
"ursache": "anfang",
|
||||||
|
"belohnung": "erfolg",
|
||||||
|
"ersatz": "arbeitet in Blöcken",
|
||||||
"tags": ["prokrastination", "fokus"],
|
"tags": ["prokrastination", "fokus"],
|
||||||
"momente": ["arbeitet", "zoegert"],
|
"momente": ["arbeitet", "zoegert"],
|
||||||
"farbe": Color(0.95, 0.45, 0.30),
|
"farbe": Color(0.95, 0.45, 0.30),
|
||||||
@@ -20,7 +23,10 @@ static var LIST: Array = [
|
|||||||
"was": "Was unter zwei Minuten dauert, sofort erledigen. Große Vorhaben auf einen Zwei-Minuten-Anfang schrumpfen.",
|
"was": "Was unter zwei Minuten dauert, sofort erledigen. Große Vorhaben auf einen Zwei-Minuten-Anfang schrumpfen.",
|
||||||
"wann": "Bei einem Berg von Kleinkram oder wenn schon der erste Schritt blockiert.",
|
"wann": "Bei einem Berg von Kleinkram oder wenn schon der erste Schritt blockiert.",
|
||||||
"warum": "Der Start kostet die meiste Energie. Zwei Minuten sind zu klein zum Ablehnen und ziehen meist die ganze Aufgabe nach sich.",
|
"warum": "Der Start kostet die meiste Energie. Zwei Minuten sind zu klein zum Ablehnen und ziehen meist die ganze Aufgabe nach sich.",
|
||||||
"woran": "jemandem, der zögert, lieber aufräumt als anzufangen, oder beim Arbeiten im Kleinkram hängt.",
|
"woran": "jemandem, der aufräumt statt anzufangen oder eine Später-Liste schreibt.",
|
||||||
|
"ursache": "anfang",
|
||||||
|
"belohnung": "erfolg",
|
||||||
|
"ersatz": "fängt zwei Minuten an",
|
||||||
"tags": ["prokrastination", "ueberforderung"],
|
"tags": ["prokrastination", "ueberforderung"],
|
||||||
"momente": ["zoegert", "aufraeumen", "arbeitet"],
|
"momente": ["zoegert", "aufraeumen", "arbeitet"],
|
||||||
"farbe": Color(0.98, 0.72, 0.25),
|
"farbe": Color(0.98, 0.72, 0.25),
|
||||||
@@ -31,7 +37,10 @@ static var LIST: Array = [
|
|||||||
"was": "Den Vorsatz an einen konkreten Auslöser binden: \"Wenn ich X tue, dann mache ich Y.\"",
|
"was": "Den Vorsatz an einen konkreten Auslöser binden: \"Wenn ich X tue, dann mache ich Y.\"",
|
||||||
"wann": "Wenn ein Vorhaben im Alltag jedes Mal untergeht.",
|
"wann": "Wenn ein Vorhaben im Alltag jedes Mal untergeht.",
|
||||||
"warum": "Der Plan hängt an einer Situation statt an Willenskraft. Der Auslöser erinnert von allein.",
|
"warum": "Der Plan hängt an einer Situation statt an Willenskraft. Der Auslöser erinnert von allein.",
|
||||||
"woran": "der Morgenroutine und der Pause — den festen Punkten, an die sich ein Vorsatz hängen lässt.",
|
"woran": "jemandem, der eine Später-Liste schreibt und dann doch nichts tut.",
|
||||||
|
"ursache": "anfang",
|
||||||
|
"belohnung": "ordnung",
|
||||||
|
"ersatz": "folgt dem Wenn-Dann-Plan",
|
||||||
"tags": ["gewohnheit", "prokrastination"],
|
"tags": ["gewohnheit", "prokrastination"],
|
||||||
"momente": ["morgenroutine", "pause"],
|
"momente": ["morgenroutine", "pause"],
|
||||||
"farbe": Color(0.45, 0.80, 0.55),
|
"farbe": Color(0.45, 0.80, 0.55),
|
||||||
@@ -42,7 +51,10 @@ static var LIST: Array = [
|
|||||||
"was": "Eine neue, kleine Gewohnheit direkt an eine bestehende anhängen.",
|
"was": "Eine neue, kleine Gewohnheit direkt an eine bestehende anhängen.",
|
||||||
"wann": "Wenn eine neue Routine nie einen Platz im Tag findet.",
|
"wann": "Wenn eine neue Routine nie einen Platz im Tag findet.",
|
||||||
"warum": "Die alte Gewohnheit ist der Anker. Es muss kein neuer Zeitpunkt erfunden werden.",
|
"warum": "Die alte Gewohnheit ist der Anker. Es muss kein neuer Zeitpunkt erfunden werden.",
|
||||||
"woran": "den Ankern des Tages: Morgenroutine, Essen, Abendroutine.",
|
"woran": "jemandem, der auf etwas anderes umschaltet, sobald es zäh wird.",
|
||||||
|
"ursache": "halt",
|
||||||
|
"belohnung": "ordnung",
|
||||||
|
"ersatz": "hängt es an die Routine",
|
||||||
"tags": ["gewohnheit"],
|
"tags": ["gewohnheit"],
|
||||||
"momente": ["morgenroutine", "essen", "abendroutine"],
|
"momente": ["morgenroutine", "essen", "abendroutine"],
|
||||||
"farbe": Color(0.40, 0.70, 0.85),
|
"farbe": Color(0.40, 0.70, 0.85),
|
||||||
@@ -53,7 +65,10 @@ static var LIST: Array = [
|
|||||||
"was": "Ein großes Ziel in benennbare Einzelschritte teilen, bis der nächste Schritt trivial ist.",
|
"was": "Ein großes Ziel in benennbare Einzelschritte teilen, bis der nächste Schritt trivial ist.",
|
||||||
"wann": "Wenn jemand vor einem Vorhaben erstarrt und nicht weiß, wo er anfangen soll.",
|
"wann": "Wenn jemand vor einem Vorhaben erstarrt und nicht weiß, wo er anfangen soll.",
|
||||||
"warum": "Unklarheit lähmt stärker als Aufwand. Ein sichtbarer nächster Schritt macht Handeln wieder möglich.",
|
"warum": "Unklarheit lähmt stärker als Aufwand. Ein sichtbarer nächster Schritt macht Handeln wieder möglich.",
|
||||||
"woran": "jemandem, der grübelt statt anzufangen, oder der arbeitet und sich im Vorhaben verliert.",
|
"woran": "jemandem, der recherchiert statt anzufangen oder eine Später-Liste schreibt.",
|
||||||
|
"ursache": "anfang",
|
||||||
|
"belohnung": "ordnung",
|
||||||
|
"ersatz": "zerlegt die Aufgabe",
|
||||||
"tags": ["ueberforderung", "prokrastination", "ziel"],
|
"tags": ["ueberforderung", "prokrastination", "ziel"],
|
||||||
"momente": ["gruebelt", "arbeitet"],
|
"momente": ["gruebelt", "arbeitet"],
|
||||||
"farbe": Color(0.75, 0.55, 0.95),
|
"farbe": Color(0.75, 0.55, 0.95),
|
||||||
@@ -64,7 +79,10 @@ static var LIST: Array = [
|
|||||||
"was": "Das gewünschte Verhalten leichter machen, das störende schwerer. Handy in einen anderen Raum, Instrument sichtbar aufstellen.",
|
"was": "Das gewünschte Verhalten leichter machen, das störende schwerer. Handy in einen anderen Raum, Instrument sichtbar aufstellen.",
|
||||||
"wann": "Wenn gute Vorsätze regelmäßig an Ablenkung scheitern.",
|
"wann": "Wenn gute Vorsätze regelmäßig an Ablenkung scheitern.",
|
||||||
"warum": "Verhalten folgt dem geringsten Widerstand. Die Umgebung wirkt zuverlässiger als Disziplin.",
|
"warum": "Verhalten folgt dem geringsten Widerstand. Die Umgebung wirkt zuverlässiger als Disziplin.",
|
||||||
"woran": "jemandem, der aufräumt, arbeitet oder sich ausruht — dann ist der Raum um ihn herum greifbar.",
|
"woran": "jemandem, der noch eine Runde spielt oder ständig umschaltet.",
|
||||||
|
"ursache": "halt",
|
||||||
|
"belohnung": "",
|
||||||
|
"ersatz": "hat es sich leicht gemacht",
|
||||||
"tags": ["ablenkung", "gewohnheit"],
|
"tags": ["ablenkung", "gewohnheit"],
|
||||||
"momente": ["aufraeumen", "arbeitet", "ruht"],
|
"momente": ["aufraeumen", "arbeitet", "ruht"],
|
||||||
"farbe": Color(0.55, 0.85, 0.40),
|
"farbe": Color(0.55, 0.85, 0.40),
|
||||||
@@ -75,7 +93,10 @@ static var LIST: Array = [
|
|||||||
"was": "Einen belastenden Gedanken prüfen und durch eine ebenso wahre, aber tragfähigere Sicht ersetzen.",
|
"was": "Einen belastenden Gedanken prüfen und durch eine ebenso wahre, aber tragfähigere Sicht ersetzen.",
|
||||||
"wann": "Wenn jemand in einem Gedanken feststeckt, der ihn klein hält.",
|
"wann": "Wenn jemand in einem Gedanken feststeckt, der ihn klein hält.",
|
||||||
"warum": "Nicht das Ereignis belastet, sondern seine Deutung. Eine andere Deutung verändert Gefühl und Handlung.",
|
"warum": "Nicht das Ereignis belastet, sondern seine Deutung. Eine andere Deutung verändert Gefühl und Handlung.",
|
||||||
"woran": "jemandem, der grübelt, angespannt ist oder sich ausruht und den Gedanken doch nicht loswird.",
|
"woran": "jemandem, der sich mit anderen vergleicht und dabei klein wird.",
|
||||||
|
"ursache": "grund",
|
||||||
|
"belohnung": "einordnung",
|
||||||
|
"ersatz": "deutet den Gedanken um",
|
||||||
"tags": ["selbstzweifel", "angst"],
|
"tags": ["selbstzweifel", "angst"],
|
||||||
"momente": ["gruebelt", "ruht", "angespannt"],
|
"momente": ["gruebelt", "ruht", "angespannt"],
|
||||||
"farbe": Color(0.95, 0.55, 0.75),
|
"farbe": Color(0.95, 0.55, 0.75),
|
||||||
@@ -86,7 +107,10 @@ static var LIST: Array = [
|
|||||||
"was": "Vier Sekunden einatmen, vier halten, vier ausatmen, vier halten. Mehrere Runden lang.",
|
"was": "Vier Sekunden einatmen, vier halten, vier ausatmen, vier halten. Mehrere Runden lang.",
|
||||||
"wann": "Bei akuter Anspannung, kurz vor einem gefürchteten Gespräch oder Auftritt.",
|
"wann": "Bei akuter Anspannung, kurz vor einem gefürchteten Gespräch oder Auftritt.",
|
||||||
"warum": "Langes Ausatmen bremst den Alarmzustand des Körpers. Der Puls sinkt, der Kopf wird wieder klar.",
|
"warum": "Langes Ausatmen bremst den Alarmzustand des Körpers. Der Puls sinkt, der Kopf wird wieder klar.",
|
||||||
"woran": "jemandem, der angespannt ist, wartet oder in der Pause nicht runterkommt.",
|
"woran": "jemandem, der abends eine Serie schaut, um überhaupt runterzukommen.",
|
||||||
|
"ursache": "kraft",
|
||||||
|
"belohnung": "abschalten",
|
||||||
|
"ersatz": "atmet sich ruhig",
|
||||||
"tags": ["angst", "stress"],
|
"tags": ["angst", "stress"],
|
||||||
"momente": ["angespannt", "wartet", "pause"],
|
"momente": ["angespannt", "wartet", "pause"],
|
||||||
"farbe": Color(0.40, 0.85, 0.95),
|
"farbe": Color(0.40, 0.85, 0.95),
|
||||||
@@ -97,7 +121,10 @@ static var LIST: Array = [
|
|||||||
"was": "Mit sich selbst so sprechen wie mit einem guten Freund in derselben Lage.",
|
"was": "Mit sich selbst so sprechen wie mit einem guten Freund in derselben Lage.",
|
||||||
"wann": "Nach einem Fehler oder Rückschlag, wenn die innere Kritik lauter wird als der Vorsatz.",
|
"wann": "Nach einem Fehler oder Rückschlag, wenn die innere Kritik lauter wird als der Vorsatz.",
|
||||||
"warum": "Harte Selbstkritik erhöht die Vermeidung. Freundlichkeit hält handlungsfähig und senkt die Abbruchquote.",
|
"warum": "Harte Selbstkritik erhöht die Vermeidung. Freundlichkeit hält handlungsfähig und senkt die Abbruchquote.",
|
||||||
"woran": "jemandem, der nach einem Fehler grübelt, angespannt ist oder sich ausruht, ohne zur Ruhe zu kommen.",
|
"woran": "jemandem, der am Telefon klagt, statt weiterzumachen.",
|
||||||
|
"ursache": "grund",
|
||||||
|
"belohnung": "verbundenheit",
|
||||||
|
"ersatz": "ist freundlich mit sich",
|
||||||
"tags": ["selbstzweifel", "rueckschlag"],
|
"tags": ["selbstzweifel", "rueckschlag"],
|
||||||
"momente": ["gruebelt", "ruht", "angespannt"],
|
"momente": ["gruebelt", "ruht", "angespannt"],
|
||||||
"farbe": Color(1.0, 0.80, 0.60),
|
"farbe": Color(1.0, 0.80, 0.60),
|
||||||
@@ -108,7 +135,10 @@ static var LIST: Array = [
|
|||||||
"was": "Feste Aufsteh- und Schlafenszeit, die letzte Stunde ohne Bildschirm, Zimmer dunkel und kühl.",
|
"was": "Feste Aufsteh- und Schlafenszeit, die letzte Stunde ohne Bildschirm, Zimmer dunkel und kühl.",
|
||||||
"wann": "Bei Dauermüdigkeit, Reizbarkeit und wegbrechender Konzentration.",
|
"wann": "Bei Dauermüdigkeit, Reizbarkeit und wegbrechender Konzentration.",
|
||||||
"warum": "Der innere Rhythmus braucht feste Anker. Erholter Schlaf ist die Grundlage für jede andere Veränderung.",
|
"warum": "Der innere Rhythmus braucht feste Anker. Erholter Schlaf ist die Grundlage für jede andere Veränderung.",
|
||||||
"woran": "der Abendroutine, an jemandem, der müde ist oder sich mitten am Tag ausruht.",
|
"woran": "jemandem, der wach bleibt oder abends am Kühlschrank steht.",
|
||||||
|
"ursache": "kraft",
|
||||||
|
"belohnung": "zeit_fuer_sich",
|
||||||
|
"ersatz": "hält das Schlaffenster",
|
||||||
"tags": ["erschoepfung", "gesundheit"],
|
"tags": ["erschoepfung", "gesundheit"],
|
||||||
"momente": ["abendroutine", "muede", "ruht"],
|
"momente": ["abendroutine", "muede", "ruht"],
|
||||||
"farbe": Color(0.45, 0.50, 0.90),
|
"farbe": Color(0.45, 0.50, 0.90),
|
||||||
@@ -119,7 +149,10 @@ static var LIST: Array = [
|
|||||||
"was": "Eine klare, kleine Bitte an eine konkrete Person richten, statt allgemein zu hoffen.",
|
"was": "Eine klare, kleine Bitte an eine konkrete Person richten, statt allgemein zu hoffen.",
|
||||||
"wann": "Wenn jemand allein an etwas hängen bleibt, das andere leicht lösen könnten.",
|
"wann": "Wenn jemand allein an etwas hängen bleibt, das andere leicht lösen könnten.",
|
||||||
"warum": "Vage Bitten werden überhört. Menschen helfen gern, wenn sie genau wissen, was zu tun ist.",
|
"warum": "Vage Bitten werden überhört. Menschen helfen gern, wenn sie genau wissen, was zu tun ist.",
|
||||||
"woran": "jemandem, der wartet, Pause macht oder unterwegs ist — da ist Luft für eine Bitte.",
|
"woran": "jemandem, der zu allem ja sagt und alles allein stemmt.",
|
||||||
|
"ursache": "zeit",
|
||||||
|
"belohnung": "anschluss",
|
||||||
|
"ersatz": "bittet um Hilfe",
|
||||||
"tags": ["einsamkeit", "ueberforderung"],
|
"tags": ["einsamkeit", "ueberforderung"],
|
||||||
"momente": ["wartet", "pause", "unterwegs"],
|
"momente": ["wartet", "pause", "unterwegs"],
|
||||||
"farbe": Color(0.90, 0.90, 0.45),
|
"farbe": Color(0.90, 0.90, 0.45),
|
||||||
@@ -130,7 +163,10 @@ static var LIST: Array = [
|
|||||||
"was": "Absagen und zugleich benennen, was ginge: \"Heute nicht, am Donnerstag gern.\"",
|
"was": "Absagen und zugleich benennen, was ginge: \"Heute nicht, am Donnerstag gern.\"",
|
||||||
"wann": "Wenn der eigene Kalender von fremden Anliegen aufgebraucht wird.",
|
"wann": "Wenn der eigene Kalender von fremden Anliegen aufgebraucht wird.",
|
||||||
"warum": "Ein nacktes Nein fühlt sich riskant an. Mit Alternative bleibt die Beziehung heil und die Zeit geschützt.",
|
"warum": "Ein nacktes Nein fühlt sich riskant an. Mit Alternative bleibt die Beziehung heil und die Zeit geschützt.",
|
||||||
"woran": "jemandem, der arbeitet, angespannt ist oder unterwegs zwischen Terminen hängt.",
|
"woran": "jemandem, der zu allem ja sagt, bis für ihn nichts übrig bleibt.",
|
||||||
|
"ursache": "zeit",
|
||||||
|
"belohnung": "anerkennung",
|
||||||
|
"ersatz": "sagt Nein mit Alternative",
|
||||||
"tags": ["stress", "grenzen"],
|
"tags": ["stress", "grenzen"],
|
||||||
"momente": ["arbeitet", "angespannt", "unterwegs"],
|
"momente": ["arbeitet", "angespannt", "unterwegs"],
|
||||||
"farbe": Color(0.85, 0.35, 0.45),
|
"farbe": Color(0.85, 0.35, 0.45),
|
||||||
@@ -138,6 +174,21 @@ static var LIST: Array = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
## Techniken, die gegen diese Ursache helfen.
|
||||||
|
static func fuer_ursache(ursache: String) -> Array:
|
||||||
|
var out: Array = []
|
||||||
|
for t in LIST:
|
||||||
|
if t["ursache"] == ursache:
|
||||||
|
out.append(t["id"])
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
## Manche Techniken ersetzen die Handlung nicht, sie nehmen ihr den Auslöser.
|
||||||
|
## Die passen überall, wo ihre Ursache stimmt.
|
||||||
|
static func entfernt_ausloeser(id: String) -> bool:
|
||||||
|
return str(by_id(id).get("belohnung", "")) == ""
|
||||||
|
|
||||||
|
|
||||||
static func by_id(id: String) -> Dictionary:
|
static func by_id(id: String) -> Dictionary:
|
||||||
for t in LIST:
|
for t in LIST:
|
||||||
if t["id"] == id:
|
if t["id"] == id:
|
||||||
|
|||||||
236
scripts/ui.gd
236
scripts/ui.gd
@@ -154,9 +154,9 @@ func _hud_aktualisieren() -> void:
|
|||||||
[Game.known.size(), Game.offene_techniken(), TechDB.LIST.size()])
|
[Game.known.size(), Game.offene_techniken(), TechDB.LIST.size()])
|
||||||
if Game.active_mission != "":
|
if Game.active_mission != "":
|
||||||
var h := HumanDB.by_id(Game.active_mission)
|
var h := HumanDB.by_id(Game.active_mission)
|
||||||
zeilen.append("Mission: [color=#ffdd77]%s[/color] — %d %% · %d Regeln" %
|
zeilen.append("Mission: [color=#ffdd77]%s[/color] — %d %% · %d %% je Tag" %
|
||||||
[h["name"], int(Game.mission_progress(Game.active_mission)),
|
[h["name"], int(Game.mission_progress(Game.active_mission)),
|
||||||
Game.regel_anzahl(Game.active_mission)])
|
int(round(Game.traum_tempo(Game.active_mission)))])
|
||||||
zeilen.append("[color=#aaaaaa]%s[/color]" % h["traum"])
|
zeilen.append("[color=#aaaaaa]%s[/color]" % h["traum"])
|
||||||
elif Game.completed.size() >= HumanDB.LIST.size():
|
elif Game.completed.size() >= HumanDB.LIST.size():
|
||||||
zeilen.append("[color=#88ff99]Alle Träume erfüllt.[/color]")
|
zeilen.append("[color=#88ff99]Alle Träume erfüllt.[/color]")
|
||||||
@@ -347,84 +347,126 @@ func _journal_missionen() -> void:
|
|||||||
_text("[color=#aaaaaa]Zurückgestellt — %d %%[/color]" %
|
_text("[color=#aaaaaa]Zurückgestellt — %d %%[/color]" %
|
||||||
int(Game.mission_progress(id)), 15)
|
int(Game.mission_progress(id)), 15)
|
||||||
if not Game.completed.has(id):
|
if not Game.completed.has(id):
|
||||||
_knopf("Regelwerk — %d Regeln" % Game.regel_anzahl(id),
|
_knopf("Tagesablauf — %d Systeme" % Game.system_anzahl(id),
|
||||||
func() -> void: pipeline_panel(id))
|
func() -> void: systeme_panel(id))
|
||||||
_trenner()
|
_trenner()
|
||||||
|
|
||||||
|
|
||||||
# -------------------------------------------------------- Regelwerk einer Mission
|
# ---------------------------------------------- Diagnose und Systeme
|
||||||
|
|
||||||
## Wenn-Dann-Regeln: tut der Mensch etwas Bestimmtes, greift die zugeordnete
|
## Der Traum scheitert an Ursachen. Die stehen nicht im Panel -- man findet sie,
|
||||||
## Technik von allein. So automatisiert der Spieler den Fortschritt.
|
## indem man dabeisteht. Gegen jede gefundene Ursache baut man ein System in
|
||||||
func pipeline_panel(human_id: String) -> void:
|
## den Tag. Je mehr abgedeckt ist, desto schneller kommt der Traum voran.
|
||||||
var scroll_alt := _scroll.scroll_vertical if offen and _kind == "pipeline" else 0
|
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)
|
var h := HumanDB.by_id(human_id)
|
||||||
_leeren("Regelwerk — %s" % h["name"])
|
_leeren("%s — Tagesablauf" % h["name"])
|
||||||
_text("Jede Tätigkeit im Tag von %s kann eine Technik auslösen. " % h["name"] +
|
_text("[b]Traum:[/b] %s" % h["traum"], 16)
|
||||||
"Wechselt sie hinein, greift die Regel von allein — solange du auf der Erde bist.\n" +
|
_text("[b]Fortschritt:[/b] %d %% · [b]Tempo:[/b] %d %% je Tag" %
|
||||||
"Nach jedem Einsatz braucht eine Technik Ruhe, bevor sie wieder anschlägt.", 15)
|
[int(Game.mission_progress(human_id)), int(round(Game.traum_tempo(human_id)))], 16)
|
||||||
_text("[color=#aaaaaa]Fortschritt: [b]%d %%[/b] · Regeln: [b]%d[/b][/color]" %
|
|
||||||
[int(Game.mission_progress(human_id)), Game.regel_anzahl(human_id)], 15)
|
|
||||||
_trenner()
|
_trenner()
|
||||||
for activity in HumanDB.aktivitaeten(human_id):
|
|
||||||
var tat := Orte.text(activity)
|
_text("[b]Woran es scheitert[/b]", 17)
|
||||||
if not Game.erreichbar(activity):
|
var offene := 0
|
||||||
_knopf("%s → unerreichbar" % tat, func() -> void: pass, false)
|
for u in Game.ursachen_von(human_id):
|
||||||
|
var name: String = str(u)
|
||||||
|
if not Game.ursache_bekannt(human_id, name):
|
||||||
|
_text("[color=#8e93a8]? — noch nicht erkannt[/color]", 15)
|
||||||
|
offene += 1
|
||||||
continue
|
continue
|
||||||
var tech: String = Game.regel_fuer(human_id, activity)
|
var g := Game.ursache_geloest(human_id, name)
|
||||||
var beschriftung := "%s → keine Regel" % tat
|
var stand := "[color=#88ff99]gelöst[/color]" if g > 0.0 else \
|
||||||
if tech != "":
|
"[color=#ff9977]offen · bremst auf %d %%[/color]" % \
|
||||||
beschriftung = "%s → %s" % [tat, TechDB.by_id(tech)["name"]]
|
int(float(Ursachen.LISTE[name]["faktor"]) * 100.0)
|
||||||
if not Game.bereit(tech):
|
_text("[b]%s[/b] — %s %s" % [Ursachen.LISTE[name]["name"],
|
||||||
beschriftung += " (noch gesperrt)"
|
Ursachen.LISTE[name]["kurz"], stand], 15)
|
||||||
_knopf(beschriftung, func() -> void: regel_panel(human_id, activity))
|
if offene > 0:
|
||||||
|
_text("[color=#aaaaaa]Steh dabei, wenn sie etwas tut, das du noch nicht " +
|
||||||
|
"kennst. Dann zeigt sich, warum.[/color]", 14)
|
||||||
|
_trenner()
|
||||||
|
|
||||||
|
_text("[b]Ihr Tag[/b]", 17)
|
||||||
|
for nr in range(Game.slots(human_id).size()):
|
||||||
|
_slot_zeile(human_id, nr)
|
||||||
_trenner()
|
_trenner()
|
||||||
_knopf("Zurück zum Journal", func() -> void: journal_panel("missionen"))
|
_knopf("Zurück zum Journal", func() -> void: journal_panel("missionen"))
|
||||||
_zeigen("pipeline")
|
_zeigen("systeme")
|
||||||
_scroll_wunsch = scroll_alt
|
_scroll_wunsch = scroll_alt
|
||||||
_scroll_frames = 4
|
_scroll_frames = 4
|
||||||
|
|
||||||
|
|
||||||
## Welche Technik soll bei dieser Tätigkeit greifen?
|
func _slot_zeile(human_id: String, nr: int) -> void:
|
||||||
func regel_panel(human_id: String, activity: String) -> void:
|
var slot: Array = Game.slots(human_id)[nr]
|
||||||
var h := HumanDB.by_id(human_id)
|
var stunde := "%02d:00" % int(slot[0])
|
||||||
_leeren("Regel für »%s«" % Orte.text(activity))
|
var grund := Game.slot_grund(human_id, nr)
|
||||||
if Game.known.is_empty():
|
if grund == "schlaeft":
|
||||||
_text("[color=#ffcc66]Du kennst keine Technik. Im Hörsaal der Wege " +
|
_knopf("%s schläft" % stunde, func() -> void: pass, false)
|
||||||
"werden sie gelehrt.[/color]", 16)
|
|
||||||
_knopf("Zurück", func() -> void: pipeline_panel(human_id))
|
|
||||||
_zeigen("regel")
|
|
||||||
return
|
return
|
||||||
_text("Was soll greifen, wenn %s %s? Ob eine Technik hier taugt, steht in ihr " %
|
var sys := Game.system_in(human_id, nr)
|
||||||
[h["name"], Orte.text(activity)] +
|
if not sys.is_empty():
|
||||||
"selbst — nachzulesen im Journal. Ein Fehlgriff wirft den Traum zurück.", 15)
|
_knopf("%s %s ← %s" % [stunde, Game.slot_aktivitaet(human_id, nr),
|
||||||
|
TechDB.by_id(str(sys["tech"]))["name"]],
|
||||||
|
func() -> void: slot_panel(human_id, nr))
|
||||||
|
return
|
||||||
|
if not Game.erkannt(human_id, nr):
|
||||||
|
_knopf("%s ?" % stunde, func() -> void: pass, false)
|
||||||
|
return
|
||||||
|
var text := Orte.text(grund)
|
||||||
|
if Ursachen.ist_blocker(grund):
|
||||||
|
text = "%s (%s)" % [Ursachen.BLOCKER[grund]["name"],
|
||||||
|
Ursachen.LISTE[Ursachen.BLOCKER[grund]["ursache"]]["name"]]
|
||||||
|
_knopf("%s %s" % [stunde, text], func() -> void: slot_panel(human_id, nr))
|
||||||
|
|
||||||
|
|
||||||
|
## Was soll in diesem Slot stehen?
|
||||||
|
func slot_panel(human_id: String, nr: int) -> void:
|
||||||
|
var h := HumanDB.by_id(human_id)
|
||||||
|
var grund := Game.slot_grund(human_id, nr)
|
||||||
|
var stunde := "%02d:00" % int(Game.slots(human_id)[nr][0])
|
||||||
|
_leeren("%s um %s" % [h["name"], stunde])
|
||||||
|
if Ursachen.ist_blocker(grund):
|
||||||
|
var b: Dictionary = Ursachen.BLOCKER[grund]
|
||||||
|
_text("Sie %s.\n[b]Auslöser:[/b] %s\n[b]Belohnung:[/b] %s" %
|
||||||
|
[b["name"], b["ausloeser"], Ursachen.belohnung_text(str(b["belohnung"]))], 16)
|
||||||
|
_text("[color=#aaaaaa]Eine Ersatzhandlung muss dieselbe Belohnung liefern, " +
|
||||||
|
"sonst hält sie nicht.[/color]", 15)
|
||||||
|
else:
|
||||||
|
_text("Hier ist Platz. Ein neues System passt in diesen Slot.", 16)
|
||||||
|
_trenner()
|
||||||
|
var sys := Game.system_in(human_id, nr)
|
||||||
|
if not sys.is_empty():
|
||||||
|
_text("[color=#88ff99]Hier steht: %s[/color]" %
|
||||||
|
TechDB.by_id(str(sys["tech"]))["name"], 16)
|
||||||
|
_knopf("System wieder herausnehmen", func() -> void:
|
||||||
|
Game.system_entfernen(human_id, nr)
|
||||||
|
systeme_panel(human_id))
|
||||||
_trenner()
|
_trenner()
|
||||||
for id in TechDB.ids():
|
for id in TechDB.ids():
|
||||||
if not Game.knows(id):
|
if not Game.knows(id):
|
||||||
continue
|
continue
|
||||||
|
var pruef := Game.system_pruefen(human_id, nr, id)
|
||||||
var t := TechDB.by_id(id)
|
var t := TechDB.by_id(id)
|
||||||
var ev := Game.evaluate(id, human_id, activity, false)
|
|
||||||
var wo: Array = Game.regel_momente(human_id, id)
|
|
||||||
var gewaehlt := ""
|
|
||||||
if wo.has(activity):
|
|
||||||
gewaehlt = " — hier eingestellt"
|
|
||||||
elif not wo.is_empty():
|
|
||||||
var namen: Array = []
|
|
||||||
for a in wo:
|
|
||||||
namen.append("»%s«" % Orte.text(a))
|
|
||||||
gewaehlt = " — hängt an %s" % ", ".join(namen)
|
|
||||||
var beschriftung := "%s · Stufe %d" % [t["name"], Game.skill_of(id)]
|
var beschriftung := "%s · Stufe %d" % [t["name"], Game.skill_of(id)]
|
||||||
if ev["blocked"]:
|
if not pruef["geht"]:
|
||||||
beschriftung += " — " + str(ev["grund"])
|
beschriftung += " — " + str(pruef["grund"])
|
||||||
elif gewaehlt != "":
|
elif float(pruef["guete"]) > Game.GUETE_NEU:
|
||||||
beschriftung += gewaehlt
|
beschriftung += " — passt genau"
|
||||||
_knopf(beschriftung, func() -> void:
|
_knopf(beschriftung, func() -> void: _system_setzen(human_id, nr, id),
|
||||||
Game.regel_setzen(human_id, activity, id)
|
bool(pruef["geht"]))
|
||||||
pipeline_panel(human_id), not ev["blocked"])
|
_trenner()
|
||||||
_knopf("Keine Regel für diese Tätigkeit", func() -> void:
|
_knopf("Zurück", func() -> void: systeme_panel(human_id))
|
||||||
Game.regel_setzen(human_id, activity, "")
|
_zeigen("slot")
|
||||||
pipeline_panel(human_id))
|
|
||||||
_zeigen("regel")
|
|
||||||
|
func _system_setzen(human_id: String, nr: int, tech_id: String) -> void:
|
||||||
|
var res := Game.system_setzen(human_id, nr, tech_id, false)
|
||||||
|
if not res["ok"]:
|
||||||
|
Game.notified.emit(str(res["grund"]), Color(1, 0.6, 0.4))
|
||||||
|
return
|
||||||
|
if not res["erfolg"]:
|
||||||
|
Game.notified.emit("%s greift diesmal nicht. Später noch einmal." %
|
||||||
|
TechDB.by_id(tech_id)["name"], Color(1, 0.6, 0.5))
|
||||||
|
systeme_panel(human_id)
|
||||||
|
|
||||||
|
|
||||||
# -------------------------------------------------------- Lehrorte
|
# -------------------------------------------------------- Lehrorte
|
||||||
@@ -522,70 +564,66 @@ func brett_panel() -> void:
|
|||||||
_scroll_frames = 4
|
_scroll_frames = 4
|
||||||
|
|
||||||
|
|
||||||
# -------------------------------------------------------- Anwenden auf der Erde
|
# -------------------------------------------------------- Vor Ort
|
||||||
|
|
||||||
|
## Draußen am Menschen: hier greift man in den Slot ein, der gerade läuft.
|
||||||
func anwenden_panel(mensch: Node3D) -> void:
|
func anwenden_panel(mensch: Node3D) -> void:
|
||||||
_apply_human = mensch
|
_apply_human = mensch
|
||||||
var h: Dictionary = mensch.data
|
var h: Dictionary = mensch.data
|
||||||
var aktiv: String = mensch.activity
|
var id: String = str(h["id"])
|
||||||
_leeren("%s — %s" % [h["name"], Orte.text(aktiv)])
|
var nr: int = int(mensch.slot)
|
||||||
|
_leeren("%s — %s" % [h["name"], Orte.text(mensch.activity)])
|
||||||
_text("[b]Traum:[/b] %s" % h["traum"], 16)
|
_text("[b]Traum:[/b] %s" % h["traum"], 16)
|
||||||
if Game.active_mission == h["id"]:
|
if Game.active_mission != id:
|
||||||
_text("Fortschritt: [b]%d %%[/b]" % int(Game.mission_progress(h["id"])), 16)
|
_text("[color=#ffcc66]Keine aktive Mission für diesen Menschen.[/color]", 15)
|
||||||
elif Game.completed.has(h["id"]):
|
_zeigen("anwenden")
|
||||||
_text("[color=#88ff99]★ Traum erfüllt.[/color]", 16)
|
return
|
||||||
else:
|
var grund := Game.slot_grund(id, nr)
|
||||||
_text("[color=#ffcc66]Keine aktive Mission für diesen Menschen. " +
|
if not Game.erkannt(id, nr):
|
||||||
"Fortschritt zählt nur mit angenommener Mission.[/color]", 15)
|
_text("[color=#ffcc66]Was hier läuft, hast du noch nicht gesehen. " +
|
||||||
|
"Bleib stehen und schau zu.[/color]", 16)
|
||||||
|
_zeigen("anwenden")
|
||||||
|
return
|
||||||
|
if Ursachen.ist_blocker(grund):
|
||||||
|
var b: Dictionary = Ursachen.BLOCKER[grund]
|
||||||
|
_text("Sie %s. [b]Auslöser:[/b] %s · [b]Belohnung:[/b] %s" %
|
||||||
|
[b["name"], b["ausloeser"], Ursachen.belohnung_text(str(b["belohnung"]))], 15)
|
||||||
_trenner()
|
_trenner()
|
||||||
|
|
||||||
if Game.known.is_empty():
|
if Game.known.is_empty():
|
||||||
_text("[color=#ffcc66]Du kennst keine Technik.[/color]")
|
_text("[color=#ffcc66]Du kennst keine Technik.[/color]")
|
||||||
_zeigen("anwenden")
|
_zeigen("anwenden")
|
||||||
return
|
return
|
||||||
_text("[color=#aaaaaa]Was eine Technik tut, steht im Journal.[/color]", 15)
|
_text("[color=#aaaaaa]Was eine Technik tut, steht im Journal.[/color]", 15)
|
||||||
|
for tid in TechDB.ids():
|
||||||
for id in TechDB.ids():
|
if not Game.knows(tid):
|
||||||
if not Game.knows(id):
|
|
||||||
continue
|
continue
|
||||||
var t := TechDB.by_id(id)
|
var pruef := Game.system_pruefen(id, nr, tid)
|
||||||
var ev := Game.evaluate(id, h["id"], aktiv, mensch.resist_left > 0.0)
|
var t := TechDB.by_id(tid)
|
||||||
var gesperrt := not Game.bereit(id)
|
var beschriftung := "%s · Stufe %d" % [t["name"], Game.skill_of(tid)]
|
||||||
var beschriftung := "%s · Stufe %d" % [t["name"], Game.skill_of(id)]
|
if not pruef["geht"]:
|
||||||
if gesperrt:
|
beschriftung += " — " + str(pruef["grund"])
|
||||||
beschriftung += " — noch %d s gesperrt" % int(ceil(Game.cooldown_rest(id)))
|
|
||||||
elif ev["blocked"]:
|
|
||||||
beschriftung += " — " + str(ev["grund"])
|
|
||||||
elif mensch.resist_left > 0.0:
|
elif mensch.resist_left > 0.0:
|
||||||
beschriftung += " — macht gerade dicht"
|
beschriftung += " — macht gerade dicht"
|
||||||
_knopf(beschriftung, func() -> void: _anwenden(id), not ev["blocked"] and not gesperrt)
|
_knopf(beschriftung, func() -> void: _vor_ort_setzen(tid), bool(pruef["geht"]))
|
||||||
_zeigen("anwenden")
|
_zeigen("anwenden")
|
||||||
|
|
||||||
|
|
||||||
func _anwenden(id: String) -> void:
|
func _vor_ort_setzen(tech_id: String) -> void:
|
||||||
if _apply_human == null or not is_instance_valid(_apply_human):
|
if _apply_human == null or not is_instance_valid(_apply_human):
|
||||||
schliessen()
|
schliessen()
|
||||||
return
|
return
|
||||||
var mensch := _apply_human
|
var mensch := _apply_human
|
||||||
var h: Dictionary = mensch.data
|
var id: String = str(mensch.data["id"])
|
||||||
var res := Game.apply_technique(id, h["id"], mensch.activity, mensch.resist_left > 0.0)
|
var res := Game.system_setzen(id, int(mensch.slot), tech_id, mensch.resist_left > 0.0)
|
||||||
schliessen()
|
schliessen()
|
||||||
if not res["ok"]:
|
if not res["ok"]:
|
||||||
Game.notified.emit(res["grund"], Color(1, 0.6, 0.4))
|
Game.notified.emit(str(res["grund"]), Color(1, 0.6, 0.4))
|
||||||
return
|
return
|
||||||
var t := TechDB.by_id(id)
|
var t := TechDB.by_id(tech_id)
|
||||||
if res["success"]:
|
if res["erfolg"]:
|
||||||
mensch.reagiere(true, "%s wirkt\n+%d %%" % [t["name"], int(round(float(res["gain"])))])
|
mensch.reagiere(true, "%s\nsteht" % t["name"])
|
||||||
Game.notified.emit("%s erreicht %s. (+%d %%)" %
|
|
||||||
[t["name"], h["name"], int(round(float(res["gain"])))], Color(0.6, 1, 0.7))
|
|
||||||
if res["wiederholung"] >= 2:
|
|
||||||
Game.notified.emit("Immer dieselbe Technik wirkt schwächer. Probier eine andere.",
|
|
||||||
Color(0.85, 0.85, 0.6))
|
|
||||||
else:
|
else:
|
||||||
mensch.reagiere(false, "%s prallt ab\n−%d %%" % [t["name"],
|
mensch.reagiere(false, "%s greift nicht" % t["name"])
|
||||||
int(round(float(res["verlust"])))])
|
|
||||||
Game.notified.emit("%s dringt nicht durch. (−%d %%)" %
|
|
||||||
[t["name"], int(round(float(res["verlust"])))], Color(1, 0.6, 0.5))
|
|
||||||
|
|
||||||
|
|
||||||
func _unhandled_input(event: InputEvent) -> void:
|
func _unhandled_input(event: InputEvent) -> void:
|
||||||
|
|||||||
136
scripts/ursachen.gd
Normal file
136
scripts/ursachen.gd
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
class_name Ursachen
|
||||||
|
## Woran ein Traum scheitert, und was im Tag davon zu sehen ist.
|
||||||
|
##
|
||||||
|
## Ein Traum hat eine Grundrate. Jede ungelöste Ursache bremst sie. Zwei
|
||||||
|
## ungelöste Ursachen bremsen doppelt -- deshalb lohnt es, alle zu finden.
|
||||||
|
## Sichtbar wird eine Ursache nur an den Tätigkeiten, die sie hervorbringt:
|
||||||
|
## wer nie in Gang kommt, räumt auf, recherchiert und schreibt Listen.
|
||||||
|
##
|
||||||
|
## Grundlage: Habit Reversal Training beginnt mit awareness training -- erst
|
||||||
|
## bemerken, dann ersetzen. Und Duhiggs goldene Regel: Auslöser und Belohnung
|
||||||
|
## bleiben, nur die Handlung dazwischen wird getauscht.
|
||||||
|
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
## Tätigkeiten, die einen Traum aufhalten. Jede hat einen Auslöser und eine
|
||||||
|
## Belohnung -- genau die muss eine Ersatzhandlung wieder liefern.
|
||||||
|
## zeit: wann im Tag die Tätigkeit auftaucht.
|
||||||
|
static var BLOCKER: Dictionary = {
|
||||||
|
"putzflucht": {
|
||||||
|
"name": "räumt auf statt anzufangen", "ausloeser": "eine große Aufgabe",
|
||||||
|
"belohnung": "erfolg", "ursache": "anfang", "zeit": "tag",
|
||||||
|
},
|
||||||
|
"recherche": {
|
||||||
|
"name": "recherchiert statt anzufangen", "ausloeser": "Unsicherheit",
|
||||||
|
"belohnung": "erfolg", "ursache": "anfang", "zeit": "tag",
|
||||||
|
},
|
||||||
|
"liste": {
|
||||||
|
"name": "schreibt eine Später-Liste", "ausloeser": "Überforderung",
|
||||||
|
"belohnung": "ordnung", "ursache": "anfang", "zeit": "morgen",
|
||||||
|
},
|
||||||
|
"jasagen": {
|
||||||
|
"name": "sagt zu allem ja", "ausloeser": "eine fremde Bitte",
|
||||||
|
"belohnung": "anerkennung", "ursache": "zeit", "zeit": "tag",
|
||||||
|
},
|
||||||
|
"scrollen": {
|
||||||
|
"name": "scrollt endlos", "ausloeser": "Leerlauf",
|
||||||
|
"belohnung": "ablenkung", "ursache": "zeit", "zeit": "tag",
|
||||||
|
},
|
||||||
|
"serie": {
|
||||||
|
"name": "schaut eine Serie", "ausloeser": "Erschöpfung",
|
||||||
|
"belohnung": "abschalten", "ursache": "kraft", "zeit": "abend",
|
||||||
|
},
|
||||||
|
"wach": {
|
||||||
|
"name": "bleibt wach", "ausloeser": "ein fremdbestimmter Tag",
|
||||||
|
"belohnung": "zeit_fuer_sich", "ursache": "kraft", "zeit": "nacht",
|
||||||
|
},
|
||||||
|
"kuehlschrank": {
|
||||||
|
"name": "steht am Kühlschrank", "ausloeser": "Langeweile",
|
||||||
|
"belohnung": "unterbrechung", "ursache": "kraft", "zeit": "abend",
|
||||||
|
},
|
||||||
|
"spielen": {
|
||||||
|
"name": "spielt noch eine Runde", "ausloeser": "Anspannung",
|
||||||
|
"belohnung": "erfolg", "ursache": "halt", "zeit": "abend",
|
||||||
|
},
|
||||||
|
"umschalten": {
|
||||||
|
"name": "schaltet auf etwas anderes um", "ausloeser": "Widerstand",
|
||||||
|
"belohnung": "neuheit", "ursache": "halt", "zeit": "tag",
|
||||||
|
},
|
||||||
|
"klagen": {
|
||||||
|
"name": "klagt am Telefon", "ausloeser": "Frust",
|
||||||
|
"belohnung": "verbundenheit", "ursache": "grund", "zeit": "abend",
|
||||||
|
},
|
||||||
|
"vergleichen": {
|
||||||
|
"name": "vergleicht sich mit anderen", "ausloeser": "ein fremder Erfolg",
|
||||||
|
"belohnung": "einordnung", "ursache": "grund", "zeit": "morgen",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
static var BELOHNUNG_TEXT: Dictionary = {
|
||||||
|
"erfolg": "ein Erfolgserlebnis",
|
||||||
|
"ordnung": "Ordnung",
|
||||||
|
"anerkennung": "Anerkennung",
|
||||||
|
"anschluss": "Anschluss",
|
||||||
|
"abschalten": "Abschalten",
|
||||||
|
"zeit_fuer_sich": "Zeit für sich",
|
||||||
|
"unterbrechung": "eine Unterbrechung",
|
||||||
|
"neuheit": "etwas Neues",
|
||||||
|
"verbundenheit": "Verbundenheit",
|
||||||
|
"einordnung": "Einordnung",
|
||||||
|
"ablenkung": "Ablenkung",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static func ist_blocker(activity: String) -> bool:
|
||||||
|
return BLOCKER.has(activity)
|
||||||
|
|
||||||
|
|
||||||
|
static func ursache_von(activity: String) -> String:
|
||||||
|
return str(BLOCKER[activity]["ursache"]) if BLOCKER.has(activity) else ""
|
||||||
|
|
||||||
|
|
||||||
|
static func belohnung_text(schluessel: String) -> String:
|
||||||
|
return str(BELOHNUNG_TEXT.get(schluessel, schluessel))
|
||||||
|
|
||||||
|
|
||||||
|
## Blocker einer Ursache, die in dieses Zeitfenster passen.
|
||||||
|
static func blocker_fuer(ursache: String, zeit: String) -> Array:
|
||||||
|
var out: Array = []
|
||||||
|
for id in BLOCKER:
|
||||||
|
if BLOCKER[id]["ursache"] == ursache and BLOCKER[id]["zeit"] == zeit:
|
||||||
|
out.append(id)
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
static func alle_blocker(ursache: String) -> Array:
|
||||||
|
var out: Array = []
|
||||||
|
for id in BLOCKER:
|
||||||
|
if BLOCKER[id]["ursache"] == ursache:
|
||||||
|
out.append(id)
|
||||||
|
return out
|
||||||
1
scripts/ursachen.gd.uid
Normal file
1
scripts/ursachen.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://ddavhllmw3nlk
|
||||||
@@ -87,15 +87,24 @@ func _ready() -> void:
|
|||||||
await warte(6)
|
await warte(6)
|
||||||
await knipse("11_journal_missionen")
|
await knipse("11_journal_missionen")
|
||||||
|
|
||||||
# Regelwerk: Wenn-Dann-Ketten, die den Fortschritt automatisieren
|
# Diagnose: erst aufdecken, dann Systeme bauen
|
||||||
Game.regel_setzen("mensch_0", "zoegert", str(DreamDB.techniken_von("hoersaal")[0]))
|
Game.erkannt_slots["mensch_0"] = {}
|
||||||
main.ui.pipeline_panel("mensch_0")
|
main.ui.systeme_panel("mensch_0")
|
||||||
await warte(6)
|
await warte(6)
|
||||||
await knipse("12_regelwerk")
|
await knipse("12_tagesablauf_verdeckt")
|
||||||
|
|
||||||
main.ui.regel_panel("mensch_0", "arbeitet")
|
var blocker := -1
|
||||||
|
for nr in range(Game.slots("mensch_0").size()):
|
||||||
|
Game.beobachten("mensch_0", nr, Game.ERKENNEN_SEK * 2.0)
|
||||||
|
if Ursachen.ist_blocker(Game.slot_grund("mensch_0", nr)) and blocker < 0:
|
||||||
|
blocker = nr
|
||||||
|
main.ui.systeme_panel("mensch_0")
|
||||||
await warte(6)
|
await warte(6)
|
||||||
await knipse("13_regel_waehlen")
|
await knipse("12b_tagesablauf_erkannt")
|
||||||
|
|
||||||
|
main.ui.slot_panel("mensch_0", blocker)
|
||||||
|
await warte(6)
|
||||||
|
await knipse("13_system_waehlen")
|
||||||
main.ui.schliessen()
|
main.ui.schliessen()
|
||||||
|
|
||||||
# Lichtung, wenn sich die Wesen dort treffen
|
# Lichtung, wenn sich die Wesen dort treffen
|
||||||
@@ -145,26 +154,30 @@ func _ready() -> void:
|
|||||||
await warte(20)
|
await warte(20)
|
||||||
await knipse("17_lena_zoegert")
|
await knipse("17_lena_zoegert")
|
||||||
|
|
||||||
# Das Regelwerk greift ohne Zutun, sobald Lena die Tätigkeit wechselt
|
# Der Traum läuft von allein weiter, solange Systeme stehen
|
||||||
var vor := Game.mission_progress("mensch_0")
|
for i in range(4000):
|
||||||
for i in range(20000):
|
|
||||||
Game.time_h += 0.004
|
Game.time_h += 0.004
|
||||||
main._process(0.02)
|
main._process(0.02)
|
||||||
for k in main.welt.get_children():
|
for k in main.welt.get_children():
|
||||||
if k is Bewohner:
|
if k is Bewohner:
|
||||||
k._process(0.05)
|
k._process(0.05)
|
||||||
if Game.mission_progress("mensch_0") > vor:
|
|
||||||
break
|
|
||||||
main.player.global_position = lena.global_position + Vector3(0, 1.6, -5.5)
|
main.player.global_position = lena.global_position + Vector3(0, 1.6, -5.5)
|
||||||
main.player.yaw = PI
|
main.player.yaw = PI
|
||||||
main.player.pitch = -0.10
|
main.player.pitch = -0.10
|
||||||
await warte(4)
|
await warte(4)
|
||||||
await knipse("18_regel_greift")
|
await knipse("18_traum_laeuft")
|
||||||
|
|
||||||
main.ui.anwenden_panel(lena)
|
main.ui.anwenden_panel(lena)
|
||||||
await warte(6)
|
await warte(6)
|
||||||
await knipse("19_anwenden")
|
await knipse("19_vor_ort")
|
||||||
main.ui._anwenden(str(DreamDB.techniken_von("hoersaal")[0]))
|
main.ui.schliessen()
|
||||||
|
Game.cooldown.clear()
|
||||||
|
var wege: Array = []
|
||||||
|
for tid in Game.known:
|
||||||
|
wege.append(str(tid))
|
||||||
|
if not wege.is_empty():
|
||||||
|
main.ui._apply_human = lena
|
||||||
|
main.ui._vor_ort_setzen(str(wege[0]))
|
||||||
await warte(25)
|
await warte(25)
|
||||||
await knipse("20_reaktion")
|
await knipse("20_reaktion")
|
||||||
|
|
||||||
|
|||||||
916
tests/verify.gd
916
tests/verify.gd
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user