From 503d6134dd5ba3050287ace1e4d8469e39b5c6d5 Mon Sep 17 00:00:00 2001 From: Duncan Brown Date: Thu, 31 Mar 2022 21:49:53 -0400 Subject: [PATCH] fix: eliminates the need to run two batches of ESC commands for loading games by introducing an extra ESC command; also corrects situations where transitions that are mixed and matched don't work together; and additional cleanup --- .../esc/commands/set_active_if_exists.gd | 43 ++++ .../core-scripts/esc/commands/transition.gd | 1 + .../game/core-scripts/esc/esc_room_manager.gd | 223 ++++++++---------- .../game/core-scripts/esc_item.gd | 7 + .../save_data/esc_save_manager.gd | 21 +- addons/escoria-core/game/main.gd | 14 ++ .../transitions/esc_transition_player.gd | 8 + game/rooms/room01/room01.tscn | 1 + 8 files changed, 181 insertions(+), 137 deletions(-) create mode 100644 addons/escoria-core/game/core-scripts/esc/commands/set_active_if_exists.gd diff --git a/addons/escoria-core/game/core-scripts/esc/commands/set_active_if_exists.gd b/addons/escoria-core/game/core-scripts/esc/commands/set_active_if_exists.gd new file mode 100644 index 00000000..b7e9e3b5 --- /dev/null +++ b/addons/escoria-core/game/core-scripts/esc/commands/set_active_if_exists.gd @@ -0,0 +1,43 @@ +# `set_active_if_exists object active` +# +# Changes the "active" state of the object in the current room. +# Inactive objects are invisible in the room. +# +# **Parameters** +# +# - *object* Global ID of the object +# - *active* Whether `object` should be active. `active` can be `true` or `false`. +# +# @ESC +extends ESCBaseCommand +class_name SetActiveIfExistsCommand + + +# Return the descriptor of the arguments of this command +func configure() -> ESCCommandArgumentDescriptor: + return ESCCommandArgumentDescriptor.new( + 2, + [TYPE_STRING, TYPE_BOOL], + [null, null] + ) + + +# Validate whether the given arguments match the command descriptor +func validate(arguments: Array): + if not escoria.object_manager.has(arguments[0]): + escoria.logger.report_errors( + "set_active: invalid object", + [ + "Object with global id %s not found" % arguments[0] + ] + ) + return false + return .validate(arguments) + + +# Run the command +func run(command_params: Array) -> int: + if escoria.object_manager.has(command_params[0]): + escoria.object_manager.get_object(command_params[0]).active = \ + command_params[1] + return ESCExecution.RC_OK diff --git a/addons/escoria-core/game/core-scripts/esc/commands/transition.gd b/addons/escoria-core/game/core-scripts/esc/commands/transition.gd index 9ff75bba..9bbbbc02 100644 --- a/addons/escoria-core/game/core-scripts/esc/commands/transition.gd +++ b/addons/escoria-core/game/core-scripts/esc/commands/transition.gd @@ -56,6 +56,7 @@ func run(command_params: Array) -> int: if transition_id == ESCTransitionPlayer.TRANSITION_ID_INSTANT: escoria.logger.debug("Performing instant transition.") + escoria.main.scene_transition.reset_shader_cutoff() return ESCExecution.RC_OK escoria.logger.debug("Starting transition #%s [%s, %s]" diff --git a/addons/escoria-core/game/core-scripts/esc/esc_room_manager.gd b/addons/escoria-core/game/core-scripts/esc/esc_room_manager.gd index 486ace68..c8a7af44 100644 --- a/addons/escoria-core/game/core-scripts/esc/esc_room_manager.gd +++ b/addons/escoria-core/game/core-scripts/esc/esc_room_manager.gd @@ -268,140 +268,123 @@ func init_room(room: ESCRoom) -> void: # #### Parameters # # - room: The ESCRoom to be initialized for use. -# -# *Returns* ESCExecution.RC_OK when completed or the function's state in the -# case a coroutine is yielding. -func _perform_script_events(room: ESCRoom) -> int: - # If we're loading from a saved game, we don't want to run :setup or :ready - # as it could potentially alter the loaded save state; however, we still need - # to swap the scene in since it would ordinarily happen between :setup and - # :ready. Fun, huh? - if not escoria.event_manager.is_channel_free(escoria.event_manager.CHANNEL_FRONT) \ - and escoria.event_manager.get_running_event( - escoria.event_manager.CHANNEL_FRONT - ).name == escoria.event_manager.EVENT_LOAD: - escoria.main.set_scene_finish(room) - else: - # If the room was loaded from change_scene and automatic transitions - # are not disabled, do the transition out now - if room.enabled_automatic_transitions \ - and not room.is_run_directly \ - and not room.exited_previous_room: - var script_transition_out = escoria.esc_compiler.compile([ - "%s%s" % [ESCEvent.PREFIX, escoria.event_manager.EVENT_TRANSITION_OUT], - "%s %s out" % - [ - _transition.get_command_name(), - escoria.project_settings_manager.get_setting( - escoria.project_settings_manager.DEFAULT_TRANSITION - ) - ], - "%s 0.1" % _wait.get_command_name() - ]) - escoria.event_manager.queue_event( - script_transition_out.events[escoria.event_manager.EVENT_TRANSITION_OUT] - ) - - # Unpause the game if it was - escoria.set_game_paused(false) - - # Wait for transition_out event to be done - var rc = yield(escoria.event_manager, "event_finished") - while rc[1] != escoria.event_manager.EVENT_TRANSITION_OUT: - rc = yield(escoria.event_manager, "event_finished") - if rc[0] != ESCExecution.RC_OK: - return rc[0] - - # Hide main and pause menus - escoria.game_scene.hide_main_menu() - escoria.game_scene.unpause_game() - - var setup_event_added: bool = false - # Run the setup event, if there is one. - setup_event_added = _run_script_event(escoria.event_manager.EVENT_SETUP, room) - - if setup_event_added: - # Wait for setup event to be done - var rc = yield(escoria.event_manager, "event_finished") - while rc[1] != escoria.event_manager.EVENT_SETUP: - rc = yield(escoria.event_manager, "event_finished") - if rc[0] != ESCExecution.RC_OK: - return rc[0] - - escoria.main.set_scene_finish() - - # We know the scene has been loaded. Make its global ID available for - # use by ESC script. - escoria.globals_manager.set_global( - escoria.room_manager.GLOBAL_CURRENT_SCENE, - room.global_id, - true +func _perform_script_events(room: ESCRoom) -> void: + if room.enabled_automatic_transitions \ + and not room.is_run_directly \ + and not room.exited_previous_room: + var script_transition_out = escoria.esc_compiler.compile([ + "%s%s" % [ESCEvent.PREFIX, escoria.event_manager.EVENT_TRANSITION_OUT], + "%s %s out" % + [ + _transition.get_command_name(), + escoria.project_settings_manager.get_setting( + escoria.project_settings_manager.DEFAULT_TRANSITION + ) + ], + "%s 0.1" % _wait.get_command_name() + ]) + escoria.event_manager.queue_event( + script_transition_out.events[escoria.event_manager.EVENT_TRANSITION_OUT] ) - # Clear queued resources - escoria.resource_cache.clear() + # Unpause the game if it was + escoria.set_game_paused(false) - escoria.inputs_manager.hotspot_focused = "" + # Wait for transition_out event to be done + var rc = yield(escoria.event_manager, "event_finished") + while rc[1] != escoria.event_manager.EVENT_TRANSITION_OUT: + rc = yield(escoria.event_manager, "event_finished") + if rc[0] != ESCExecution.RC_OK: + return rc[0] - if room.enabled_automatic_transitions \ - or ( - not room.enabled_automatic_transitions \ - and escoria.globals_manager.get_global( \ - escoria.room_manager.GLOBAL_FORCE_LAST_SCENE_NULL) - ): - var script_transition_in = escoria.esc_compiler.compile([ - "%s%s" % [ESCEvent.PREFIX, escoria.event_manager.EVENT_TRANSITION_IN], - "%s %s in" % - [ - _transition.get_command_name(), - escoria.project_settings_manager.get_setting( - escoria.project_settings_manager.DEFAULT_TRANSITION - ) - ], - "%s 0.1" % _wait.get_command_name() - ]) - escoria.event_manager.queue_event( - script_transition_in.events[escoria.event_manager.EVENT_TRANSITION_IN] - ) + # Hide main and pause menus + escoria.game_scene.hide_main_menu() + escoria.game_scene.unpause_game() + + var setup_event_added: bool = false + # Run the setup event, if there is one. + setup_event_added = _run_script_event(escoria.event_manager.EVENT_SETUP, room) + + if setup_event_added: + # Wait for setup event to be done + var rc = yield(escoria.event_manager, "event_finished") + while rc[1] != escoria.event_manager.EVENT_SETUP: + rc = yield(escoria.event_manager, "event_finished") + if rc[0] != ESCExecution.RC_OK: + return rc[0] - var ready_event_added: bool = false - # Run the ready event, if there is one. - ready_event_added = _run_script_event(escoria.event_manager.EVENT_READY, room) + escoria.main.set_scene_finish() - if ready_event_added: - # Wait for ready event to be done - var rc = yield(escoria.event_manager, "event_finished") - while rc[1] != escoria.event_manager.EVENT_READY: - rc = yield(escoria.event_manager, "event_finished") - if rc[0] != ESCExecution.RC_OK: - return rc[0] + # We know the scene has been loaded. Make its global ID available for + # use by ESC script. + escoria.globals_manager.set_global( + escoria.room_manager.GLOBAL_CURRENT_SCENE, + room.global_id, + true + ) - # Now that :ready is finished, if FORCE_LAST_SCENE_NULL was true, reset it - # to false - if escoria.globals_manager.get_global( \ - escoria.room_manager.GLOBAL_FORCE_LAST_SCENE_NULL): + # Clear queued resources + escoria.resource_cache.clear() - escoria.globals_manager.set_global( - escoria.room_manager.GLOBAL_FORCE_LAST_SCENE_NULL, - false, - true - ) - escoria.globals_manager.set_global( - escoria.room_manager.GLOBAL_LAST_SCENE, - escoria.main.current_scene.global_id \ - if escoria.main.current_scene != null else "", - true - ) + escoria.inputs_manager.hotspot_focused = "" + + if room.enabled_automatic_transitions \ + or ( + not room.enabled_automatic_transitions \ + and escoria.globals_manager.get_global( \ + escoria.room_manager.GLOBAL_FORCE_LAST_SCENE_NULL) + ): + var script_transition_in = escoria.esc_compiler.compile([ + "%s%s" % [ESCEvent.PREFIX, escoria.event_manager.EVENT_TRANSITION_IN], + "%s %s in" % + [ + _transition.get_command_name(), + escoria.project_settings_manager.get_setting( + escoria.project_settings_manager.DEFAULT_TRANSITION + ) + ], + "%s 0.1" % _wait.get_command_name() + ]) + escoria.event_manager.queue_event( + script_transition_in.events[escoria.event_manager.EVENT_TRANSITION_IN] + ) + + var ready_event_added: bool = false + # Run the ready event, if there is one. + ready_event_added = _run_script_event(escoria.event_manager.EVENT_READY, room) + + if ready_event_added: + # Wait for ready event to be done + var rc = yield(escoria.event_manager, "event_finished") + while rc[1] != escoria.event_manager.EVENT_READY: + rc = yield(escoria.event_manager, "event_finished") + if rc[0] != ESCExecution.RC_OK: + return rc[0] + + # Now that :ready is finished, if FORCE_LAST_SCENE_NULL was true, reset it + # to false + if escoria.globals_manager.get_global( \ + escoria.room_manager.GLOBAL_FORCE_LAST_SCENE_NULL): - # Make the room's global ID available for use in ESC script. escoria.globals_manager.set_global( - escoria.room_manager.GLOBAL_CURRENT_SCENE, + escoria.room_manager.GLOBAL_FORCE_LAST_SCENE_NULL, + false, + true + ) + escoria.globals_manager.set_global( + escoria.room_manager.GLOBAL_LAST_SCENE, escoria.main.current_scene.global_id \ if escoria.main.current_scene != null else "", true ) - - return ESCExecution.RC_OK + + # Make the room's global ID available for use in ESC script. + escoria.globals_manager.set_global( + escoria.room_manager.GLOBAL_CURRENT_SCENE, + escoria.main.current_scene.global_id \ + if escoria.main.current_scene != null else "", + true + ) # Runs the script event from the script attached, if any. diff --git a/addons/escoria-core/game/core-scripts/esc_item.gd b/addons/escoria-core/game/core-scripts/esc_item.gd index c512a381..07aa1c0e 100644 --- a/addons/escoria-core/game/core-scripts/esc_item.gd +++ b/addons/escoria-core/game/core-scripts/esc_item.gd @@ -57,6 +57,9 @@ signal mouse_right_clicked_item(global_id) signal arrived(walk_context) +const GROUP_ITEM_CAN_COLLIDE = "item_can_collide" + + # The global ID of this item export(String) var global_id @@ -170,6 +173,10 @@ func _ready(): self.pause_mode = Node.PAUSE_MODE_STOP _detect_children() + + # We add ourselves to this group so we can easily get a reference to all + # items in a scene tree. + add_to_group(GROUP_ITEM_CAN_COLLIDE) if not self.is_connected("mouse_entered", self, "_on_mouse_entered"): connect("mouse_entered", self, "_on_mouse_entered") diff --git a/addons/escoria-core/game/core-scripts/save_data/esc_save_manager.gd b/addons/escoria-core/game/core-scripts/save_data/esc_save_manager.gd index 4671b91b..8c441d5b 100644 --- a/addons/escoria-core/game/core-scripts/save_data/esc_save_manager.gd +++ b/addons/escoria-core/game/core-scripts/save_data/esc_save_manager.gd @@ -29,6 +29,7 @@ var _transition: TransitionCommand var _hide_menu: HideMenuCommand var _change_scene: ChangeSceneCommand var _set_active: SetActiveCommand +var _set_active_if_exists: SetActiveIfExistsCommand var _set_interactive: SetInteractiveCommand var _teleport_pos: TeleportPosCommand var _set_angle: SetAngleCommand @@ -49,6 +50,7 @@ func _init(): _hide_menu = HideMenuCommand.new() _change_scene = ChangeSceneCommand.new() _set_active = SetActiveCommand.new() + _set_active_if_exists = SetActiveIfExistsCommand.new() _set_interactive = SetInteractiveCommand.new() _teleport_pos = TeleportPosCommand.new() _set_angle = SetAngleCommand.new() @@ -291,20 +293,6 @@ func load_game(id: int): ) ) - load_event.statements = load_statements - - escoria.set_game_paused(false) - escoria.event_manager.queue_event(load_event) - - # Wait for the scene to be loaded so we have access to objects, etc. - var rc = yield(escoria.event_manager, "event_finished") - while rc[1] != escoria.event_manager.EVENT_LOAD: - rc = yield(escoria.event_manager, "event_finished") - - # We then carry on with other "load"-related commands. - escoria.set_game_paused(true) - load_statements = [] - ## GLOBALS for k in save_game.globals.keys(): var global_value = save_game.globals[k] @@ -324,11 +312,10 @@ func load_game(id: int): ## OBJECTS for object_global_id in save_game.objects.keys(): - if escoria.object_manager.has(object_global_id) and \ - save_game.objects[object_global_id].has("active"): + if save_game.objects[object_global_id].has("active"): load_statements.append(ESCCommand.new("%s %s %s" \ % [ - _set_active.get_command_name(), + _set_active_if_exists.get_command_name(), object_global_id, save_game.objects[object_global_id]["active"] ] diff --git a/addons/escoria-core/game/main.gd b/addons/escoria-core/game/main.gd index 0d152e49..cdf3c6d8 100644 --- a/addons/escoria-core/game/main.gd +++ b/addons/escoria-core/game/main.gd @@ -42,6 +42,9 @@ func set_scene(p_scene: Node) -> void: previous_scene = current_scene + if is_instance_valid(previous_scene): + _disable_collisions() + if not p_scene.is_inside_tree(): # Set the scene's visiblity for :setup events if the new room is not the # same one as the current room. @@ -207,3 +210,14 @@ func _is_same_scene(scene_1: Node, scene_2: Node) -> bool: return scene_1.global_id == scene_2.global_id return false + + +# Disable collisions in the previous scene so if we have two scenes in the same +# game tree, collisions won't result. +func _disable_collisions() -> void: + var items_to_disable = previous_scene.get_tree().get_nodes_in_group(ESCItem.GROUP_ITEM_CAN_COLLIDE) + + for item in items_to_disable: + if is_instance_valid(item.collision): + item.collision.disabled = true + diff --git a/addons/escoria-core/game/scenes/transitions/esc_transition_player.gd b/addons/escoria-core/game/scenes/transitions/esc_transition_player.gd index 81c8c270..d320fde4 100644 --- a/addons/escoria-core/game/scenes/transitions/esc_transition_player.gd +++ b/addons/escoria-core/game/scenes/transitions/esc_transition_player.gd @@ -137,6 +137,14 @@ func has_transition(name: String) -> bool: return name == TRANSITION_INSTANT or get_transition(name) != "" +# Resets the current material's cutoff parameter instantly. +func reset_shader_cutoff() -> void: + if not is_instance_valid(material): + return + + material.set_shader_param("cutoff", 1.0) + + func _on_tween_completed(): if not _was_canceled: _tween.stop_all() diff --git a/game/rooms/room01/room01.tscn b/game/rooms/room01/room01.tscn index fadb8cd4..1cd2e6b7 100644 --- a/game/rooms/room01/room01.tscn +++ b/game/rooms/room01/room01.tscn @@ -180,6 +180,7 @@ pause_mode = 1 script = ExtResource( 5 ) global_id = "trigger_talk" esc_script = "res://game/rooms/room01/esc/trigger.esc" +is_trigger = true player_orients_on_arrival = false dialog_color = Color( 1, 1, 1, 1 ) animations = null