first commit
This commit is contained in:
223
scripts/game.gd
Normal file
223
scripts/game.gd
Normal file
@@ -0,0 +1,223 @@
|
||||
extends Node
|
||||
## Globaler Spielzustand: Wissen, Fertigkeiten, Missionen, Uhrzeit.
|
||||
|
||||
signal state_changed
|
||||
signal notified(text: String, color: Color)
|
||||
signal mission_done(human_id: String)
|
||||
|
||||
const DAY_SECONDS := 360.0 # eine Erdenrunde in Echtzeit-Sekunden
|
||||
const XP_LEVELS := [0, 4, 10, 18, 28]
|
||||
const MISSION_ZIEL := 100.0
|
||||
const RESIST_SEKUNDEN := 18.0
|
||||
|
||||
var einsicht: int = 3
|
||||
var known: Dictionary = {} # tech_id -> xp
|
||||
var active_mission: String = "" # human_id oder ""
|
||||
var progress: Dictionary = {} # human_id -> 0..100
|
||||
var used: Dictionary = {} # "human:tech" -> Anzahl
|
||||
var completed: Array = []
|
||||
var time_h: float = 7.0
|
||||
var day: int = 1
|
||||
var teleport_lock: float = 0.0
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
_setup_input()
|
||||
|
||||
|
||||
func _setup_input() -> void:
|
||||
var binds := {
|
||||
"vor": [KEY_W, KEY_UP],
|
||||
"zurueck": [KEY_S, KEY_DOWN],
|
||||
"links": [KEY_A, KEY_LEFT],
|
||||
"rechts": [KEY_D, KEY_RIGHT],
|
||||
"steigen": [KEY_SPACE],
|
||||
"sinken": [KEY_SHIFT],
|
||||
"interagieren": [KEY_E],
|
||||
"kodex": [KEY_TAB],
|
||||
}
|
||||
for action in binds:
|
||||
if not InputMap.has_action(action):
|
||||
InputMap.add_action(action)
|
||||
for code in binds[action]:
|
||||
var ev := InputEventKey.new()
|
||||
ev.physical_keycode = code
|
||||
InputMap.action_add_event(action, ev)
|
||||
|
||||
|
||||
func advance_time(delta: float) -> void:
|
||||
time_h += delta * 24.0 / DAY_SECONDS
|
||||
while time_h >= 24.0:
|
||||
time_h -= 24.0
|
||||
day += 1
|
||||
|
||||
|
||||
func time_string() -> String:
|
||||
var h := int(time_h)
|
||||
var m := int((time_h - h) * 60.0)
|
||||
return "Tag %d · %02d:%02d" % [day, h, m]
|
||||
|
||||
|
||||
# ---------------------------------------------------------------- Fertigkeiten
|
||||
|
||||
func knows(tech_id: String) -> bool:
|
||||
return known.has(tech_id)
|
||||
|
||||
|
||||
func skill_of(tech_id: String) -> int:
|
||||
if not known.has(tech_id):
|
||||
return 0
|
||||
var xp: int = known[tech_id]
|
||||
var lvl := 1
|
||||
for i in range(XP_LEVELS.size()):
|
||||
if xp >= XP_LEVELS[i]:
|
||||
lvl = i + 1
|
||||
return lvl
|
||||
|
||||
|
||||
func xp_to_next(tech_id: String) -> String:
|
||||
var lvl := skill_of(tech_id)
|
||||
if lvl >= XP_LEVELS.size():
|
||||
return "Meisterschaft"
|
||||
var need: int = XP_LEVELS[lvl]
|
||||
return "%d / %d EP" % [known[tech_id], need]
|
||||
|
||||
|
||||
func learn(tech_id: String) -> bool:
|
||||
if known.has(tech_id):
|
||||
return false
|
||||
if einsicht < 1:
|
||||
notified.emit("Dafür fehlt dir Einsicht. Hilf erst einem Menschen.", Color(1, 0.6, 0.4))
|
||||
return false
|
||||
einsicht -= 1
|
||||
known[tech_id] = 0
|
||||
var t := TechDB.by_id(tech_id)
|
||||
notified.emit("Technik gelernt: %s" % t["name"], Color(0.6, 1, 0.7))
|
||||
state_changed.emit()
|
||||
return true
|
||||
|
||||
|
||||
func add_xp(tech_id: String, amount: int) -> void:
|
||||
if not known.has(tech_id):
|
||||
return
|
||||
var before := skill_of(tech_id)
|
||||
known[tech_id] = int(known[tech_id]) + amount
|
||||
if skill_of(tech_id) > before:
|
||||
var t := TechDB.by_id(tech_id)
|
||||
notified.emit("%s ist jetzt Stufe %d." % [t["name"], skill_of(tech_id)], Color(0.7, 0.9, 1))
|
||||
state_changed.emit()
|
||||
|
||||
|
||||
func deepen(tech_id: String) -> bool:
|
||||
if not known.has(tech_id):
|
||||
return false
|
||||
if einsicht < 1:
|
||||
notified.emit("Keine Einsicht übrig.", Color(1, 0.6, 0.4))
|
||||
return false
|
||||
einsicht -= 1
|
||||
add_xp(tech_id, 3)
|
||||
notified.emit("Vertieft: %s (+3 EP)" % TechDB.by_id(tech_id)["name"], Color(0.7, 0.9, 1))
|
||||
return true
|
||||
|
||||
|
||||
# ------------------------------------------------------------------ Missionen
|
||||
|
||||
func accept_mission(human_id: String) -> bool:
|
||||
if completed.has(human_id):
|
||||
return false
|
||||
if active_mission == human_id:
|
||||
return false
|
||||
active_mission = human_id
|
||||
if not progress.has(human_id):
|
||||
progress[human_id] = 0.0
|
||||
var h := HumanDB.by_id(human_id)
|
||||
notified.emit("Mission angenommen: %s" % h["name"], Color(1, 0.9, 0.5))
|
||||
state_changed.emit()
|
||||
return true
|
||||
|
||||
|
||||
func mission_progress(human_id: String) -> float:
|
||||
return progress.get(human_id, 0.0)
|
||||
|
||||
|
||||
# ----------------------------------------------------- Technik auf Mensch anwenden
|
||||
|
||||
## Bewertet eine Technik in genau dieser Situation, ohne sie anzuwenden.
|
||||
func evaluate(tech_id: String, human_id: String, activity: String, resisting: bool) -> Dictionary:
|
||||
var t := TechDB.by_id(tech_id)
|
||||
var h := HumanDB.by_id(human_id)
|
||||
var skill := skill_of(tech_id)
|
||||
var res := {
|
||||
"chance": 0.0, "tag": false, "moment": false, "blocked": false,
|
||||
"grund": "", "skill": skill,
|
||||
}
|
||||
if activity == "schlaeft":
|
||||
res["blocked"] = true
|
||||
res["grund"] = "Sie oder er schläft. Techniken erreichen nur wache Menschen."
|
||||
return res
|
||||
if skill == 0:
|
||||
res["blocked"] = true
|
||||
res["grund"] = "Technik nicht gelernt."
|
||||
return res
|
||||
|
||||
for tag in t["tags"]:
|
||||
if h["tags"].has(tag):
|
||||
res["tag"] = true
|
||||
break
|
||||
res["moment"] = t["momente"].has(activity)
|
||||
|
||||
var c := 0.08 + 0.11 * float(skill)
|
||||
if res["tag"]:
|
||||
c += 0.25
|
||||
if res["moment"]:
|
||||
c += 0.22
|
||||
if resisting:
|
||||
c -= 0.30
|
||||
res["grund"] = "Der Mensch macht gerade dicht."
|
||||
res["chance"] = clampf(c, 0.05, 0.95)
|
||||
return res
|
||||
|
||||
|
||||
## Wendet die Technik wirklich an: würfelt, verteilt EP und Fortschritt.
|
||||
func apply_technique(tech_id: String, human_id: String, activity: String, resisting: bool) -> Dictionary:
|
||||
var ev := evaluate(tech_id, human_id, activity, resisting)
|
||||
if ev["blocked"]:
|
||||
return {"ok": false, "grund": ev["grund"]}
|
||||
|
||||
var roll := randf()
|
||||
var success: bool = roll < float(ev["chance"])
|
||||
var key := "%s:%s" % [human_id, tech_id]
|
||||
var wiederholung: int = used.get(key, 0)
|
||||
used[key] = wiederholung + 1
|
||||
|
||||
var gain := 0.0
|
||||
if success:
|
||||
var base := 8.0 + 2.0 * float(ev["skill"])
|
||||
if ev["tag"]:
|
||||
base += 5.0
|
||||
if ev["moment"]:
|
||||
base += 5.0
|
||||
gain = base / (1.0 + 0.6 * float(wiederholung))
|
||||
add_xp(tech_id, 2)
|
||||
else:
|
||||
add_xp(tech_id, 1)
|
||||
|
||||
var done := false
|
||||
if human_id == active_mission and gain > 0.0:
|
||||
var p: float = progress.get(human_id, 0.0) + gain
|
||||
progress[human_id] = minf(p, MISSION_ZIEL)
|
||||
if progress[human_id] >= MISSION_ZIEL and not completed.has(human_id):
|
||||
completed.append(human_id)
|
||||
active_mission = ""
|
||||
einsicht += 3
|
||||
done = true
|
||||
mission_done.emit(human_id)
|
||||
notified.emit("%s hat es geschafft. (+3 Einsicht)" % HumanDB.by_id(human_id)["name"],
|
||||
Color(1, 0.85, 0.4))
|
||||
state_changed.emit()
|
||||
|
||||
return {
|
||||
"ok": true, "success": success, "chance": ev["chance"], "gain": gain,
|
||||
"wiederholung": wiederholung, "mission_done": done,
|
||||
"tag": ev["tag"], "moment": ev["moment"],
|
||||
}
|
||||
Reference in New Issue
Block a user