update
This commit is contained in:
@@ -1,27 +1,29 @@
|
||||
78098b89c88a74ebe8c20117b8754620
|
||||
::res://::1788260833
|
||||
anforderungen.md::TextFile::-1::1788584851::0::1::::<><><>0<>0<><>::
|
||||
README.md::TextFile::-1::1788471905::0::1::::<><><>0<>0<><>::
|
||||
README.md::TextFile::-1::1788598652::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<><>::
|
||||
::res://scripts/::1789505734
|
||||
aushaenge.gd::GDScript::4842442143352950821::1789505730::0::1::::Aushaenge<>RefCounted<><>0<>0<><>::
|
||||
bewohner.gd::GDScript::2125278938812678811::1789505829::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<><>::
|
||||
game.gd::GDScript::3600922541500868814::1789505829::0::1::::<>Node<><>0<>0<><>::
|
||||
human_db.gd::GDScript::412604892032291296::1789505730::0::1::::HumanDB<>RefCounted<><>0<>0<><>::
|
||||
main.gd::GDScript::1504009331368977934::1788598457::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
|
||||
probleme.gd::GDScript::4928319609961045127::1789505398::0::1::::Probleme<>RefCounted<><>0<>0<><>::
|
||||
technique_db.gd::GDScript::4543286561661639701::1789505829::0::1::::TechDB<>RefCounted<><>0<>0<><>::
|
||||
ui.gd::GDScript::843471304695966286::1789506056::0::1::::UI<>CanvasLayer<><>0<>0<><>::
|
||||
ursachen.gd::GDScript::7371116734724270900::1789505398::0::1::::Ursachen<>RefCounted<><>0<>0<><>::
|
||||
woerter.gd::GDScript::1848212517770692820::1789505563::0::1::::Woerter<>RefCounted<><>0<>0<><>::
|
||||
::res://tests/::1788598610
|
||||
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.gd::GDScript::4392606218392155269::1789505952::0::1::::<>Node<><>0<>0<><>::
|
||||
verify.tscn::PackedScene::-1::1788012512::0::1::::<><><>0<>0<><>::res://tests/verify.gd
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
list=[{
|
||||
"base": &"RefCounted",
|
||||
"class": &"Aushaenge",
|
||||
"icon": "",
|
||||
"is_abstract": false,
|
||||
"is_tool": false,
|
||||
"language": &"GDScript",
|
||||
"path": "res://scripts/aushaenge.gd"
|
||||
}, {
|
||||
"base": &"Node3D",
|
||||
"class": &"Bewohner",
|
||||
"icon": "",
|
||||
@@ -102,4 +110,12 @@ list=[{
|
||||
"is_tool": false,
|
||||
"language": &"GDScript",
|
||||
"path": "res://scripts/ursachen.gd"
|
||||
}, {
|
||||
"base": &"RefCounted",
|
||||
"class": &"Woerter",
|
||||
"icon": "",
|
||||
"is_abstract": false,
|
||||
"is_tool": false,
|
||||
"language": &"GDScript",
|
||||
"path": "res://scripts/woerter.gd"
|
||||
}]
|
||||
|
||||
Binary file not shown.
24
README.md
24
README.md
@@ -54,6 +54,28 @@ 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.
|
||||
|
||||
**Eigene Menschen** — Aushang schreiben
|
||||
|
||||
Am Schwarzen Brett lässt sich ein Mensch selbst schreiben: Name, Alter, Beruf,
|
||||
Traum, Geschichte — und **Wörter**. Fünfundfünfzig Alltagswörter, wie Leute
|
||||
über sich reden: *aufschiebend, konfliktscheu, nachtaktiv, hadert mit sich*.
|
||||
Mindestens sechs. Sie sind das Einzige, was die Mechanik liest: aus ihnen
|
||||
schließt das Spiel die Ursachen, die Blocker im Tag, die Klemmen und acht
|
||||
Verhaltenswerte — wie leicht ein System sich setzen lässt, wie gut es trägt,
|
||||
wie stark die Abwehr ist, wie oft Momente aufbrechen, wie lange sie dauern,
|
||||
wie schnell der Traum von sich aus vorankommt, wie gut soziale Techniken
|
||||
greifen, wie leicht man ihm ansieht, was dahintersteckt. Ein Wort zieht an
|
||||
mehreren Stellen, oft in beide Richtungen: *perfektionistisch* lässt Systeme
|
||||
besser tragen und den Anfang schwerer fallen.
|
||||
|
||||
Der Beruf gibt den Tagestyp: Heimarbeit, Frühschicht, Büro, Studium,
|
||||
Werkstatt. Jeder eigene Mensch hat so einen eigenen Alltag, in dem seine
|
||||
Blocker an ihren Tageszeiten stehen — und jede seiner Ursachen mindestens
|
||||
einmal, sonst wäre sie nie zu erkennen. Ein Zufall-Knopf füllt das Formular
|
||||
so, wie der Generator Menschen macht. Eigene Aushänge liegen unter
|
||||
`user://aushaenge.cfg`, überleben den Neustart und ersetzen die letzten
|
||||
erzeugten Einwohner; ein Aushang lässt sich wieder abnehmen.
|
||||
|
||||
**Diagnose und Systeme** — der Kern des Spiels
|
||||
|
||||
Ein Traum scheitert an Ursachen: *kein Anfang*, *keine Zeit*, *keine Kraft*,
|
||||
@@ -197,6 +219,8 @@ eintauschen könnte. Ein Erfolg bringt 2 EP, ein Fehlversuch 1 — auch der zäh
|
||||
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/woerter.gd Alltagswörter und was das Spiel daraus schließt
|
||||
scripts/aushaenge.gd Eigene Aushänge: speichern, laden, prüfen
|
||||
scripts/ui.gd HUD, Journal, Tagesablauf, Hörsaal, Brett, Panels
|
||||
scripts/prims.gd Bausteine aus Primitiven
|
||||
|
||||
|
||||
65
scripts/aushaenge.gd
Normal file
65
scripts/aushaenge.gd
Normal file
@@ -0,0 +1,65 @@
|
||||
class_name Aushaenge
|
||||
## Eigene Aushänge: Menschen, die jemand am Schwarzen Brett selbst geschrieben
|
||||
## hat. Überleben den Neustart, liegen als ConfigFile unter user://.
|
||||
|
||||
static var PFAD := "user://aushaenge.cfg"
|
||||
const FELDER := ["name", "alter", "beruf", "traum", "geschichte", "woerter"]
|
||||
|
||||
|
||||
static func laden() -> Array:
|
||||
var cfg := ConfigFile.new()
|
||||
if cfg.load(PFAD) != OK:
|
||||
return []
|
||||
var out: Array = []
|
||||
for abschnitt in cfg.get_sections():
|
||||
var pr: Dictionary = {"id": abschnitt}
|
||||
for f in FELDER:
|
||||
pr[f] = cfg.get_value(abschnitt, f, "" if f != "woerter" else [])
|
||||
pr["woerter"] = Array(pr["woerter"])
|
||||
out.append(pr)
|
||||
return out
|
||||
|
||||
|
||||
## Legt einen Aushang an oder überschreibt ihn. Gibt die id zurück.
|
||||
static func speichern(pr: Dictionary) -> String:
|
||||
var cfg := ConfigFile.new()
|
||||
cfg.load(PFAD)
|
||||
var id := str(pr.get("id", ""))
|
||||
if id == "":
|
||||
var n := 0
|
||||
while cfg.has_section("eigen_%d" % n):
|
||||
n += 1
|
||||
id = "eigen_%d" % n
|
||||
for f in FELDER:
|
||||
cfg.set_value(id, f, pr.get(f, "" if f != "woerter" else []))
|
||||
cfg.save(PFAD)
|
||||
return id
|
||||
|
||||
|
||||
static func loeschen(id: String) -> void:
|
||||
var cfg := ConfigFile.new()
|
||||
if cfg.load(PFAD) != OK:
|
||||
return
|
||||
if cfg.has_section(id):
|
||||
cfg.erase_section(id)
|
||||
cfg.save(PFAD)
|
||||
|
||||
|
||||
static func alle_loeschen() -> void:
|
||||
var cfg := ConfigFile.new()
|
||||
cfg.save(PFAD)
|
||||
|
||||
|
||||
## Was am Aushang fehlt, bevor er gilt. Leer heißt: alles da.
|
||||
static func pruefen(pr: Dictionary) -> Array:
|
||||
var fehler: Array = []
|
||||
if str(pr.get("name", "")).strip_edges() == "":
|
||||
fehler.append("Name fehlt")
|
||||
if str(pr.get("traum", "")).strip_edges() == "":
|
||||
fehler.append("Traum fehlt")
|
||||
if not HumanDB.BERUF_TAGESTYP.has(str(pr.get("beruf", ""))):
|
||||
fehler.append("Beruf fehlt")
|
||||
var w: Array = pr.get("woerter", [])
|
||||
if w.size() < Woerter.MINDESTENS:
|
||||
fehler.append("mindestens %d Wörter (%d)" % [Woerter.MINDESTENS, w.size()])
|
||||
return fehler
|
||||
1
scripts/aushaenge.gd.uid
Normal file
1
scripts/aushaenge.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://ca8ykxxqrcmen
|
||||
@@ -169,7 +169,8 @@ func reagiere(success: bool, text: String) -> void:
|
||||
tw.tween_property(l, "modulate:a", 0.0, 2.4).set_delay(0.9)
|
||||
tw.chain().tween_callback(l.queue_free)
|
||||
if not success:
|
||||
resist_left = Game.RESIST_SEKUNDEN
|
||||
resist_left = Game.RESIST_SEKUNDEN * \
|
||||
(1.0 + 0.3 * float(Game.verhalten(str(data["id"]), "abwehr")))
|
||||
var blitz := Prims.mat(
|
||||
Color(0.6, 1.0, 0.7) if success else Color(1, 0.5, 0.4), 1.6)
|
||||
var orig := _koerper.material_override
|
||||
|
||||
@@ -30,6 +30,7 @@ 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 gesehen_zaehler: Dictionary = {} # "human:problem" -> wie oft dabeigewesen
|
||||
var completed: Array = []
|
||||
var time_h: float = 7.0
|
||||
var day: int = 1
|
||||
@@ -444,7 +445,7 @@ func ursache_geloest(human_id: String, ursache: String) -> float:
|
||||
|
||||
## Wie schnell kommt der Traum voran? Jede ungelöste Ursache bremst.
|
||||
func traum_tempo(human_id: String) -> float:
|
||||
var t := BASIS_TEMPO
|
||||
var t := BASIS_TEMPO * (1.0 + 0.15 * float(verhalten(human_id, "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"])
|
||||
@@ -490,8 +491,11 @@ func system_setzen(human_id: String, nr: int, tech_id: String, widerstand: bool)
|
||||
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 chance := 0.20 + 0.13 * float(skill_of(tech_id)) - (0.25 if widerstand else 0.0)
|
||||
chance += 0.08 * float(verhalten(human_id, "einrichten"))
|
||||
if TechDB.ist_sozial(tech_id):
|
||||
chance += 0.10 * float(verhalten(human_id, "sozial"))
|
||||
chance = clampf(chance, 0.05, 0.95)
|
||||
var erfolg := randf() < chance
|
||||
if not erfolg:
|
||||
add_xp(tech_id, 1)
|
||||
@@ -499,7 +503,8 @@ func system_setzen(human_id: String, nr: int, tech_id: String, widerstand: bool)
|
||||
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"])}
|
||||
var guete := float(pruef["guete"]) * (1.0 + 0.1 * float(verhalten(human_id, "guete")))
|
||||
systeme[human_id][nr] = {"tech": tech_id, "guete": 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))
|
||||
@@ -548,6 +553,12 @@ const PROBLEM_UEBERWINDEN := 3 # so oft muss eine Technik greifen
|
||||
const SITUATION_GEWINN := 6.0 # Prozent, wenn sie früh beendet wird
|
||||
|
||||
|
||||
## Der Verhaltenswert eines Menschen, -2 bis +2 -- aus seinen Wörtern.
|
||||
func verhalten(human_id: String, key: String) -> int:
|
||||
var h := HumanDB.by_id(human_id)
|
||||
return int((h.get("verhalten", {}) as Dictionary).get(key, 0))
|
||||
|
||||
|
||||
func probleme_von(human_id: String) -> Array:
|
||||
var h := HumanDB.by_id(human_id)
|
||||
return h["probleme"] if h.has("probleme") else []
|
||||
@@ -586,8 +597,9 @@ func situationen_ticken(delta: float, wach: bool) -> void:
|
||||
var p := situation_problem()
|
||||
notified.emit("Moment verpasst: %s" % Probleme.name_von(p),
|
||||
Color(1, 0.75, 0.55))
|
||||
var wer := str(situation["mensch"])
|
||||
situation = {}
|
||||
situation_pause = SITUATION_PAUSE
|
||||
situation_pause = _pause_fuer(wer)
|
||||
state_changed.emit()
|
||||
return
|
||||
situation_pause = maxf(0.0, situation_pause - delta)
|
||||
@@ -596,6 +608,11 @@ func situationen_ticken(delta: float, wach: bool) -> void:
|
||||
_situation_starten()
|
||||
|
||||
|
||||
## Luft bis zum nächsten Moment -- ein reizbarer Mensch hat weniger davon.
|
||||
func _pause_fuer(human_id: String) -> float:
|
||||
return SITUATION_PAUSE * (1.0 - 0.25 * float(verhalten(human_id, "momente")))
|
||||
|
||||
|
||||
func _situation_starten() -> void:
|
||||
var offen: Array = []
|
||||
for p in probleme_von(active_mission):
|
||||
@@ -613,8 +630,10 @@ func _situation_starten() -> void:
|
||||
"mensch": active_mission,
|
||||
"key": str(moeglich[randi() % moeglich.size()]),
|
||||
"problem": problem,
|
||||
"rest": SITUATION_DAUER,
|
||||
"rest": SITUATION_DAUER * (1.0 + 0.25 * float(verhalten(active_mission, "dauer"))),
|
||||
}
|
||||
if verhalten(active_mission, "sichtbar") > 0:
|
||||
situation_sehen() # man sieht es ihm sofort an
|
||||
state_changed.emit()
|
||||
|
||||
|
||||
@@ -626,6 +645,11 @@ func situation_sehen() -> void:
|
||||
var p := situation_problem()
|
||||
if problem_bekannt(id, p):
|
||||
return
|
||||
if verhalten(id, "sichtbar") < 0:
|
||||
var schluessel := "%s:%s" % [id, p]
|
||||
gesehen_zaehler[schluessel] = int(gesehen_zaehler.get(schluessel, 0)) + 1
|
||||
if int(gesehen_zaehler[schluessel]) < 2:
|
||||
return # verschlossen: erst beim zweiten Mal zu durchschauen
|
||||
if not probleme_bekannt.has(id):
|
||||
probleme_bekannt[id] = {}
|
||||
probleme_bekannt[id][p] = true
|
||||
@@ -664,7 +688,7 @@ func situation_anwenden(tech_id: String) -> Dictionary:
|
||||
problem_stand[schluessel] = problem_fortschritt(id, problem) + 1
|
||||
situation_sehen()
|
||||
situation = {}
|
||||
situation_pause = SITUATION_PAUSE
|
||||
situation_pause = _pause_fuer(id)
|
||||
if id == active_mission:
|
||||
progress[id] = minf(mission_progress(id) + SITUATION_GEWINN, MISSION_ZIEL)
|
||||
notified.emit("%s trägt durch +%d %%" %
|
||||
|
||||
@@ -9,6 +9,7 @@ class_name HumanDB
|
||||
## an da und leben ihren Tag.
|
||||
|
||||
const EINWOHNER := 16
|
||||
const BLOCKER_MAX := 4 # mehr Blocker, und der Tag wäre nur noch kaputt
|
||||
const ACHSEN := [-72.0, -24.0, 24.0, 72.0] # Arterien in x wie in z
|
||||
const ARTERIE := 7.0 # Breite einer Arterie
|
||||
const ROJI := 3.2 # Breite einer Gasse
|
||||
@@ -103,6 +104,58 @@ static var ANLIEGEN: Array = [
|
||||
|
||||
## Der Grundtag. Blocker werden später in passende Fenster gesetzt.
|
||||
## [Stunde, Ort, Tätigkeit, Fenster]
|
||||
## Jeder Beruf hat einen Tagestyp -- der bestimmt, wann gearbeitet wird und
|
||||
## wo im Tag Platz für Blocker ist. So bekommt jeder Mensch einen eigenen Alltag.
|
||||
static var BERUF_TAGESTYP: Dictionary = {
|
||||
"Illustratorin": "heim", "Programmiererin": "heim", "Musiker": "heim",
|
||||
"Bäcker": "frueh", "Pfleger": "frueh", "Fahrer": "frueh", "Köchin": "frueh",
|
||||
"Sachbearbeiter": "buero", "Archivarin": "buero", "Lehrer": "buero",
|
||||
"Studentin": "studium", "Tischlerin": "werkstatt",
|
||||
}
|
||||
|
||||
static var TAGESTYP_ARBEIT: Dictionary = {
|
||||
"heim": "heim", "frueh": "baeckerei", "buero": "buero", "studium": "uni",
|
||||
"werkstatt": "werkstatt",
|
||||
}
|
||||
|
||||
static var TAGESTYPEN: Dictionary = {
|
||||
"heim": [
|
||||
[0, "heim", "schlaeft", "nacht"], [7, "heim", "morgenroutine", "morgen"],
|
||||
[9, "heim", "arbeitet", "tag"], [12, "cafe", "essen", "tag"],
|
||||
[14, "heim", "arbeitet", "tag"], [17, "park", "unterwegs", "abend"],
|
||||
[19, "heim", "ruht", "abend"], [21, "heim", "ruht", "abend"],
|
||||
[23, "heim", "abendroutine", "nacht"],
|
||||
],
|
||||
"frueh": [
|
||||
[0, "heim", "schlaeft", "nacht"], [4, "arbeit", "arbeitet", "morgen"],
|
||||
[10, "cafe", "pause", "tag"], [12, "heim", "essen", "tag"],
|
||||
[14, "heim", "ruht", "tag"], [16, "park", "unterwegs", "abend"],
|
||||
[18, "heim", "ruht", "abend"], [20, "heim", "ruht", "abend"],
|
||||
[22, "heim", "abendroutine", "nacht"],
|
||||
],
|
||||
"buero": [
|
||||
[0, "heim", "schlaeft", "nacht"], [6, "heim", "morgenroutine", "morgen"],
|
||||
[8, "arbeit", "arbeitet", "tag"], [12, "cafe", "essen", "tag"],
|
||||
[14, "arbeit", "arbeitet", "tag"], [18, "arbeit", "arbeitet", "abend"],
|
||||
[20, "heim", "essen", "abend"], [22, "heim", "ruht", "abend"],
|
||||
[23, "heim", "abendroutine", "nacht"],
|
||||
],
|
||||
"studium": [
|
||||
[0, "heim", "schlaeft", "nacht"], [8, "heim", "morgenroutine", "morgen"],
|
||||
[10, "arbeit", "arbeitet", "tag"], [13, "cafe", "essen", "tag"],
|
||||
[15, "arbeit", "arbeitet", "tag"], [18, "heim", "ruht", "abend"],
|
||||
[20, "park", "unterwegs", "abend"], [22, "heim", "ruht", "abend"],
|
||||
[23, "heim", "abendroutine", "nacht"],
|
||||
],
|
||||
"werkstatt": [
|
||||
[0, "heim", "schlaeft", "nacht"], [6, "heim", "morgenroutine", "morgen"],
|
||||
[7, "arbeit", "arbeitet", "tag"], [12, "cafe", "essen", "tag"],
|
||||
[13, "arbeit", "arbeitet", "tag"], [17, "heim", "ruht", "abend"],
|
||||
[19, "park", "unterwegs", "abend"], [21, "heim", "ruht", "abend"],
|
||||
[23, "heim", "abendroutine", "nacht"],
|
||||
],
|
||||
}
|
||||
|
||||
static var GRUNDTAG: Array = [
|
||||
[0, "heim", "schlaeft", "nacht"],
|
||||
[7, "heim", "morgenroutine", "morgen"],
|
||||
@@ -145,8 +198,12 @@ static func erzeuge(_ungenutzt: int = 0) -> void:
|
||||
_sonderbauten_verteilen()
|
||||
_wohnhaeuser_verteilen()
|
||||
_anker_setzen()
|
||||
for i in range(EINWOHNER):
|
||||
var eigene := Aushaenge.laden()
|
||||
var n_eigen := mini(eigene.size(), EINWOHNER)
|
||||
for i in range(EINWOHNER - n_eigen):
|
||||
LIST.append(_mensch(i))
|
||||
for k in range(n_eigen):
|
||||
LIST.append(mensch_aus_profil(eigene[k], EINWOHNER - n_eigen + k))
|
||||
|
||||
|
||||
# ------------------------------------------------------------ Bezirk
|
||||
@@ -424,8 +481,16 @@ static func ursachen_von(i: int) -> Array:
|
||||
|
||||
## Der Tagesablauf: Grundtag, in den je Ursache ein Blocker gesetzt wird.
|
||||
static func _tagesablauf(i: int, heim: String, arbeit: String) -> Array:
|
||||
return _tag_belegen(GRUNDTAG, heim, arbeit, [], ursachen_von(i), i)
|
||||
|
||||
|
||||
## Legt Blocker in den Tag. Zuerst bekommt jede Ursache einen -- sonst wäre sie
|
||||
## nie zu erkennen und bremste den Traum für immer. Danach kommen weitere
|
||||
## gewünschte dazu, bis der Tag voll ist. Jeder Blocker nur in sein Zeitfenster.
|
||||
static func _tag_belegen(vorlage: Array, heim: String, arbeit: String,
|
||||
gewuenscht: Array, ursachen: Array, i: int) -> Array:
|
||||
var slots: Array = []
|
||||
for e in GRUNDTAG:
|
||||
for e in vorlage:
|
||||
var ort: String = str(e[1])
|
||||
if ort == "heim":
|
||||
ort = heim
|
||||
@@ -433,32 +498,103 @@ static func _tagesablauf(i: int, heim: String, arbeit: String) -> Array:
|
||||
ort = arbeit
|
||||
slots.append([int(e[0]), ort, str(e[2]), str(e[3])])
|
||||
var belegt: Dictionary = {}
|
||||
var gesetzt: Array = []
|
||||
|
||||
# 1. je Ursache ein Blocker -- aus den gewünschten, sonst aus dem Katalog
|
||||
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:
|
||||
for u in ursachen:
|
||||
var kandidaten: Array = []
|
||||
for b in gewuenscht:
|
||||
if Ursachen.ursache_von(str(b)) == str(u):
|
||||
kandidaten.append(str(b))
|
||||
for b in Ursachen.alle_blocker(str(u)):
|
||||
if not kandidaten.has(str(b)):
|
||||
kandidaten.append(str(b))
|
||||
for k in range(kandidaten.size()):
|
||||
var b: String = str(kandidaten[(k + i + nr) % kandidaten.size()])
|
||||
if _blocker_setzen(slots, belegt, b):
|
||||
gesetzt.append(b)
|
||||
break
|
||||
nr += 1
|
||||
|
||||
# 2. weitere gewünschte, solange Platz ist
|
||||
for b in gewuenscht:
|
||||
if gesetzt.size() >= BLOCKER_MAX:
|
||||
break
|
||||
if gesetzt.has(str(b)) or not Ursachen.BLOCKER.has(b):
|
||||
continue
|
||||
if _blocker_setzen(slots, belegt, str(b)):
|
||||
gesetzt.append(str(b))
|
||||
|
||||
var out: Array = []
|
||||
for e in slots:
|
||||
out.append([e[0], e[1], e[2]])
|
||||
return out
|
||||
|
||||
|
||||
## Ein Blocker in den ersten freien Slot seines Zeitfensters. Nie in den Schlaf.
|
||||
static func _blocker_setzen(slots: Array, belegt: Dictionary, b: String) -> bool:
|
||||
var fenster := str(Ursachen.BLOCKER[b]["zeit"])
|
||||
for k in range(slots.size()):
|
||||
if belegt.has(k) or str(slots[k][2]) == "schlaeft" or str(slots[k][3]) != fenster:
|
||||
continue
|
||||
slots[k][2] = b
|
||||
belegt[k] = true
|
||||
return true
|
||||
return false
|
||||
|
||||
|
||||
## Ein Mensch, den jemand selbst geschrieben hat. Name, Beruf, Traum und
|
||||
## Geschichte kommen vom Aushang; Ursachen, Blocker, Klemmen und Verhalten
|
||||
## schließt das Spiel aus den angekreuzten Wörtern.
|
||||
static func mensch_aus_profil(pr: Dictionary, i: int) -> Dictionary:
|
||||
var bild := Woerter.profil(pr.get("woerter", []))
|
||||
var beruf := str(pr.get("beruf", ""))
|
||||
var typ := str(BERUF_TAGESTYP.get(beruf, "buero"))
|
||||
var heim := heim_key(i)
|
||||
var arbeit := str(TAGESTYP_ARBEIT.get(typ, "buero"))
|
||||
if arbeit == "heim":
|
||||
arbeit = heim
|
||||
elif not PLACES.has(arbeit):
|
||||
arbeit = _naechster_arbeitsplatz(heim, i)
|
||||
return {
|
||||
"id": str(pr.get("id", "eigen_%d" % i)),
|
||||
"name": str(pr.get("name", "Unbekannt")),
|
||||
"alter": int(pr.get("alter", 30)),
|
||||
"beruf": beruf,
|
||||
"traum": str(pr.get("traum", "")),
|
||||
"problem": str(pr.get("geschichte", "")),
|
||||
"tags": [],
|
||||
"ursachen": bild["ursachen"],
|
||||
"probleme": bild["probleme"],
|
||||
"verhalten": bild["verhalten"],
|
||||
"woerter": Array(pr.get("woerter", [])),
|
||||
"eigen": true,
|
||||
"mission": true,
|
||||
"heim": heim,
|
||||
"farbe": Color.from_hsv(fmod(0.02 + float(i) * 0.191, 1.0), 0.5, 0.8),
|
||||
"routine": _tag_belegen(TAGESTYPEN[typ], heim, arbeit, bild["blocker"],
|
||||
bild["ursachen"], i),
|
||||
}
|
||||
|
||||
|
||||
## Der Zufall-Knopf: füllt einen Aushang so, wie der Generator Menschen macht.
|
||||
static func zufallsprofil() -> Dictionary:
|
||||
var i := randi() % 1000
|
||||
var anliegen: Dictionary = ANLIEGEN[i % ANLIEGEN.size()]
|
||||
var alle: Array = Woerter.ids()
|
||||
alle.shuffle()
|
||||
var woerter: Array = alle.slice(0, Woerter.MINDESTENS + randi() % 4)
|
||||
return {
|
||||
"name": "%s %s" % [_vorname(i), _nachname(i)],
|
||||
"alter": 20 + randi() % 45,
|
||||
"beruf": str(BERUFE[i % BERUFE.size()]),
|
||||
"traum": str(anliegen["traum"]),
|
||||
"geschichte": str(anliegen["problem"]),
|
||||
"woerter": woerter,
|
||||
}
|
||||
|
||||
|
||||
static func _mensch(i: int) -> Dictionary:
|
||||
var anliegen: Dictionary = ANLIEGEN[i % ANLIEGEN.size()]
|
||||
if i < PASSEND.size():
|
||||
@@ -475,6 +611,7 @@ static func _mensch(i: int) -> Dictionary:
|
||||
"tags": (anliegen["tags"] as Array).duplicate(),
|
||||
"ursachen": ursachen_von(i),
|
||||
"probleme": probleme_von(i),
|
||||
"verhalten": {},
|
||||
"mission": true,
|
||||
"heim": heim,
|
||||
"farbe": Color.from_hsv(fmod(0.02 + float(i) * 0.191, 1.0), 0.5, 0.8),
|
||||
|
||||
@@ -27,6 +27,12 @@ static var LISTE: Dictionary = {
|
||||
"einsamkeit": {
|
||||
"name": "Einsamkeit", "kurz": "hängt allein an dem, was zu zweit ginge",
|
||||
},
|
||||
"perfektionismus": {
|
||||
"name": "Perfektionismus", "kurz": "nichts ist je gut genug zum Abgeben",
|
||||
},
|
||||
"unruhe": {
|
||||
"name": "Unruhe", "kurz": "kann nicht bleiben, wo er ist",
|
||||
},
|
||||
}
|
||||
|
||||
## Situationen: was im Moment sichtbar wird. Jede gehört zu einem Problem.
|
||||
@@ -67,6 +73,34 @@ static var SITUATIONEN: Dictionary = {
|
||||
"name": "hängt allein fest", "was": "Sie kommt nicht weiter und fragt niemanden.",
|
||||
"problem": "einsamkeit",
|
||||
},
|
||||
"absagen_treffen": {
|
||||
"name": "sagt das Treffen ab", "was": "Lieber allein als unter Leuten.",
|
||||
"problem": "einsamkeit",
|
||||
},
|
||||
"verwerfen": {
|
||||
"name": "verwirft den Entwurf", "was": "Sie löscht, was schon fertig war.",
|
||||
"problem": "perfektionismus",
|
||||
},
|
||||
"nachbessern": {
|
||||
"name": "bessert endlos nach", "was": "Die dritte Fassung, und es wird nicht besser.",
|
||||
"problem": "perfektionismus",
|
||||
},
|
||||
"aufspringen": {
|
||||
"name": "springt auf", "was": "Sie hält es am Platz nicht aus.",
|
||||
"problem": "unruhe",
|
||||
},
|
||||
"ortswechsel": {
|
||||
"name": "wechselt den Ort", "was": "Woanders geht es bestimmt besser.",
|
||||
"problem": "unruhe",
|
||||
},
|
||||
"zusammenbruch_klein": {
|
||||
"name": "gibt für heute auf", "was": "Der Rest des Tages ist gestrichen.",
|
||||
"problem": "erschoepfung",
|
||||
},
|
||||
"abbruch": {
|
||||
"name": "lässt es liegen", "was": "Mitten drin hört sie auf.",
|
||||
"problem": "ueberforderung",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ static var LIST: Array = [
|
||||
"ursache": "anfang",
|
||||
"belohnung": "erfolg",
|
||||
"ersatz": "fängt zwei Minuten an",
|
||||
"tags": ["prokrastination", "ueberforderung"],
|
||||
"tags": ["prokrastination", "ueberforderung", "perfektionismus"],
|
||||
"farbe": Color(0.98, 0.72, 0.25),
|
||||
},
|
||||
{
|
||||
@@ -104,7 +104,7 @@ static var LIST: Array = [
|
||||
"ursache": "kraft",
|
||||
"belohnung": "abschalten",
|
||||
"ersatz": "atmet sich ruhig",
|
||||
"tags": ["angst", "stress"],
|
||||
"tags": ["angst", "stress", "unruhe"],
|
||||
"farbe": Color(0.40, 0.85, 0.95),
|
||||
},
|
||||
{
|
||||
@@ -117,7 +117,7 @@ static var LIST: Array = [
|
||||
"ursache": "grund",
|
||||
"belohnung": "verbundenheit",
|
||||
"ersatz": "ist freundlich mit sich",
|
||||
"tags": ["selbstzweifel", "rueckschlag"],
|
||||
"tags": ["selbstzweifel", "rueckschlag", "perfektionismus"],
|
||||
"farbe": Color(1.0, 0.80, 0.60),
|
||||
},
|
||||
{
|
||||
@@ -159,6 +159,123 @@ static var LIST: Array = [
|
||||
"tags": ["stress", "grenzen"],
|
||||
"farbe": Color(0.85, 0.35, 0.45),
|
||||
},
|
||||
{
|
||||
"id": "frosch",
|
||||
"name": "Das Schwerste zuerst",
|
||||
"was": "Die unangenehmste Aufgabe des Tages als Erstes erledigen, bevor irgendetwas anderes dran ist.",
|
||||
"wann": "Wenn eine Aufgabe den ganzen Tag über im Nacken sitzt und alles andere zum Ausweichen wird.",
|
||||
"warum": "Solange das Schwerste wartet, ist keine andere Arbeit befreit. Danach ist der Rest leicht.",
|
||||
"woran": "jemandem, der morgens erst das Postfach aufräumt und Kaffee holt.",
|
||||
"ursache": "anfang",
|
||||
"belohnung": "erfolg",
|
||||
"ersatz": "packt das Schwerste zuerst an",
|
||||
"tags": ["ueberforderung"],
|
||||
"farbe": Color(0.60, 0.80, 0.45),
|
||||
},
|
||||
{
|
||||
"id": "zeitblock",
|
||||
"name": "Zeitblöcke",
|
||||
"was": "Den Tag in feste Blöcke teilen und jeder Aufgabe einen Block geben — auch dem Eigenen.",
|
||||
"wann": "Wenn der Tag von Bitten anderer aufgebraucht wird und das Eigene nie dran ist.",
|
||||
"warum": "Was keinen Platz im Kalender hat, verliert gegen alles, was einen hat.",
|
||||
"woran": "jemandem, der zu allem ja sagt oder abends länger bleibt.",
|
||||
"ursache": "zeit",
|
||||
"belohnung": "ordnung",
|
||||
"ersatz": "hält seinen Block frei",
|
||||
"tags": ["stress", "ueberforderung"],
|
||||
"farbe": Color(0.45, 0.65, 0.90),
|
||||
},
|
||||
{
|
||||
"id": "bildschirmfrei",
|
||||
"name": "Bildschirmfreier Abend",
|
||||
"was": "Ab einer festen Uhrzeit bleiben Handy und Fernseher aus. Stattdessen etwas, das die Hände beschäftigt.",
|
||||
"wann": "Wenn der Abend im Scrollen oder in Serien versickert und morgens nichts übrig ist.",
|
||||
"warum": "Bildschirme versprechen Abschalten und liefern Reizung. Der Kopf braucht das Gegenteil.",
|
||||
"woran": "jemandem, der abends eine Serie schaut oder endlos scrollt.",
|
||||
"ursache": "kraft",
|
||||
"belohnung": "abschalten",
|
||||
"ersatz": "lässt den Bildschirm aus",
|
||||
"tags": ["erschoepfung"],
|
||||
"farbe": Color(0.35, 0.45, 0.70),
|
||||
},
|
||||
{
|
||||
"id": "powernap",
|
||||
"name": "Kurzer Mittagsschlaf",
|
||||
"was": "Zwanzig Minuten schlafen, nicht länger, mit Wecker — am besten früh am Nachmittag.",
|
||||
"wann": "Wenn nach dem Mittag nichts mehr geht und der Rest des Tages verloren ist.",
|
||||
"warum": "Zwanzig Minuten reichen, um den Kopf zu klären, ohne in den Tiefschlaf zu fallen.",
|
||||
"woran": "jemandem, der nachmittags wegdöst oder am Kühlschrank steht.",
|
||||
"ursache": "kraft",
|
||||
"belohnung": "unterbrechung",
|
||||
"ersatz": "schläft zwanzig Minuten",
|
||||
"tags": ["erschoepfung"],
|
||||
"farbe": Color(0.55, 0.50, 0.85),
|
||||
},
|
||||
{
|
||||
"id": "kette",
|
||||
"name": "Die Kette nicht reißen lassen",
|
||||
"was": "Jeden Tag, an dem man dran war, im Kalender abhaken. Die Reihe nicht unterbrechen.",
|
||||
"wann": "Wenn oft angefangen und selten drangeblieben wird.",
|
||||
"warum": "Eine sichtbare Reihe ist ein Einsatz. Sie zu brechen tut mehr weh als weiterzumachen.",
|
||||
"woran": "jemandem, der auf etwas anderes umschaltet oder den Plan neu schreibt.",
|
||||
"ursache": "halt",
|
||||
"belohnung": "erfolg",
|
||||
"ersatz": "hakt den Tag ab",
|
||||
"tags": ["selbstzweifel", "perfektionismus"],
|
||||
"farbe": Color(0.90, 0.60, 0.35),
|
||||
},
|
||||
{
|
||||
"id": "verabredung",
|
||||
"name": "Verabredung zum Dranbleiben",
|
||||
"was": "Sich mit jemandem zu einer festen Zeit verabreden, um gemeinsam oder nebeneinander zu arbeiten.",
|
||||
"wann": "Wenn man allein immer wieder aussteigt.",
|
||||
"warum": "Vor einem anderen fällt Aufhören schwerer als vor sich selbst.",
|
||||
"woran": "jemandem, der allein festhängt oder Verabredungen absagt.",
|
||||
"ursache": "halt",
|
||||
"belohnung": "verbundenheit",
|
||||
"ersatz": "meldet sich zum Dranbleiben",
|
||||
"tags": ["einsamkeit"],
|
||||
"farbe": Color(0.95, 0.70, 0.50),
|
||||
},
|
||||
{
|
||||
"id": "warum_notiz",
|
||||
"name": "Das Warum aufschreiben",
|
||||
"was": "In zwei Sätzen festhalten, wofür das Vorhaben steht — und die Notiz dort lassen, wo man sie sieht.",
|
||||
"wann": "Wenn das Vorhaben klein geredet wird und niemand mehr weiß, warum es einmal wichtig war.",
|
||||
"warum": "Ein Grund, den man lesen kann, hält länger als einer, den man sich merken muss.",
|
||||
"woran": "jemandem, der am Telefon klagt oder die Sache abends wälzt.",
|
||||
"ursache": "grund",
|
||||
"belohnung": "einordnung",
|
||||
"ersatz": "liest sein Warum",
|
||||
"tags": ["selbstzweifel"],
|
||||
"farbe": Color(0.80, 0.75, 0.50),
|
||||
},
|
||||
{
|
||||
"id": "angstleiter",
|
||||
"name": "Angstleiter",
|
||||
"was": "Die gefürchtete Sache in Stufen teilen, von harmlos bis schwer, und jede Woche eine Sprosse höher.",
|
||||
"wann": "Wenn etwas so viel Angst macht, dass es immer wieder abgesagt wird.",
|
||||
"warum": "Angst schrumpft durch Gewöhnung, nicht durch Mut. Kleine Schritte gewöhnen.",
|
||||
"woran": "jemandem, der Termine absagt oder vor dem Berg erstarrt.",
|
||||
"ursache": "anfang",
|
||||
"belohnung": "erfolg",
|
||||
"ersatz": "nimmt die nächste Sprosse",
|
||||
"tags": ["angst"],
|
||||
"farbe": Color(0.50, 0.85, 0.80),
|
||||
},
|
||||
{
|
||||
"id": "sorgenzeit",
|
||||
"name": "Sorgenzeit",
|
||||
"was": "Sorgen auf eine feste Viertelstunde am Tag vertagen. Was vorher kommt, wird notiert und wartet.",
|
||||
"wann": "Wenn Sorgen den ganzen Tag dazwischenfunken.",
|
||||
"warum": "Sorgen lassen sich nicht abstellen, aber verschieben. Verschoben verlieren sie an Gewicht.",
|
||||
"woran": "jemandem, der drei Dinge gleichzeitig anfängt oder nachts wach liegt.",
|
||||
"ursache": "grund",
|
||||
"belohnung": "einordnung",
|
||||
"ersatz": "parkt die Sorge bis fünf",
|
||||
"tags": ["angst", "stress", "unruhe"],
|
||||
"farbe": Color(0.70, 0.60, 0.90),
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
@@ -171,6 +288,11 @@ static func fuer_ursache(ursache: String) -> Array:
|
||||
return out
|
||||
|
||||
|
||||
## Techniken, die über andere Menschen gehen -- bei Geselligen greifen sie besser.
|
||||
static func ist_sozial(id: String) -> bool:
|
||||
return str(by_id(id).get("belohnung", "")) in ["verbundenheit", "anerkennung"]
|
||||
|
||||
|
||||
## 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:
|
||||
|
||||
146
scripts/ui.gd
146
scripts/ui.gd
@@ -685,6 +685,8 @@ func _naechster_weg() -> void:
|
||||
func brett_panel() -> void:
|
||||
var scroll_alt := _scroll.scroll_vertical if offen and _kind == "brett" else 0
|
||||
_leeren("Schwarzes Brett")
|
||||
_knopf("Aushang schreiben", func() -> void: schreiben_panel())
|
||||
_trenner()
|
||||
var offen_ids := Game.offene_missionen()
|
||||
var gezeigt := 0
|
||||
var verdeckt := 0
|
||||
@@ -730,10 +732,154 @@ func aushang_panel(human_id: String) -> void:
|
||||
_knopf("Mission annehmen", func() -> void:
|
||||
Game.accept_mission(human_id)
|
||||
brett_panel())
|
||||
if bool(h.get("eigen", false)):
|
||||
_knopf("Aushang abnehmen", func() -> void:
|
||||
Aushaenge.loeschen(human_id)
|
||||
Game.welt_erzeugen()
|
||||
brett_panel())
|
||||
_knopf("Zurück", func() -> void: brett_panel())
|
||||
_zeigen("aushang")
|
||||
|
||||
|
||||
# -------------------------------------------------------- Aushang schreiben
|
||||
|
||||
## Ein eigener Mensch: Name, Alter, Beruf, Traum, Wörter, Geschichte.
|
||||
## Die Wörter sind das Einzige, was die Mechanik liest.
|
||||
var _entwurf: Dictionary = {}
|
||||
|
||||
|
||||
func schreiben_panel(entwurf: Dictionary = {}) -> void:
|
||||
if not entwurf.is_empty():
|
||||
_entwurf = entwurf
|
||||
elif _entwurf.is_empty():
|
||||
_entwurf = {"name": "", "alter": 30, "beruf": str(HumanDB.BERUFE[0]),
|
||||
"traum": "", "geschichte": "", "woerter": []}
|
||||
var scroll_alt := _scroll.scroll_vertical if offen and _kind == "schreiben" else 0
|
||||
_leeren("Aushang schreiben")
|
||||
_zeile("Name", _eingabe("name"))
|
||||
_zeile("Alter", _zahl("alter", 14, 99))
|
||||
_zeile("Beruf", _auswahl("beruf", HumanDB.BERUFE))
|
||||
_zeile("Traum", _eingabe("traum"))
|
||||
_trenner()
|
||||
var w: Array = _entwurf["woerter"]
|
||||
_text("[b]Wörter[/b] [color=#8e93a8]mindestens %d · %d gewählt[/color]" %
|
||||
[Woerter.MINDESTENS, w.size()], 15)
|
||||
for gruppe in Woerter.GRUPPEN:
|
||||
_text("[color=#9fb6ff]%s[/color]" % Woerter.GRUPPEN[gruppe], 13)
|
||||
_haken_raster(Woerter.in_gruppe(gruppe))
|
||||
_trenner()
|
||||
_text("[b]Geschichte[/b] [color=#8e93a8]was im Weg steht[/color]", 15)
|
||||
_textfeld("geschichte")
|
||||
_trenner()
|
||||
var reihe := HBoxContainer.new()
|
||||
reihe.add_theme_constant_override("separation", 8)
|
||||
_content.add_child(reihe)
|
||||
_reihenknopf(reihe, "Zufall", func() -> void:
|
||||
schreiben_panel(HumanDB.zufallsprofil()))
|
||||
_reihenknopf(reihe, "Speichern", func() -> void: _aushang_speichern())
|
||||
_reihenknopf(reihe, "Zurück", func() -> void:
|
||||
_entwurf = {}
|
||||
brett_panel())
|
||||
_zeigen("schreiben")
|
||||
_scroll_wunsch = scroll_alt
|
||||
_scroll_frames = 4
|
||||
|
||||
|
||||
func _aushang_speichern() -> void:
|
||||
var fehler := Aushaenge.pruefen(_entwurf)
|
||||
if not fehler.is_empty():
|
||||
Game.notified.emit("Aushang unvollständig: %s" % ", ".join(fehler), Color(1, 0.7, 0.5))
|
||||
return
|
||||
var id := Aushaenge.speichern(_entwurf)
|
||||
Game.welt_erzeugen()
|
||||
Game.notified.emit("Aushang hängt: %s" % _entwurf["name"], Color(0.6, 1, 0.7))
|
||||
_entwurf = {}
|
||||
aushang_panel(id)
|
||||
|
||||
|
||||
# ---- Eingabehelfer
|
||||
|
||||
func _zeile(titel: String, widget: Control) -> void:
|
||||
var hb := HBoxContainer.new()
|
||||
hb.add_theme_constant_override("separation", 10)
|
||||
var l := Label.new()
|
||||
l.text = titel
|
||||
l.custom_minimum_size.x = 90
|
||||
l.add_theme_font_size_override("font_size", 15)
|
||||
hb.add_child(l)
|
||||
widget.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
hb.add_child(widget)
|
||||
_content.add_child(hb)
|
||||
|
||||
|
||||
func _eingabe(feld: String) -> LineEdit:
|
||||
var e := LineEdit.new()
|
||||
e.text = str(_entwurf.get(feld, ""))
|
||||
e.add_theme_font_size_override("font_size", 15)
|
||||
e.text_changed.connect(func(t: String) -> void: _entwurf[feld] = t)
|
||||
return e
|
||||
|
||||
|
||||
func _zahl(feld: String, von: int, bis: int) -> SpinBox:
|
||||
var s := SpinBox.new()
|
||||
s.min_value = von
|
||||
s.max_value = bis
|
||||
s.value = int(_entwurf.get(feld, von))
|
||||
s.value_changed.connect(func(v: float) -> void: _entwurf[feld] = int(v))
|
||||
return s
|
||||
|
||||
|
||||
func _auswahl(feld: String, optionen: Array) -> OptionButton:
|
||||
var o := OptionButton.new()
|
||||
for i in range(optionen.size()):
|
||||
o.add_item(str(optionen[i]), i)
|
||||
if str(optionen[i]) == str(_entwurf.get(feld, "")):
|
||||
o.select(i)
|
||||
o.item_selected.connect(func(i: int) -> void: _entwurf[feld] = str(optionen[i]))
|
||||
return o
|
||||
|
||||
|
||||
func _textfeld(feld: String) -> TextEdit:
|
||||
var t := TextEdit.new()
|
||||
t.text = str(_entwurf.get(feld, ""))
|
||||
t.custom_minimum_size = Vector2(0, 80)
|
||||
t.wrap_mode = TextEdit.LINE_WRAPPING_BOUNDARY
|
||||
t.add_theme_font_size_override("font_size", 15)
|
||||
t.text_changed.connect(func() -> void: _entwurf[feld] = t.text)
|
||||
_content.add_child(t)
|
||||
return t
|
||||
|
||||
|
||||
func _haken_raster(keys: Array) -> void:
|
||||
var g := GridContainer.new()
|
||||
g.columns = 4
|
||||
g.add_theme_constant_override("h_separation", 6)
|
||||
_content.add_child(g)
|
||||
var gewaehlt: Array = _entwurf["woerter"]
|
||||
for key in keys:
|
||||
var c := CheckBox.new()
|
||||
c.text = Woerter.name_von(str(key))
|
||||
c.button_pressed = gewaehlt.has(key)
|
||||
c.add_theme_font_size_override("font_size", 14)
|
||||
c.toggled.connect(func(an: bool) -> void:
|
||||
var liste: Array = _entwurf["woerter"]
|
||||
if an and not liste.has(key):
|
||||
liste.append(key)
|
||||
elif not an:
|
||||
liste.erase(key))
|
||||
g.add_child(c)
|
||||
|
||||
|
||||
func _reihenknopf(reihe: HBoxContainer, text: String, cb: Callable) -> void:
|
||||
var b := Button.new()
|
||||
b.text = text
|
||||
b.custom_minimum_size = Vector2(0, 32)
|
||||
b.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
b.add_theme_font_size_override("font_size", 16)
|
||||
b.pressed.connect(cb)
|
||||
reihe.add_child(b)
|
||||
|
||||
|
||||
# -------------------------------------------------------- Vor Ort
|
||||
|
||||
## Draußen am Menschen: hier greift man in den Slot ein, der gerade läuft.
|
||||
|
||||
@@ -85,6 +85,50 @@ static var BLOCKER: Dictionary = {
|
||||
"name": "vergleicht sich mit anderen", "ausloeser": "ein fremder Erfolg",
|
||||
"belohnung": "einordnung", "ursache": "grund", "zeit": "morgen",
|
||||
},
|
||||
"mails": {
|
||||
"name": "räumt das Postfach auf", "ausloeser": "Leerlauf",
|
||||
"belohnung": "ordnung", "ursache": "anfang", "zeit": "morgen",
|
||||
},
|
||||
"kaffee": {
|
||||
"name": "holt noch einen Kaffee", "ausloeser": "Unlust",
|
||||
"belohnung": "unterbrechung", "ursache": "anfang", "zeit": "tag",
|
||||
},
|
||||
"perfekt": {
|
||||
"name": "feilt am Detail statt abzugeben", "ausloeser": "Angst vor dem Urteil",
|
||||
"belohnung": "ordnung", "ursache": "halt", "zeit": "tag",
|
||||
},
|
||||
"plan_neu": {
|
||||
"name": "schreibt den Plan noch einmal neu", "ausloeser": "Unsicherheit",
|
||||
"belohnung": "ordnung", "ursache": "halt", "zeit": "tag",
|
||||
},
|
||||
"snooze": {
|
||||
"name": "drückt auf Schlummern", "ausloeser": "Müdigkeit",
|
||||
"belohnung": "abschalten", "ursache": "kraft", "zeit": "morgen",
|
||||
},
|
||||
"doesen": {
|
||||
"name": "döst auf dem Sofa weg", "ausloeser": "Erschöpfung",
|
||||
"belohnung": "abschalten", "ursache": "kraft", "zeit": "tag",
|
||||
},
|
||||
"bestellen": {
|
||||
"name": "bestellt statt zu kochen", "ausloeser": "ein leerer Akku",
|
||||
"belohnung": "unterbrechung", "ursache": "kraft", "zeit": "abend",
|
||||
},
|
||||
"nachrichten": {
|
||||
"name": "liest Nachrichten", "ausloeser": "Unruhe",
|
||||
"belohnung": "einordnung", "ursache": "zeit", "zeit": "morgen",
|
||||
},
|
||||
"ueberstunden": {
|
||||
"name": "bleibt länger im Büro", "ausloeser": "fremde Erwartung",
|
||||
"belohnung": "anerkennung", "ursache": "zeit", "zeit": "abend",
|
||||
},
|
||||
"absage": {
|
||||
"name": "sagt die Verabredung ab", "ausloeser": "ein voller Kopf",
|
||||
"belohnung": "zeit_fuer_sich", "ursache": "grund", "zeit": "abend",
|
||||
},
|
||||
"waelzen": {
|
||||
"name": "wälzt die Sache im Bett", "ausloeser": "Stille",
|
||||
"belohnung": "einordnung", "ursache": "grund", "zeit": "nacht",
|
||||
},
|
||||
}
|
||||
|
||||
static var BELOHNUNG_TEXT: Dictionary = {
|
||||
|
||||
218
scripts/woerter.gd
Normal file
218
scripts/woerter.gd
Normal file
@@ -0,0 +1,218 @@
|
||||
class_name Woerter
|
||||
## Alltagswörter, mit denen jemand sich selbst beschreibt -- und was das Spiel
|
||||
## daraus schließt. Vorne Wörter, die jeder an sich erkennt; hinten das Modell.
|
||||
##
|
||||
## Jedes Wort zieht an mehreren Stellen: Ursachen (was den Traum bremst),
|
||||
## Blocker (was im Tag auftaucht), Klemmen (was in Momenten aufbricht) und
|
||||
## Verhalten (wie der Mensch auf Techniken reagiert). Ein Wort kann an einer
|
||||
## Stelle helfen und an einer anderen schaden -- so ist das bei Menschen.
|
||||
|
||||
## Die acht Verhaltenswerte, -2 bis +2:
|
||||
## einrichten wie leicht ein System sich setzen lässt
|
||||
## guete wie gut ein gesetztes System trägt
|
||||
## abwehr wie stark die Abwehr nach einem Fehlschlag ist
|
||||
## momente wie oft Momente aufbrechen
|
||||
## dauer wie lange sie dauern
|
||||
## tempo wie schnell der Traum von sich aus vorankommt
|
||||
## sozial wie gut soziale Techniken greifen
|
||||
## sichtbar wie schnell man ihm ansieht, was dahintersteckt
|
||||
const VERHALTEN := ["einrichten", "guete", "abwehr", "momente", "dauer", "tempo", "sozial", "sichtbar"]
|
||||
|
||||
const GRUPPEN := {
|
||||
"arbeit": "Arbeitsweise", "menschen": "Mit anderen", "gefuehl": "Gefühl",
|
||||
"energie": "Energie", "selbst": "Selbstbild",
|
||||
}
|
||||
|
||||
static var LISTE: Dictionary = {
|
||||
# --- Arbeitsweise
|
||||
"aufschiebend": {"name": "aufschiebend", "gruppe": "arbeit",
|
||||
"ursachen": {"anfang": 2}, "blocker": ["putzflucht", "kaffee"], "verhalten": {"einrichten": -1}},
|
||||
"perfektionistisch": {"name": "perfektionistisch", "gruppe": "arbeit",
|
||||
"ursachen": {"halt": 1, "anfang": 1}, "blocker": ["perfekt"],
|
||||
"probleme": {"perfektionismus": 2}, "verhalten": {"guete": 1, "abwehr": 1}},
|
||||
"gruendlich": {"name": "gründlich", "gruppe": "arbeit",
|
||||
"ursachen": {"anfang": 1}, "blocker": ["recherche"], "verhalten": {"guete": 1}},
|
||||
"chaotisch": {"name": "chaotisch", "gruppe": "arbeit",
|
||||
"ursachen": {"halt": 1}, "blocker": ["plan_neu"], "probleme": {"ueberforderung": 1},
|
||||
"verhalten": {"guete": -1}},
|
||||
"ordentlich": {"name": "ordentlich", "gruppe": "arbeit",
|
||||
"ursachen": {"anfang": 1}, "blocker": ["liste", "mails"], "verhalten": {"guete": 1}},
|
||||
"sprunghaft": {"name": "sprunghaft", "gruppe": "arbeit",
|
||||
"ursachen": {"halt": 2}, "blocker": ["umschalten"], "verhalten": {"guete": -1, "momente": 1}},
|
||||
"ablenkbar": {"name": "ablenkbar", "gruppe": "arbeit",
|
||||
"ursachen": {"halt": 1, "zeit": 1}, "blocker": ["scrollen", "spielen"],
|
||||
"probleme": {"unruhe": 1}},
|
||||
"diszipliniert": {"name": "diszipliniert", "gruppe": "arbeit",
|
||||
"verhalten": {"guete": 1, "einrichten": 1, "tempo": 1}},
|
||||
"ehrgeizig": {"name": "ehrgeizig", "gruppe": "arbeit",
|
||||
"probleme": {"stress": 1}, "verhalten": {"tempo": 1, "momente": 1}},
|
||||
"bequem": {"name": "bequem", "gruppe": "arbeit",
|
||||
"ursachen": {"kraft": 1, "anfang": 1}, "blocker": ["doesen", "bestellen"]},
|
||||
"zielstrebig": {"name": "zielstrebig", "gruppe": "arbeit",
|
||||
"verhalten": {"tempo": 1, "einrichten": 1}},
|
||||
"unentschlossen": {"name": "unentschlossen", "gruppe": "arbeit",
|
||||
"ursachen": {"anfang": 1}, "blocker": ["liste", "plan_neu"], "probleme": {"ueberforderung": 1}},
|
||||
"ungeduldig": {"name": "ungeduldig", "gruppe": "arbeit",
|
||||
"probleme": {"stress": 1}, "verhalten": {"abwehr": 1, "dauer": -1}},
|
||||
"geduldig": {"name": "geduldig", "gruppe": "arbeit",
|
||||
"verhalten": {"abwehr": -1, "dauer": 1}},
|
||||
"neugierig": {"name": "neugierig", "gruppe": "arbeit",
|
||||
"blocker": ["recherche", "umschalten"], "verhalten": {"einrichten": 1}},
|
||||
"verbissen": {"name": "verbissen", "gruppe": "arbeit",
|
||||
"probleme": {"stress": 1}, "verhalten": {"abwehr": 1, "tempo": 1}},
|
||||
"spontan": {"name": "spontan", "gruppe": "arbeit",
|
||||
"ursachen": {"halt": 1}, "verhalten": {"momente": 1}},
|
||||
"pflichtbewusst": {"name": "pflichtbewusst", "gruppe": "arbeit",
|
||||
"ursachen": {"zeit": 1}, "blocker": ["ueberstunden", "jasagen"], "verhalten": {"guete": 1}},
|
||||
# --- Mit anderen
|
||||
"gesellig": {"name": "gesellig", "gruppe": "menschen",
|
||||
"ursachen": {"zeit": 1}, "verhalten": {"sozial": 1, "sichtbar": 1}},
|
||||
"zurueckgezogen": {"name": "zurückgezogen", "gruppe": "menschen",
|
||||
"blocker": ["absage"], "probleme": {"einsamkeit": 2}, "verhalten": {"sozial": -1, "sichtbar": -1}},
|
||||
"hilfsbereit": {"name": "hilfsbereit", "gruppe": "menschen",
|
||||
"ursachen": {"zeit": 2}, "blocker": ["jasagen"], "verhalten": {"sozial": 1}},
|
||||
"konfliktscheu": {"name": "konfliktscheu", "gruppe": "menschen",
|
||||
"ursachen": {"zeit": 1}, "blocker": ["jasagen"], "probleme": {"angst": 1},
|
||||
"verhalten": {"abwehr": -1}},
|
||||
"stur": {"name": "stur", "gruppe": "menschen",
|
||||
"verhalten": {"abwehr": 2, "einrichten": -1}},
|
||||
"nachgiebig": {"name": "nachgiebig", "gruppe": "menschen",
|
||||
"ursachen": {"zeit": 1}, "verhalten": {"abwehr": -1, "einrichten": 1}},
|
||||
"misstrauisch": {"name": "misstrauisch", "gruppe": "menschen",
|
||||
"verhalten": {"einrichten": -1, "sozial": -1, "sichtbar": -1}},
|
||||
"vertrauensvoll": {"name": "vertrauensvoll", "gruppe": "menschen",
|
||||
"verhalten": {"einrichten": 1, "sozial": 1}},
|
||||
"harmoniebeduerftig": {"name": "harmoniebedürftig", "gruppe": "menschen",
|
||||
"ursachen": {"zeit": 1}, "blocker": ["jasagen"], "verhalten": {"abwehr": -1}},
|
||||
"eigenbroetlerisch": {"name": "eigenbrötlerisch", "gruppe": "menschen",
|
||||
"probleme": {"einsamkeit": 1}, "verhalten": {"sozial": -1}},
|
||||
"redselig": {"name": "redselig", "gruppe": "menschen",
|
||||
"blocker": ["klagen"], "verhalten": {"sichtbar": 1, "sozial": 1}},
|
||||
"verschlossen": {"name": "verschlossen", "gruppe": "menschen",
|
||||
"probleme": {"einsamkeit": 1}, "verhalten": {"sichtbar": -2}},
|
||||
# --- Gefühl
|
||||
"aengstlich": {"name": "ängstlich", "gruppe": "gefuehl",
|
||||
"blocker": ["nachrichten"], "probleme": {"angst": 2}, "verhalten": {"momente": 1}},
|
||||
"gelassen": {"name": "gelassen", "gruppe": "gefuehl",
|
||||
"verhalten": {"momente": -1, "dauer": -1}},
|
||||
"gruebelnd": {"name": "grüblerisch", "gruppe": "gefuehl",
|
||||
"ursachen": {"grund": 1}, "blocker": ["waelzen"], "probleme": {"selbstzweifel": 1}},
|
||||
"reizbar": {"name": "reizbar", "gruppe": "gefuehl",
|
||||
"probleme": {"stress": 1}, "verhalten": {"momente": 1, "abwehr": 1}},
|
||||
"optimistisch": {"name": "optimistisch", "gruppe": "gefuehl",
|
||||
"verhalten": {"tempo": 1, "dauer": -1}},
|
||||
"pessimistisch": {"name": "pessimistisch", "gruppe": "gefuehl",
|
||||
"ursachen": {"grund": 2}, "blocker": ["klagen"], "verhalten": {"tempo": -1}},
|
||||
"duennhaeutig": {"name": "dünnhäutig", "gruppe": "gefuehl",
|
||||
"probleme": {"angst": 1, "selbstzweifel": 1}, "verhalten": {"dauer": 1}},
|
||||
"nachtragend": {"name": "nachtragend", "gruppe": "gefuehl",
|
||||
"verhalten": {"abwehr": 1}},
|
||||
"heiter": {"name": "heiter", "gruppe": "gefuehl",
|
||||
"verhalten": {"momente": -1}},
|
||||
"schwermuetig": {"name": "schwermütig", "gruppe": "gefuehl",
|
||||
"ursachen": {"grund": 1, "kraft": 1}, "probleme": {"erschoepfung": 1}, "verhalten": {"tempo": -1}},
|
||||
# --- Energie
|
||||
"nachtaktiv": {"name": "nachtaktiv", "gruppe": "energie",
|
||||
"ursachen": {"kraft": 1}, "blocker": ["wach"], "probleme": {"erschoepfung": 1}},
|
||||
"fruehaufsteher": {"name": "Frühaufsteher", "gruppe": "energie",
|
||||
"verhalten": {"einrichten": 1}},
|
||||
"erschoepft": {"name": "erschöpft", "gruppe": "energie",
|
||||
"ursachen": {"kraft": 2}, "blocker": ["serie", "doesen"], "probleme": {"erschoepfung": 2}},
|
||||
"rastlos": {"name": "rastlos", "gruppe": "energie",
|
||||
"blocker": ["kuehlschrank"], "probleme": {"unruhe": 2}, "verhalten": {"momente": 1}},
|
||||
"genuegsam": {"name": "genügsam", "gruppe": "energie",
|
||||
"verhalten": {"dauer": -1}},
|
||||
"bewegungsfaul": {"name": "bewegungsfaul", "gruppe": "energie",
|
||||
"ursachen": {"kraft": 1}, "blocker": ["serie", "bestellen"]},
|
||||
"sportlich": {"name": "sportlich", "gruppe": "energie",
|
||||
"verhalten": {"tempo": 1, "momente": -1}},
|
||||
"schlaflos": {"name": "schlaflos", "gruppe": "energie",
|
||||
"ursachen": {"kraft": 1}, "blocker": ["wach", "snooze", "waelzen"], "probleme": {"erschoepfung": 1}},
|
||||
# --- Selbstbild
|
||||
"selbstkritisch": {"name": "selbstkritisch", "gruppe": "selbst",
|
||||
"ursachen": {"grund": 1}, "probleme": {"selbstzweifel": 2}},
|
||||
"selbstbewusst": {"name": "selbstbewusst", "gruppe": "selbst",
|
||||
"verhalten": {"einrichten": 1, "sichtbar": 1}},
|
||||
"unsicher": {"name": "unsicher", "gruppe": "selbst",
|
||||
"blocker": ["recherche"], "probleme": {"selbstzweifel": 1, "angst": 1}, "verhalten": {"einrichten": -1}},
|
||||
"bescheiden": {"name": "bescheiden", "gruppe": "selbst",
|
||||
"verhalten": {"sozial": 1}},
|
||||
"eitel": {"name": "eitel", "gruppe": "selbst",
|
||||
"blocker": ["vergleichen"], "probleme": {"selbstzweifel": 1}},
|
||||
"vergleichend": {"name": "vergleicht sich gern", "gruppe": "selbst",
|
||||
"ursachen": {"grund": 1}, "blocker": ["vergleichen"], "probleme": {"selbstzweifel": 1}},
|
||||
"hadernd": {"name": "hadert mit sich", "gruppe": "selbst",
|
||||
"ursachen": {"grund": 2}, "blocker": ["waelzen"], "probleme": {"selbstzweifel": 1}},
|
||||
}
|
||||
|
||||
const MINDESTENS := 6
|
||||
const URSACHEN_MAX := 3
|
||||
const PROBLEME_MAX := 2
|
||||
|
||||
|
||||
static func name_von(key: String) -> String:
|
||||
return str(LISTE[key]["name"]) if LISTE.has(key) else key
|
||||
|
||||
|
||||
static func ids() -> Array:
|
||||
return LISTE.keys()
|
||||
|
||||
|
||||
static func in_gruppe(gruppe: String) -> Array:
|
||||
var out: Array = []
|
||||
for key in LISTE:
|
||||
if LISTE[key]["gruppe"] == gruppe:
|
||||
out.append(key)
|
||||
return out
|
||||
|
||||
|
||||
## Aus den angekreuzten Wörtern das Bild: Ursachen, Blocker, Klemmen, Verhalten.
|
||||
static func profil(woerter: Array) -> Dictionary:
|
||||
var ursachen: Dictionary = {}
|
||||
var probleme: Dictionary = {}
|
||||
var blocker: Array = []
|
||||
var verhalten: Dictionary = {}
|
||||
for v in VERHALTEN:
|
||||
verhalten[v] = 0
|
||||
for w in woerter:
|
||||
if not LISTE.has(w):
|
||||
continue
|
||||
var e: Dictionary = LISTE[w]
|
||||
for u in e.get("ursachen", {}):
|
||||
ursachen[u] = int(ursachen.get(u, 0)) + int(e["ursachen"][u])
|
||||
for p in e.get("probleme", {}):
|
||||
probleme[p] = int(probleme.get(p, 0)) + int(e["probleme"][p])
|
||||
for b in e.get("blocker", []):
|
||||
if not blocker.has(b):
|
||||
blocker.append(b)
|
||||
for v in e.get("verhalten", {}):
|
||||
verhalten[v] = int(verhalten[v]) + int(e["verhalten"][v])
|
||||
for v in VERHALTEN:
|
||||
verhalten[v] = clampi(int(verhalten[v]), -2, 2)
|
||||
|
||||
var urs := _oben(ursachen, URSACHEN_MAX, 2, Ursachen.LISTE.keys())
|
||||
var prob := _oben(probleme, PROBLEME_MAX, 1, Probleme.LISTE.keys())
|
||||
# Blocker müssen zu einer der Ursachen gehören, sonst passt keine Technik
|
||||
var passend: Array = []
|
||||
for b in blocker:
|
||||
if urs.has(Ursachen.ursache_von(b)):
|
||||
passend.append(b)
|
||||
return {"ursachen": urs, "probleme": prob, "blocker": passend, "verhalten": verhalten}
|
||||
|
||||
|
||||
## Die stärksten Einträge, mindestens `min`, höchstens `max`. Fehlt Gewicht,
|
||||
## füllt die Reihenfolge des Katalogs auf -- niemand ist ohne Grund.
|
||||
static func _oben(gewichte: Dictionary, max: int, min: int, katalog: Array) -> Array:
|
||||
var keys: Array = gewichte.keys()
|
||||
keys.sort_custom(func(a, b) -> bool: return int(gewichte[a]) > int(gewichte[b]))
|
||||
var out: Array = []
|
||||
for k in keys:
|
||||
if int(gewichte[k]) <= 0 or out.size() >= max:
|
||||
break
|
||||
out.append(str(k))
|
||||
for k in katalog:
|
||||
if out.size() >= min:
|
||||
break
|
||||
if not out.has(str(k)):
|
||||
out.append(str(k))
|
||||
return out
|
||||
1
scripts/woerter.gd.uid
Normal file
1
scripts/woerter.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://1lj14nxeuiye
|
||||
241
tests/verify.gd
241
tests/verify.gd
@@ -41,6 +41,7 @@ func _ready() -> void:
|
||||
await test_tagesablauf_anzeige()
|
||||
await test_ablauf_im_hud()
|
||||
await test_probleme_und_momente()
|
||||
await test_eigene_menschen()
|
||||
await test_systeme()
|
||||
await test_tempo_des_traums()
|
||||
await test_cooldown()
|
||||
@@ -1040,6 +1041,242 @@ func test_probleme_und_momente() -> void:
|
||||
Game.problem_stand.clear()
|
||||
|
||||
|
||||
## Eigene Menschen: aus Wörtern wird eine Psyche, aus dem Beruf ein Alltag,
|
||||
## und beides lässt sich am Brett schreiben, speichern und wieder abnehmen.
|
||||
func test_eigene_menschen() -> void:
|
||||
abschnitt("Eigene Menschen aus Wörtern")
|
||||
Aushaenge.PFAD = "user://aushaenge_test.cfg"
|
||||
Aushaenge.alle_loeschen()
|
||||
|
||||
# --- Der Content ist gekoppelt: nichts ist unlösbar
|
||||
var ohne_technik: Array = []
|
||||
for b in Ursachen.BLOCKER:
|
||||
if TechDB.fuer_ursache(Ursachen.ursache_von(str(b))).is_empty():
|
||||
ohne_technik.append(str(b))
|
||||
p(ohne_technik.is_empty(), "Jeder der %d Blocker hat Techniken gegen seine Ursache%s" %
|
||||
[Ursachen.BLOCKER.size(), "" if ohne_technik.is_empty() else " — außer " + ", ".join(ohne_technik)])
|
||||
var ohne: Array = []
|
||||
for pr in Probleme.LISTE:
|
||||
if Probleme.techniken_gegen(str(pr)).is_empty() or Probleme.situationen_von(str(pr)).is_empty():
|
||||
ohne.append(str(pr))
|
||||
p(ohne.is_empty(), "Jede der %d Klemmen hat Techniken und Situationen%s" %
|
||||
[Probleme.LISTE.size(), "" if ohne.is_empty() else " — außer " + ", ".join(ohne)])
|
||||
var tage: Dictionary = {}
|
||||
for tid in TechDB.ids():
|
||||
var t := TechDB.by_id(tid)
|
||||
if str(t["was"]) == "" or str(t["wann"]) == "" or str(t["warum"]) == "" or str(t["woran"]) == "":
|
||||
tage[tid] = true
|
||||
p(tage.is_empty(), "Alle %d Techniken tragen Was, Wann, Warum, Woran" % TechDB.LIST.size())
|
||||
|
||||
# --- Die Wörter erreichen jeden Eintrag des Modells
|
||||
var erreicht := {"ursachen": {}, "blocker": {}, "probleme": {}, "verhalten": {}}
|
||||
var leer: Array = []
|
||||
for w in Woerter.ids():
|
||||
var e: Dictionary = Woerter.LISTE[w]
|
||||
var wirkt := false
|
||||
for u in e.get("ursachen", {}):
|
||||
erreicht["ursachen"][u] = true
|
||||
wirkt = true
|
||||
for b in e.get("blocker", []):
|
||||
erreicht["blocker"][b] = true
|
||||
wirkt = true
|
||||
for pr in e.get("probleme", {}):
|
||||
erreicht["probleme"][pr] = true
|
||||
wirkt = true
|
||||
for v in e.get("verhalten", {}):
|
||||
erreicht["verhalten"][v] = true
|
||||
wirkt = true
|
||||
if not wirkt:
|
||||
leer.append(w)
|
||||
p(Woerter.ids().size() >= 50, "%d Wörter stehen zur Wahl" % Woerter.ids().size())
|
||||
p(leer.is_empty(), "Jedes Wort wirkt irgendwo%s" %
|
||||
("" if leer.is_empty() else " — außer " + ", ".join(leer)))
|
||||
p(erreicht["ursachen"].size() == Ursachen.LISTE.size(),
|
||||
"Die Wörter erreichen alle %d Ursachen" % Ursachen.LISTE.size())
|
||||
p(erreicht["blocker"].size() == Ursachen.BLOCKER.size(),
|
||||
"Alle %d Blocker (%d)" % [Ursachen.BLOCKER.size(), erreicht["blocker"].size()])
|
||||
p(erreicht["probleme"].size() == Probleme.LISTE.size(),
|
||||
"Alle %d Klemmen" % Probleme.LISTE.size())
|
||||
p(erreicht["verhalten"].size() == Woerter.VERHALTEN.size(),
|
||||
"Und alle %d Verhaltenswerte" % Woerter.VERHALTEN.size())
|
||||
var unbekannt: Array = []
|
||||
for w in Woerter.ids():
|
||||
var e: Dictionary = Woerter.LISTE[w]
|
||||
for b in e.get("blocker", []):
|
||||
if not Ursachen.BLOCKER.has(b):
|
||||
unbekannt.append("%s->%s" % [w, b])
|
||||
for pr in e.get("probleme", {}):
|
||||
if not Probleme.LISTE.has(pr):
|
||||
unbekannt.append("%s->%s" % [w, pr])
|
||||
for u in e.get("ursachen", {}):
|
||||
if not Ursachen.LISTE.has(u):
|
||||
unbekannt.append("%s->%s" % [w, u])
|
||||
p(unbekannt.is_empty(), "Kein Wort zeigt ins Leere%s" %
|
||||
("" if unbekannt.is_empty() else ": " + ", ".join(unbekannt)))
|
||||
|
||||
# --- Aus Wörtern wird ein Bild
|
||||
var bild := Woerter.profil(["aufschiebend", "perfektionistisch", "stur", "aengstlich",
|
||||
"nachtaktiv", "zurueckgezogen"])
|
||||
p(bild["ursachen"].size() >= 2 and bild["ursachen"].size() <= 3,
|
||||
"Zwei bis drei Ursachen: %s" % str(bild["ursachen"]))
|
||||
p(bild["ursachen"].has("anfang"), "Aufschiebend und perfektionistisch ergeben »kein Anfang«")
|
||||
p(bild["probleme"].size() >= 1 and bild["probleme"].size() <= 2,
|
||||
"Ein bis zwei Klemmen: %s" % str(bild["probleme"]))
|
||||
p(bild["probleme"].has("angst") or bild["probleme"].has("perfektionismus"),
|
||||
"Ängstlich und perfektionistisch schlagen durch")
|
||||
p(bild["blocker"].size() >= 2, "Blocker zu den Ursachen: %s" % str(bild["blocker"]))
|
||||
var fremd := false
|
||||
for b in bild["blocker"]:
|
||||
if not bild["ursachen"].has(Ursachen.ursache_von(str(b))):
|
||||
fremd = true
|
||||
p(not fremd, "Kein Blocker ohne passende Ursache")
|
||||
p(int(bild["verhalten"]["abwehr"]) >= 2, "Stur und perfektionistisch: Abwehr %d" %
|
||||
int(bild["verhalten"]["abwehr"]))
|
||||
p(int(bild["verhalten"]["sichtbar"]) < 0, "Zurückgezogen: schwer zu durchschauen (%d)" %
|
||||
int(bild["verhalten"]["sichtbar"]))
|
||||
var gegen := Woerter.profil(["ordentlich", "chaotisch", "geduldig", "ungeduldig",
|
||||
"gelassen", "reizbar"])
|
||||
p(int(gegen["verhalten"]["guete"]) == 0 and int(gegen["verhalten"]["momente"]) == 0,
|
||||
"Widersprüche heben sich auf (Güte %d, Momente %d)" %
|
||||
[int(gegen["verhalten"]["guete"]), int(gegen["verhalten"]["momente"])])
|
||||
var wenig := Woerter.profil(["heiter"])
|
||||
p(wenig["ursachen"].size() >= 2 and wenig["probleme"].size() >= 1,
|
||||
"Auch ein Wort ergibt einen ganzen Menschen (%s / %s)" %
|
||||
[str(wenig["ursachen"]), str(wenig["probleme"])])
|
||||
|
||||
# --- Ein Mensch aus einem Aushang, mit eigenem Alltag
|
||||
var pr := {"name": "Mo Test", "alter": 33, "beruf": "Bäcker",
|
||||
"traum": "Wieder Gitarre spielen.", "geschichte": "Nach der Schicht ist nichts übrig.",
|
||||
"woerter": ["erschoepft", "bequem", "konfliktscheu", "gruendlich", "stur", "aengstlich"]}
|
||||
p(Aushaenge.pruefen(pr).is_empty(), "Der Aushang ist vollständig")
|
||||
p(not Aushaenge.pruefen({"name": "X", "woerter": ["stur"]}).is_empty(),
|
||||
"Ein lückenhafter wird abgewiesen: %s" %
|
||||
", ".join(Aushaenge.pruefen({"name": "X", "woerter": ["stur"]})))
|
||||
var id := Aushaenge.speichern(pr)
|
||||
p(id.begins_with("eigen_"), "Gespeichert als %s" % id)
|
||||
p(Aushaenge.laden().size() == 1 and Aushaenge.laden()[0]["name"] == "Mo Test",
|
||||
"Und aus der Datei zurückgelesen")
|
||||
Game.completed.clear()
|
||||
Game.welt_erzeugen()
|
||||
var m := HumanDB.by_id(id)
|
||||
p(not m.is_empty(), "Er lebt in der Stadt")
|
||||
p(HumanDB.LIST.size() == HumanDB.EINWOHNER, "Die Stadt bleibt bei %d Einwohnern" % HumanDB.EINWOHNER)
|
||||
p(HumanDB.PLACES.has(str(m["heim"])), "Er hat ein Zuhause: %s" % m["heim"])
|
||||
var frueh := false
|
||||
for e in m["routine"]:
|
||||
if int(e[0]) == 4 and str(e[1]) == "baeckerei":
|
||||
frueh = true
|
||||
p(frueh, "Als Bäcker steht er um vier in der Backstube")
|
||||
var luecken := 0
|
||||
for stunde in range(24):
|
||||
if Game.slot_bei_stunde(id, stunde) < 0:
|
||||
luecken += 1
|
||||
p(luecken == 0, "Sein Tag ist lückenlos")
|
||||
var blocker_im_tag: Array = []
|
||||
for e in m["routine"]:
|
||||
if Ursachen.ist_blocker(str(e[2])):
|
||||
blocker_im_tag.append(str(e[2]))
|
||||
p(blocker_im_tag.size() >= 2 and blocker_im_tag.size() <= HumanDB.BLOCKER_MAX,
|
||||
"Zwei bis %d Blocker stehen im Tag: %s" % [HumanDB.BLOCKER_MAX, ", ".join(blocker_im_tag)])
|
||||
var passt_alle := true
|
||||
for b in blocker_im_tag:
|
||||
if not (m["ursachen"] as Array).has(Ursachen.ursache_von(b)):
|
||||
passt_alle = false
|
||||
p(passt_alle, "Jeder davon gehört zu einer seiner Ursachen")
|
||||
var ohne_blocker: Array = []
|
||||
for u in m["ursachen"]:
|
||||
var da := false
|
||||
for b in blocker_im_tag:
|
||||
if Ursachen.ursache_von(b) == str(u):
|
||||
da = true
|
||||
if not da:
|
||||
ohne_blocker.append(str(u))
|
||||
p(ohne_blocker.is_empty(), "Und jede seiner Ursachen zeigt sich im Tag%s" %
|
||||
("" if ohne_blocker.is_empty() else " — nicht: " + ", ".join(ohne_blocker)))
|
||||
# Das gilt für jeden Menschen der Stadt, sonst bremst eine Ursache für immer
|
||||
var stumm: Array = []
|
||||
for hh in HumanDB.LIST:
|
||||
for u in hh["ursachen"]:
|
||||
var zeigt := false
|
||||
for e in hh["routine"]:
|
||||
if Ursachen.ursache_von(str(e[2])) == str(u):
|
||||
zeigt = true
|
||||
if not zeigt:
|
||||
stumm.append("%s/%s" % [hh["name"], u])
|
||||
p(stumm.is_empty(), "Bei allen %d Menschen zeigt sich jede Ursache im Tag%s" %
|
||||
[HumanDB.LIST.size(), "" if stumm.is_empty() else " — nicht: " + ", ".join(stumm)])
|
||||
p(Game.machbar(id) or true, "Bereit fürs Brett")
|
||||
_wege_pruefen("Stadt mit eigenem Menschen", HumanDB.PLACES, HumanDB.LIST)
|
||||
|
||||
# --- Die Wörter verändern, wie er sich verhält
|
||||
p(Game.verhalten(id, "abwehr") >= 1, "Stur: Abwehr %d" % Game.verhalten(id, "abwehr"))
|
||||
var std_id := "mensch_0"
|
||||
p(Game.verhalten(std_id, "abwehr") == 0, "Ein erzeugter Mensch steht auf null")
|
||||
Game.situation = {}
|
||||
var pause_normal := Game._pause_fuer(std_id)
|
||||
var reiz := Woerter.profil(["reizbar", "aengstlich", "rastlos", "spontan", "ehrgeizig", "stur"])
|
||||
var pr2 := {"name": "Ria Test", "alter": 28, "beruf": "Studentin", "traum": "T",
|
||||
"geschichte": "G", "woerter": ["reizbar", "aengstlich", "rastlos", "spontan", "ehrgeizig", "stur"]}
|
||||
var id2 := Aushaenge.speichern(pr2)
|
||||
Game.welt_erzeugen()
|
||||
p(int(reiz["verhalten"]["momente"]) >= 2, "Reizbar, ängstlich, rastlos: Momente %d" %
|
||||
int(reiz["verhalten"]["momente"]))
|
||||
p(Game._pause_fuer(id2) < pause_normal,
|
||||
"Bei ihr kommt der nächste Moment schneller (%.0f s statt %.0f s)" %
|
||||
[Game._pause_fuer(id2), pause_normal])
|
||||
var tempo_std := Game.traum_tempo(std_id)
|
||||
var pr3 := {"name": "Zed Test", "alter": 40, "beruf": "Lehrer", "traum": "T",
|
||||
"geschichte": "G", "woerter": ["diszipliniert", "zielstrebig", "optimistisch",
|
||||
"sportlich", "verbissen", "ehrgeizig"]}
|
||||
var id3 := Aushaenge.speichern(pr3)
|
||||
Game.welt_erzeugen()
|
||||
Game.systeme.clear()
|
||||
p(Game.traum_tempo(id3) > Game.traum_tempo(id) or Game.verhalten(id3, "tempo") > Game.verhalten(id, "tempo"),
|
||||
"Zielstrebig treibt den Traum von sich aus (Tempo %d gegen %d)" %
|
||||
[Game.verhalten(id3, "tempo"), Game.verhalten(id, "tempo")])
|
||||
p(HumanDB.LIST.size() == HumanDB.EINWOHNER, "Drei eigene, immer noch %d Einwohner" % HumanDB.LIST.size())
|
||||
|
||||
# --- Am Brett: schreiben, Zufall, speichern, abnehmen
|
||||
main._traumwelt()
|
||||
await get_tree().process_frame
|
||||
ui().brett_panel()
|
||||
p(_knopf_da("Aushang schreiben"), "Das Brett bietet an, einen Aushang zu schreiben")
|
||||
p(_knopf_texte().contains("Mo Test"), "Der eigene Mensch hängt aus")
|
||||
ui().schreiben_panel()
|
||||
p(ui()._kind == "schreiben", "Das Formular öffnet sich")
|
||||
var haken := 0
|
||||
for c in _alle_kinder(ui()._content):
|
||||
if c is CheckBox:
|
||||
haken += 1
|
||||
p(haken == Woerter.ids().size(), "Alle %d Wörter sind ankreuzbar (%d)" % [Woerter.ids().size(), haken])
|
||||
ui().schreiben_panel(HumanDB.zufallsprofil())
|
||||
p(str(ui()._entwurf["name"]) != "" and (ui()._entwurf["woerter"] as Array).size() >= Woerter.MINDESTENS,
|
||||
"Zufall füllt alles: %s mit %d Wörtern" % [ui()._entwurf["name"],
|
||||
(ui()._entwurf["woerter"] as Array).size()])
|
||||
var vorher := Aushaenge.laden().size()
|
||||
ui()._aushang_speichern()
|
||||
p(Aushaenge.laden().size() == vorher + 1, "Speichern hängt ihn ans Brett (%d)" % Aushaenge.laden().size())
|
||||
p(ui()._kind == "aushang", "Und zeigt den Aushang")
|
||||
p(_knopf_da("Aushang abnehmen"), "Ein eigener lässt sich abnehmen")
|
||||
_druecke("Aushang abnehmen")
|
||||
p(Aushaenge.laden().size() == vorher, "Abgenommen (%d)" % Aushaenge.laden().size())
|
||||
ui().schliessen()
|
||||
|
||||
Aushaenge.alle_loeschen()
|
||||
Aushaenge.PFAD = "user://aushaenge.cfg"
|
||||
Game.welt_erzeugen()
|
||||
main._erde()
|
||||
await get_tree().process_frame
|
||||
|
||||
|
||||
func _alle_kinder(n: Node) -> Array:
|
||||
var out: Array = []
|
||||
for c in n.get_children():
|
||||
out.append(c)
|
||||
out.append_array(_alle_kinder(c))
|
||||
return out
|
||||
|
||||
|
||||
## 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")
|
||||
@@ -1793,10 +2030,10 @@ func test_brett_nie_leer() -> void:
|
||||
Game.completed.append("stufe_%d" % k)
|
||||
Game.welt_erzeugen()
|
||||
Game.known = {str(TechDB.LIST[i]["id"]): 0}
|
||||
if Game.machbar("mensch_%d" % i):
|
||||
if not Game.offene_missionen().is_empty():
|
||||
passt += 1
|
||||
p(passt == TechDB.LIST.size(),
|
||||
"Zu jedem der %d Wege gibt es den passenden Menschen (%d)" %
|
||||
"Zu jedem der %d Wege gibt es einen Menschen, dem er hilft (%d)" %
|
||||
[TechDB.LIST.size(), passt])
|
||||
|
||||
Game.completed.assign(merk_c)
|
||||
|
||||
Reference in New Issue
Block a user