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

290 lines
8.2 KiB
GDScript

extends Node
## Prüft die tatsächliche Eingabekette: Events -> GUI -> _unhandled_input.
var main
var step := 0
var wait := 0.0
var ok := 0
var fail := 0
var y0 := 0.0
var p0 := 0.0
var s0 := 0.0
var x0 := 0.0
var m0 := 0
var n0 := 0
func chk(name: String, cond: bool, info := "") -> void:
if cond:
ok += 1
print(" OK %s %s" % [name, info])
else:
fail += 1
print(" FAIL %s %s" % [name, info])
func _key(c: int, d: bool) -> void:
var e := InputEventKey.new()
e.physical_keycode = c
e.keycode = c
e.pressed = d
Input.parse_input_event(e)
func _mouse(dx: float, dy: float) -> void:
var e := InputEventMouseMotion.new()
e.relative = Vector2(dx, dy)
e.position = get_viewport().get_visible_rect().size * 0.5
e.global_position = e.position
Input.parse_input_event(e)
## Stellt den Spieler vor einen Hotspot und laesst ihn hinsehen.
func goto(car_index: int, kind: String) -> bool:
var car = main.train.cars[car_index]
for h in car.hotspots:
if String(h["kind"]) != kind:
continue
var pos: Vector3 = h["pos"]
var hs: float = car.center_s + pos.z
var p = main.player
for dz in [-1.0, 1.0, -1.4, 1.4, -0.7, 0.7]:
for px in [pos.x * 0.35, 0.0, pos.x * 0.6, -pos.x * 0.35]:
if p._blocked(px, hs + dz):
continue
p.x = px
p.s = hs + dz
p.yaw = atan2(pos.x - px, hs - p.s)
p.pitch = clampf(atan2(pos.y - (2.72), Vector2(pos.x - px, hs - p.s).length()), -1.2, 1.2)
return true
return false
func _process(d):
if main == null:
main = get_tree().current_scene
return
if not main.started:
main._start_solo()
return
if wait > 0.0:
wait -= d
return
var p = main.player
match step:
0:
chk("Maus gefangen", Input.mouse_mode == Input.MOUSE_MODE_CAPTURED,
"mode=%d" % Input.mouse_mode)
y0 = p.yaw
p0 = p.pitch
_mouse(120.0, 60.0)
wait = 0.3
1:
chk("Mausblick horizontal", absf(p.yaw - y0) > 0.05,
"yaw %.3f -> %.3f" % [y0, p.yaw])
chk("Mausblick vertikal", absf(p.pitch - p0) > 0.05,
"pitch %.3f -> %.3f" % [p0, p.pitch])
p.yaw = 0.0
p.pitch = 0.0
s0 = p.s
_key(KEY_W, true)
wait = 1.0
2:
_key(KEY_W, false)
chk("Vorwärts laufen", p.s - s0 > 0.5, "ds=%.2f" % (p.s - s0))
x0 = p.x
_key(KEY_D, true)
wait = 0.6
3:
_key(KEY_D, false)
chk("Seitwärts laufen", absf(p.x - x0) > 0.2, "dx=%.2f" % (p.x - x0))
# Ans Fahrpult stellen und E drücken
var loco = main.train.cars[0]
p.s = loco.center_s + loco.inner_z1 - 1.7
p.x = 0.0
p.yaw = 0.0
p.pitch = 0.0
wait = 0.3
4:
chk("Hotspot erkannt", String(p.hotspot.get("kind", "")) == "drive",
"kind=%s" % String(p.hotspot.get("kind", "-")))
_key(KEY_E, true)
wait = 0.3
5:
_key(KEY_E, false)
chk("E übernimmt Steuerung", main.driver_id == 1, "driver=%d" % main.driver_id)
chk("Spieler im Fahrmodus", p.mode == 1, "mode=%d" % p.mode)
_key(KEY_W, true)
wait = 1.5
6:
_key(KEY_W, false)
chk("W gibt Gas", main.train.speed > 1.0, "v=%.1f" % main.train.speed)
_key(KEY_S, true)
wait = 3.0
7:
_key(KEY_S, false)
chk("S bremst", main.train.speed < 0.05, "v=%.2f" % main.train.speed)
_key(KEY_E, true)
wait = 0.3
8:
_key(KEY_E, false)
chk("E gibt Steuerung frei", main.driver_id == 0)
_key(KEY_V, true)
_key(KEY_V, false)
wait = 0.3
9:
chk("V schaltet auf Außenkamera", main.cam_rig.is_active())
_key(KEY_V, true)
_key(KEY_V, false)
wait = 0.3
10:
chk("V schaltet zurück", p.camera.current)
_key(KEY_ESCAPE, true)
_key(KEY_ESCAPE, false)
wait = 0.3
11:
chk("Esc gibt Maus frei", Input.mouse_mode != Input.MOUSE_MODE_CAPTURED)
p.capture_mouse(true)
# Zweiter Spieler darf nicht dazwischenfunken
main._srv_toggle_drive(1)
main._srv_toggle_drive(2)
chk("Führerstand exklusiv", main.driver_id == 1, "driver=%d" % main.driver_id)
main._srv_toggle_drive(1)
# Zug mit Speisewagen und Gästen ausstatten
main.train.consist = ["coach", "dining", "freight"] as Array[String]
main._rebuild_train()
main._park_at(main.stations[0])
for i in 4:
main.spawn_passenger(0, 2)
wait = 7.0
12:
chk("Gäste eingestiegen", _seated() >= 4, "seated=%d" % _seated())
chk("Zum Depot-Terminal gelaufen", goto(0, "shop"))
wait = 0.3
13:
chk("Terminal im Blick", String(p.hotspot.get("kind", "")) == "shop",
"kind=%s" % String(p.hotspot.get("kind", "-")))
_key(KEY_E, true); _key(KEY_E, false)
wait = 0.4
14:
chk("Terminal offen", main.shop.is_open)
main.shop._tabs.current_tab = 1
wait = 0.3
15:
var btn := _find_button(main.shop, "Kaufen")
chk("Kaufen-Knopf sichtbar", btn != null)
m0 = main.money
n0 = main.train.consist.size()
if btn != null:
_click(btn.get_global_rect().get_center())
wait = 0.5
16:
chk("Klick im Laden kauft", main.train.consist.size() == n0 + 1 and main.money < m0,
"consist %d->%d, geld %d->%d" % [n0, main.train.consist.size(), m0, main.money])
_key(KEY_ESCAPE, true); _key(KEY_ESCAPE, false)
wait = 0.4
17:
chk("Terminal geschlossen", not main.shop.is_open)
chk("Gäste überleben den Umbau", _seated() >= 4, "seated=%d" % _seated())
chk("Maus wieder gefangen", Input.mouse_mode == Input.MOUSE_MODE_CAPTURED)
chk("Zur Theke gelaufen", goto(_car_of("tap"), "tap"))
wait = 0.3
18:
chk("Theke im Blick", String(p.hotspot.get("kind", "")) == "tap",
"kind=%s" % String(p.hotspot.get("kind", "-")))
_key(KEY_E, true); _key(KEY_E, false)
wait = 0.3
19:
chk("Getränk aufgenommen", p.carrying > 0, "carrying=%d" % p.carrying)
chk("Zum Gast gelaufen", _goto_occupied_seat())
wait = 0.3
20:
chk("Gast im Blick", String(p.hotspot.get("kind", "")) == "seat",
"kind=%s" % String(p.hotspot.get("kind", "-")))
m0 = main.money
_key(KEY_E, true); _key(KEY_E, false)
wait = 0.3
21:
chk("Ticket bringt Geld", main.money > m0, "+%d €" % (main.money - m0))
var occ = _seat_occupant()
chk("Gast erreichbar", occ != null)
if occ != null:
occ.wants_drink = true
occ.served = false
m0 = main.money
_key(KEY_E, true); _key(KEY_E, false)
wait = 0.3
22:
var occ2 = _seat_occupant()
chk("Serviert", occ2 != null and occ2.served)
chk("Trinkgeld", main.money > m0, "+%d €" % (main.money - m0))
chk("Getränk verbraucht", p.carrying == 0, "carrying=%d" % p.carrying)
chk("Zur Ladekonsole gelaufen", goto(_car_of("load"), "load"))
wait = 0.3
23:
chk("Konsole im Blick", String(p.hotspot.get("kind", "")) == "load",
"kind=%s" % String(p.hotspot.get("kind", "-")))
main.stations[0].stock = 10.0
_key(KEY_E, true)
wait = 2.5
24:
_key(KEY_E, false)
chk("E halten lädt Ware", main.train.total_cargo() > 0,
"cargo=%d" % main.train.total_cargo())
print("== %d ok, %d fail ==" % [ok, fail])
get_tree().quit(1 if fail > 0 else 0)
step += 1
func _seated() -> int:
var n := 0
for pa in main.passengers:
if pa.state == 2:
n += 1
return n
func _seat_occupant():
var h = main.player.hotspot
if String(h.get("kind", "")) != "seat":
return null
return main.train.cars[int(h["car"])].seats[int(h["seat"])]["occupant"]
func _click(pos: Vector2) -> void:
for pressed in [true, false]:
var e := InputEventMouseButton.new()
e.button_index = MOUSE_BUTTON_LEFT
e.pressed = pressed
e.position = pos
e.global_position = pos
Input.parse_input_event(e)
func _find_button(n: Node, text: String) -> Button:
if n is Button and (n as Button).text == text and not (n as Button).disabled:
return n
for c in n.get_children():
var r := _find_button(c, text)
if r != null:
return r
return null
func _car_of(kind: String) -> int:
for ci in main.train.cars.size():
for h in main.train.cars[ci].hotspots:
if String(h["kind"]) == kind:
return ci
return -1
func _goto_occupied_seat() -> bool:
var pl = main.player
for ci in main.train.cars.size():
var car = main.train.cars[ci]
for h in car.hotspots:
if String(h["kind"]) != "seat":
continue
if car.seats[int(h["seat"])]["occupant"] == null:
continue
var pos: Vector3 = h["pos"]
var hs: float = car.center_s + pos.z
for dz in [0.0, -0.8, 0.8, -1.2, 1.2]:
if pl._blocked(0.0, hs + dz):
continue
pl.x = 0.0
pl.s = hs + dz
pl.yaw = atan2(pos.x, hs - pl.s)
pl.pitch = 0.0
return true
return false