diff --git a/addons/escoria-core/game/core-scripts/esc/esc_event_manager.gd b/addons/escoria-core/game/core-scripts/esc/esc_event_manager.gd index 4ea9ad5a..b3ab2f7c 100644 --- a/addons/escoria-core/game/core-scripts/esc/esc_event_manager.gd +++ b/addons/escoria-core/game/core-scripts/esc/esc_event_manager.gd @@ -6,6 +6,9 @@ class_name ESCEventManager # Emitted when the event did finish running signal event_finished(event_name, return_code) +# Emitted when the event was interrupted +signal event_interrupted(event_name, return_code) + # A queue of events to run var events_queue: Array = [] @@ -13,6 +16,9 @@ var events_queue: Array = [] # A list of currently scheduled events var scheduled_events: Array = [] +# Currently running event +var _running_event: ESCEvent + func _ready(): self.pause_mode = Node.PAUSE_MODE_STOP @@ -21,17 +27,27 @@ func _ready(): # Handle the events queue and scheduled events func _process(delta: float) -> void: if events_queue.size() > 0: - var running_event = events_queue.pop_front() - if not running_event.is_connected( + _running_event = events_queue.pop_front() + if not _running_event.is_connected( "finished", self, "_on_event_finished" ): - running_event.connect( + _running_event.connect( "finished", self, "_on_event_finished", - [running_event] + [_running_event] ) - running_event.run() + if not _running_event.is_connected( + "interrupted", self, "_on_event_finished" + ): + _running_event.connect( + "interrupted", + self, + "_on_event_finished", + [_running_event] + ) + + _running_event.run() for event in self.scheduled_events: (event as ESCScheduledEvent).timeout -= delta if (event as ESCScheduledEvent).timeout <= 0: @@ -55,9 +71,18 @@ func _on_event_finished(return_code: int, event: ESCEvent) -> void: "Event %s ended with return code %d" % [event.name, return_code] ) event.disconnect("finished", self, "_on_event_finished") + event.disconnect("interrupted", self, "_on_event_finished") + _running_event = null match(return_code): ESCExecution.RC_CANCEL: self.scheduled_events = [] self.events_queue = [] return_code = ESCExecution.RC_OK emit_signal("event_finished", return_code, event.name) + + +# Interrupt the event currently running. +func interrupt_running_event(): + if _running_event == null: + return + _running_event.interrupt() diff --git a/addons/escoria-core/game/core-scripts/esc/types/esc_statement.gd b/addons/escoria-core/game/core-scripts/esc/types/esc_statement.gd index 07d2e76e..98a26853 100644 --- a/addons/escoria-core/game/core-scripts/esc/types/esc_statement.gd +++ b/addons/escoria-core/game/core-scripts/esc/types/esc_statement.gd @@ -6,10 +6,15 @@ class_name ESCStatement # Emitted when the event did finish running signal finished(return_code) +# Emitted when the event was interrupted +signal interrupted(return_code) # The list of ESC commands var statements: Array = [] +# Indicated whether this event was interrupted. +var _is_interrupted: bool = false + # Check wether the statement should be run based on its conditions func is_valid() -> bool: @@ -23,6 +28,11 @@ func is_valid() -> bool: func run() -> int: var final_rc = ESCExecution.RC_OK for statement in statements: + if _is_interrupted: + final_rc = ESCExecution.RC_CANCEL + emit_signal("interrupted", final_rc) + return final_rc + if statement.is_valid(): var rc = statement.run() if rc is GDScriptFunctionState: @@ -35,3 +45,11 @@ func run() -> int: emit_signal("finished", final_rc) return final_rc + + +# Interrupt the statement in the middle of its execution. +func interrupt(): + escoria.logger.info("Interrupting event %s" % str(self)) + _is_interrupted = true + for statement in statements: + statement.interrupt() diff --git a/addons/escoria-core/game/core-scripts/esc_game.gd b/addons/escoria-core/game/core-scripts/esc_game.gd index e90d7260..86794b58 100644 --- a/addons/escoria-core/game/core-scripts/esc_game.gd +++ b/addons/escoria-core/game/core-scripts/esc_game.gd @@ -52,7 +52,11 @@ func _draw(): # # - position: Position clicked func left_click_on_bg(position: Vector2) -> void: - escoria.do("walk", [escoria.main.current_scene.player.global_id, position]) + escoria.do( + "walk", + [escoria.main.current_scene.player.global_id, position], + true + ) # Called when the player right clicks on the background @@ -62,7 +66,11 @@ func left_click_on_bg(position: Vector2) -> void: # # - position: Position clicked func right_click_on_bg(position: Vector2) -> void: - escoria.do("walk", [escoria.main.current_scene.player.global_id, position]) + escoria.do( + "walk", + [escoria.main.current_scene.player.global_id, position], + true + ) # Called when the player double clicks on the background @@ -72,8 +80,11 @@ func right_click_on_bg(position: Vector2) -> void: # # - position: Position clicked func left_double_click_on_bg(position: Vector2) -> void: - escoria.do("walk", [escoria.main.current_scene.player.global_id, position, \ - true]) + escoria.do( + "walk", + [escoria.main.current_scene.player.global_id, position, true], + true + ) # Called when an element in the scene was focused # (Needs to be overridden, if supported) @@ -99,7 +110,11 @@ func element_unfocused() -> void: # - item_global_id: Global id of the item that was clicked # - event: The received input event func left_click_on_item(item_global_id: String, event: InputEvent) -> void: - escoria.do("item_left_click", [item_global_id, event]) + escoria.do( + "item_left_click", + [item_global_id, event], + true + ) # Called when an item was right clicked @@ -110,7 +125,11 @@ func left_click_on_item(item_global_id: String, event: InputEvent) -> void: # - item_global_id: Global id of the item that was clicked # - event: The received input event func right_click_on_item(item_global_id: String, event: InputEvent) -> void: - escoria.do("item_right_click", [item_global_id, event]) + escoria.do( + "item_right_click", + [item_global_id, event], + true + ) # Called when an item was double clicked @@ -124,7 +143,11 @@ func left_double_click_on_item( item_global_id: String, event: InputEvent ) -> void: - escoria.do("item_left_click", [item_global_id, event]) + escoria.do( + "item_left_click", + [item_global_id, event], + true + ) # Called when an inventory item was left clicked diff --git a/addons/escoria-core/game/escoria.gd b/addons/escoria-core/game/escoria.gd index 3b230453..2ed6e1a4 100644 --- a/addons/escoria-core/game/escoria.gd +++ b/addons/escoria-core/game/escoria.gd @@ -136,10 +136,15 @@ func new_game(): # # - action: type of the action to run # - params: Parameters for the action -func do(action: String, params: Array = []) -> void: +# - can_interrupt: if true, this command will interrupt any ongoing event +# before it is finished +func do(action: String, params: Array = [], can_interrupt: bool = false) -> void: if current_state == GAME_STATE.DEFAULT: match action: "walk": + if can_interrupt: + event_manager.interrupt_running_event() + self.action_manager.clear_current_action() var walk_fast = false @@ -183,6 +188,10 @@ func do(action: String, params: Array = []) -> void: "escoria.do(): item_left_click on item ", [params[0]] ) + + if can_interrupt: + event_manager.interrupt_running_event() + var item = self.object_manager.get_object(params[0]) self.controller.perform_inputevent_on_object(item, params[1]) @@ -192,6 +201,10 @@ func do(action: String, params: Array = []) -> void: "escoria.do(): item_right_click on item ", [params[0]] ) + + if can_interrupt: + event_manager.interrupt_running_event() + var item = self.object_manager.get_object(params[0]) self.controller.perform_inputevent_on_object(item, params[1], true) diff --git a/addons/escoria-ui-9verbs/game.gd b/addons/escoria-ui-9verbs/game.gd index 60c2b958..0e792142 100644 --- a/addons/escoria-ui-9verbs/game.gd +++ b/addons/escoria-ui-9verbs/game.gd @@ -48,20 +48,31 @@ func _input(event): ## BACKGROUND ## func left_click_on_bg(position: Vector2) -> void: - escoria.do("walk", [escoria.main.current_scene.player.global_id, position]) + escoria.do( + "walk", + [escoria.main.current_scene.player.global_id, position], + true + ) escoria.action_manager.clear_current_action() verbs_menu.unselect_actions() func right_click_on_bg(position: Vector2) -> void: - escoria.do("walk", [escoria.main.current_scene.player.global_id, position]) + escoria.do( + "walk", + [escoria.main.current_scene.player.global_id, position], + true + ) escoria.action_manager.clear_current_action() verbs_menu.unselect_actions() func left_double_click_on_bg(position: Vector2) -> void: - escoria.do("walk", [escoria.main.current_scene.player.global_id, position, \ - true]) + escoria.do( + "walk", + [escoria.main.current_scene.player.global_id, position, true], + true + ) escoria.action_manager.clear_current_action() verbs_menu.unselect_actions() @@ -85,16 +96,16 @@ func element_unfocused() -> void: ## ITEMS ## func left_click_on_item(item_global_id: String, event: InputEvent) -> void: - escoria.do("item_left_click", [item_global_id, event]) + escoria.do("item_left_click", [item_global_id, event], true) func right_click_on_item(item_global_id: String, event: InputEvent) -> void: escoria.action_manager.set_current_action(verbs_menu.selected_action) - escoria.do("item_right_click", [item_global_id, event]) + escoria.do("item_right_click", [item_global_id, event], true) func left_double_click_on_item(item_global_id: String, event: InputEvent) -> void: - escoria.do("item_left_click", [item_global_id, event]) + escoria.do("item_left_click", [item_global_id, event], true) ## INVENTORY ## diff --git a/addons/escoria-ui-simplemouse/game.gd b/addons/escoria-ui-simplemouse/game.gd index 8c649d4f..0fa4b70c 100644 --- a/addons/escoria-ui-simplemouse/game.gd +++ b/addons/escoria-ui-simplemouse/game.gd @@ -38,18 +38,29 @@ func _ready(): ## BACKGROUND ## func left_click_on_bg(position: Vector2) -> void: - escoria.do("walk", [escoria.main.current_scene.player.global_id, position]) + escoria.do( + "walk", + [escoria.main.current_scene.player.global_id, position], + true + ) $ui/verbs_layer/verbs_menu.set_by_name("walk") $ui/verbs_layer/verbs_menu.clear_tool_texture() func right_click_on_bg(position: Vector2) -> void: - escoria.do("walk", [escoria.main.current_scene.player.global_id, position]) + escoria.do( + "walk", + [escoria.main.current_scene.player.global_id, position], + true + ) $ui/verbs_layer/verbs_menu.set_by_name("walk") $ui/verbs_layer/verbs_menu.clear_tool_texture() func left_double_click_on_bg(position: Vector2) -> void: - escoria.do("walk", [escoria.main.current_scene.player.global_id, position, \ - true]) + escoria.do( + "walk", + [escoria.main.current_scene.player.global_id, position, true], + true + ) $ui/verbs_layer/verbs_menu.set_by_name("walk") $ui/verbs_layer/verbs_menu.clear_tool_texture() @@ -71,13 +82,13 @@ func element_unfocused() -> void: ## ITEMS ## func left_click_on_item(item_global_id: String, event: InputEvent) -> void: - escoria.do("item_left_click", [item_global_id, event]) + escoria.do("item_left_click", [item_global_id, event], true) func right_click_on_item(item_global_id: String, event: InputEvent) -> void: - escoria.do("item_right_click", [item_global_id, event]) + escoria.do("item_right_click", [item_global_id, event], true) func left_double_click_on_item(item_global_id: String, event: InputEvent) -> void: - escoria.do("item_left_click", [item_global_id, event]) + escoria.do("item_left_click", [item_global_id, event], true) ## INVENTORY ## @@ -98,7 +109,7 @@ func left_click_on_inventory_item(inventory_item_global_id: String, event: Input func right_click_on_inventory_item(inventory_item_global_id: String, event: InputEvent) -> void: - escoria.do("item_right_click", [inventory_item_global_id, event]) + escoria.do("item_right_click", [inventory_item_global_id, event], true) func left_double_click_on_inventory_item(inventory_item_global_id: String, event: InputEvent) -> void: diff --git a/docs/api/ESCEventManager.md b/docs/api/ESCEventManager.md index 40f7ee91..e5afd9a7 100644 --- a/docs/api/ESCEventManager.md +++ b/docs/api/ESCEventManager.md @@ -44,6 +44,15 @@ func schedule_event(event: ESCEvent, timeout: float) -> void Schedule an event to run after a timeout +### interrupt\_running\_event + +```gdscript +func interrupt_running_event() +``` + +Interrupt the event currently running. + ## Signals - signal event_finished(event_name, return_code): Emitted when the event did finish running +- signal event_interrupted(event_name, return_code): Emitted when the event was interrupted diff --git a/docs/api/ESCStatement.md b/docs/api/ESCStatement.md index 64687b40..1bf83fca 100644 --- a/docs/api/ESCStatement.md +++ b/docs/api/ESCStatement.md @@ -36,6 +36,15 @@ func run() -> var Execute this statement and return its return code +### interrupt + +```gdscript +func interrupt() +``` + +Interrupt the statement in the middle of its execution. + ## Signals - signal finished(return_code): Emitted when the event did finish running +- signal interrupted(return_code): Emitted when the event was interrupted diff --git a/docs/api/escoria.gd.md b/docs/api/escoria.gd.md index ba5cc75e..05d99533 100644 --- a/docs/api/escoria.gd.md +++ b/docs/api/escoria.gd.md @@ -215,7 +215,7 @@ Called by Main menu "start new game" ### do ```gdscript -func do(action: String, params: Array) -> void +func do(action: String, params: Array, can_interrupt: bool = false) -> void ``` Run a generic action @@ -224,6 +224,8 @@ Run a generic action - action: type of the action to run - params: Parameters for the action +- can_interrupt: if true, this command will interrupt any ongoing event +before it is finished ### set\_game\_paused diff --git a/saves/save_003.tres b/saves/save_003.tres new file mode 100644 index 00000000..7d86ec69 --- /dev/null +++ b/saves/save_003.tres @@ -0,0 +1,88 @@ +[gd_resource type="Resource" load_steps=2 format=2] + +[ext_resource path="res://addons/escoria-core/game/core-scripts/save_data/esc_savegame.gd" type="Script" id=1] + +[resource] +script = ExtResource( 1 ) +escoria_version = "0.1.0" +game_version = "0.1.0" +name = "5" +date = "26/08/2021 08:59" +main = { +"current_scene_filename": "res://game/rooms/room01/room01.tscn", +"last_scene_global_id": "" +} +globals = { +"dialog_advance": 0, +"dialog_popup_advance": 0, +"room1_visited": true +} +objects = { +"bg_music": { +"active": true, +"interactive": true, +"state": "res://game/sfx/contemplation.ogg" +}, +"bg_sound": { +"active": true, +"interactive": true, +"state": "default" +}, +"camera": { +"active": true, +"interactive": true, +"state": "default" +}, +"player": { +"active": true, +"global_transform": Transform2D( 1, 0, 0, 1, 994.586, 458.862 ), +"interactive": true, +"last_dir": 2, +"state": "default" +}, +"player_start": { +"active": true, +"interactive": true, +"state": "default" +}, +"r1_destination_point": { +"active": true, +"interactive": true, +"state": "default" +}, +"r1_destination_point2": { +"active": true, +"interactive": true, +"state": "default" +}, +"r1_left_object_interaction": { +"active": true, +"interactive": true, +"state": "default" +}, +"r1_r_exit": { +"active": true, +"interactive": true, +"state": "default" +}, +"r1_start": { +"active": true, +"interactive": true, +"state": "default" +}, +"r1_wall_item1": { +"active": true, +"interactive": true, +"state": "default" +}, +"r1_wall_item2": { +"active": true, +"interactive": true, +"state": "default" +}, +"r2_left_object_interaction": { +"active": true, +"interactive": true, +"state": "default" +} +}