LuneSession hält den autoritativen Matchzustand; Clients senden nur Absichten. Fremde Sitze, veraltete Befehle und Doppelkäufe sind geprüft, Disconnect führt zur Bot-Übernahme statt zum Kernverlust. Exporte und entpackbare Demos 0.16.0-m4 für Linux und Windows.
135 lines
5 KiB
GDScript
135 lines
5 KiB
GDScript
extends Node
|
|
## Entry scene of Champions of Luneraria: title menu, match, return, rematch.
|
|
## Offline is a local host with bot-filled seats. Host/Join uses LuneSession (ENet).
|
|
## Legacy QA switches open the archived Saumwacht scene unchanged.
|
|
|
|
const Game = preload("res://scripts/luneraria/lune_game.gd")
|
|
const Menu = preload("res://scripts/luneraria/ui/lune_menu.gd")
|
|
const Session = preload("res://scripts/luneraria/net/lune_session.gd")
|
|
const LEGACY_SWITCHES: Array[String] = ["--smoke-test", "--faction-test", "--expedition-test", "--ringborke", "--legacy"]
|
|
|
|
var menu: MainMenu
|
|
var game: Node3D
|
|
var settings: Control
|
|
var session: Node
|
|
var _layer: CanvasLayer
|
|
var _last_options: Dictionary = {}
|
|
|
|
func _ready() -> void:
|
|
for arg: String in OS.get_cmdline_user_args():
|
|
if arg in LEGACY_SWITCHES:
|
|
get_tree().change_scene_to_file.call_deferred("res://scenes/main.tscn")
|
|
return
|
|
DisplayServer.window_set_title("Champions of Luneraria")
|
|
get_tree().auto_accept_quit = false
|
|
get_tree().root.close_requested.connect(Soundscape.quit_game)
|
|
_layer = CanvasLayer.new()
|
|
_layer.layer = 10
|
|
add_child(_layer)
|
|
menu = Menu.new()
|
|
_layer.add_child(menu)
|
|
menu.start_requested.connect(func() -> void: start_match({"seed": int(Time.get_unix_time_from_system()) % 100000}))
|
|
menu.quit_requested.connect(func() -> void: Soundscape.quit_game())
|
|
menu.settings_requested.connect(toggle_settings)
|
|
if menu.has_signal("host_requested"):
|
|
menu.host_requested.connect(_host_match)
|
|
menu.join_requested.connect(_join_match)
|
|
settings = LuneSettings.new()
|
|
_layer.add_child(settings)
|
|
settings.visible = false
|
|
settings.closed.connect(toggle_settings)
|
|
menu.enter()
|
|
|
|
func start_match(options: Dictionary) -> void:
|
|
var own_team_slots: Array[int] = [0, 1, 2]
|
|
var human: int = own_team_slots[LuneMap.LANES.find(menu.lane)] if menu.lane in LuneMap.LANES else 1
|
|
var bunds: Array = []
|
|
var rng := RandomNumberGenerator.new()
|
|
rng.seed = int(options.get("seed", 1))
|
|
for slot: int in range(6):
|
|
bunds.append(menu.bund if slot == human else DataCatalog.FACTIONS[rng.randi() % DataCatalog.FACTIONS.size()])
|
|
_last_options = {"seed": int(options.get("seed", 1)), "human_slot": human, "bunds": bunds}
|
|
_launch(_last_options)
|
|
|
|
func _host_match(port: int, display_name: String) -> void:
|
|
_reset_session()
|
|
session = Session.new()
|
|
session.name = "LuneSession"
|
|
add_child(session)
|
|
var options := {"seed": int(Time.get_unix_time_from_system()) % 100000, "human_slot": 0, "bunds": []}
|
|
var rng := RandomNumberGenerator.new()
|
|
rng.seed = options.seed
|
|
for slot: int in range(6):
|
|
options.bunds.append(menu.bund if slot == 0 else DataCatalog.FACTIONS[rng.randi() % DataCatalog.FACTIONS.size()])
|
|
var err: int = session.host_enet(port, options, display_name)
|
|
if err == OK:
|
|
_last_options = options
|
|
_launch(_last_options)
|
|
|
|
func _join_match(address: String, port: int, display_name: String) -> void:
|
|
_reset_session()
|
|
session = Session.new()
|
|
session.name = "LuneSession"
|
|
add_child(session)
|
|
session.session_message.connect(func(text: String, is_error: bool) -> void:
|
|
print(("FEHLER: " if is_error else "") + text))
|
|
if session.join_enet(address, port, display_name) != OK:
|
|
return
|
|
session.match_resetup.connect(func() -> void:
|
|
if game == null and session != null and session.match_state != null:
|
|
_last_options = {"seed": session.match_state.seed_value, "human_slot": session.local_slot, "bunds": []}
|
|
_launch(_last_options), CONNECT_ONE_SHOT)
|
|
|
|
func _reset_session() -> void:
|
|
if session != null and is_instance_valid(session):
|
|
session.close()
|
|
session.queue_free()
|
|
session = null
|
|
|
|
func _launch(options: Dictionary) -> void:
|
|
# The rematch button lives inside the old match; detach it now, free it after the signal.
|
|
if is_instance_valid(game):
|
|
remove_child(game)
|
|
game.queue_free()
|
|
game = Game.new()
|
|
add_child(game)
|
|
game.input_blocked = func() -> bool: return menu.visible or settings.visible
|
|
if session != null and is_instance_valid(session):
|
|
game.session = session
|
|
game.start(options)
|
|
game.exit_requested.connect(return_to_menu)
|
|
game.rematch_requested.connect(func() -> void:
|
|
_last_options.seed = int(_last_options.seed) + 1
|
|
_launch(_last_options))
|
|
game.hud.settings_requested.connect(toggle_settings)
|
|
menu.leave()
|
|
|
|
func return_to_menu() -> void:
|
|
if is_instance_valid(game):
|
|
remove_child(game)
|
|
game.queue_free()
|
|
game = null
|
|
_reset_session()
|
|
menu._locked = false
|
|
menu.pending_screen = MainMenu.Screen.TITLE
|
|
menu.enter()
|
|
|
|
func toggle_settings() -> void:
|
|
settings.visible = not settings.visible
|
|
if is_instance_valid(game):
|
|
game.paused = settings.visible or game.paused
|
|
if settings.visible:
|
|
settings.sync()
|
|
|
|
func _unhandled_input(event: InputEvent) -> void:
|
|
if event is InputEventKey and event.pressed and not event.echo:
|
|
if event.keycode == KEY_F1 or (event.keycode == KEY_ESCAPE and settings.visible):
|
|
toggle_settings()
|
|
get_viewport().set_input_as_handled()
|
|
elif event.keycode in [KEY_M, KEY_F11]:
|
|
if event.keycode == KEY_M:
|
|
Preferences.muted = not Preferences.muted
|
|
else:
|
|
Preferences.fullscreen = not Preferences.fullscreen
|
|
Preferences.commit()
|
|
get_viewport().set_input_as_handled()
|