Files
train-game/scripts/passenger.gd
2026-08-29 11:44:31 +02:00

131 lines
3.7 KiB
GDScript

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"