class_name Fahrplan extends Node3D ## easy graph: : [Track1Train1 (next halt), Track1Train2], [Track2Train1(next halt), ...] ## CAVEAT: These must be direct children of the fahrplan! @onready var fahrplan : Dictionary[Station, Array] = { $hirschfeld: [["u2", $uni_mensa, "u1", $parity_square],[]], $uni_mensa : [["u2", $uni_main],[]], $uni_main: [["u2", $ministry],["u8", $rosenthal, "u2", $uni_mensa, "u1", $saint_exupery]], $parity_square : [["u4", $saint_exupery, "u1", $saint_exupery], []], $saint_exupery : [["u4", $rosenthal], ["u1", $uni_main]], $ministry : ["", null, "", null], # Endstation $rosenthal : ["", null, "", null], # Endstation } ## List of all registered station nodes, used to unparent them @onready var stations : Array[Station] = fahrplan.keys() @onready var tracks : Array[Dolly] = [%Track0Dolly, %Track1Dolly] @export var empty_train_random_delay : Vector2 = Vector2(5.0, 20.0) func _set_signage_texts(group: StringName, message: String) -> void: get_tree().call_group(group, "set_text", "") for i in range(len(message)): get_tree().call_group(group, "set_text", message.substr(0, i+1)) await get_tree().create_timer(0.05).timeout func _ready() -> void: await get_tree().process_frame tracks[0].train_left.connect(_player_train_left) tracks[1].train_left.connect(_player_train_left) _unparent_all_stations_except($hirschfeld) enter_station(current) ## The current station var current : Station var stop := false var destinations : Array[Station] = [null, null] ## Begins the scheduled traffic (looping through the list of destinations) on a given track func _begin_traffic_loop(track: Dolly, cancel: Array) -> void: if not track.player_on_board and fahrplan[current][track.index] == null: # empty trains dont arrive at endstation track.arrive(true) _set_signage_texts(track.signage_group, "Endstation") return var routes : Array = fahrplan[current][track.index] if routes.is_empty(): _set_signage_texts(track.signage_group, "Verkehr z. Zt.\nunregelmäßig") return while true: if cancel.is_empty(): return # abort the loop var line : StringName = routes.pop_front() var next : Station = routes.pop_front() routes.append(line) # It's a ring buffer routes.append(next) # It's a ring buffer destinations[track.index] = next track.set_line(line) _set_signage_texts(track.signage_group, current.get_label(line, next)) # TODO: load nice string # Vary our schedule a little by making empty trains wait a random amount of time if not track.player_on_board: await get_tree().create_timer(randf_range(empty_train_random_delay.x, empty_train_random_delay.y)).timeout if cancel.is_empty(): return # abort the loop await track.cycle() # arrive and depart var cancellation_token : Array func enter_station(station: Station): prints("------------", "ENTER STATION", station, station.name, "------------") remove_child(current) current = station add_child(station) cancellation_token = ["go"] # Allocate a new stopping token _begin_traffic_loop(tracks[0], cancellation_token) _begin_traffic_loop(tracks[1], cancellation_token) func _player_train_left(track: Dolly) -> void: cancellation_token.clear() enter_station(destinations[track.index]) func _unparent_all_stations_except(except : Node3D): for station in stations: assert(station.get_parent() == self, "A station that isn't a child of Fahrplan is in the Fahrplan: %s" % station.name) station.visible = true # Make visible by default, parenting handles visibility and collision if station == except: current = station continue remove_child(station)