- Refactored VibrationComponent (RumbleComponent) -- Now supports multiple vibrations and adjustable curves. -- Inspired by the RumblePak addon. - Added a new startup scene.
193 lines
5.5 KiB
GDScript
193 lines
5.5 KiB
GDScript
@tool
|
|
class_name Game
|
|
extends Node
|
|
|
|
## TODO: sicherungskasten minigames (Kabel verbinden, oder draufhauen und geht wieder)
|
|
|
|
const USER_SETTINGS_PATH: String = "user://settings.ini"
|
|
const SAVE_DIR: String = "user://saves/%d/" # TODO "user://ch1/saves/%d/ # Chapter 1
|
|
const SAVE_PATH: String = SAVE_DIR + "%s"
|
|
const INITIAL_SAVE_DATA: SaveData = preload("uid://b8ojagpq5pxr2")
|
|
|
|
static var is_debug: bool = true
|
|
|
|
@export_file("*.tscn", "*.scn") var initial_setup_path: String = "uid://8bxv3c5f8d2j"
|
|
@export_file("*.tscn", "*.scn") var main_menu_path: String = "uid://7v62dybcabgw"
|
|
|
|
var save_slot: int = 0
|
|
var save_data: SaveData = INITIAL_SAVE_DATA.duplicate()
|
|
var world: World
|
|
var main_menu: MainMenu
|
|
|
|
var _os_dialog_window_result: int = -1
|
|
|
|
@onready var world_holder: Node = %WorldHolder
|
|
@onready var loading_screen: LoadingScreen = %LoadingScreen
|
|
|
|
|
|
static func _static_init() -> void:
|
|
is_debug = OS.is_debug_build() or Engine.is_editor_hint()
|
|
|
|
|
|
static func debug_draw(draw_shape: String, args: Array) -> void:
|
|
const DD3D: StringName = &"DebugDraw3D"
|
|
if is_debug and Engine.has_singleton(DD3D):
|
|
Engine.get_singleton(DD3D).callv("draw_" + draw_shape, args)
|
|
## Turns res://example.tscn into example.tres (and .scn -> .res) and uid://1234567 into 1234567.tres.
|
|
static func convert_path_to_resource_filename(path: String) -> String:
|
|
path = ResourceUID.path_to_uid(path)
|
|
|
|
if path.begins_with("res://"):
|
|
return path.get_file().replace(".tscn", ".tres").replace(".scn", ".res")
|
|
|
|
return path.replace("uid://", "") + ".tres"
|
|
|
|
|
|
func _ready() -> void:
|
|
if not Engine.is_editor_hint():
|
|
load_startup()
|
|
register_commands()
|
|
|
|
|
|
func load_game(_save_data: SaveData, _save_slot: int) -> void:
|
|
if not await check_computer_hash(save_data.com_hash):
|
|
return
|
|
|
|
save_data = _save_data.duplicate()
|
|
save_slot = _save_slot
|
|
InputManager.capture_mouse()
|
|
load_world(save_data.current_world, false)
|
|
|
|
|
|
func save_game() -> Error:
|
|
if not is_instance_valid(world):
|
|
return ERR_DOES_NOT_EXIST
|
|
|
|
var file_name: String = "save_data.tres"
|
|
|
|
if is_instance_valid(world):
|
|
save_data.current_world = ResourceUID.path_to_uid(world.scene_file_path)
|
|
|
|
DirAccess.make_dir_recursive_absolute(SAVE_DIR % save_slot)
|
|
return ResourceSaver.save(save_data, SAVE_PATH % [save_slot, file_name])
|
|
|
|
|
|
func load_world(world_path: String, save_previous: bool = true, load_from_save: bool = true) -> Error:
|
|
if not ResourceLoader.exists(world_path, "PackedScene"):
|
|
return ERR_FILE_NOT_FOUND
|
|
|
|
await loading_screen.fade_in()
|
|
|
|
unload_main_menu()
|
|
unload_world(save_previous)
|
|
|
|
var loader := InteractiveLoader.create_oneshot_and_bind(self)
|
|
var loaded_scene: PackedScene = await loader.load_threaded(world_path)
|
|
world = loaded_scene.instantiate() as World
|
|
|
|
if not is_instance_valid(world):
|
|
loading_screen.fade_out()
|
|
push_error("Loaded world is not valid or not of type [World].")
|
|
return ERR_INVALID_DATA
|
|
|
|
if load_from_save:
|
|
world.world_state = load_world_state(world_path)
|
|
|
|
world.change_world_requested.connect(load_world)
|
|
world.world_unload_requested.connect(_on_unload_world_request)
|
|
|
|
world_holder.add_child.call_deferred(world)
|
|
await world.loaded
|
|
loading_screen.fade_out()
|
|
return OK
|
|
|
|
|
|
func unload_world(do_save: bool = true) -> void:
|
|
if not is_instance_valid(world):
|
|
return
|
|
|
|
if do_save:
|
|
save_world_state()
|
|
|
|
world.process_mode = Node.PROCESS_MODE_DISABLED
|
|
world.queue_free()
|
|
|
|
|
|
func save_world_state() -> Error:
|
|
if not is_instance_valid(world):
|
|
return ERR_DOES_NOT_EXIST
|
|
|
|
world.update_world_state()
|
|
var world_state: WorldState = world.world_state
|
|
var file_name: String = convert_path_to_resource_filename(world_state.world_path)
|
|
print("File name: ", file_name)
|
|
print(SAVE_PATH % [save_slot, file_name])
|
|
DirAccess.make_dir_recursive_absolute(SAVE_DIR % save_slot)
|
|
save_game()
|
|
return ResourceSaver.save(world_state, SAVE_PATH % [save_slot, file_name])
|
|
|
|
|
|
func load_world_state(world_path: String) -> WorldState:
|
|
var file_name: String = convert_path_to_resource_filename(world_path)
|
|
var file_path: String = SAVE_PATH % [save_slot, file_name]
|
|
if not ResourceLoader.exists(file_path):
|
|
return null
|
|
|
|
return ResourceLoader.load(file_path)
|
|
|
|
|
|
func load_main_menu() -> void:
|
|
var loader := InteractiveLoader.create_oneshot_and_bind(self)
|
|
var loaded_scene: PackedScene = await loader.load_threaded(main_menu_path)
|
|
var _main_menu: MainMenu = loaded_scene.instantiate()
|
|
_main_menu.load_game_request.connect(load_game)
|
|
_main_menu.quit_request.connect(quit_game)
|
|
main_menu = _main_menu
|
|
world_holder.add_child(main_menu)
|
|
|
|
|
|
func load_startup() -> void:
|
|
var startup: StartupScene = load(startup_scene).instantiate()
|
|
startup.startup_finished.connect(func() -> void:
|
|
startup.queue_free()
|
|
await loading_screen.fade_in(0.0)
|
|
load_main_menu()
|
|
loading_screen.fade_out()
|
|
)
|
|
add_child(startup)
|
|
|
|
|
|
func unload_main_menu() -> void:
|
|
if is_instance_valid(main_menu):
|
|
main_menu.queue_free()
|
|
|
|
|
|
func quit_game() -> void:
|
|
await loading_screen.fade_in()
|
|
get_tree().quit()
|
|
|
|
|
|
func register_commands() -> void:
|
|
var load_save_func: Callable = func(save_index: int) -> void:
|
|
var path: String = MainMenu.get_save_path(save_index)
|
|
if ResourceLoader.exists(path):
|
|
load_game(load(path), save_index)
|
|
|
|
LimboConsole.register_command(load_save_func, "load_save", "Loads the save with the given save slot index.")
|
|
LimboConsole.register_command(save_game, "save_game", "Saves the game based on the current save slot.")
|
|
|
|
|
|
func _on_unload_world_request(do_save: bool) -> void:
|
|
if do_save:
|
|
save_game()
|
|
|
|
if is_instance_valid(world):
|
|
world.process_mode = Node.PROCESS_MODE_DISABLED
|
|
|
|
await loading_screen.fade_in()
|
|
|
|
unload_world(do_save)
|
|
|
|
await load_main_menu()
|
|
loading_screen.fade_out()
|