This commit is contained in:
Team3
2026-08-30 19:56:47 +02:00
parent a46eba4145
commit f936dd2b2a
13 changed files with 1681 additions and 444 deletions

View File

@@ -13,66 +13,90 @@ func _process(_d: float) -> void:
func _ready() -> void:
seed(20240)
DirAccess.make_dir_recursive_absolute(ProjectSettings.globalize_path(OUT))
main = load("res://scenes/main.tscn").instantiate()
add_child(main)
await get_tree().process_frame
await get_tree().process_frame
await knipse("01_intro")
await knipse("01_start")
main.ui.schliessen()
main.player.global_position = Vector3(0, 4.0, 34.0)
main.player.global_position = Vector3(0, 6.0, 24.0) # vor dem Hörsaal, Blick ins Dorf
main.player.yaw = 0.0
main.player.pitch = -0.14
main.player.pitch = -0.35
Game.time_h = 10.0
await warte(30)
await knipse("02_traumwelt")
main.player.global_position = Vector3(0, 12.0, 30.0)
main.player.pitch = -0.5
main.player.global_position = Vector3(0, 32.0, 14.0) # über der Lichtung
main.player.yaw = 0.0
main.player.pitch = -0.78
await warte(20)
await knipse("03_traumdorf_ueberblick")
var haus := Orte.center(DreamDB.PLACES, "haus_ailen")
main.player.global_position = haus + Vector3(0, 2.0, 12.0)
main.player.yaw = 0.0
main.player.pitch = -0.18
# Der Hörsaal ist zu Beginn das einzige Gebäude auf der Insel
var saal_aussen := Orte.center(DreamDB.PLACES, "hoersaal")
main.player.global_position = saal_aussen + Vector3(0, 2.0, -14.0)
main.player.yaw = PI
main.player.pitch = -0.12
await warte(20)
await knipse("04_haus_aussen")
await knipse("04_hoersaal_aussen")
# ein Wesen in seinem Haus
var ailen: Bewohner = null
for w in main.welt.bewohner:
if w.data["id"] == "ailen":
ailen = w
for i in range(900):
main._process(0.05)
for k in main.welt.get_children():
if k is Bewohner:
k._process(0.05)
Game.time_h = 10.0
if ailen.place == "haus_ailen" and ailen._path.is_empty():
break
main.player.global_position = ailen.global_position + Vector3(3.0, 0.6, 1.2)
main.player.yaw = -PI * 0.32
main.player.pitch = -0.06
# Wo später die Häuser stehen, ist noch nichts
main.player.global_position = Vector3(-18.0, 8.0, -6.0)
main.player.yaw = -0.9
main.player.pitch = -0.30
await warte(20)
await knipse("05_haus_innen")
await knipse("05_insel_ohne_haeuser")
# Hörsaal der Wege: hier werden die Techniken gelehrt
var saal := Orte.center(DreamDB.PLACES, "hoersaal")
main.player.global_position = saal + Vector3(0, 1.0, -1.0)
main.player.yaw = PI
main.player.pitch = -0.05
await warte(20)
await knipse("06_hoersaal")
main.ui.lehre_panel()
await warte(6)
await knipse("07_techniken_lernen")
main.ui.schliessen()
Game.learn(str(DreamDB.techniken_von("hoersaal")[0]))
main.ui.journal_panel("techniken")
await warte(6)
await knipse("06_journal_techniken")
await knipse("08_journal_techniken")
main.ui.schliessen()
Game.learn("pomodoro")
Game.learn("zerlegen")
Game.learn("box_atmung")
# Schwarzes Brett an der Lichtung
var brett := Orte.center(DreamDB.PLACES, "lichtung") + Vector3(-6.0, 0, 9.0)
main.player.global_position = brett + Vector3(0, 1.0, 4.0)
main.player.yaw = 0.0
main.player.pitch = -0.02
await warte(20)
await knipse("09_schwarzes_brett")
main.ui.brett_panel()
await warte(6)
await knipse("10_missionen")
main.ui.schliessen()
Game.accept_mission("mensch_0")
main.ui.journal_panel("missionen")
await warte(6)
await knipse("07_journal_missionen")
await knipse("11_journal_missionen")
# Regelwerk: Wenn-Dann-Ketten, die den Fortschritt automatisieren
Game.regel_setzen("mensch_0", "zoegert", str(DreamDB.techniken_von("hoersaal")[0]))
main.ui.pipeline_panel("mensch_0")
await warte(6)
await knipse("12_regelwerk")
main.ui.regel_panel("mensch_0", "arbeitet")
await warte(6)
await knipse("13_regel_waehlen")
main.ui.schliessen()
Game.accept_mission("lena")
# Lichtung, wenn sich die Wesen dort treffen
for i in range(1200):
@@ -85,14 +109,14 @@ func _ready() -> void:
main.player.yaw = 0.0
main.player.pitch = -0.20
await warte(20)
await knipse("08_lichtung")
await knipse("14_dorfplatz_leer")
var tor := Orte.center(DreamDB.PLACES, "tor")
main.player.global_position = tor + Vector3(0, 2.5, 14.0)
main.player.yaw = 0.0
main.player.pitch = -0.12
await warte(20)
await knipse("09_tor_zur_erde")
await knipse("15_tor_zur_erde")
main._erde()
Game.time_h = 10.5
@@ -101,11 +125,11 @@ func _ready() -> void:
main.player.pitch = -0.62
main.player.yaw = 0.0
await warte(20)
await knipse("10_erde_uebersicht")
await knipse("16_erde_uebersicht")
var lena: Bewohner = null
for m in main.welt.humans:
if m.data["id"] == "lena":
if m.data["id"] == "mensch_0":
lena = m
for i in range(900):
main._process(0.05)
@@ -119,14 +143,30 @@ func _ready() -> void:
main.player.yaw = PI
main.player.pitch = -0.15
await warte(20)
await knipse("11_lena_zoegert")
await knipse("17_lena_zoegert")
# Das Regelwerk greift ohne Zutun, sobald Lena die Tätigkeit wechselt
var vor := Game.mission_progress("mensch_0")
for i in range(20000):
Game.time_h += 0.004
main._process(0.02)
for k in main.welt.get_children():
if k is Bewohner:
k._process(0.05)
if Game.mission_progress("mensch_0") > vor:
break
main.player.global_position = lena.global_position + Vector3(0, 1.6, -5.5)
main.player.yaw = PI
main.player.pitch = -0.10
await warte(4)
await knipse("18_regel_greift")
main.ui.anwenden_panel(lena)
await warte(6)
await knipse("12_anwenden")
main.ui._anwenden("pomodoro")
await knipse("19_anwenden")
main.ui._anwenden(str(DreamDB.techniken_von("hoersaal")[0]))
await warte(25)
await knipse("13_reaktion")
await knipse("20_reaktion")
Game.time_h = 13.5
for i in range(1200):
@@ -139,7 +179,7 @@ func _ready() -> void:
main.player.yaw = PI
main.player.pitch = -0.5
await warte(20)
await knipse("14_cafe_mittag")
await knipse("21_cafe_mittag")
Game.time_h = 22.5
await warte(40)
@@ -147,7 +187,81 @@ func _ready() -> void:
main.player.yaw = 0.0
main.player.pitch = -0.5
await warte(20)
await knipse("15_nacht")
await knipse("22_nacht")
# Loop 2: ein erfüllter Traum lässt die Insel wachsen
if not Game.completed.has("mensch_0"):
Game.completed.append("mensch_0")
Game.active_mission = ""
Game.einsicht = 3
Game.welt_erzeugen()
main._traumwelt()
await warte(20)
main.player.global_position = Vector3(-30.0, 26.0, 30.0)
main.player.yaw = 0.7
main.player.pitch = -0.55
Game.time_h = 11.0
await warte(20)
await knipse("23_insel_gewachsen")
var erstes := Orte.center(DreamDB.PLACES, DreamDB.haus_key(0))
var tuer := Orte.door(DreamDB.PLACES, DreamDB.haus_key(0))
var hinein := (erstes - tuer).normalized()
main.player.global_position = erstes - hinein * 2.0 + Vector3(0, 1.0, 0)
main.player.yaw = atan2(-hinein.x, -hinein.z)
main.player.pitch = -0.05
await warte(20)
await knipse("24_erstes_haus")
main.ui.lehre_panel(DreamDB.haus_key(0))
await warte(6)
await knipse("25_neuer_weg")
main.ui.schliessen()
# Neun erfüllte Träume: das Dorf ist über den ersten Ring hinausgewachsen
while Game.completed.size() < 9:
Game.completed.append("traum_%d" % Game.completed.size())
Game.welt_erzeugen()
main._traumwelt()
await warte(20)
main.player.global_position = Vector3(0, 110.0, 70.0)
main.player.yaw = 0.0
main.player.pitch = -0.85
Game.time_h = 12.0
await warte(20)
await knipse("26_insel_vollstaendig")
# Jetzt wohnt jemand hier: die Wesen treffen sich auf der Lichtung
for i in range(1500):
main._process(0.05)
for k in main.welt.get_children():
if k is Bewohner:
k._process(0.05)
Game.time_h = 19.5
main.player.global_position = Vector3(0.0, 1.2, 20.0)
main.player.yaw = 0.0
main.player.pitch = -0.14
await warte(20)
await knipse("27_wesen_am_dorfplatz")
var ailen: Bewohner = null
for w in main.welt.bewohner:
if w.data["id"] == "wesen_0":
ailen = w
for i in range(1200):
main._process(0.05)
for k in main.welt.get_children():
if k is Bewohner:
k._process(0.05)
Game.time_h = 10.0
if ailen != null and ailen.place == DreamDB.haus_key(0) and ailen._path.is_empty():
break
if ailen != null:
main.player.global_position = ailen.global_position + Vector3(3.0, 0.6, 1.2)
main.player.yaw = -PI * 0.32
main.player.pitch = -0.06
await warte(20)
await knipse("28_wesen_im_haus")
print("Screenshots: %d" % n)
print("Ordner: %s" % ProjectSettings.globalize_path(OUT))

