Files
dreamer-game/scripts/dream_db.gd
2026-08-30 19:56:47 +02:00

171 lines
5.6 KiB
GDScript

class_name DreamDB
## Die Traumwelt: ein Dorf, das mit jedem erfüllten Traum wächst.
## Fest sind nur Hörsaal, Dorfplatz und Tor zur Erde. Jedes Haus und sein
## Bewohner werden erzeugt — der Reihe nach, immer weiter nach außen.
const HAEUSER_JE_RING := 6
const RING_ERSTER := 30.0
const RING_ABSTAND := 24.0
## Häuser sitzen auf Achtelrichtungen. Die Achsen 0 (Hörsaal) und 4 (Tor)
## bleiben frei, damit der Weg vom Dorfplatz zu beiden offen bleibt.
const SLOTS := [1, 2, 3, 5, 6, 7]
static var FEST: Dictionary = {
"hoersaal": {
"name": "Hörsaal der Wege", "pos": [0.0, 34.0], "size": [16.0, 12.0],
"dir": "forward", "color": Color(0.66, 0.72, 0.94),
},
"lichtung": {
"name": "Der Dorfplatz", "pos": [0.0, 2.0], "size": [0.0, 0.0],
"dir": "none", "color": Color(0.60, 0.50, 0.85),
},
"tor": {
"name": "Tor zur Erde", "pos": [0.0, -34.0], "size": [0.0, 0.0],
"dir": "none", "color": Color(0.50, 0.80, 1.0),
},
}
## Wird von erzeuge() gefüllt und wächst mit dem Dorf.
static var PLACES: Dictionary = FEST.duplicate(true)
static var LIST: Array = []
static var FESTE_NAMEN: Array = ["Ailen", "Morr", "Ivo", "Sela"]
static var FESTE_ROLLEN: Array = ["Traumweberin", "Erinnerungssammler", "Bote",
"Wächterin des Tors"]
static var SILBE_A: Array = ["Nu", "Ta", "Es", "Wre", "O", "Ma", "Si", "Te"]
static var SILBE_B: Array = ["un", "lia", "kar", "n", "vin", "lu", "rin", "nne"]
static var ROLLEN: Array = ["Lichtgießer", "Kartenzeichnerin", "Schwellenhüter",
"Fadensucherin", "Stillenzähler", "Wegbereiterin", "Klangsammler", "Nachtgärtnerin"]
## Vier Tagesabläufe, alle mit reichlich Zeit zwischen den Stationen —
## auch ein Haus am äußeren Ring ist so bequem zu erreichen.
static var ABLAEUFE: Array = [
[[0, "haus", "traeumt"], [6, "lichtung", "ruht"], [10, "haus", "webt"],
[14, "lichtung", "singt"], [18, "haus", "sortiert"], [21, "haus", "traeumt"]],
[[0, "haus", "traeumt"], [6, "lichtung", "sammelt"], [10, "haus", "sortiert"],
[15, "tor", "beobachtet"], [19, "haus", "webt"], [21, "haus", "traeumt"]],
[[0, "tor", "wacht"], [7, "lichtung", "ruht"], [11, "haus", "sortiert"],
[15, "tor", "wacht"], [19, "lichtung", "singt"], [21, "haus", "traeumt"]],
[[0, "haus", "traeumt"], [4, "tor", "beobachtet"], [8, "lichtung", "wandert"],
[12, "haus", "ruht"], [16, "lichtung", "singt"], [20, "haus", "traeumt"]],
]
static func haus_key(i: int) -> String:
return "haus_%d" % i
## Baut Orte und Bewohner für ein Dorf mit so vielen Häusern neu auf.
static func erzeuge(haeuser: int) -> void:
PLACES = FEST.duplicate(true)
LIST = []
for i in range(maxi(haeuser, 0)):
PLACES[haus_key(i)] = _haus(i)
LIST.append(_bewohner(i))
## Wie weit reicht das Dorf hinaus?
static func aeusserster_ring(haeuser: int) -> float:
if haeuser <= 0:
return 0.0
var ring := (haeuser - 1) / HAEUSER_JE_RING
return RING_ERSTER + float(ring) * RING_ABSTAND
static func _haus(i: int) -> Dictionary:
var ring := i / HAEUSER_JE_RING
var winkel := float(SLOTS[i % HAEUSER_JE_RING]) * TAU / 8.0
var r := RING_ERSTER + float(ring) * RING_ABSTAND
var x := sin(winkel) * r
var z := cos(winkel) * r
var breite := 12.0 + float(i % 2) * 2.0
var tiefe := 10.0 + float(i % 3)
return {
"name": "%s Haus" % _besitz(_name(i)),
"pos": [x, z],
"size": [breite, tiefe],
"dir": _tuer_zur_mitte(x, z),
"color": Color.from_hsv(fmod(0.60 + float(i) * 0.137, 1.0), 0.34, 0.86),
}
## Die Tür zeigt zur Dorfmitte — auf die Seite, die ihr am nächsten liegt.
static func _tuer_zur_mitte(x: float, z: float) -> String:
if absf(x) > absf(z):
return "left" if x > 0.0 else "right"
return "forward" if z > 0.0 else "back"
static func _bewohner(i: int) -> Dictionary:
var haus := haus_key(i)
var ablauf: Array = []
for e in ABLAEUFE[i % ABLAEUFE.size()]:
ablauf.append([e[0], haus if e[1] == "haus" else e[1], e[2]])
return {
"id": "wesen_%d" % i,
"name": _name(i),
"rolle": _rolle(i),
"haus": haus,
"leuchtet": true,
"farbe": Color.from_hsv(fmod(0.72 + float(i) * 0.161, 1.0), 0.55, 0.95),
"routine": ablauf,
}
static func _name(i: int) -> String:
if i < FESTE_NAMEN.size():
return str(FESTE_NAMEN[i])
var j := i - FESTE_NAMEN.size()
return str(SILBE_A[j % SILBE_A.size()]) + str(SILBE_B[(j / SILBE_A.size()) % SILBE_B.size()])
## Genitiv: "Ailens", aber "Morrs" und "Esas'" — Apostroph nur nach Zischlaut.
static func _besitz(n: String) -> String:
var letzter := n.substr(n.length() - 1).to_lower()
return n + "'" if ["s", "z", "x", "ß"].has(letzter) else n + "s"
static func _rolle(i: int) -> String:
if i < FESTE_ROLLEN.size():
return str(FESTE_ROLLEN[i])
return str(ROLLEN[(i - FESTE_ROLLEN.size()) % ROLLEN.size()])
static func by_id(id: String) -> Dictionary:
for w in LIST:
if w["id"] == id:
return w
return {}
# ------------------------------------------------------------------ Lehrorte
## Der Hörsaal lehrt den ersten Weg. Jedes Haus bringt einen weiteren mit.
static func techniken_von(place_key: String) -> Array:
var nr := -1
if place_key == "hoersaal":
nr = 0
elif place_key.begins_with("haus_"):
nr = int(place_key.substr(5)) + 1
if nr < 0 or nr >= TechDB.LIST.size():
return []
return [TechDB.LIST[nr]["id"]]
## An welchem Ort wird diese Technik gelehrt? "" wenn nirgends.
static func ort_von_technik(tech_id: String) -> String:
for i in range(TechDB.LIST.size()):
if TechDB.LIST[i]["id"] == tech_id:
return "hoersaal" if i == 0 else haus_key(i - 1)
return ""
## Alle Orte, an denen im aktuellen Dorf gelehrt wird.
static func lehrorte() -> Array:
var out: Array = ["hoersaal"]
for i in range(LIST.size()):
if not techniken_von(haus_key(i)).is_empty():
out.append(haus_key(i))
return out