extends Node3D class_name Human ## Ein Mensch auf der Erde. Läuft seinen Tagesablauf ab und kann von einer ## Technik erreicht werden -- oder eben nicht. const GEHTEMPO := 6.0 var data: Dictionary var idx: int = 0 var place: String = "" var activity: String = "schlaeft" var resist_left: float = 0.0 var _visual: Node3D var _label: Label3D var _koerper: MeshInstance3D var _kopf: MeshInstance3D var _aura: MeshInstance3D var _strahl: MeshInstance3D var _path: Array = [] var _bob: float = 0.0 var _offset: Vector3 func setup(d: Dictionary, index: int) -> void: data = d idx = index name = "Human_" + str(d["id"]) var winkel := float(index) * TAU / 4.0 _offset = Vector3(cos(winkel), 0, sin(winkel)) * 2.2 _visual = Node3D.new() add_child(_visual) var c: Color = d["farbe"] var hoehe := 1.05 + float(index % 3) * 0.08 _koerper = Prims.capsule(_visual, Vector3(0, hoehe * 0.62, 0), 0.32, hoehe, c) _kopf = Prims.sphere(_visual, Vector3(0, hoehe * 1.18 + 0.1, 0), 0.24, c.lightened(0.45)) Prims.box(_visual, Vector3(0, hoehe * 0.95, 0), Vector3(0.9, 0.14, 0.3), c.darkened(0.25), false) Prims.box(_visual, Vector3(0, 0.06, 0), Vector3(0.5, 0.12, 0.7), c.darkened(0.45), false) _aura = Prims.cyl(self, Vector3(0, 0.05, 0), 0.95, 0.05, Color(1, 0.85, 0.35), false, 2.0) _aura.visible = false _strahl = Prims.cyl(self, Vector3(0, 11.0, 0), 0.14, 16.0, Color(1, 0.85, 0.35, 0.22), false, 1.2) _strahl.visible = false _label = Prims.label(self, Vector3(0, 2.9, 0), d["name"], 0.30) var start := _routine_at(Game.time_h) place = start[0] activity = start[1] global_position = HumanDB.place_center(place) + _offset func _routine_at(h: float) -> Array: var r: Array = data["routine"] var cur: Array = r[r.size() - 1] for eintrag in r: if h >= float(eintrag[0]): cur = eintrag return [cur[1], cur[2]] func _process(delta: float) -> void: resist_left = maxf(0.0, resist_left - delta) var soll := _routine_at(Game.time_h) if soll[0] != place: var war_unterwegs := not _path.is_empty() _path = HumanDB.route(place, soll[0], _offset) if war_unterwegs and _path.size() > 1: _path.remove_at(0) # steht schon draußen, alte Tür überspringen place = soll[0] activity = "unterwegs" elif _path.is_empty() and activity != soll[1]: activity = soll[1] if not _path.is_empty(): var ziel: Vector3 = _path[0] ziel.y = 0.0 var hier := global_position hier.y = 0.0 var d := ziel - hier if d.length() < 0.4: _path.remove_at(0) if _path.is_empty(): activity = soll[1] else: var schritt := d.normalized() * GEHTEMPO * delta global_position += schritt _visual.rotation.y = lerp_angle(_visual.rotation.y, atan2(-d.x, -d.z), 1.0 - pow(0.002, delta)) _bob += delta * 9.0 _visual.position.y = absf(sin(_bob)) * 0.09 if _path.is_empty(): _visual.position.y = lerpf(_visual.position.y, 0.0, 1.0 - pow(0.01, delta)) _visual.rotation.z = lerp_angle(_visual.rotation.z, PI * 0.5 if activity == "schlaeft" else 0.0, 1.0 - pow(0.01, delta)) var erledigt: bool = Game.completed.has(data["id"]) var aktiv: bool = Game.active_mission == data["id"] _aura.visible = aktiv or erledigt _strahl.visible = aktiv if _aura.visible: _aura.material_override = Prims.mat( Color(0.4, 1.0, 0.5) if erledigt else Color(1, 0.85, 0.35), 2.0) _aura.scale.x = 1.0 + sin(Time.get_ticks_msec() * 0.003) * 0.08 _aura.scale.z = _aura.scale.x _label.text = beschriftung() _label.modulate = Color(0.55, 0.85, 0.6) if erledigt else ( Color(1, 0.9, 0.6) if aktiv else Color(1, 1, 1)) func beschriftung() -> String: var s: String = data["name"] + "\n" + HumanDB.activity_text(activity) if resist_left > 0.0: s += " (macht dicht)" if Game.completed.has(data["id"]): s += "\n★ Traum erfüllt" elif Game.active_mission == data["id"]: s += "\nTraum: %d %%" % int(Game.mission_progress(data["id"])) return s ## Sichtbare Reaktion auf eine angewandte Technik. func reagiere(success: bool, text: String) -> void: var l := Prims.label(self, Vector3(0, 3.5, 0), text, 0.34, Color(0.55, 1.0, 0.6) if success else Color(1, 0.55, 0.45)) var tw := l.create_tween() tw.set_parallel(true) tw.tween_property(l, "position:y", 5.2, 2.4) 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 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 _koerper.material_override = blitz _kopf.material_override = blitz var t2 := create_tween() t2.tween_interval(0.35) t2.tween_callback(func() -> void: if is_instance_valid(_koerper): _koerper.material_override = orig _kopf.material_override = Prims.mat((data["farbe"] as Color).lightened(0.45)))