extends Node3D ## Ein Fahrgast. Wartet am Bahnsteig, faehrt mit, will kontrolliert ## und bedient werden und steigt am Ziel wieder aus. const Mat = preload("res://scripts/mat.gd") const Deco = preload("res://scripts/deco.gd") const Car = preload("res://scripts/car.gd") enum State { WAITING, BOARDING, SEATED, ALIGHTING, DONE } const SHIRTS := ["c65b4a", "4a7cc6", "5fa86b", "c6a44a", "9a5fc6", "c66b9a", "4ab0a8"] const SKIN := ["e8c39e", "c99a6e", "8d5f3f", "f0d5b8"] const THIRST_AFTER := 26.0 const MOOD_DECAY := 0.055 var pid := 0 var state := State.WAITING var origin_station := 0 var dest_station := 0 var fare := 0 var ticket_checked := false var wants_drink := false var served := false var mood := 1.0 var seat_car := -1 var seat_index := -1 var _legs: Node3D var _label: Label3D var _seated_time := 0.0 var _lerp_from := Transform3D() var _lerp_to := Transform3D() var _lerp_t := 0.0 var _lerp_dur := 1.0 func build(rng: RandomNumberGenerator) -> void: var shirt := Color(SHIRTS[rng.randi() % SHIRTS.size()]) var skin := Color(SKIN[rng.randi() % SKIN.size()]) var trousers := Color("3d4450").lightened(rng.randf() * 0.25) _legs = Node3D.new() add_child(_legs) var lm := MeshInstance3D.new() lm.mesh = Deco.box(Vector3(0.42, 0.8, 0.3)) lm.material_override = Mat.flat(trousers) lm.position = Vector3(0, -0.4, 0) _legs.add_child(lm) _legs.position = Vector3(0, 0.8, 0) var torso := MeshInstance3D.new() torso.mesh = Deco.box(Vector3(0.5, 0.62, 0.32)) torso.material_override = Mat.flat(shirt) torso.position = Vector3(0, 1.12, 0) add_child(torso) for sx: float in [-1.0, 1.0]: var arm := MeshInstance3D.new() arm.mesh = Deco.box(Vector3(0.13, 0.58, 0.18)) arm.material_override = Mat.flat(shirt.darkened(0.1)) arm.position = Vector3(sx * 0.32, 1.1, 0) add_child(arm) var head := MeshInstance3D.new() head.mesh = Deco.blob(0.17) head.material_override = Mat.flat(skin) head.position = Vector3(0, 1.58, 0) add_child(head) var hair := MeshInstance3D.new() hair.mesh = Deco.box(Vector3(0.34, 0.12, 0.34)) hair.material_override = Mat.flat(Color("3a2c22").lightened(rng.randf() * 0.4)) hair.position = Vector3(0, 1.72, 0) add_child(hair) _label = Label3D.new() _label.font_size = 36 _label.pixel_size = 0.0042 _label.billboard = BaseMaterial3D.BILLBOARD_ENABLED _label.outline_size = 12 _label.outline_modulate = Color(0, 0, 0, 0.7) _label.position = Vector3(0, 2.05, 0) _label.visible = false add_child(_label) func set_seated(on: bool) -> void: _legs.rotation.x = deg_to_rad(-82.0) if on else 0.0 func start_lerp(from: Transform3D, to: Transform3D, dur: float) -> void: _lerp_from = from _lerp_to = to _lerp_t = 0.0 _lerp_dur = dur ## true, sobald die Bewegung fertig ist. func advance_lerp(delta: float) -> bool: _lerp_t = minf(_lerp_t + delta / _lerp_dur, 1.0) var t := _lerp_t * _lerp_t * (3.0 - 2.0 * _lerp_t) global_transform = _lerp_from.interpolate_with(_lerp_to, t) return _lerp_t >= 1.0 func tick(delta: float, drinks_available: bool) -> void: if state != State.SEATED: return _seated_time += delta if drinks_available and not wants_drink and not served and _seated_time > THIRST_AFTER: wants_drink = true if wants_drink and not served: mood = maxf(mood - MOOD_DECAY * delta, 0.15) _refresh_label() func _refresh_label() -> void: if not ticket_checked: _label.text = "Ticket" _label.modulate = Color("ffd978") _label.visible = true elif wants_drink and not served: _label.text = "Durst" _label.modulate = Color("8fd8ff") _label.visible = true else: _label.visible = false func mood_word() -> String: if mood > 0.85: return "bestens" if mood > 0.55: return "zufrieden" if mood > 0.3: return "genervt" return "sauer"