View File

@@ -26,16 +26,20 @@ func _ready() -> void:
await test_journal()
await test_traumdorf()
await test_haus_betreten()
await test_hoersaal()
await test_mission_annehmen()
await test_reise_zur_erde()
await test_tagesablauf()
await test_wege_machbar()
await test_geist()
await test_technik_anwenden()
await test_pipeline()
await test_mission_abschliessen()
await test_welt_waechst()
await test_techniken_verbessern_sich()
await test_journal_ueberall()
await test_steuerung()
await test_erster_traum_schaffbar()
print("\n=========================================")
print("Fehlende Prüfungen: %d" % fehler)
@@ -63,6 +67,77 @@ func schritte(n: int, dt: float = 0.05, zeit: float = -1.0) -> void:
kind._process(dt)
func _panel_text() -> String:
var out: Array = []
for c in ui()._content.get_children():
if c is RichTextLabel:
out.append((c as RichTextLabel).get_parsed_text())
return "\n".join(out)
func _journal_text() -> String:
return _panel_text()
## Welche Gebäude stehen wirklich in der Traumwelt? Erkennbar an ihren Schildern.
## Was der Hörsaal von Anfang an lehrt.
func _basiswege() -> Array:
return DreamDB.techniken_von("hoersaal")
func _gebaute_orte() -> Array:
var namen: Array = []
for key in DreamDB.PLACES:
if float(DreamDB.PLACES[key]["size"][0]) <= 0.0:
continue
namen.append(str(DreamDB.PLACES[key]["name"]))
var da: Array = []
for n in welt().get_children():
if n is Label3D and namen.has((n as Label3D).text):
da.append((n as Label3D).text)
return da
func _marke(kind: String) -> Node3D:
for n in get_tree().get_nodes_in_group("interactable"):
if n.get_meta("kind") == kind:
return n
return null
## Stellt den Spieler vor eine Marke und lässt den Fokus neu suchen.
func _hingehen(ziel: Node3D) -> void:
main.player.set_mode(Player.Mode.TRAUM)
main.player.global_position = ziel.global_position + Vector3(0, 0, 1.2)
main.player.velocity = Vector3.ZERO
ui().schliessen()
main._process(0.05)
## Drückt den ersten aktiven Knopf, dessen Beschriftung so beginnt.
func _knopf_texte() -> String:
var out: Array = []
for c in ui()._content.get_children():
if c is Button:
out.append((c as Button).text)
return "\n".join(out)
func _knopf_da(anfang: String) -> bool:
for c in ui()._content.get_children():
if c is Button and (c as Button).text.begins_with(anfang):
return true
return false
func _druecke(anfang: String) -> bool:
for c in ui()._content.get_children():
if c is Button and not (c as Button).disabled and (c as Button).text.begins_with(anfang):
(c as Button).pressed.emit()
return true
return false
func laufe(von: Vector3, yaw: float, frames: int) -> Vector3:
main.player.set_mode(Player.Mode.TRAUM)
main.player.look_enabled = true
@@ -80,16 +155,28 @@ func laufe(von: Vector3, yaw: float, frames: int) -> Vector3:
func test_start() -> void:
abschnitt("Start")
p(ui().offen, "Intro-Panel ist offen")
ui().schliessen()
p(not ui().offen, "Intro lässt sich schließen")
p(not ui().offen, "Kein Startbildschirm — das Spiel läuft sofort")
p(welt() is DreamWorld, "Startwelt ist die Traumwelt")
p(main.player != null and main.player.mode == Player.Mode.TRAUM, "Spieler läuft (kein Geist)")
var inter := get_tree().get_nodes_in_group("interactable")
p(inter.size() == 1 and inter[0].get_meta("kind") == "erde",
"Einzige Interaktion in der Traumwelt ist das Tor zur Erde (%d)" % inter.size())
var arten: Dictionary = {}
for n in get_tree().get_nodes_in_group("interactable"):
arten[n.get_meta("kind")] = true
p(arten.has("erde") and arten.has("lehre") and arten.has("brett"),
"Traumwelt bietet Tor, Hörsaal und Schwarzes Brett (%s)" % ", ".join(arten.keys()))
p(Game.einsicht == 3, "Startkapital 3 Einsicht")
p(Game.known.is_empty(), "Noch keine Technik gelernt")
p((welt() as DreamWorld).bewohner.is_empty(),
"Das Traumdorf steht am Anfang leer (%d Wesen)" %
(welt() as DreamWorld).bewohner.size())
var lebt := false
for n in welt().get_children():
if n is Bewohner:
lebt = true
p(not lebt, "Auch kein Wesen im Szenenbaum")
var gebaut := _gebaute_orte()
p(gebaut.size() == 1 and gebaut.has("Hörsaal der Wege"),
"Nur der Hörsaal steht als Gebäude (%s)" % ", ".join(gebaut))
func test_journal() -> void:
@@ -102,45 +189,71 @@ func test_journal() -> void:
ui().journal_panel("techniken")
p(ui().offen and ui()._kind == "journal", "Journal öffnet sich")
var knoepfe := 0
for c in ui()._content.get_children():
if c is Button:
knoepfe += 1
p(knoepfe >= TechDB.LIST.size(), "Jede der %d Techniken hat einen Knopf (%d)" %
[TechDB.LIST.size(), knoepfe])
p(_journal_text().contains("Hörsaal"),
"Ohne gelernte Technik verweist das Journal auf den Hörsaal")
p(not _knopf_da("Lernen") and not _knopf_da("Vertiefen"),
"Das Journal lehrt und vertieft nicht selbst")
ui().journal_panel("missionen")
p(ui()._journal_seite == "missionen" and ui()._content.get_child_count() > 0,
"Missionsseite baut auf")
p(_journal_text().contains("Schwarzen Brett"),
"Ohne Mission verweist das Journal auf das Schwarze Brett")
p(not _knopf_da("Mission annehmen"), "Das Journal vergibt keine Missionen")
ui().schliessen()
p(Game.learn("pomodoro"), "Pomodoro gelernt")
p(Game.learn("zerlegen"), "Aufgabe zerlegen gelernt")
p(Game.learn("umgebung"), "Umgebung gestalten gelernt")
p(Game.einsicht == 0, "Einsicht auf 0 verbraucht")
p(not Game.learn("reframing"), "Ohne Einsicht keine weitere Technik")
p(Game.skill_of("pomodoro") == 1, "Frisch gelernte Technik ist Stufe 1")
Game.add_xp("pomodoro", 4)
p(Game.skill_of("pomodoro") == 2, "4 EP heben auf Stufe 2")
Game.add_xp("pomodoro", 24)
p(Game.skill_of("pomodoro") == 5, "28 EP erreichen Stufe 5")
Game.known["pomodoro"] = 0
var erster := str(_basiswege()[0])
p(Game.offene_techniken() == 1,
"Am Anfang ist genau ein Weg entdeckt (%d)" % Game.offene_techniken())
p(Game.learn(erster), "Der erste Weg ist gelernt: %s" % TechDB.by_id(erster)["name"])
p(Game.einsicht == 2, "Das kostet 1 von 3 Einsicht (%d)" % Game.einsicht)
p(not Game.learn(str(TechDB.LIST[1]["id"])),
"Der zweite Weg ist trotz Einsicht nirgends zu lernen")
p(Game.skill_of(erster) == 1, "Frisch gelernte Technik ist Stufe 1")
Game.add_xp(erster, 4)
p(Game.skill_of(erster) == 2, "4 EP heben auf Stufe 2")
Game.add_xp(erster, 24)
p(Game.skill_of(erster) == 5, "28 EP erreichen Stufe 5")
Game.known[erster] = 0
ui().journal_panel("techniken")
var buch := _journal_text()
var alle_gelernten := true
for id in Game.known:
if not buch.contains(str(TechDB.by_id(id)["name"])):
alle_gelernten = false
p(alle_gelernten, "Das Journal führt alle %d gelernten Techniken" % Game.known.size())
var fremde := 0
for t in TechDB.LIST:
if not Game.knows(t["id"]) and buch.contains(str(t["name"])):
fremde += 1
p(fremde == 0, "Ungelernte Techniken stehen nicht im Journal (%d)" % fremde)
ui().schliessen()
func test_traumdorf() -> void:
abschnitt("Traumwesen leben ihren Tag")
abschnitt("Traumwesen ziehen ein und leben ihren Tag")
p(welt().bewohner.is_empty(), "Vorher wohnt niemand hier")
for i in range(4):
Game.completed.append("probe_%d" % i)
Game.welt_erzeugen()
main._traumwelt()
await get_tree().process_frame
if welt().bewohner.size() != i + 1:
p(false, "Nach %d Träumen wohnen %d Wesen hier" %
[i + 1, welt().bewohner.size()])
p(welt().bewohner.size() == 4,
"Je erfülltem Traum zieht eines ein, hier sind es vier (%d)" %
welt().bewohner.size())
var wesen: Array = welt().bewohner
p(wesen.size() == 4, "Vier Wesen wohnen in der Traumwelt (%d)" % wesen.size())
var haeuser := 0
for key in DreamDB.PLACES:
var s: Array = DreamDB.PLACES[key]["size"]
if s[0] > 0.0:
if key.begins_with("haus_"):
haeuser += 1
p(haeuser == 4, "Es gibt vier Häuser (%d)" % haeuser)
p(haeuser == 4, "Vier Häuser sind erzeugt (%d)" % haeuser)
p(float(DreamDB.PLACES["hoersaal"]["size"][0]) > 0.0, "Dazu steht der Hörsaal")
var eigene: Dictionary = {}
for w in wesen:
var haus := "haus_" + str(w.data["id"])
var haus: String = str(w.data["haus"])
p(DreamDB.PLACES.has(haus), "%s hat ein eigenes Haus (%s)" % [w.data["name"], haus])
eigene[haus] = true
var kommt_vor := false
@@ -190,35 +303,143 @@ func test_traumdorf() -> void:
zuhause += 1
p(zuhause == 4, "Um 01:00 sind alle vier an ihrem Nachtplatz (%d)" % zuhause)
# Ausgangslage wiederherstellen: das Dorf ist wieder leer
Game.completed.clear()
Game.welt_erzeugen()
main._traumwelt()
await get_tree().process_frame
func test_haus_betreten() -> void:
abschnitt("Orte betreten")
var haus := Orte.center(DreamDB.PLACES, "haus_ailen")
var tuer := Orte.door(DreamDB.PLACES, "haus_ailen")
p(not Game.ort_offen(DreamDB.haus_key(0)), "Ohne Bewohner steht kein Haus")
Game.completed.append("probe_haus")
Game.welt_erzeugen()
main._traumwelt()
await get_tree().process_frame
var haus_name := str(DreamDB.PLACES[DreamDB.haus_key(0)]["name"])
p(_gebaute_orte().has(haus_name), "Mit dem ersten Bewohner steht sein Haus: %s" % haus_name)
var haus := Orte.center(DreamDB.PLACES, DreamDB.haus_key(0))
var tuer := Orte.door(DreamDB.PLACES, DreamDB.haus_key(0))
var hinein: Vector3 = (haus - tuer).normalized()
var yaw_hinein := atan2(-hinein.x, -hinein.z)
var ziel: Vector3 = await laufe(tuer + Vector3(0, 1.0, 1.5), 0.0, 80)
var ziel: Vector3 = await laufe(tuer - hinein * 1.5 + Vector3(0, 1.0, 0), yaw_hinein, 80)
var drin: bool = absf(ziel.x - haus.x) < 6.0 and absf(ziel.z - haus.z) < 5.0
p(drin, "Durch die Tür läuft man ins Haus (Ziel %.1f / %.1f, Haus %.1f / %.1f)" %
[ziel.x, ziel.z, haus.x, haus.z])
# Die Wand hält
var vor_wand := haus + Vector3(-11.0, 1.0, 0)
var gestoppt: Vector3 = await laufe(vor_wand, -PI * 0.5, 80)
p(gestoppt.x < haus.x - 5.5,
"Die Seitenwand hält den Spieler auf (x = %.1f, Wand bei %.1f)" %
[gestoppt.x, haus.x - 6.0])
# Die Wand hält: von der türabgewandten Seite kommt niemand hinein
var rueck := haus + hinein * 11.0 + Vector3(0, 1.0, 0)
var gestoppt: Vector3 = await laufe(rueck, atan2(hinein.x, hinein.z), 80)
var drin2: bool = absf(gestoppt.x - haus.x) < 6.0 and absf(gestoppt.z - haus.z) < 5.0
p(not drin2, "Die Rückwand hält den Spieler auf (%.1f / %.1f)" % [gestoppt.x, gestoppt.z])
main.player.set_mode(Player.Mode.TRAUM)
main.player.global_position = (welt() as DreamWorld).spawn
Game.completed.clear()
Game.welt_erzeugen()
main._traumwelt()
await get_tree().process_frame
func test_hoersaal() -> void:
abschnitt("Techniken werden im Hörsaal gelehrt")
var pult := _marke("lehre")
p(pult != null, "Der Hörsaal hat ein Lehrpult")
var raum := Orte.center(DreamDB.PLACES, "hoersaal")
p(absf(pult.global_position.x - raum.x) < 8.0 and absf(pult.global_position.z - raum.z) < 6.0,
"Das Pult steht im Hörsaal (%.1f / %.1f)" % [pult.global_position.x, pult.global_position.z])
var im_saal: Vector3 = await laufe(Vector3(0, 1.0, 24.0), PI, 150)
p(im_saal.z > 33.0,
"Vom Eingang führt ein freier Mittelgang zum Pult (z = %.1f, Pult bei %.1f)" %
[im_saal.z, raum.z + 3.4])
p(absf(im_saal.x) < 2.0, "Der Gang hält den Spieler in der Mitte (x = %.1f)" % im_saal.x)
_hingehen(pult)
p(main._fokus == pult, "Das Pult wird als Fokus erkannt")
main._interagieren()
p(ui().offen and ui()._kind == "lehre", "Der Hörsaal öffnet sich")
var seite := _panel_text()
var basis_da := true
for id in _basiswege():
if not seite.contains(str(TechDB.by_id(id)["name"])):
basis_da = false
p(basis_da, "Die %d Basiswege werden gelehrt" % 1)
var lernbar := 0
for c in ui()._content.get_children():
if c is Button and (c as Button).text.begins_with("Lernen"):
lernbar += 1
p(lernbar <= 1, "Und höchstens einer davon ist zu lernen (%d)" % lernbar)
p(seite.contains(str(TechDB.LIST[1]["name"])),
"Der Hörsaal nennt den nächsten noch unentdeckten Weg")
p(not Game.learn("box_atmung"), "Eine unentdeckte Technik lässt sich nicht lernen")
Game.einsicht = 1
Game.known.clear()
ui().lehre_panel()
var vorher := Game.known.size()
p(_druecke("Lernen"), "Ein Lernen-Knopf steht bereit")
p(Game.known.size() == vorher + 1, "Im Hörsaal gelernt (%d -> %d)" % [vorher, Game.known.size()])
p(Game.einsicht == 0, "Lernen kostet 1 Einsicht")
Game.einsicht = 1
ui().lehre_panel()
var xp_summe := 0
for id in Game.known:
xp_summe += int(Game.known[id])
p(_druecke("Vertiefen"), "Ein Vertiefen-Knopf steht bereit")
var xp_neu := 0
for id in Game.known:
xp_neu += int(Game.known[id])
p(xp_neu == xp_summe + 3, "Vertiefen bringt 3 EP (%d -> %d)" % [xp_summe, xp_neu])
p(Game.einsicht == 0, "Vertiefen kostet 1 Einsicht")
ui().schliessen()
# Ausgangslage für die folgenden Prüfungen wiederherstellen
Game.known = {"pomodoro": 0, "zerlegen": 0, "umgebung": 0}
Game.einsicht = 0
func test_mission_annehmen() -> void:
abschnitt("Mission annehmen")
ui().journal_panel("missionen")
p(ui().offen and ui()._journal_seite == "missionen", "Missionsseite des Journals offen")
abschnitt("Mission am Schwarzen Brett annehmen")
var brett := _marke("brett")
p(brett != null, "Das Schwarze Brett steht in der Traumwelt")
var spawn: Vector3 = (welt() as DreamWorld).spawn
p(absf(brett.global_position.x) > 2.5,
"Es steht neben der Achse Start–Tor, versperrt sie also nicht (x = %.1f)" %
brett.global_position.x)
p(brett.global_position.distance_to(spawn) < 14.0,
"Vom Start aus in Sichtweite (%.1f)" % brett.global_position.distance_to(spawn))
var hin: Vector3 = await laufe(Vector3(brett.global_position.x, 1.0, spawn.z), 0.0, 150)
p(hin.z < 14.0, "Man läuft vom Start ungehindert bis davor (z = %.1f)" % hin.z)
main._process(0.05)
p(main._fokus == brett, "Davor steht man in Reichweite")
ui().schliessen()
main._interagieren()
p(ui().offen and ui()._kind == "brett", "Das Brett öffnet sich")
var alle_aus := true
for h in HumanDB.LIST:
if not _panel_text().contains(str(h["name"])):
alle_aus = false
p(alle_aus, "Alle %d Menschen hängen aus" % HumanDB.LIST.size())
p(Game.active_mission == "", "Vorher keine Mission")
var gedrueckt := _druecke("Mission annehmen")
p(gedrueckt, "Ein Aushang lässt sich annehmen")
p(Game.active_mission == "mensch_0", "Mission Lena ist aktiv (%s)" % Game.active_mission)
p(Game.angenommen("mensch_0"), "Lena steht als angenommen im Buch")
ui().schliessen()
ui().journal_panel("missionen")
var buch := _panel_text()
p(buch.contains(str(HumanDB.by_id("mensch_0")["name"])),
"Das Journal führt die angenommene Mission")
p(not buch.contains(str(HumanDB.by_id("mensch_1")["name"])),
"Nicht angenommene Menschen fehlen im Journal")
p(not _knopf_da("Mission annehmen"), "Im Journal lässt sich keine Mission annehmen")
ui().schliessen()
p(Game.accept_mission("lena"), "Mission Lena angenommen")
p(Game.active_mission == "lena", "Mission ist aktiv")
func test_reise_zur_erde() -> void:
@@ -228,6 +449,28 @@ func test_reise_zur_erde() -> void:
if n.get_meta("kind") == "erde":
tor = n
p(tor != null, "Tor zur Erde existiert")
# Zu Fuß hin: die Torplattform darf keine unüberwindliche Stufe sein
ui().schliessen()
main.player.set_mode(Player.Mode.TRAUM)
main.player.look_enabled = true
main.player.global_position = Vector3(0, 1.0, -20.0)
main.player.velocity = Vector3.ZERO
main.player.yaw = 0.0
Input.action_press("vor")
var erreicht := false
var weit: float = main.player.global_position.z
for i in range(200):
await get_tree().physics_frame
main._process(0.02)
weit = main.player.global_position.z
if main._fokus == tor:
erreicht = true
break
Input.action_release("vor")
p(erreicht, "Zu Fuß kommt man ans Tor — keine Stufe im Weg (z = %.1f, Tor bei %.1f)" %
[weit, tor.global_position.z])
Game.teleport_lock = 1.0
main.player.global_position = tor.global_position + Vector3(0, 0, 1.5)
main._process(0.05)
@@ -235,39 +478,39 @@ func test_reise_zur_erde() -> void:
main._interagieren()
await get_tree().process_frame
p(main.auf_erde and welt() is EarthWorld, "Spieler ist auf der Erde")
p(welt().humans.size() == 4, "Vier Menschen leben in der Stadt")
p(welt().humans.size() == HumanDB.LIST.size() and welt().humans.size() >= 3,
"%d Menschen leben in der Stadt" % welt().humans.size())
func test_tagesablauf() -> void:
abschnitt("Tagesablauf der Menschen")
var lena: Bewohner = null
var mensch: Bewohner = null
for m in welt().humans:
if m.data["id"] == "lena":
lena = m
p(lena != null, "Lena existiert auf der Erde")
if m.data["id"] == "mensch_0":
mensch = m
p(mensch != null, "Der erste Mensch lebt auf der Erde: %s" % mensch.data["name"])
schritte(30, 0.05, 2.0)
p(lena.activity == "schlaeft", "Um 02:00 schläft Lena (%s)" % lena.activity)
p(lena.global_position.distance_to(Orte.center(HumanDB.PLACES, "haus_lena")) < 4.0,
"Sie schläft in ihrem Atelier")
p(mensch.activity == "schlaeft", "Um 02:00 schläft er (%s)" % mensch.activity)
p(mensch.global_position.distance_to(
Orte.center(HumanDB.PLACES, str(mensch.data["heim"]))) < 5.0,
"Und zwar zu Hause")
var gewandert := false
for i in range(600):
schritte(1, 0.05, 8.1)
if lena.place == "cafe" and lena._path.is_empty():
gewandert = true
break
p(gewandert, "Um 08:00 geht Lena ins Café und kommt dort an")
p(lena.activity == "essen", "Im Café isst sie (%s)" % lena.activity)
var daheim := false
for i in range(600):
schritte(1, 0.05, 10.2)
if lena.place == "haus_lena" and lena._path.is_empty():
daheim = true
break
p(daheim, "Um 10:00 ist sie zurück im Atelier")
p(lena.activity == "zoegert", "Dort zögert sie vor der Arbeit (%s)" % lena.activity)
# Jede Station des eigenen Tagesablaufs wird pünktlich erreicht
var verfehlt: Array = []
for e in mensch.data["routine"]:
var stunde: float = float(e[0]) + 0.5
var da := false
for i in range(1200):
schritte(1, 0.05, stunde)
if mensch.place == e[1] and mensch._path.is_empty():
da = true
break
if not da or mensch.activity != e[2]:
verfehlt.append("%s um %d Uhr" % [e[1], int(e[0])])
p(verfehlt.is_empty(), "Alle %d Stationen seines Tages werden erreicht (%s)" %
[(mensch.data["routine"] as Array).size(),
"lückenlos" if verfehlt.is_empty() else ", ".join(verfehlt)])
var luecken := 0
for m in welt().humans:
@@ -275,7 +518,8 @@ func test_tagesablauf() -> void:
var r: Array = m._routine_at(float(h) + 0.5)
if not HumanDB.PLACES.has(r[0]) or not Orte.ACTIVITY_TEXT.has(r[1]):
luecken += 1
p(luecken == 0, "Alle 4 Menschen haben rund um die Uhr Ort und Tätigkeit")
p(luecken == 0, "Alle %d Menschen haben rund um die Uhr Ort und Tätigkeit" %
welt().humans.size())
Game.time_h = 0.0
Game.day = 1
@@ -294,10 +538,10 @@ func test_tagesablauf() -> void:
var soll: Dictionary = {}
for e in m.data["routine"]:
soll[e[1]] = true
var ist: int = besucht[m.data["id"]].size()
if ist < soll.size():
if besucht[m.data["id"]].size() < soll.size():
alle_ok = false
p(false, "%s erreichte nur %d von %d Stationen" % [m.data["name"], ist, soll.size()])
p(false, "%s erreichte nur %d von %d Stationen" %
[m.data["name"], besucht[m.data["id"]].size(), soll.size()])
p(alle_ok, "Über einen ganzen Tag erreicht jeder Mensch jede Station seiner Routine")
@@ -368,14 +612,20 @@ func test_technik_anwenden() -> void:
abschnitt("Techniken anwenden — Erfolgschance")
var lena: Bewohner = null
for m in welt().humans:
if m.data["id"] == "lena":
if m.data["id"] == "mensch_0":
lena = m
for i in range(900):
schritte(1, 0.05, 10.2)
if lena.place == "haus_lena" and lena._path.is_empty():
# Die Stunde suchen, in der dieser Mensch zögert — sie steht in seiner Routine
var zoegert_um := -1.0
for e in lena.data["routine"]:
if e[2] == "zoegert":
zoegert_um = float(e[0]) + 0.5
for i in range(1200):
schritte(1, 0.05, zoegert_um)
if lena.activity == "zoegert" and lena._path.is_empty():
break
p(lena.activity == "zoegert", "Lena zögert gerade")
p(lena.activity == "zoegert", "%s zögert um %.0f Uhr (%s)" %
[lena.data["name"], zoegert_um, lena.activity])
main.player.set_mode(Player.Mode.GEIST)
main.player.global_position = lena.global_position + Vector3(0, 1.0, 1.5)
@@ -386,91 +636,308 @@ func test_technik_anwenden() -> void:
ui().schliessen()
Game.known["pomodoro"] = 0
var s1: float = Game.evaluate("pomodoro", "lena", "zoegert", false)["chance"]
var s1: float = Game.evaluate("pomodoro", "mensch_0", "zoegert", false)["chance"]
Game.known["pomodoro"] = 28
var s5: float = Game.evaluate("pomodoro", "lena", "zoegert", false)["chance"]
var s5: float = Game.evaluate("pomodoro", "mensch_0", "zoegert", false)["chance"]
p(s5 > s1, "Höherer Skill = höhere Erfolgschance (%.0f%% -> %.0f%%)" % [s1 * 100, s5 * 100])
Game.known["pomodoro"] = 0
var passend: Dictionary = Game.evaluate("pomodoro", "lena", "zoegert", false)
var unpassend: Dictionary = Game.evaluate("pomodoro", "lena", "essen", false)
var passend: Dictionary = Game.evaluate("pomodoro", "mensch_0", "zoegert", false)
var unpassend: Dictionary = Game.evaluate("pomodoro", "mensch_0", "essen", false)
p(passend["moment"] and not unpassend["moment"], "Moment-Erkennung: zögert ja, isst nein")
p(passend["chance"] > unpassend["chance"], "Passender Moment erhöht die Chance")
p(passend["tag"], "Pomodoro trifft Lenas Thema Aufschieben")
var falsches_thema: Dictionary = Game.evaluate("pomodoro", "mira", "zoegert", false)
var falsches_thema: Dictionary = Game.evaluate("pomodoro", "mensch_2", "zoegert", false)
p(not falsches_thema["tag"], "Bei Mira trifft Pomodoro das Thema nicht")
p(passend["chance"] > falsches_thema["chance"], "Passendes Thema erhöht die Chance")
p(Game.evaluate("pomodoro", "lena", "schlaeft", false)["blocked"],
p(Game.evaluate("pomodoro", "mensch_0", "schlaeft", false)["blocked"],
"Schlafende Menschen sind nicht erreichbar")
p(Game.evaluate("pomodoro", "lena", "zoegert", true)["chance"] < passend["chance"],
p(Game.evaluate("pomodoro", "mensch_0", "zoegert", true)["chance"] < passend["chance"],
"Wer abblockt, ist schwerer zu erreichen")
p(Game.evaluate("nein_sagen", "lena", "zoegert", false)["blocked"],
p(Game.evaluate("nein_sagen", "mensch_0", "zoegert", false)["blocked"],
"Ungelernte Techniken lassen sich nicht anwenden")
var vorher_p: float = Game.mission_progress("lena")
var res := Game.apply_technique("pomodoro", "lena", "zoegert", false)
var vorher_p: float = Game.mission_progress("mensch_0")
var res := Game.apply_technique("pomodoro", "mensch_0", "zoegert", false)
p(res["ok"], "Anwendung wird ausgeführt")
if res["success"]:
p(Game.mission_progress("lena") > vorher_p, "Erfolg bringt Missionsfortschritt")
p(Game.mission_progress("mensch_0") > vorher_p, "Erfolg bringt Missionsfortschritt")
else:
p(Game.mission_progress("lena") == vorher_p, "Misserfolg bringt keinen Fortschritt")
p(Game.mission_progress("mensch_0") == vorher_p, "Misserfolg bringt keinen Fortschritt")
p(Game.known["pomodoro"] > 0, "Jede Anwendung bringt Erfahrung")
Game.progress["lena"] = 0.0
Game.progress["mensch_0"] = 0.0
Game.used.clear()
Game.known["pomodoro"] = 28
var ertraege: Array = []
for i in range(6):
var r := Game.apply_technique("pomodoro", "lena", "zoegert", false)
var r := Game.apply_technique("pomodoro", "mensch_0", "zoegert", false)
if r["success"]:
ertraege.append(r["gain"])
p(ertraege.size() >= 2 and ertraege[ertraege.size() - 1] < ertraege[0],
"Dieselbe Technik immer wieder wirkt schwächer")
func test_pipeline() -> void:
abschnitt("Regelwerk — Missionsfortschritt automatisieren")
Game.active_mission = "mensch_0"
Game.progress["mensch_0"] = 0.0
Game.completed.clear()
Game.used.clear()
Game.pipeline.clear()
Game.known = {"pomodoro": 28, "zerlegen": 28, "umgebung": 28}
var taten := HumanDB.aktivitaeten("mensch_0")
p(taten.size() >= 5, "Lenas Tag hat %d verschiedene Tätigkeiten" % taten.size())
p(taten.has("zoegert") and taten.has("schlaeft"),
"Darunter zögert und schläft: %s" % ", ".join(taten))
# Regelwerk über das Journal aufbauen
ui().journal_panel("missionen")
p(_knopf_da("Regelwerk"), "Die angenommene Mission trägt ein Regelwerk")
p(_druecke("Regelwerk"), "Das Regelwerk öffnet sich")
p(ui()._kind == "pipeline", "Panel »pipeline« ist offen")
var zeilen := _knopf_texte()
var fehlt: Array = []
for a in taten:
if not zeilen.contains(Orte.text(a)):
fehlt.append(a)
p(fehlt.is_empty(), "Jede der %d Tätigkeiten hat eine Zeile (fehlt: %s)" %
[taten.size(), ", ".join(fehlt)])
p(zeilen.contains("schläft → unerreichbar"),
"Schlaf ist als unerreichbar ausgewiesen, statt eine Regel anzubieten")
var schlaf_aktiv := false
for c in ui()._content.get_children():
if c is Button and (c as Button).text.begins_with("schläft") and not (c as Button).disabled:
schlaf_aktiv = true
p(not schlaf_aktiv, "Und lässt sich gar nicht erst anklicken")
ui().regel_panel("mensch_0", "zoegert")
p(ui()._kind == "regel", "Die Technikwahl für »zögert« öffnet sich")
p(_panel_text().contains("Pomodoro-Technik"), "Gelernte Techniken stehen zur Wahl")
p(_druecke("Diese Regel"), "Eine Technik lässt sich zuordnen")
p(Game.regel_fuer("mensch_0", "zoegert") != "",
"Regel steht: zögert -> %s" % Game.regel_fuer("mensch_0", "zoegert"))
p(ui()._kind == "pipeline", "Danach ist wieder das Regelwerk offen")
ui().schliessen()
Game.regel_setzen("mensch_0", "gruebelt", "zerlegen")
Game.regel_setzen("mensch_0", "aufraeumen", "umgebung")
p(Game.regel_anzahl("mensch_0") == 3, "Drei Regeln im Werk (%d)" % Game.regel_anzahl("mensch_0"))
# Eine Technik hält nur einen Posten
Game.regel_setzen("mensch_0", "arbeitet", "zerlegen")
p(Game.regel_anzahl("mensch_0") == 3,
"Dieselbe Technik anderswo einzusetzen fügt keine Regel hinzu (%d)" %
Game.regel_anzahl("mensch_0"))
p(Game.regel_fuer("mensch_0", "gruebelt") == "" and Game.regel_fuer("mensch_0", "arbeitet") == "zerlegen",
"Sie ist umgezogen statt sich zu verdoppeln")
Game.regel_setzen("mensch_0", "arbeitet", "")
Game.regel_setzen("mensch_0", "gruebelt", "zerlegen")
# Ohne Zutun einen Tag laufen lassen
var lena: Bewohner = null
for m in welt().humans:
if m.data["id"] == "mensch_0":
lena = m
p(lena != null, "Lena lebt in der Stadt")
var vorher: float = Game.mission_progress("mensch_0")
var vor_xp: int = int(Game.known["pomodoro"]) + int(Game.known["zerlegen"])
Game.time_h = 0.0
main.player.global_position = Vector3(0, 30.0, 60.0) # weit weg, kein Zutun
for i in range(9000):
schritte(1)
if Game.time_h >= 23.5:
break
var nachher: float = Game.mission_progress("mensch_0")
p(nachher > vorher, "Der Traum wächst von allein: %d %% -> %d %%" % [int(vorher), int(nachher)])
p(int(Game.known["pomodoro"]) + int(Game.known["zerlegen"]) > vor_xp,
"Die Regeln sammeln nebenbei Erfahrung")
# Ohne Regeln passiert nichts
Game.pipeline.clear()
Game.progress["mensch_0"] = 0.0
var still: float = Game.mission_progress("mensch_0")
Game.time_h = 0.0
for i in range(9000):
schritte(1)
if Game.time_h >= 23.5:
break
p(is_equal_approx(Game.mission_progress("mensch_0"), still),
"Ohne Regeln bewegt sich nichts (%d %%)" % int(Game.mission_progress("mensch_0")))
# Regeln greifen nur für die aktive Mission
Game.regel_setzen("mensch_1", "zoegert", "zerlegen")
Game.progress["mensch_1"] = 0.0
Game.time_h = 0.0
for i in range(9000):
schritte(1)
if Game.time_h >= 23.5:
break
p(is_equal_approx(Game.mission_progress("mensch_1"), 0.0),
"Regeln fremder Missionen bleiben still (%d %%)" % int(Game.mission_progress("mensch_1")))
# Ausgangslage für die folgenden Prüfungen
Game.pipeline.clear()
Game.progress["mensch_0"] = 0.0
Game.used.clear()
Game.known = {"pomodoro": 0, "zerlegen": 0, "umgebung": 0}
func test_mission_abschliessen() -> void:
abschnitt("Mission abschließen")
Game.progress["lena"] = 0.0
Game.progress["mensch_0"] = 0.0
Game.used.clear()
var einsicht_vorher := Game.einsicht
var runden := 0
while Game.mission_progress("lena") < Game.MISSION_ZIEL and runden < 400:
Game.apply_technique("pomodoro", "lena", "zoegert", false)
Game.apply_technique("zerlegen", "lena", "gruebelt", false)
Game.apply_technique("umgebung", "lena", "aufraeumen", false)
while Game.mission_progress("mensch_0") < Game.MISSION_ZIEL and runden < 400:
Game.apply_technique("pomodoro", "mensch_0", "zoegert", false)
Game.apply_technique("zerlegen", "mensch_0", "gruebelt", false)
Game.apply_technique("umgebung", "mensch_0", "aufraeumen", false)
runden += 1
p(Game.mission_progress("lena") >= Game.MISSION_ZIEL,
p(Game.mission_progress("mensch_0") >= Game.MISSION_ZIEL,
"Lenas Traum erreicht 100 %% (nach %d Runden)" % runden)
p(Game.completed.has("lena"), "Mission gilt als abgeschlossen")
p(Game.completed.has("mensch_0"), "Mission gilt als abgeschlossen")
p(Game.active_mission == "", "Aktive Mission wurde freigegeben")
p(Game.einsicht == einsicht_vorher + 3, "Abschluss bringt 3 Einsicht")
p(DreamDB.LIST.size() == Game.completed.size(),
"Der Abschluss lässt das Dorf wachsen (%d Wesen)" % DreamDB.LIST.size())
schritte(3)
var lena: Bewohner = welt().humans[0]
p(lena.beschriftung().contains("erfüllt"), "Lena zeigt sichtbar den erfüllten Traum")
func test_welt_waechst() -> void:
abschnitt("Erfüllte Träume lassen das Dorf wachsen")
var zugeordnet: Dictionary = {}
var doppelt: Array = []
for i in range(TechDB.LIST.size()):
var ort := DreamDB.ort_von_technik(str(TechDB.LIST[i]["id"]))
if zugeordnet.has(ort):
doppelt.append(ort)
zugeordnet[ort] = TechDB.LIST[i]["id"]
p(zugeordnet.size() == TechDB.LIST.size() and doppelt.is_empty(),
"Jede der %d Techniken hat einen eigenen Lehrort (%d Orte, %d doppelt)" %
[TechDB.LIST.size(), zugeordnet.size(), doppelt.size()])
p(DreamDB.ort_von_technik(str(TechDB.LIST[0]["id"])) == "hoersaal",
"Den ersten Weg lehrt der Hörsaal")
p(DreamDB.ort_von_technik(str(TechDB.LIST[1]["id"])) == DreamDB.haus_key(0),
"Den zweiten das erste Haus")
p(Game.completed.size() == 1, "Ein Traum ist erfüllt (%d)" % Game.completed.size())
main._traumwelt()
await get_tree().process_frame
var lehrorte: Dictionary = {}
for n in get_tree().get_nodes_in_group("interactable"):
if n.get_meta("kind") == "lehre":
lehrorte[n.get_meta("arg")] = n
p(lehrorte.has("hoersaal") and lehrorte.has(DreamDB.haus_key(0)),
"Hörsaal und das erste Haus lehren (%s)" % ", ".join(lehrorte.keys()))
p(not lehrorte.has(DreamDB.haus_key(1)), "Ein zweites Haus gibt es noch nicht")
p(Game.insel_radius() >= Game.INSEL_GRUND,
"Die Insel trägt das Dorf (%.0f)" % Game.insel_radius())
Game.einsicht = 3
var neu_id := str(TechDB.LIST[1]["id"])
ui().lehre_panel(DreamDB.haus_key(0))
p(ui()._kind == "lehre", "Das neue Haus lehrt")
p(_panel_text().contains(str(TechDB.by_id(neu_id)["name"])),
"Und zwar den Weg, den sein Bewohner mitbrachte")
p(_druecke("Lernen"), "Er lässt sich lernen")
p(Game.knows(neu_id), "Gelernt: %s" % TechDB.by_id(neu_id)["name"])
ui().schliessen()
p(not Game.technik_offen(str(TechDB.LIST[2]["id"])),
"%s bleibt unentdeckt" % TechDB.by_id(str(TechDB.LIST[2]["id"]))["name"])
p(Game.offene_techniken() == 2, "Entdeckt sind zwei Wege (%d)" % Game.offene_techniken())
await _dorf_platz_pruefen()
# Ausgangslage für die folgenden Prüfungen
Game.known.erase(neu_id)
Game.einsicht = 2
Game.welt_erzeugen()
main._erde()
await get_tree().process_frame
## Das Dorf wird erzeugt — also muss über viele Ausbaustufen gelten:
## nichts überlappt, nichts ragt über den Rand, jeder Weg passt ins Zeitfenster.
func _dorf_platz_pruefen() -> void:
var merker: Array = Game.completed.duplicate()
var stufen := 24
var engster := 999.0
var engster_text := ""
var ueberlappung := ""
var rand_fehler := ""
for stufe in range(stufen + 1):
Game.completed.clear()
for i in range(stufe):
Game.completed.append("stufe_%d" % i)
Game.welt_erzeugen()
var radius := Game.insel_radius()
var keys: Array = []
for key in DreamDB.PLACES:
if float(DreamDB.PLACES[key]["size"][0]) > 0.0:
keys.append(key)
for a in range(keys.size()):
var ka: String = keys[a]
var ca := Orte.center(DreamDB.PLACES, ka)
var sa: Array = DreamDB.PLACES[ka]["size"]
var ecke: float = Vector3(absf(ca.x) + float(sa[0]) * 0.5, 0,
absf(ca.z) + float(sa[1]) * 0.5).length()
if radius - ecke < engster:
engster = radius - ecke
engster_text = ("%s bei %d Häusern (%.1f von %.0f)"
% [DreamDB.PLACES[ka]["name"], stufe, ecke, radius])
if ecke >= radius and rand_fehler == "":
rand_fehler = "%s ragt bei %d Häusern über den Rand (%.1f >= %.0f)" % \
[DreamDB.PLACES[ka]["name"], stufe, ecke, radius]
for b in range(a + 1, keys.size()):
var kb: String = keys[b]
var cb := Orte.center(DreamDB.PLACES, kb)
var sb: Array = DreamDB.PLACES[kb]["size"]
var dx: float = absf(ca.x - cb.x) - (float(sa[0]) + float(sb[0])) * 0.5
var dz: float = absf(ca.z - cb.z) - (float(sa[1]) + float(sb[1])) * 0.5
if dx < 2.0 and dz < 2.0 and ueberlappung == "":
ueberlappung = "%s und %s stehen ineinander (%.1f / %.1f)" % \
[DreamDB.PLACES[ka]["name"], DreamDB.PLACES[kb]["name"], dx, dz]
p(ueberlappung == "", "Über %d Ausbaustufen berührt sich kein Gebäude (%s)" %
[stufen, "keins" if ueberlappung == "" else ueberlappung])
p(rand_fehler == "" and engster >= 4.0,
"Und keins ragt über den Rand — enger Fall: %s%s" %
[engster_text, "" if rand_fehler == "" else " — " + rand_fehler])
Game.completed.clear()
for i in range(stufen):
Game.completed.append("stufe_%d" % i)
Game.welt_erzeugen()
_wege_pruefen("Traumdorf mit %d Häusern" % stufen, DreamDB.PLACES, DreamDB.LIST)
_wege_pruefen("Stadt mit %d Menschen" % HumanDB.LIST.size(), HumanDB.PLACES, HumanDB.LIST)
Game.completed.assign(merker)
Game.welt_erzeugen()
func test_techniken_verbessern_sich() -> void:
abschnitt("Techniken verbessern sich durch Anwendung")
Game.einsicht = 2
p(Game.learn("reframing"), "Technik im Journal gelernt")
p(Game.skill_of("reframing") == 1, "Start auf Stufe 1")
p(Game.learn("zwei_minuten"), "Technik gelernt")
p(Game.skill_of("zwei_minuten") == 1, "Start auf Stufe 1")
var einsicht_vorher := Game.einsicht
var anwendungen := 0
while Game.skill_of("reframing") < 3 and anwendungen < 60:
Game.apply_technique("reframing", "mira", "gruebelt", false)
while Game.skill_of("zwei_minuten") < 3 and anwendungen < 60:
Game.apply_technique("zwei_minuten", "mensch_2", "gruebelt", false)
anwendungen += 1
p(Game.skill_of("reframing") >= 3,
"Nach %d Anwendungen von allein auf Stufe %d" % [anwendungen, Game.skill_of("reframing")])
p(Game.skill_of("zwei_minuten") >= 3,
"Nach %d Anwendungen von allein auf Stufe %d" % [anwendungen, Game.skill_of("zwei_minuten")])
p(Game.einsicht == einsicht_vorher, "Das kostet keine Einsicht")
var vor_xp: int = Game.known["reframing"]
var res := Game.apply_technique("reframing", "mira", "essen", false)
p(Game.known["reframing"] > vor_xp,
var vor_xp: int = Game.known["zwei_minuten"]
var res := Game.apply_technique("zwei_minuten", "mensch_2", "essen", false)
p(Game.known["zwei_minuten"] > vor_xp,
"Auch ein %s bringt Erfahrung" % ("Erfolg" if res["success"] else "Fehlversuch"))
var xp_vor: int = Game.known["reframing"]
p(Game.deepen("reframing"), "Vertiefen im Journal funktioniert")
p(Game.known["reframing"] == xp_vor + 3, "Vertiefen bringt 3 EP")
var xp_vor: int = Game.known["zwei_minuten"]
p(Game.deepen("zwei_minuten"), "Vertiefen funktioniert")
p(Game.known["zwei_minuten"] == xp_vor + 3, "Vertiefen bringt 3 EP")
p(Game.einsicht == einsicht_vorher - 1, "Vertiefen kostet 1 Einsicht")
@@ -556,3 +1023,71 @@ func test_steuerung() -> void:
Input.action_release("sinken")
p(main.player.global_position.y < hoch - 1.0,
"Umschalt lässt den Geist sinken (y = %.1f)" % main.player.global_position.y)
## Die Probe auf Loop 2: ohne einen erfüllten Traum gibt es keine neuen Wege.
## Also muss der erste Traum mit dem Startkapital allein zu schaffen sein —
## und zwar zuverlässig, nicht nur bei gutem Würfelglück.
func _erster_traum_tage(saat: int) -> int:
seed(saat)
Game.einsicht = 3
Game.known.clear()
Game.used.clear()
Game.pipeline.clear()
Game.progress.clear()
Game.completed.clear()
Game.active_mission = ""
Game.welt_erzeugen()
for id in _basiswege():
Game.learn(id)
Game.accept_mission("mensch_0")
# So ordnet ein Spieler zu: jede Technik an den Moment, wo sie am besten wirkt.
for id in Game.known:
var bester := ""
var beste_chance := 0.0
for activity in HumanDB.aktivitaeten("mensch_0"):
if not Game.erreichbar(activity) or Game.regel_fuer("mensch_0", activity) != "":
continue
var ev := Game.evaluate(id, "mensch_0", activity, false)
if float(ev["chance"]) > beste_chance:
beste_chance = float(ev["chance"])
bester = activity
if bester != "":
Game.regel_setzen("mensch_0", bester, id)
main._erde()
await get_tree().process_frame
main.player.global_position = Vector3(0, 30.0, 60.0) # der Spieler tut nichts
Game.time_h = 7.0
Game.day = 1
for i in range(140000):
schritte(1)
if Game.completed.has("mensch_0") or Game.day > 14:
break
return Game.day
func test_erster_traum_schaffbar() -> void:
abschnitt("Der erste Traum ist mit dem Startkapital zu schaffen")
Game.completed.clear()
Game.welt_erzeugen()
p(Game.offene_techniken() == 1,
"Am Anfang ist genau ein Weg entdeckt (%d)" % Game.offene_techniken())
var tage: Array = []
for saat in [1, 7, 555, 20240, 90210]:
tage.append(await _erster_traum_tage(saat))
p(Game.known.size() == 1, "Man startet mit einem Weg (%d)" % Game.known.size())
p(Game.regel_anzahl("mensch_0") == 1,
"Der trägt genau eine Regel (%d)" % Game.regel_anzahl("mensch_0"))
var schlimmster: int = tage.max()
var bester: int = tage.min()
p(schlimmster <= 14, "Der Traum erfüllt sich in allen %d Läufen ohne Zutun (%s)" %
[tage.size(), str(tage)])
p(bester >= 2, "Nie geschenkt — mindestens %d Tage" % bester)
p(schlimmster <= 8, "Nie zäh — höchstens %d Tage (von Hand geht es schneller)" %
schlimmster)
p(Game.einsicht >= 3, "Der erfüllte Traum bringt 3 Einsicht (%d)" % Game.einsicht)
p(Game.offene_techniken() > 1,
"Und öffnet neue Wege: %d entdeckt" % Game.offene_techniken())