This commit is contained in:
Team3
2026-09-15 23:17:07 +02:00
parent c62c6e551f
commit f1b0f15e30
16 changed files with 1116 additions and 44 deletions

65
scripts/aushaenge.gd Normal file
View 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
View File

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

View File

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

View File

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

View File

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

View File

@@ -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",
},
}

View File

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

View File

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

View File

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

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