summaryrefslogtreecommitdiff
path: root/addons/escoria-core/game/core-scripts/esc
diff options
context:
space:
mode:
Diffstat (limited to 'addons/escoria-core/game/core-scripts/esc')
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/accept_input.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/anim.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/anim_block.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/block_say.gd6
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/camera_push.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/camera_push_block.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/camera_set_limits.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/camera_set_pos.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/camera_set_pos_block.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/camera_set_target.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/camera_set_target_block.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/camera_set_zoom.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/camera_set_zoom_block.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/camera_set_zoom_height.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/camera_set_zoom_height_block.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/camera_shift.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/camera_shift_block.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/change_scene.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/change_scene_godot.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/custom.gd6
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/dec_global.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/enable_terrain.gd7
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/end_block_say.gd6
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/hide_menu.gd4
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/inc_global.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/inventory_add.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/inventory_remove.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/play_snd.gd15
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/print_internal.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/queue_event.gd4
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/queue_resource.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/rand_global.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/repeat.gd4
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/save_game.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/say.gd10
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/sched_event.gd6
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/set_active.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/set_active_if_exists.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/set_angle.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/set_animations.gd8
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/set_direction.gd6
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/set_global.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/set_globals.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/set_gui_visible.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/set_interactive.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/set_item_custom_data.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/set_speed.gd9
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/set_state.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/show_menu.gd4
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/slide.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/slide_block.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/spawn.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/stop.gd4
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/stop_snd.gd26
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/teleport.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/teleport_pos.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/transition.gd6
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/turn_to.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/wait.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/walk.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/walk_block.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/walk_to_pos.gd4
-rw-r--r--addons/escoria-core/game/core-scripts/esc/commands/walk_to_pos_block.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/compiler/esc_break_counter.gd75
-rw-r--r--addons/escoria-core/game/core-scripts/esc/compiler/esc_environment.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/compiler/esc_grammar_expr.gd4
-rw-r--r--addons/escoria-core/game/core-scripts/esc/compiler/esc_grammar_stmt.gd4
-rw-r--r--addons/escoria-core/game/core-scripts/esc/compiler/esc_grammar_stmts.gd62
-rw-r--r--addons/escoria-core/game/core-scripts/esc/compiler/esc_interpreter.gd249
-rw-r--r--addons/escoria-core/game/core-scripts/esc/compiler/esc_interpreter_factory.gd64
-rw-r--r--addons/escoria-core/game/core-scripts/esc/compiler/esc_parse_error.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/compiler/esc_parser.gd205
-rw-r--r--addons/escoria-core/game/core-scripts/esc/compiler/esc_resolver.gd12
-rw-r--r--addons/escoria-core/game/core-scripts/esc/compiler/esc_scanner.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/compiler/esc_script_builder.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/compiler/esc_token.gd12
-rw-r--r--addons/escoria-core/game/core-scripts/esc/esc_action_manager.gd237
-rw-r--r--addons/escoria-core/game/core-scripts/esc/esc_command_registry.gd5
-rw-r--r--addons/escoria-core/game/core-scripts/esc/esc_compiler.gd23
-rw-r--r--addons/escoria-core/game/core-scripts/esc/esc_event_manager.gd156
-rw-r--r--addons/escoria-core/game/core-scripts/esc/esc_globals_manager.gd15
-rw-r--r--addons/escoria-core/game/core-scripts/esc/esc_inventory_manager.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/esc_object_manager.gd119
-rw-r--r--addons/escoria-core/game/core-scripts/esc/esc_room_manager.gd55
-rw-r--r--addons/escoria-core/game/core-scripts/esc/types/esc_base_command.gd10
-rw-r--r--addons/escoria-core/game/core-scripts/esc/types/esc_camera_base_command.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/types/esc_command.gd62
-rw-r--r--addons/escoria-core/game/core-scripts/esc/types/esc_command_argument_descriptor.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/types/esc_dialog.gd42
-rw-r--r--addons/escoria-core/game/core-scripts/esc/types/esc_dialog_option.gd16
-rw-r--r--addons/escoria-core/game/core-scripts/esc/types/esc_event.gd20
-rw-r--r--addons/escoria-core/game/core-scripts/esc/types/esc_events_container.gd52
-rw-r--r--addons/escoria-core/game/core-scripts/esc/types/esc_events_container.gd.uid1
-rw-r--r--addons/escoria-core/game/core-scripts/esc/types/esc_execution.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/types/esc_object.gd65
-rw-r--r--addons/escoria-core/game/core-scripts/esc/types/esc_room_container.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/types/esc_room_objects.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/types/esc_room_objects_key.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/types/esc_room_terrains.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/types/esc_scheduled_event.gd2
-rw-r--r--addons/escoria-core/game/core-scripts/esc/types/esc_script.gd44
-rw-r--r--addons/escoria-core/game/core-scripts/esc/types/esc_statement.gd4
102 files changed, 1286 insertions, 578 deletions
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/accept_input.gd b/addons/escoria-core/game/core-scripts/esc/commands/accept_input.gd
index f29f9c7..18a6228 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/accept_input.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/accept_input.gd
@@ -10,8 +10,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name AcceptInputCommand
+extends ESCBaseCommand
## The list of supported input types
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/anim.gd b/addons/escoria-core/game/core-scripts/esc/commands/anim.gd
index 6525654..5711707 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/anim.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/anim.gd
@@ -12,8 +12,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name AnimCommand
+extends ESCBaseCommand
## The descriptor of the arguments of this command.[br]
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/anim_block.gd b/addons/escoria-core/game/core-scripts/esc/commands/anim_block.gd
index b64b166..f564a94 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/anim_block.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/anim_block.gd
@@ -12,8 +12,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name AnimBlockCommand
+extends ESCBaseCommand
## The descriptor of the arguments of this command.[br]
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/block_say.gd b/addons/escoria-core/game/core-scripts/esc/commands/block_say.gd
index d2b7dd2..6ebb0c1 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/block_say.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/block_say.gd
@@ -8,8 +8,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name BlockSayCommand
+extends ESCBaseCommand
## Constructor[br]
@@ -48,7 +48,7 @@ func configure() -> ESCCommandArgumentDescriptor:
## #### Returns[br]
## [br]
## Returns True if the arguments are valid, false otherwise. (`bool`)
-func validate(arguments: Array):
+func validate(_arguments: Array):
return true
@@ -63,7 +63,7 @@ func validate(arguments: Array):
## #### Returns[br]
## [br]
## Returns the execution result code. (`int`)
-func run(command_params: Array) -> int:
+func run(_command_params: Array) -> int:
escoria.dialog_player.enable_preserve_dialog_box()
return ESCExecution.RC_OK
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/camera_push.gd b/addons/escoria-core/game/core-scripts/esc/commands/camera_push.gd
index 37f99dd..710a195 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/camera_push.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/camera_push.gd
@@ -26,8 +26,8 @@
##
## @ASHES
## @COMMAND
-extends ESCCameraBaseCommand
class_name CameraPushCommand
+extends ESCCameraBaseCommand
## The list of supported transitions as per the link mentioned above
const SUPPORTED_TRANSITIONS = ["LINEAR","SINE","QUINT","QUART","QUAD" ,"EXPO","ELASTIC","CUBIC",
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/camera_push_block.gd b/addons/escoria-core/game/core-scripts/esc/commands/camera_push_block.gd
index 289cfc7..52db676 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/camera_push_block.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/camera_push_block.gd
@@ -26,8 +26,8 @@
##
## @ASHES
## @COMMAND
-extends ESCCameraBaseCommand
class_name CameraPushBlockCommand
+extends ESCCameraBaseCommand
## The list of supported transitions as per the link mentioned above
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/camera_set_limits.gd b/addons/escoria-core/game/core-scripts/esc/commands/camera_set_limits.gd
index 79dc992..b468e7d 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/camera_set_limits.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/camera_set_limits.gd
@@ -15,8 +15,8 @@
##
## @ASHES
## @COMMAND
-extends ESCCameraBaseCommand
class_name CameraSetLimitsCommand
+extends ESCCameraBaseCommand
## The descriptor of the arguments of this command.[br]
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/camera_set_pos.gd b/addons/escoria-core/game/core-scripts/esc/commands/camera_set_pos.gd
index 5403bcf..365b668 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/camera_set_pos.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/camera_set_pos.gd
@@ -12,8 +12,8 @@
##
## @ASHES
## @COMMAND
-extends ESCCameraBaseCommand
class_name CameraSetPosCommand
+extends ESCCameraBaseCommand
## The descriptor of the arguments of this command.[br]
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/camera_set_pos_block.gd b/addons/escoria-core/game/core-scripts/esc/commands/camera_set_pos_block.gd
index 2fe7dc0..8833c24 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/camera_set_pos_block.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/camera_set_pos_block.gd
@@ -15,8 +15,8 @@
##
## @ASHES
## @COMMAND
-extends ESCCameraBaseCommand
class_name CameraSetPosBlockCommand
+extends ESCCameraBaseCommand
# Tween for blocking
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/camera_set_target.gd b/addons/escoria-core/game/core-scripts/esc/commands/camera_set_target.gd
index 8d5e3e0..485dd28 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/camera_set_target.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/camera_set_target.gd
@@ -13,8 +13,8 @@
##
## @ASHES
## @COMMAND
-extends ESCCameraBaseCommand
class_name CameraSetTargetCommand
+extends ESCCameraBaseCommand
## Provides the argument descriptor that defines the command signature.[br]
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/camera_set_target_block.gd b/addons/escoria-core/game/core-scripts/esc/commands/camera_set_target_block.gd
index e071dec..07841fd 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/camera_set_target_block.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/camera_set_target_block.gd
@@ -17,8 +17,8 @@
##
## @ASHES
## @COMMAND
-extends ESCCameraBaseCommand
class_name CameraSetTargetBlockCommand
+extends ESCCameraBaseCommand
# Tween for blocking
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/camera_set_zoom.gd b/addons/escoria-core/game/core-scripts/esc/commands/camera_set_zoom.gd
index 515aa44..4be55ee 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/camera_set_zoom.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/camera_set_zoom.gd
@@ -16,8 +16,8 @@
##
## @ASHES
## @COMMAND
-extends ESCCameraBaseCommand
class_name CameraSetZoomCommand
+extends ESCCameraBaseCommand
## The descriptor of the arguments of this command.[br]
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/camera_set_zoom_block.gd b/addons/escoria-core/game/core-scripts/esc/commands/camera_set_zoom_block.gd
index 07ea05f..4ae84b8 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/camera_set_zoom_block.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/camera_set_zoom_block.gd
@@ -20,8 +20,8 @@
##
## @ASHES
## @COMMAND
-extends ESCCameraBaseCommand
class_name CameraSetZoomBlockCommand
+extends ESCCameraBaseCommand
var _camera_tween: Tween3
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/camera_set_zoom_height.gd b/addons/escoria-core/game/core-scripts/esc/commands/camera_set_zoom_height.gd
index 5ffa7c0..dba9ad5 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/camera_set_zoom_height.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/camera_set_zoom_height.gd
@@ -11,8 +11,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name CameraSetZoomHeightCommand
+extends ESCBaseCommand
## The descriptor of the arguments of this command.[br]
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/camera_set_zoom_height_block.gd b/addons/escoria-core/game/core-scripts/esc/commands/camera_set_zoom_height_block.gd
index b526d9c..429be97 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/camera_set_zoom_height_block.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/camera_set_zoom_height_block.gd
@@ -11,8 +11,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name CameraSetZoomHeightBlockCommand
+extends ESCBaseCommand
## Tween for blocking
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/camera_shift.gd b/addons/escoria-core/game/core-scripts/esc/commands/camera_shift.gd
index fb95bb0..379b4f3 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/camera_shift.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/camera_shift.gd
@@ -20,8 +20,8 @@
##
## @ASHES
## @COMMAND
-extends ESCCameraBaseCommand
class_name CameraShiftCommand
+extends ESCCameraBaseCommand
## The list of supported transitions as per the link mentioned above
const SUPPORTED_TRANSITIONS = ["LINEAR","SINE","QUINT","QUART","QUAD" ,"EXPO","ELASTIC","CUBIC",
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/camera_shift_block.gd b/addons/escoria-core/game/core-scripts/esc/commands/camera_shift_block.gd
index a06a8db..c7294a3 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/camera_shift_block.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/camera_shift_block.gd
@@ -23,8 +23,8 @@
##
## @ASHES
## @COMMAND
-extends ESCCameraBaseCommand
class_name CameraShiftBlockCommand
+extends ESCCameraBaseCommand
# The list of supported transitions as per the link mentioned above
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/change_scene.gd b/addons/escoria-core/game/core-scripts/esc/commands/change_scene.gd
index 2ae6e23..b1ff671 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/change_scene.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/change_scene.gd
@@ -12,8 +12,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name ChangeSceneCommand
+extends ESCBaseCommand
## The descriptor of the arguments of this command.[br]
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/change_scene_godot.gd b/addons/escoria-core/game/core-scripts/esc/commands/change_scene_godot.gd
index 9be93a8..e7b8b70 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/change_scene_godot.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/change_scene_godot.gd
@@ -10,8 +10,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name ChangeSceneGodotCommand
+extends ESCBaseCommand
## The descriptor of the arguments of this command.[br]
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/custom.gd b/addons/escoria-core/game/core-scripts/esc/commands/custom.gd
index afacce8..c2fe35f 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/custom.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/custom.gd
@@ -13,8 +13,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name CustomCommand
+extends ESCBaseCommand
## The descriptor of the arguments of this command.[br]
@@ -54,7 +54,7 @@ func validate(arguments: Array):
if not escoria.object_manager.has(arguments[0]):
raise_invalid_object_error(self, arguments[0])
return false
- elif not escoria.object_manager.get_object(arguments[0]).node.has_node(
+ if not escoria.object_manager.get_object(arguments[0]).node.has_node(
arguments[1]
):
raise_error(self, "Invalid node. Object with global id %s has no child node called %s."
@@ -63,7 +63,7 @@ func validate(arguments: Array):
arguments[1],
])
return false
- elif not escoria.object_manager.get_object(arguments[0]).node\
+ if not escoria.object_manager.get_object(arguments[0]).node\
.get_node(
arguments[1]
)\
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/dec_global.gd b/addons/escoria-core/game/core-scripts/esc/commands/dec_global.gd
index 8f91433..33aa173 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/dec_global.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/dec_global.gd
@@ -11,8 +11,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name DecGlobalCommand
+extends ESCBaseCommand
## The descriptor of the arguments of this command.[br]
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/enable_terrain.gd b/addons/escoria-core/game/core-scripts/esc/commands/enable_terrain.gd
index 106c297..76b3fe9 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/enable_terrain.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/enable_terrain.gd
@@ -10,8 +10,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name EnableTerrainCommand
+extends ESCBaseCommand
## The descriptor of the arguments of this command.[br]
@@ -52,9 +52,8 @@ func run(command_params: Array) -> int:
new_active_navigation_instance
escoria.room_terrain.current_active_navigation_instance.enabled = true
return ESCExecution.RC_OK
- else:
- raise_error(self, "Can not find terrain node. Terrain node %s could not be found." % name)
- return ESCExecution.RC_ERROR
+ raise_error(self, "Can not find terrain node. Terrain node %s could not be found." % name)
+ return ESCExecution.RC_ERROR
## Function called when the command is interrupted.[br]
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/end_block_say.gd b/addons/escoria-core/game/core-scripts/esc/commands/end_block_say.gd
index 9a68f4f..d940ce9 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/end_block_say.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/end_block_say.gd
@@ -8,8 +8,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name EndBlockSayCommand
+extends ESCBaseCommand
## Constructor (bypasses the default constructor to avoid)[br]
@@ -49,7 +49,7 @@ func configure() -> ESCCommandArgumentDescriptor:
## #### Returns[br]
## [br]
## Returns True if the arguments are valid, false otherwise. (`bool`)
-func validate(arguments: Array):
+func validate(_arguments: Array):
return true
@@ -64,7 +64,7 @@ func validate(arguments: Array):
## #### Returns[br]
## [br]
## Returns the execution result code. (`int`)
-func run(command_params: Array) -> int:
+func run(_command_params: Array) -> int:
escoria.dialog_player.disable_preserve_dialog_box()
return ESCExecution.RC_OK
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/hide_menu.gd b/addons/escoria-core/game/core-scripts/esc/commands/hide_menu.gd
index 65567d7..da23186 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/hide_menu.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/hide_menu.gd
@@ -10,8 +10,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name HideMenuCommand
+extends ESCBaseCommand
## The descriptor of the arguments of this command.[br]
@@ -69,7 +69,7 @@ func run(command_params: Array) -> int:
# Transition out from menu
transition_id = escoria.main.scene_transition.transition(
"",
- ESCTransitionPlayer.TRANSITION_MODE.OUT
+ ESCTransitionPlayer.TransitionMode.OUT
)
if transition_id != ESCTransitionPlayer.TRANSITION_ID_INSTANT:
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/inc_global.gd b/addons/escoria-core/game/core-scripts/esc/commands/inc_global.gd
index 2bacd61..2452dcc 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/inc_global.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/inc_global.gd
@@ -11,8 +11,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name IncGlobalCommand
+extends ESCBaseCommand
## The descriptor of the arguments of this command.[br]
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/inventory_add.gd b/addons/escoria-core/game/core-scripts/esc/commands/inventory_add.gd
index d715dea..ba59d17 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/inventory_add.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/inventory_add.gd
@@ -10,8 +10,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name InventoryAddCommand
+extends ESCBaseCommand
## List of illegal strings that cannot be used in item names.
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/inventory_remove.gd b/addons/escoria-core/game/core-scripts/esc/commands/inventory_remove.gd
index bd45f66..93e4bab 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/inventory_remove.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/inventory_remove.gd
@@ -10,8 +10,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name InventoryRemoveCommand
+extends ESCBaseCommand
## List of illegal strings that cannot be used in item names.
const ILLEGAL_STRINGS = ["/"]
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/play_snd.gd b/addons/escoria-core/game/core-scripts/esc/commands/play_snd.gd
index 90dcc94..41321d8 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/play_snd.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/play_snd.gd
@@ -12,14 +12,27 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name PlaySndCommand
+extends ESCBaseCommand
## The specified sound player
var _snd_player: String
+## Constructor of this command.[br]
+## [br]
+## #### Parameters[br]
+## [br]
+## None.
+## [br]
+## #### Returns[br]
+## [br]
+## Returns nothing.
+func _init() -> void:
+ run_in_ready_allowed_during_savegame_loading = false
+
+
## The descriptor of the arguments of this command.[br]
## [br]
## #### Parameters[br]
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/print_internal.gd b/addons/escoria-core/game/core-scripts/esc/commands/print_internal.gd
index 56a601f..418cc72 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/print_internal.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/print_internal.gd
@@ -10,8 +10,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name PrintCommand
+extends ESCBaseCommand
## The descriptor of the arguments of this command.[br]
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/queue_event.gd b/addons/escoria-core/game/core-scripts/esc/commands/queue_event.gd
index f676fda..bad3a19 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/queue_event.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/queue_event.gd
@@ -13,8 +13,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name QueueEventCommand
+extends ESCBaseCommand
## The descriptor of the arguments of this command.[br]
@@ -64,7 +64,7 @@ func validate(arguments: Array):
var esc_script = escoria.esc_compiler.load_esc_file(node.esc_script)
- if not arguments[1] in esc_script.events:
+ if not esc_script.has_event_with_target(arguments[1]):
raise_error(
self,
"Event with name '%s' not found." % arguments[1]
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/queue_resource.gd b/addons/escoria-core/game/core-scripts/esc/commands/queue_resource.gd
index 845ae1c..c0598d2 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/queue_resource.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/queue_resource.gd
@@ -11,8 +11,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name QueueResourceCommand
+extends ESCBaseCommand
## The descriptor of the arguments of this command.[br]
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/rand_global.gd b/addons/escoria-core/game/core-scripts/esc/commands/rand_global.gd
index a165f8d..9db0c20 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/rand_global.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/rand_global.gd
@@ -11,8 +11,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name RandGlobalCommand
+extends ESCBaseCommand
## The descriptor of the arguments of this command.[br]
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/repeat.gd b/addons/escoria-core/game/core-scripts/esc/commands/repeat.gd
index 0c0e4b6..db891bf 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/repeat.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/repeat.gd
@@ -8,8 +8,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name RepeatCommand
+extends ESCBaseCommand
## The descriptor of the arguments of this command.[br]
@@ -40,7 +40,7 @@ func configure() -> ESCCommandArgumentDescriptor:
## #### Returns[br]
## [br]
## Returns the execution result code. (`int`)
-func run(command_params: Array) -> int:
+func run(_command_params: Array) -> int:
return ESCExecution.RC_CANCEL
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/save_game.gd b/addons/escoria-core/game/core-scripts/esc/commands/save_game.gd
index e830c49..9f66993 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/save_game.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/save_game.gd
@@ -11,8 +11,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name SaveGameCommand
+extends ESCBaseCommand
## Constructor[br]
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/say.gd b/addons/escoria-core/game/core-scripts/esc/commands/say.gd
index 8c043c2..75115c5 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/say.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/say.gd
@@ -13,8 +13,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name SayCommand
+extends ESCBaseCommand
## The keyword used to refer to the current player
const CURRENT_PLAYER_KEYWORD = "CURRENT_PLAYER"
@@ -103,14 +103,14 @@ func validate(arguments: Array):
func run(command_params: Array) -> int:
var dict: Dictionary
- escoria.current_state = escoria.GAME_STATE.DIALOG
+ escoria.current_state = escoria.GameState.DIALOG
if !escoria.dialog_player:
raise_error(
self,
"No dialog player was registered and the 'say' command was encountered."
)
- escoria.current_state = escoria.GAME_STATE.DEFAULT
+ escoria.current_state = escoria.GameState.DEFAULT
return ESCExecution.RC_ERROR
if not escoria.main.current_scene.player:
@@ -119,7 +119,7 @@ func run(command_params: Array) -> int:
"[%s]: No player item in the current scene was registered and the say command was encountered."
% get_command_name()
)
- escoria.current_state = escoria.GAME_STATE.DEFAULT
+ escoria.current_state = escoria.GameState.DEFAULT
return ESCExecution.RC_CANCEL
# Replace the names of any globals in "{ }" with their value
@@ -136,7 +136,7 @@ func run(command_params: Array) -> int:
command_params[2]
)
await escoria.dialog_player.say_finished
- escoria.current_state = escoria.GAME_STATE.DEFAULT
+ escoria.current_state = escoria.GameState.DEFAULT
return ESCExecution.RC_OK
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/sched_event.gd b/addons/escoria-core/game/core-scripts/esc/commands/sched_event.gd
index 5b57dca..3fb2029 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/sched_event.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/sched_event.gd
@@ -12,8 +12,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name SchedEventCommand
+extends ESCBaseCommand
## The descriptor of the arguments of this command.[br]
@@ -63,7 +63,7 @@ func validate(arguments: Array):
var esc_script = escoria.esc_compiler.load_esc_file(node.esc_script)
- if not arguments[2] in esc_script.events:
+ if not esc_script.has_event_with_target(arguments[2]):
raise_error(
self,
"Event with name '%s' not found." % arguments[2]
@@ -104,7 +104,7 @@ func run(command_params: Array) -> int:
var esc_script = escoria.esc_compiler.load_esc_file(node.esc_script)
escoria.event_manager.schedule_event(
- esc_script.events[command_params[2]], # ESCGrammarStmts.Event
+ esc_script.get_event_with_target(command_params[2]), # ESCGrammarStmts.Event
command_params[0], # timeout float
command_params[1] # object string
)
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/set_active.gd b/addons/escoria-core/game/core-scripts/esc/commands/set_active.gd
index 90846e5..97ebee5 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/set_active.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/set_active.gd
@@ -11,8 +11,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name SetActiveCommand
+extends ESCBaseCommand
## The descriptor of the arguments of this command.[br]
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
index ebb02cb..a2303fb 100644
--- 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
@@ -11,8 +11,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name SetActiveIfExistsCommand
+extends ESCBaseCommand
## The descriptor of the arguments of this command.[br]
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/set_angle.gd b/addons/escoria-core/game/core-scripts/esc/commands/set_angle.gd
index ef503c4..936b03a 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/set_angle.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/set_angle.gd
@@ -12,8 +12,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name SetAngleCommand
+extends ESCBaseCommand
## The descriptor of the arguments of this command.[br]
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/set_animations.gd b/addons/escoria-core/game/core-scripts/esc/commands/set_animations.gd
index 7ae818f..9c22c02 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/set_animations.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/set_animations.gd
@@ -11,8 +11,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name SetAnimationsCommand
+extends ESCBaseCommand
## The descriptor of the arguments of this command.[br]
@@ -57,7 +57,7 @@ func validate(arguments: Array):
)
return false
- (escoria.object_manager.get_object(arguments[0]).node as ESCPlayer).validate_animations(load(arguments[1]))
+ (escoria.object_manager.get_object(arguments[0]).node as ESCItem).validate_animations(load(arguments[1]))
return true
@@ -74,7 +74,7 @@ func validate(arguments: Array):
## [br]
## Returns the execution result code. (`int`)
func run(command_params: Array) -> int:
- (escoria.object_manager.get_object(command_params[0]).node as ESCPlayer)\
+ (escoria.object_manager.get_object(command_params[0]).node as ESCItem)\
.animations = load(command_params[1])
if not escoria.globals_manager.has(
escoria.room_manager.GLOBAL_ANIMATION_RESOURCES
@@ -89,7 +89,7 @@ func run(command_params: Array) -> int:
)
if animations.is_empty():
animations = {}
- animations[command_params[0]] = command_params[1]
+ animations[command_params[0]] = command_params[1]
escoria.globals_manager.set_global(
escoria.room_manager.GLOBAL_ANIMATION_RESOURCES,
animations,
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/set_direction.gd b/addons/escoria-core/game/core-scripts/esc/commands/set_direction.gd
index 43bfd70..fde2cf0 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/set_direction.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/set_direction.gd
@@ -12,8 +12,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name SetDirectionCommand
+extends ESCBaseCommand
## The descriptor of the arguments of this command.[br]
@@ -55,14 +55,14 @@ func validate(arguments: Array):
% [get_command_name(), arguments[0]]
)
return false
- elif not escoria.object_manager.get_object(arguments[0]).node.is_movable:
+ if not escoria.object_manager.get_object(arguments[0]).node.is_movable:
escoria.logger.error(
self,
"[%s]: invalid object. Object with global id %s is not movable."
% [get_command_name(), arguments[0]]
)
return false
- elif arguments[1] < 0 or arguments[1] > escoria.object_manager.get_object(arguments[0]).node \
+ if arguments[1] < 0 or arguments[1] > escoria.object_manager.get_object(arguments[0]).node \
.get_directions_quantity() - 1:
escoria.logger.error(
self,
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/set_global.gd b/addons/escoria-core/game/core-scripts/esc/commands/set_global.gd
index 687fe16..f37751a 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/set_global.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/set_global.gd
@@ -12,8 +12,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name SetGlobalCommand
+extends ESCBaseCommand
## The list of illegal strings that cannot be used in global names.
const ILLEGAL_STRINGS = ["/"]
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/set_globals.gd b/addons/escoria-core/game/core-scripts/esc/commands/set_globals.gd
index 3107057..6122940 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/set_globals.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/set_globals.gd
@@ -11,8 +11,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name SetGlobalsCommand
+extends ESCBaseCommand
## The descriptor of the arguments of this command.[br]
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/set_gui_visible.gd b/addons/escoria-core/game/core-scripts/esc/commands/set_gui_visible.gd
index ec83445..d04f10c 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/set_gui_visible.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/set_gui_visible.gd
@@ -10,8 +10,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name SetGuiVisibleCommand
+extends ESCBaseCommand
## The descriptor of the arguments of this command.[br]
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/set_interactive.gd b/addons/escoria-core/game/core-scripts/esc/commands/set_interactive.gd
index 007e23a..45a8cfb 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/set_interactive.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/set_interactive.gd
@@ -11,8 +11,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name SetInteractiveCommand
+extends ESCBaseCommand
## The descriptor of the arguments of this command.[br]
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/set_item_custom_data.gd b/addons/escoria-core/game/core-scripts/esc/commands/set_item_custom_data.gd
index 2e90ce3..6985c36 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/set_item_custom_data.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/set_item_custom_data.gd
@@ -11,8 +11,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name SetItemCustomDataCommand
+extends ESCBaseCommand
## The descriptor of the arguments of this command.[br]
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/set_speed.gd b/addons/escoria-core/game/core-scripts/esc/commands/set_speed.gd
index cd8f2df..8b05814 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/set_speed.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/set_speed.gd
@@ -11,8 +11,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name SetSpeedCommand
+extends ESCBaseCommand
## The descriptor of the arguments of this command.[br]
@@ -49,6 +49,13 @@ func validate(arguments: Array):
if not escoria.object_manager.has(arguments[0]):
raise_invalid_object_error(self, arguments[0])
return false
+
+ if arguments[1] < 0:
+ raise_error(
+ self,
+ "Invalid speed. Speed cannot be negative (%d)." % arguments[1]
+ )
+ return false
return true
## Runs the command.[br]
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/set_state.gd b/addons/escoria-core/game/core-scripts/esc/commands/set_state.gd
index 597751f..4efd6c5 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/set_state.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/set_state.gd
@@ -12,8 +12,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name SetStateCommand
+extends ESCBaseCommand
## The descriptor of the arguments of this command.[br]
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/show_menu.gd b/addons/escoria-core/game/core-scripts/esc/commands/show_menu.gd
index 3ee2935..32d971b 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/show_menu.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/show_menu.gd
@@ -10,8 +10,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name ShowMenuCommand
+extends ESCBaseCommand
## The descriptor of the arguments of this command.[br]
@@ -73,7 +73,7 @@ func run(command_params: Array) -> int:
# Transition out from current scene
var transition_id = escoria.main.scene_transition.transition(
"",
- ESCTransitionPlayer.TRANSITION_MODE.OUT
+ ESCTransitionPlayer.TransitionMode.OUT
)
if transition_id != ESCTransitionPlayer.TRANSITION_ID_INSTANT:
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/slide.gd b/addons/escoria-core/game/core-scripts/esc/commands/slide.gd
index d168dfe..b3b56ab 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/slide.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/slide.gd
@@ -14,8 +14,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name SlideCommand
+extends ESCBaseCommand
## A hash of tweens currently active for animated items
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/slide_block.gd b/addons/escoria-core/game/core-scripts/esc/commands/slide_block.gd
index 59fa186..397b5d3 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/slide_block.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/slide_block.gd
@@ -13,8 +13,8 @@
##
## @ASHES
## @COMMAND
-extends SlideCommand
class_name SlideBlockCommand
+extends SlideCommand
## Runs the command.[br]
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/spawn.gd b/addons/escoria-core/game/core-scripts/esc/commands/spawn.gd
index b0f01ba..b699816 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/spawn.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/spawn.gd
@@ -13,8 +13,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name SpawnCommand
+extends ESCBaseCommand
## The descriptor of the arguments of this command.[br]
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/stop.gd b/addons/escoria-core/game/core-scripts/esc/commands/stop.gd
index b53183f..578bb3e 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/stop.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/stop.gd
@@ -8,8 +8,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name StopCommand
+extends ESCBaseCommand
## The descriptor of the arguments of this command.[br]
@@ -40,7 +40,7 @@ func configure() -> ESCCommandArgumentDescriptor:
## #### Returns[br]
## [br]
## Returns the execution result code. (`int`)
-func run(command_params: Array) -> int:
+func run(_command_params: Array) -> int:
return ESCExecution.RC_CANCEL
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/stop_snd.gd b/addons/escoria-core/game/core-scripts/esc/commands/stop_snd.gd
index ae0fc62..5218d3a 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/stop_snd.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/stop_snd.gd
@@ -10,15 +10,27 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name StopSndCommand
+extends ESCBaseCommand
+## The previous sound state, saved for interrupting
+var previous_snd_state: String
## The specified sound player
var _snd_player: String
-## The previous sound state, saved for interrupting
-var previous_snd_state: String
+
+## Constructor of this command.[br]
+## [br]
+## #### Parameters[br]
+## [br]
+## None.
+## [br]
+## #### Returns[br]
+## [br]
+## Returns nothing.
+func _init() -> void:
+ run_in_ready_allowed_during_savegame_loading = false
## The descriptor of the arguments of this command.[br]
@@ -93,20 +105,20 @@ func run(command_params: Array) -> int:
## [br]
## Returns nothing.
func interrupt():
- var _sound_players = []
+ var sound_players = []
if previous_snd_state.is_empty():
previous_snd_state = "off"
if _snd_player.is_empty():
- _sound_players = [
+ sound_players = [
ESCObjectManager.MUSIC,
ESCObjectManager.SOUND,
ESCObjectManager.SPEECH
]
else:
- _sound_players = [_snd_player]
+ sound_players = [_snd_player]
- for snd_player in _sound_players:
+ for snd_player in sound_players:
if escoria.object_manager.get_object(snd_player).node:
escoria.object_manager.get_object(snd_player).node.set_state(
previous_snd_state
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/teleport.gd b/addons/escoria-core/game/core-scripts/esc/commands/teleport.gd
index ae41393..f0d7895 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/teleport.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/teleport.gd
@@ -11,8 +11,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name TeleportCommand
+extends ESCBaseCommand
## The descriptor of the arguments of this command.[br]
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/teleport_pos.gd b/addons/escoria-core/game/core-scripts/esc/commands/teleport_pos.gd
index bf7a4fe..c561dfc 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/teleport_pos.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/teleport_pos.gd
@@ -12,8 +12,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name TeleportPosCommand
+extends ESCBaseCommand
## The descriptor of the arguments of this command.[br]
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 ff2c562..192fcdc 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/transition.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/transition.gd
@@ -12,8 +12,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name TransitionCommand
+extends ESCBaseCommand
## The descriptor of the arguments of this command.[br]
@@ -78,8 +78,8 @@ func validate(arguments: Array):
func run(command_params: Array) -> int:
var transition_id = escoria.main.scene_transition.transition(
command_params[0],
- ESCTransitionPlayer.TRANSITION_MODE.OUT if command_params[1] == "out" \
- else ESCTransitionPlayer.TRANSITION_MODE.IN,
+ ESCTransitionPlayer.TransitionMode.OUT if command_params[1] == "out" \
+ else ESCTransitionPlayer.TransitionMode.IN,
command_params[2]
)
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/turn_to.gd b/addons/escoria-core/game/core-scripts/esc/commands/turn_to.gd
index 6cf6fc4..efb5e7a 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/turn_to.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/turn_to.gd
@@ -12,8 +12,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name TurnToCommand
+extends ESCBaseCommand
## The descriptor of the arguments of this command.[br]
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/wait.gd b/addons/escoria-core/game/core-scripts/esc/commands/wait.gd
index 1775452..1032a55 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/wait.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/wait.gd
@@ -10,8 +10,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name WaitCommand
+extends ESCBaseCommand
## Timer to wait for
var timer: Timer
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/walk.gd b/addons/escoria-core/game/core-scripts/esc/commands/walk.gd
index 735e199..b38d816 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/walk.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/walk.gd
@@ -12,8 +12,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name WalkCommand
+extends ESCBaseCommand
## Walking object
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/walk_block.gd b/addons/escoria-core/game/core-scripts/esc/commands/walk_block.gd
index d144a6d..7218b87 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/walk_block.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/walk_block.gd
@@ -12,8 +12,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name WalkBlockCommand
+extends ESCBaseCommand
## Walking object
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/walk_to_pos.gd b/addons/escoria-core/game/core-scripts/esc/commands/walk_to_pos.gd
index fcbe673..f8303dc 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/walk_to_pos.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/walk_to_pos.gd
@@ -13,8 +13,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name WalkToPosCommand
+extends ESCBaseCommand
## Walking object
@@ -56,7 +56,7 @@ func validate(arguments: Array):
if not escoria.object_manager.has(arguments[0]):
raise_error(
self,
- "Invalid first object. The object to make walk with global id '%s' was not found." % arguments[0]
+ "Invalid first object. The object to make walk with global id '%s' was not found." % arguments[0]
)
return false
diff --git a/addons/escoria-core/game/core-scripts/esc/commands/walk_to_pos_block.gd b/addons/escoria-core/game/core-scripts/esc/commands/walk_to_pos_block.gd
index 6800522..7ff1a15 100644
--- a/addons/escoria-core/game/core-scripts/esc/commands/walk_to_pos_block.gd
+++ b/addons/escoria-core/game/core-scripts/esc/commands/walk_to_pos_block.gd
@@ -13,8 +13,8 @@
## [br]
## @ASHES
## @COMMAND
-extends ESCBaseCommand
class_name WalkToPosBlockCommand
+extends ESCBaseCommand
## Walking object
diff --git a/addons/escoria-core/game/core-scripts/esc/compiler/esc_break_counter.gd b/addons/escoria-core/game/core-scripts/esc/compiler/esc_break_counter.gd
index df14c0b..53d8927 100644
--- a/addons/escoria-core/game/core-scripts/esc/compiler/esc_break_counter.gd
+++ b/addons/escoria-core/game/core-scripts/esc/compiler/esc_break_counter.gd
@@ -1,20 +1,21 @@
-## Used by the intpreter to track the depth of a `break` statement invoked in a dialog.
-extends Object
+## Used by the intpreter to track dialog `break` propagation state.
class_name ESCBreakCounter
+extends Object
var _levels_left: int = 0:
set = set_levels_left,
get = get_levels_left
+var _resume_parent_dialog: bool = false
-## Sets the depth from the root of the dialog tree, with `levels == 0` at the root.[br]
+## Sets the remaining number of dialog levels to unwind before control should return to a parent dialog, where `levels == 0` means the unwind has reached the parent dialog that should resume.[br]
## [br]
## #### Parameters[br]
## [br]
## | Name | Type | Description | Required? |[br]
## |:-----|:-----|:------------|:----------|[br]
-## |levels|`int`|Number of dialog nesting levels remaining (0 represents the root).|yes|[br]
+## |levels|`int`|Number of dialog nesting levels still to exit before resuming a parent dialog.|yes|[br]
## [br]
## #### Returns[br]
## [br]
@@ -23,7 +24,7 @@ func set_levels_left(levels: int) -> void:
_levels_left = levels
-## Gets the depth from the root of the dialog tree, with `levels == 0` at the root.[br]
+## Gets the remaining number of dialog levels to unwind before control should return to a parent dialog, where `levels == 0` means the unwind has reached the parent dialog that should resume.[br]
## [br]
## #### Parameters[br]
## [br]
@@ -31,12 +32,68 @@ func set_levels_left(levels: int) -> void:
## [br]
## #### Returns[br]
## [br]
-## Returns a `int` value. (`int`)
+## Returns an `int` value.
func get_levels_left() -> int:
return _levels_left
-## Decrements by one the depth from the root of the dialog tree, with `levels == 0` at the root.[br]
+## Returns whether more dialog levels still need to be exited before reaching the parent dialog that should resume.[br]
+## [br]
+## #### Parameters[br]
+## [br]
+## None.
+## [br]
+## #### Returns[br]
+## [br]
+## Returns `true` if additional dialog levels must still be unwound, otherwise `false`. (`bool`)
+func has_levels_left() -> bool:
+ return _levels_left > 0
+
+
+## Advances the dialog-break state upward by one dialog level.[br]
+## [br]
+## #### Parameters[br]
+## [br]
+## None.
+## [br]
+## #### Returns[br]
+## [br]
+## Returns nothing.
+func advance_up_one_level() -> void:
+ if _levels_left > 0:
+ _levels_left -= 1
+
+ if _levels_left == 0:
+ _resume_parent_dialog = true
+
+
+## Marks the dialog-break state so the receiving dialog frame resumes its own option loop instead of concluding.[br]
+## [br]
+## #### Parameters[br]
+## [br]
+## None.
+## [br]
+## #### Returns[br]
+## [br]
+## Returns nothing.
+func mark_resume_parent_dialog() -> void:
+ _resume_parent_dialog = true
+
+
+## Returns whether the receiving dialog frame should resume its option loop.[br]
+## [br]
+## #### Parameters[br]
+## [br]
+## None.
+## [br]
+## #### Returns[br]
+## [br]
+## Returns `true` if the parent dialog should resume, otherwise `false`. (`bool`)
+func should_resume_parent_dialog() -> bool:
+ return _resume_parent_dialog
+
+
+## Clears the resume-parent-dialog state after it has been consumed by a dialog frame.[br]
## [br]
## #### Parameters[br]
## [br]
@@ -45,5 +102,5 @@ func get_levels_left() -> int:
## #### Returns[br]
## [br]
## Returns nothing.
-func dec_levels_left() -> void:
- _levels_left = _levels_left - 1
+func consume_parent_resume() -> void:
+ _resume_parent_dialog = false
diff --git a/addons/escoria-core/game/core-scripts/esc/compiler/esc_environment.gd b/addons/escoria-core/game/core-scripts/esc/compiler/esc_environment.gd
index d63c52b..f89bed9 100644
--- a/addons/escoria-core/game/core-scripts/esc/compiler/esc_environment.gd
+++ b/addons/escoria-core/game/core-scripts/esc/compiler/esc_environment.gd
@@ -2,8 +2,8 @@
##
## Scoping is implemented using this class, including traditional scoping rules.
## Scope binding and resolution are handled in this class.
-extends Object
class_name ESCEnvironment
+extends Object
var _enclosing: # ESCEnvironment
diff --git a/addons/escoria-core/game/core-scripts/esc/compiler/esc_grammar_expr.gd b/addons/escoria-core/game/core-scripts/esc/compiler/esc_grammar_expr.gd
index 0e8bda8..ee94810 100644
--- a/addons/escoria-core/game/core-scripts/esc/compiler/esc_grammar_expr.gd
+++ b/addons/escoria-core/game/core-scripts/esc/compiler/esc_grammar_expr.gd
@@ -3,8 +3,8 @@
## All inheriting classes must implement an `accept` method to invoke the visitor.
## For more information on the "Visitor" pattern, see:
## (Visitor Pattern)[https://en.wikipedia.org/wiki/Visitor_pattern]
-extends RefCounted
class_name ESCGrammarExpr
+extends RefCounted
## Method that invokes another method in the visitor against this, the implementing class.[br]
@@ -18,5 +18,5 @@ class_name ESCGrammarExpr
## #### Returns[br]
## [br]
## Returns nothing.
-func accept(visitor):
+func accept(_visitor):
pass
diff --git a/addons/escoria-core/game/core-scripts/esc/compiler/esc_grammar_stmt.gd b/addons/escoria-core/game/core-scripts/esc/compiler/esc_grammar_stmt.gd
index 1793f0e..126e8cc 100644
--- a/addons/escoria-core/game/core-scripts/esc/compiler/esc_grammar_stmt.gd
+++ b/addons/escoria-core/game/core-scripts/esc/compiler/esc_grammar_stmt.gd
@@ -3,8 +3,8 @@
## All inheriting classes must implement an `accept` method to invoke the visitor.
## For more information on the "Visitor" pattern, see:
## (Visitor Pattern)[https://en.wikipedia.org/wiki/Visitor_pattern]
-extends RefCounted
class_name ESCGrammarStmt
+extends RefCounted
## Method that invokes another method in the visitor against this, the implementing class.[br]
@@ -18,5 +18,5 @@ class_name ESCGrammarStmt
## #### Returns[br]
## [br]
## Returns nothing.
-func accept(visitor):
+func accept(_visitor):
pass
diff --git a/addons/escoria-core/game/core-scripts/esc/compiler/esc_grammar_stmts.gd b/addons/escoria-core/game/core-scripts/esc/compiler/esc_grammar_stmts.gd
index 2e9c575..07c197c 100644
--- a/addons/escoria-core/game/core-scripts/esc/compiler/esc_grammar_stmts.gd
+++ b/addons/escoria-core/game/core-scripts/esc/compiler/esc_grammar_stmts.gd
@@ -154,6 +154,27 @@ class Event extends ESCGrammarStmt:
## [br]
signal interrupted
+ ## Valid event flags[br]
+ ##[br]
+ ## * TK: stands for "telekinetic". It means the player won't walk over to
+ ## the item to say the line.[br]
+ ## * NO_TT: stands for "No tooltip". It hides the tooltip for the duration of
+ ## the event. Probably not very useful, because events having multiple
+ ## say commands in them are automatically hidden.[br]
+ ## * NO_UI: stands for "No User Inteface". It hides the UI for the duration of
+ ##  the event. Useful when you want something to look like a cut scene but not
+ ## disable input for skipping dialog.[br]
+ ## * NO_SAVE: disables saving. Use this in cut scenes and anywhere a
+ ## badly-timed autosave would leave your game in a messed-up state.
+ enum {
+ FLAG_TK = 1,
+ FLAG_NO_TT = 2,
+ FLAG_NO_UI = 4,
+ FLAG_NO_SAVE = 8
+ }
+
+ var source: String = "" # TODO: Make proper use of this
+
var _name: ESCToken:
get = get_name
var _target: ESCGrammarExprs.Literal:
@@ -175,28 +196,6 @@ class Event extends ESCGrammarStmt:
var _is_interrupted: bool = false:
get = is_interrupted
- var source: String = "" # TODO: Make proper use of this
-
-
- ## Valid event flags[br]
- ##[br]
- ## * TK: stands for "telekinetic". It means the player won't walk over to
- ## the item to say the line.[br]
- ## * NO_TT: stands for "No tooltip". It hides the tooltip for the duration of
- ## the event. Probably not very useful, because events having multiple
- ## say commands in them are automatically hidden.[br]
- ## * NO_UI: stands for "No User Inteface". It hides the UI for the duration of
- ##  the event. Useful when you want something to look like a cut scene but not
- ## disable input for skipping dialog.[br]
- ## * NO_SAVE: disables saving. Use this in cut scenes and anywhere a
- ## badly-timed autosave would leave your game in a messed-up state.
- enum {
- FLAG_TK = 1,
- FLAG_NO_TT = 2,
- FLAG_NO_UI = 4,
- FLAG_NO_SAVE = 8
- }
-
## Initialization method. Must be called after instantiation.[br]
## [br]
@@ -784,6 +783,8 @@ class Stop extends ESCGrammarStmt:
## say("worker", "Because I work here.")[br]
##```
class DialogOption extends ESCGrammarStmt:
+ var _translation_key: String:
+ get = get_translation_key
var _option: ESCGrammarExpr:
get = get_option
var _condition: ESCGrammarExpr:
@@ -798,6 +799,7 @@ class DialogOption extends ESCGrammarStmt:
## [br]
## | Name | Type | Description | Required? |[br]
## |:-----|:-----|:------------|:----------|[br]
+ ## |translation_key|`String`|an optional translation key for the option text|yes|[br]
## |option|`ESCGrammarExpr`|the expression whose results will be displayed on screen as an option to be selected alongside any other options at the current level|yes|[br]
## |condition|`ESCGrammarExpr`|an optional condition to be evaluated that is used to determine whether the option should be displayed at all|yes|[br]
## |body|`ESCGrammarStmt`|the block of statements to be executed should this dialog option be selected|yes|[br]
@@ -805,12 +807,26 @@ class DialogOption extends ESCGrammarStmt:
## #### Returns[br]
## [br]
## Returns nothing.
- func init(option: ESCGrammarExpr, condition: ESCGrammarExpr, body: ESCGrammarStmt):
+ func init(translation_key: String, option: ESCGrammarExpr, condition: ESCGrammarExpr, body: ESCGrammarStmt):
+ _translation_key = translation_key
_option = option
_condition = condition
_body = body
+ ## The translation key for this option, if one exists.[br]
+ ## [br]
+ ## #### Parameters[br]
+ ## [br]
+ ## None.
+ ## [br]
+ ## #### Returns[br]
+ ## [br]
+ ## Returns the translation key for this option, if one exists. (`String`)
+ func get_translation_key() -> String:
+ return _translation_key
+
+
## The option expression.[br]
## [br]
## #### Parameters[br]
diff --git a/addons/escoria-core/game/core-scripts/esc/compiler/esc_interpreter.gd b/addons/escoria-core/game/core-scripts/esc/compiler/esc_interpreter.gd
index 0944486..2097890 100644
--- a/addons/escoria-core/game/core-scripts/esc/compiler/esc_interpreter.gd
+++ b/addons/escoria-core/game/core-scripts/esc/compiler/esc_interpreter.gd
@@ -1,6 +1,6 @@
## The actual interpreter that processes a parsed ASHES script.
-extends RefCounted
class_name ESCInterpreter
+extends RefCounted
## Used to represent the current player character in scripts.
@@ -26,6 +26,7 @@ var _locals: Dictionary = {}
# Still, this should be tested extensively, and, if at all possible, with multiple
# concurrent events running.
var _current_event: ESCGrammarStmts.Event
+var _dialog_depth: int = 0
# While most of the time we only run a single event at a time, it is possible for
# multiple events to
@@ -34,10 +35,12 @@ var _event_stack: Array = []
var _builtin_functions: Array = [
"print"
]
+var _channel_name: String = ""
-func _init(callables: Array, globals: Dictionary):
+func _init(callables: Array, globals: Dictionary, channel_name: String = ""):
_globals = ESCEnvironment.new()
+ _channel_name = channel_name
for callable in callables:
_globals.define(callable.get_command_name(), callable)
@@ -77,6 +80,19 @@ func get_global_values() -> Dictionary:
return _globals.get_values()
+## Gets the event-manager channel this interpreter is executing on.[br]
+## [br]
+## #### Parameters[br]
+## [br]
+## None.
+## [br]
+## #### Returns[br]
+## [br]
+## Returns the channel name associated with this interpreter run. (`String`)
+func get_channel_name() -> String:
+ return _channel_name
+
+
## Resets the interpreter, specifically any locally-scoped variables.[br]
## [br]
## #### Parameters[br]
@@ -253,13 +269,15 @@ func visit_call_expr(expr: ESCGrammarExprs.Call):
self,
"Can only call valid commands."
)
- else:
- return _handle_builtin_function(callee, args)
+ return ESCExecution.RC_ERROR
+
+ return _handle_builtin_function(callee, args)
var command = ESCCommand.new()
command.parameters = args
command.name = callee.get_command_name()
command.parser_token = expr.get_paren_token()
+ command.channel_name = _channel_name
var rc = ESCExecution.RC_OK
@@ -282,11 +300,12 @@ func _handle_builtin_function(fn_name: String, args: Array) -> int:
match fn_name:
'print':
- if args.size() > 1:
+ if args.size() != 1:
escoria.logger.error(
self,
- "'print' only takes one argument"
+ "'print' expects exactly one argument"
)
+ return rc
_print(args)
rc = ESCExecution.RC_OK
@@ -315,13 +334,13 @@ func _print(value):
func visit_if_stmt(stmt: ESCGrammarStmts.If):
if _is_truthy(await _evaluate(stmt.get_condition())):
return await _execute(stmt.get_then_branch())
- else:
- for branch in stmt.get_elif_branches():
- if _is_truthy(await _evaluate(branch.get_condition())):
- return await _execute(branch)
- if stmt.get_else_branch():
- return await _execute(stmt.get_else_branch())
+ for branch in stmt.get_elif_branches():
+ if _is_truthy(await _evaluate(branch.get_condition())):
+ return await _execute(branch)
+
+ if stmt.get_else_branch():
+ return await _execute(stmt.get_else_branch())
return null
@@ -344,6 +363,9 @@ func visit_while_stmt(stmt: ESCGrammarStmts.While):
if ret is ESCGrammarStmts.Break:
break
+ if _is_terminal_control_flow(ret):
+ return ret
+
return null
@@ -358,10 +380,23 @@ func visit_while_stmt(stmt: ESCGrammarStmts.While):
## #### Returns[br]
## [br]
## Returns nothing.
-func visit_pass_stmt(stmt: ESCGrammarStmts.Pass):
+func visit_pass_stmt(_stmt: ESCGrammarStmts.Pass):
pass
+func _is_terminal_control_flow(ret) -> bool:
+ if ret is ESCGrammarStmts.Stop \
+ or ret is ESCGrammarStmts.Done \
+ or ret is ESCBreakCounter:
+ return true
+
+ if typeof(ret) == TYPE_INT:
+ return ret == ESCExecution.RC_ERROR \
+ or ret == ESCExecution.RC_INTERRUPTED
+
+ return false
+
+
## Executes code relevant to interpreting a `stop` statement. Relevant only to dialogs.[br]
## [br]
## #### Parameters[br]
@@ -438,14 +473,76 @@ func visit_global_stmt(stmt: ESCGrammarStmts.Global):
func visit_dialog_stmt(stmt: ESCGrammarStmts.Dialog):
var dialog: ESCDialog = ESCDialog.new()
var rc = ESCExecution.RC_OK
+ var dialog_args := stmt.get_args()
+ var dialog_options := stmt.get_options()
+
+ _dialog_depth += 1
+ dialog.authored_options_count = dialog_options.size()
+
+ if dialog_args.size() > 0:
+ var avatar = await _evaluate(dialog_args[0])
+
+ if avatar != null and not avatar is String and not avatar is StringName:
+ escoria.logger.error(
+ self,
+ "Dialog avatar must evaluate to a String."
+ )
+ _dialog_depth -= 1
+ return ESCExecution.RC_ERROR
+
+ dialog.avatar = str(avatar)
+
+ if dialog_args.size() > 1:
+ var timeout = await _evaluate(dialog_args[1])
+
+ if not timeout is int and not timeout is float:
+ escoria.logger.error(
+ self,
+ "Dialog timeout must evaluate to a number."
+ )
+ _dialog_depth -= 1
+ return ESCExecution.RC_ERROR
+
+ if timeout < 0:
+ escoria.logger.error(
+ self,
+ "Dialog timeout must be greater than or equal to 0."
+ )
+ _dialog_depth -= 1
+ return ESCExecution.RC_ERROR
+
+ dialog.timeout = int(timeout)
+
+ if dialog_args.size() > 2:
+ var timeout_option = await _evaluate(dialog_args[2])
+
+ if not timeout_option is int and not timeout_option is float:
+ escoria.logger.error(
+ self,
+ "Dialog timeout option must evaluate to a number."
+ )
+ _dialog_depth -= 1
+ return ESCExecution.RC_ERROR
+
+ if timeout_option < 0:
+ escoria.logger.error(
+ self,
+ "Dialog timeout option must be greater than or equal to 0."
+ )
+ _dialog_depth -= 1
+ return ESCExecution.RC_ERROR
+
+ dialog.timeout_option = int(timeout_option)
while true:
dialog.options = []
- for dialog_option in stmt.get_options():
+ for index in range(dialog_options.size()):
+ var dialog_option = dialog_options[index]
var option: ESCDialogOption = ESCDialogOption.new()
- # TODO: Translation keys
option.source_option = dialog_option
+ option.source_option_index = index + 1
+ option.translation_key = dialog_option.get_translation_key()
option.option = await _evaluate(dialog_option.get_option())
if dialog_option.get_condition():
@@ -453,12 +550,23 @@ func visit_dialog_stmt(stmt: ESCGrammarStmts.Dialog):
else:
option.set_is_valid(true)
- dialog.options.append(option)
+ # Dialog execution should stop once no valid options remain. Keep only
+ # currently valid options in the presented list so an exhausted dialog
+ # concludes instead of re-running forever with unselectable entries.
+ if option.is_valid():
+ dialog.options.append(option)
if dialog.options.size() == 0:
break
- if dialog.is_valid() and not _current_event.is_interrupted():
+ # If the event was interrupted while a nested command or dialog body was
+ # active, stop the dialog frame immediately instead of looping and
+ # presenting options again.
+ if _current_event and _current_event.is_interrupted():
+ _dialog_depth -= 1
+ return ESCExecution.RC_INTERRUPTED
+
+ if dialog.is_valid():
var chosen_option = await dialog.run()
if chosen_option:
@@ -468,22 +576,73 @@ func visit_dialog_stmt(stmt: ESCGrammarStmts.Dialog):
"Chosen dialog option (%s) was completed." % chosen_option
)
- if execute_ret is ESCGrammarStmts.Break:
- var break_tracker: ESCBreakCounter = ESCBreakCounter.new()
+ # Dialog frames must propagate terminal runtime errors the same
+ # way normal blocks do. Otherwise an invalid command or similar
+ # failure inside an option body is treated like normal completion
+ # and the dialog loop re-displays the same options indefinitely.
+ if typeof(execute_ret) == TYPE_INT and execute_ret == ESCExecution.RC_ERROR:
+ _dialog_depth -= 1
+ return ESCExecution.RC_ERROR
+ # An interruption can happen while the chosen option body is still
+ # running, so check again after it returns before processing normal
+ # dialog control flow like `break`, `done`, or `stop`.
+ if _current_event and _current_event.is_interrupted():
+ _dialog_depth -= 1
+ return ESCExecution.RC_INTERRUPTED
+
+ if execute_ret is ESCGrammarStmts.Break:
+ var levels_left := 0
if execute_ret.get_levels():
- break_tracker.set_levels_left(await _evaluate(execute_ret.get_levels()) - 1)
+ levels_left = await _evaluate(execute_ret.get_levels()) - 1
+
+ # A top-level dialog consumes `break` by concluding the current dialog.
+ if _dialog_depth == 1:
+ break
+
+ # Nested dialogs propagate explicit break state upward so parent
+ # dialog frames can decide whether to keep unwinding or resume.
+ var break_tracker: ESCBreakCounter = ESCBreakCounter.new()
+ if levels_left > 0:
+ break_tracker.set_levels_left(levels_left)
else:
- break_tracker.set_levels_left(0)
+ break_tracker.mark_resume_parent_dialog()
+ _dialog_depth -= 1
return break_tracker
- elif execute_ret is ESCGrammarStmts.Done:
+ if execute_ret is ESCGrammarStmts.Done:
+ _dialog_depth -= 1
+
+ if _dialog_depth == 0:
+ return rc
+
return execute_ret
- elif execute_ret is ESCBreakCounter:
- if execute_ret.get_levels_left() > 0:
- execute_ret.dec_levels_left()
+
+ if execute_ret is ESCGrammarStmts.Stop:
+ # `stop` aborts the entire event, so dialog frames must pass it through.
+ _dialog_depth -= 1
+ return execute_ret
+
+ if execute_ret is ESCBreakCounter:
+ if execute_ret.has_levels_left():
+ # Once the unwind reaches the top-most dialog, the remaining
+ # levels are consumed by concluding that dialog entirely.
+ if _dialog_depth == 1:
+ break
+
+ execute_ret.advance_up_one_level()
+ _dialog_depth -= 1
return execute_ret
+ if execute_ret.should_resume_parent_dialog():
+ # The requested dialog levels have been exited, so this frame
+ # resumes presenting its own options instead of concluding.
+ execute_ret.consume_parent_resume()
+ continue
+
+ break
+
+ _dialog_depth -= 1
return rc
@@ -498,7 +657,7 @@ func visit_dialog_stmt(stmt: ESCGrammarStmts.Dialog):
## #### Returns[br]
## [br]
## Returns nothing.
-func visit_dialog_option_stmt(stmt: ESCGrammarStmts.DialogOption):
+func visit_dialog_option_stmt(_stmt: ESCGrammarStmts.DialogOption):
pass
@@ -623,18 +782,28 @@ func visit_binary_expr(expr: ESCGrammarExprs.Binary):
return not _is_equal(left_part, right_part)
ESCTokenType.TokenType.GREATER:
var check = _check_are_numbers(left_part, expr.get_operator(), right_part)
+ if not check:
+ return null
return left_part > right_part
ESCTokenType.TokenType.GREATER_EQUAL:
var check = _check_are_numbers(left_part, expr.get_operator(), right_part)
+ if not check:
+ return null
return left_part >= right_part
ESCTokenType.TokenType.LESS:
var check = _check_are_numbers(left_part, expr.get_operator(), right_part)
+ if not check:
+ return null
return left_part < right_part
ESCTokenType.TokenType.LESS_EQUAL:
var check = _check_are_numbers(left_part, expr.get_operator(), right_part)
+ if not check:
+ return null
return left_part <= right_part
ESCTokenType.TokenType.MINUS:
var check = _check_are_numbers(left_part, expr.get_operator(), right_part)
+ if not check:
+ return null
return left_part - right_part
ESCTokenType.TokenType.PLUS:
var check = _check_are_numbers(left_part, expr.get_operator(), right_part, false)
@@ -653,9 +822,13 @@ func visit_binary_expr(expr: ESCGrammarExprs.Binary):
)
ESCTokenType.TokenType.SLASH:
var check = _check_are_numbers(left_part, expr.get_operator(), right_part)
+ if not check:
+ return null
return left_part / right_part
ESCTokenType.TokenType.STAR:
var check = _check_are_numbers(left_part, expr.get_operator(), right_part)
+ if not check:
+ return null
return left_part * right_part
return null
@@ -680,6 +853,8 @@ func visit_unary_expr(expr: ESCGrammarExprs.Unary):
return not _is_truthy(right_part)
ESCTokenType.TokenType.MINUS:
var check = _check_is_number(right_part, expr.get_operator())
+ if not check:
+ return null
return -right_part
return null
@@ -793,8 +968,8 @@ func look_up_variable(name: ESCToken, expr: ESCGrammarExpr):
if distance == -1:
return _globals.get_value(name)
- else:
- return _environment.get_at(distance, name.get_lexeme())
+
+ return _environment.get_at(distance, name.get_lexeme())
# Private methods
@@ -860,10 +1035,18 @@ func _execute_block(statements: Array, env: ESCEnvironment):
for stmt in statements:
ret = await _execute(stmt)
- if ret is ESCGrammarStmts.Break \
- or ret is ESCGrammarStmts.Done \
- or ret is ESCGrammarStmts.Stop:
+ # If the running event was interrupted while this statement was active,
+ # stop the block immediately so later statements do not continue running.
+ if _current_event and _current_event.is_interrupted():
+ _environment = previous_env
+ return ESCExecution.RC_INTERRUPTED
+ if ret is ESCGrammarStmts.Break:
+ _environment = previous_env
+ return ret
+
+ if _is_terminal_control_flow(ret):
+ _environment = previous_env
return ret
# TODO: Proper error handling per statement?
@@ -925,12 +1108,12 @@ func _check_at_least_one_string(value_1, value_2):
return typeof(value_1) == TYPE_STRING || typeof(value_2) == TYPE_STRING
-func _on_global_changed(key: String, old_value, new_value) -> void:
+func _on_global_changed(key: String, _old_value, new_value) -> void:
# Shoehorn this in as an adapter
var token: ESCToken = ESCToken.new()
token.init(ESCTokenType.TokenType.IDENTIFIER, key, null, "", -1, "")
if _globals.get_values().has(key):
_globals.assign(token, new_value)
- elif escoria.save_manager.is_loading_game:
+ else:
_globals.define(key, new_value)
diff --git a/addons/escoria-core/game/core-scripts/esc/compiler/esc_interpreter_factory.gd b/addons/escoria-core/game/core-scripts/esc/compiler/esc_interpreter_factory.gd
index 4205f92..24f6c66 100644
--- a/addons/escoria-core/game/core-scripts/esc/compiler/esc_interpreter_factory.gd
+++ b/addons/escoria-core/game/core-scripts/esc/compiler/esc_interpreter_factory.gd
@@ -1,6 +1,10 @@
## Factory class for producing an ASHES interpreter.
-extends RefCounted
class_name ESCInterpreterFactory
+extends RefCounted
+
+const ESC_INTERPRETER_SCRIPT := preload(
+ "res://addons/escoria-core/game/core-scripts/esc/compiler/esc_interpreter.gd"
+)
static var _interpreter: ESCInterpreter = null
@@ -15,16 +19,64 @@ static var _interpreter: ESCInterpreter = null
## #### Returns[br]
## [br]
## Returns a `ESCInterpreter` value. (`ESCInterpreter`)
-static func create_interpreter() -> ESCInterpreter:
- if not _interpreter:
- _interpreter = load("res://addons/escoria-core/game/core-scripts/esc/compiler/esc_interpreter.gd").new(ESCCompiler.load_commands(), ESCCompiler.load_globals())
- return _interpreter
+static func create_interpreter(channel_name: String = "") -> ESCInterpreter:
+ return create_utility_interpreter(channel_name)
+
- _interpreter = load("res://addons/escoria-core/game/core-scripts/esc/compiler/esc_interpreter.gd").new([], _interpreter.get_global_values())
+## Produces an interpreter for non-runtime utility work such as resolving or
+## evaluating statements outside the event manager.[br]
+## [br]
+## #### Parameters[br]
+## [br]
+## | Name | Type | Description | Required? |[br]
+## |:-----|:-----|:------------|:----------|[br]
+## |channel_name|`String`|Optional channel name to assign to the created interpreter.|no|[br]
+## [br]
+## #### Returns[br]
+## [br]
+## Returns a cached-or-reseeded `ESCInterpreter` instance for utility usage. (`ESCInterpreter`)
+static func create_utility_interpreter(channel_name: String = "") -> ESCInterpreter:
+ if not _interpreter:
+ _interpreter = ESC_INTERPRETER_SCRIPT.new(
+ ESCCompiler.load_commands(),
+ ESCCompiler.load_globals(),
+ channel_name
+ )
+ else:
+ _interpreter = ESC_INTERPRETER_SCRIPT.new(
+ [],
+ _interpreter.get_global_values(),
+ channel_name
+ )
return _interpreter
+## Produces a fresh interpreter intended for event-manager runtime execution.[br]
+## [br]
+## #### Parameters[br]
+## [br]
+## | Name | Type | Description | Required? |[br]
+## |:-----|:-----|:------------|:----------|[br]
+## |channel_name|`String`|Optional channel name to assign to the created interpreter.|no|[br]
+## [br]
+## #### Returns[br]
+## [br]
+## Returns a newly-created `ESCInterpreter` instance for runtime usage. (`ESCInterpreter`)
+static func create_runtime_interpreter(channel_name: String = "") -> ESCInterpreter:
+ var runtime_globals := ESCCompiler.load_globals()
+
+ if not Engine.is_editor_hint() and escoria and escoria.globals_manager:
+ runtime_globals.merge(escoria.globals_manager.get_globals(), true)
+
+ var interpreter := ESC_INTERPRETER_SCRIPT.new(
+ ESCCompiler.load_commands(),
+ runtime_globals,
+ channel_name
+ )
+ return interpreter
+
+
static func reset_interpreter() -> void:
if is_instance_valid(_interpreter):
_interpreter.cleanup()
diff --git a/addons/escoria-core/game/core-scripts/esc/compiler/esc_parse_error.gd b/addons/escoria-core/game/core-scripts/esc/compiler/esc_parse_error.gd
index 5fd01a3..1bb5b19 100644
--- a/addons/escoria-core/game/core-scripts/esc/compiler/esc_parse_error.gd
+++ b/addons/escoria-core/game/core-scripts/esc/compiler/esc_parse_error.gd
@@ -1,3 +1,3 @@
## Class to represent an error that occured during parsing.
-extends Object
class_name ESCParseError
+extends Object
diff --git a/addons/escoria-core/game/core-scripts/esc/compiler/esc_parser.gd b/addons/escoria-core/game/core-scripts/esc/compiler/esc_parser.gd
index b88adcb..6229e34 100644
--- a/addons/escoria-core/game/core-scripts/esc/compiler/esc_parser.gd
+++ b/addons/escoria-core/game/core-scripts/esc/compiler/esc_parser.gd
@@ -4,8 +4,8 @@
## Note that the vast majority of this class consists of (effectively) private methods
## in order to facilitate encapsulation, but if you're interested in how the parser
## is implemented, [check out the class in GitHub](https://github.com/godot-escoria/escoria-demo-game/blob/main/addons/escoria-core/game/core-scripts/esc/compiler/esc_interpreter.gd)
-extends RefCounted
class_name ESCParser
+extends RefCounted
var _tokens: Array
@@ -52,48 +52,56 @@ func parse() -> Array:
var statements: Array = []
while not _at_end():
- statements.append(_declaration())
+ var declaration = _declaration()
+ if declaration != null:
+ statements.append(declaration)
return statements
func _declaration() -> ESCGrammarStmt:
- var retStmt
+ while _match(ESCTokenType.TokenType.NEWLINE) or _match(ESCTokenType.TokenType.DEDENT):
+ pass
+
+ if _at_end():
+ return null
+
+ var ret_stmt
if _match(ESCTokenType.TokenType.COLON):
- retStmt = _event_declaration()
+ ret_stmt = _event_declaration()
- if retStmt is ESCParseError:
+ if ret_stmt is ESCParseError:
_synchronize()
return null
- else:
- return retStmt
+
+ return ret_stmt
if _match(ESCTokenType.TokenType.VAR):
- retStmt = _var_declaration()
+ ret_stmt = _var_declaration()
- if retStmt is ESCParseError:
+ if ret_stmt is ESCParseError:
_synchronize()
return null
- else:
- return retStmt
+
+ return ret_stmt
if _match(ESCTokenType.TokenType.GLOBAL):
- retStmt = _global_declaration()
+ ret_stmt = _global_declaration()
- if retStmt is ESCParseError:
+ if ret_stmt is ESCParseError:
_synchronize()
return null
- else:
- return retStmt
- retStmt = _statement()
+ return ret_stmt
+
+ ret_stmt = _statement()
- if retStmt is ESCParseError:
+ if ret_stmt is ESCParseError:
_synchronize()
return null
- return retStmt
+ return ret_stmt
func _event_declaration():
@@ -157,8 +165,8 @@ func _event_declaration():
ret.init(name, target, flags, body, _associated_object_global_id)
return ret
- else:
- return _error(_peek(), "Expected block after event declaration for '%s'. Code blocks require tab(s) at the start of a line." % name.get_lexeme())
+
+ return _error(_peek(), "Expected block after event declaration for '%s'. Code blocks require tab(s) at the start of a line." % name.get_lexeme())
func _literal_from_identifier(expr: ESCGrammarExprs.Variable) -> ESCGrammarExprs.Literal:
@@ -314,21 +322,25 @@ func _while_statement():
var condition = _expression()
if condition is ESCParseError:
+ _loop_level -= 1
return condition
var colon_token = _consume(ESCTokenType.TokenType.COLON, "Expect ':' after condition.")
if colon_token is ESCParseError:
+ _loop_level -= 1
return colon_token
var consume = _consume_new_block_start("start of while loop")
if consume:
+ _loop_level -= 1
return consume
var block = _block()
if block is ESCParseError:
+ _loop_level -= 1
return block
var body = ESCGrammarStmts.Block.new()
@@ -372,6 +384,7 @@ func _dialog_statement():
var arg = _expression()
if arg is ESCParseError:
+ _dialog_level -= 1
return arg
args.append(arg)
@@ -382,14 +395,32 @@ func _dialog_statement():
var consume = _consume(ESCTokenType.TokenType.RIGHT_PAREN, "Expect ')' after start dialog arguments.")
if consume is ESCParseError:
+ _dialog_level -= 1
return consume
+ elif not _check(ESCTokenType.TokenType.NEWLINE):
+ while true:
+ var arg = _expression()
+
+ if arg is ESCParseError:
+ _dialog_level -= 1
+ return arg
+
+ args.append(arg)
+
+ if _check(ESCTokenType.TokenType.NEWLINE):
+ break
+
+ if _match(ESCTokenType.TokenType.COMMA):
+ continue
if args.size() > 3:
+ _dialog_level -= 1
return _error(_peek(), "Start dialog cannot have more than 3 arguments.")
var consume = _consume_new_block_start("dialog start")
if consume is ESCParseError:
+ _dialog_level -= 1
return consume
var options: Array = []
@@ -398,6 +429,7 @@ func _dialog_statement():
var dialog_option = _dialog_option_statement()
if dialog_option is ESCParseError:
+ _dialog_level -= 1
return dialog_option
options.append(dialog_option)
@@ -433,6 +465,14 @@ func _dialog_option_statement():
if consume is ESCParseError:
return consume
+ var translation_key := ""
+
+ if _match_in_order([
+ ESCTokenType.TokenType.IDENTIFIER,
+ ESCTokenType.TokenType.COLON
+ ]):
+ translation_key = _tokens[_current - 2].get_lexeme()
+
var expr = _expression()
if expr is ESCParseError:
@@ -448,8 +488,14 @@ func _dialog_option_statement():
consume = _consume(ESCTokenType.TokenType.RIGHT_SQUARE, "Expect ']' after dialog option condition")
+ if consume is ESCParseError:
+ return consume
+
consume = _consume_new_block_start("dialog option")
+ if consume is ESCParseError:
+ return consume
+
var block_stmts = _block()
if block_stmts is ESCParseError:
@@ -459,7 +505,7 @@ func _dialog_option_statement():
block.init(block_stmts)
var option: ESCGrammarStmts.DialogOption = ESCGrammarStmts.DialogOption.new()
- option.init(expr, condition, block)
+ option.init(translation_key, expr, condition, block)
return option
@@ -512,7 +558,8 @@ func _block():
if decl is ESCParseError:
return decl
- statements.append(decl)
+ if decl != null:
+ statements.append(decl)
_consume(ESCTokenType.TokenType.DEDENT, "Expected DEDENT after block.")
return statements
@@ -536,7 +583,8 @@ func _assignment():
var ret = ESCGrammarExprs.Assign.new()
ret.init(name, value)
return ret
- elif expr is ESCGrammarExprs.Get:
+
+ if expr is ESCGrammarExprs.Get:
var ret = ESCGrammarExprs.Set.new()
ret.init(expr.get_object(), expr.get_name(), value)
return ret
@@ -723,15 +771,15 @@ func _is_checking():
var ret = ESCGrammarExprs.Is.new()
ret.init(expr, null, _previous())
return ret
- else:
- var state_expr = _expression()
- if state_expr is ESCParseError:
- return state_expr
+ var state_expr = _expression()
- var ret = ESCGrammarExprs.Is.new()
- ret.init(expr, state_expr, null)
- return ret
+ if state_expr is ESCParseError:
+ return state_expr
+
+ var ret = ESCGrammarExprs.Is.new()
+ ret.init(expr, state_expr, null)
+ return ret
return expr
@@ -777,6 +825,9 @@ func _finish_call(callee: ESCGrammarExpr):
var paren = _consume(ESCTokenType.TokenType.RIGHT_PAREN, "Expect ')' after arguments.")
+ if paren is ESCParseError:
+ return paren
+
#if paren.get_type() != ESCTokenType.TokenType.NEWLINE:
# return _error(ESCTokenType.TokenType.NEWLINE, "Expect NEWLINE after arguments.")
@@ -817,7 +868,13 @@ func _primary():
if expr is ESCParseError:
return expr
- _consume(ESCTokenType.TokenType.RIGHT_PAREN, "Expect ')' after expression.")
+ var paren = _consume(
+ ESCTokenType.TokenType.RIGHT_PAREN,
+ "Expect ')' after expression."
+ )
+
+ if paren is ESCParseError:
+ return paren
var ret = ESCGrammarExprs.Grouping.new()
ret.init(expr)
@@ -826,30 +883,52 @@ func _primary():
return _error(_peek(), "Expect expression.")
-func _var_declaration() -> ESCGrammarStmt:
+func _var_declaration():
var name = _consume(ESCTokenType.TokenType.IDENTIFIER, "Expect variable name.")
var initializer: ESCGrammarExpr = null
if _match(ESCTokenType.TokenType.EQUAL):
- initializer = _expression()
+ var initializer_expr = _expression()
+
+ if initializer_expr is ESCParseError:
+ return initializer_expr
+
+ initializer = initializer_expr
+
+ var newline = _consume(
+ ESCTokenType.TokenType.NEWLINE,
+ "Expect newline after variable declaration."
+ )
- _consume(ESCTokenType.TokenType.NEWLINE, "Expect newline after variable declaration.")
+ if newline is ESCParseError:
+ return newline
var ret = ESCGrammarStmts.Var.new()
ret.init(name, initializer)
return ret
-func _global_declaration() -> ESCGrammarStmt:
+func _global_declaration():
var name = _consume(ESCTokenType.TokenType.IDENTIFIER, "Expect global variable name.")
var initializer: ESCGrammarExpr = null
if _match(ESCTokenType.TokenType.EQUAL):
- initializer = _expression()
+ var initializer_expr = _expression()
- _consume(ESCTokenType.TokenType.NEWLINE, "Expect newline after global variable declaration.")
+ if initializer_expr is ESCParseError:
+ return initializer_expr
+
+ initializer = initializer_expr
+
+ var newline = _consume(
+ ESCTokenType.TokenType.NEWLINE,
+ "Expect newline after global variable declaration."
+ )
+
+ if newline is ESCParseError:
+ return newline
var ret = ESCGrammarStmts.Global.new()
ret.init(name, initializer)
@@ -864,11 +943,11 @@ func _peek() -> ESCToken:
return _tokens[_current]
-func _match(tokenTypes) -> bool:
- if not tokenTypes is Array:
- tokenTypes = [tokenTypes]
+func _match(token_types) -> bool:
+ if not token_types is Array:
+ token_types = [token_types]
- for type in tokenTypes:
+ for type in token_types:
if _check(type):
_advance()
return true
@@ -876,12 +955,15 @@ func _match(tokenTypes) -> bool:
return false
-func _match_in_order(tokenTypes) -> bool:
- if not tokenTypes is Array:
- tokenTypes = [tokenTypes]
+func _match_in_order(token_types) -> bool:
+ if not token_types is Array:
+ token_types = [token_types]
- for type in tokenTypes:
+ var start := _current
+
+ for type in token_types:
if not _check(type):
+ _current = start
return false
_advance()
@@ -889,21 +971,21 @@ func _match_in_order(tokenTypes) -> bool:
return true
-func _consume(tokenType, message: String):
- if _check(tokenType):
+func _consume(token_type, message: String):
+ if _check(token_type):
return _advance()
return _error(_peek(), message)
-func _check(tokenTypes) -> bool:
- if not tokenTypes is Array:
- tokenTypes = [tokenTypes]
+func _check(token_types) -> bool:
+ if not token_types is Array:
+ token_types = [token_types]
if _at_end():
return false
- for type in tokenTypes:
+ for type in token_types:
if _peek().get_type() == type:
return true
@@ -911,9 +993,9 @@ func _check(tokenTypes) -> bool:
# This turns the parser into an LL(2).
-func _check_next(tokenTypes) -> bool:
- if not tokenTypes is Array:
- tokenTypes = [tokenTypes]
+func _check_next(token_types) -> bool:
+ if not token_types is Array:
+ token_types = [token_types]
if _at_end():
return false
@@ -924,7 +1006,7 @@ func _check_next(tokenTypes) -> bool:
_current -= 1
return false
- for type in tokenTypes:
+ for type in token_types:
if _peek().get_type() == type:
_current -= 1
return true
@@ -959,16 +1041,27 @@ func _error(token: ESCToken, message: String) -> ESCParseError:
func _synchronize() -> void:
+ if _check(ESCTokenType.TokenType.DEDENT):
+ return
+
_advance()
while not _at_end():
- if _previous().get_type() == ESCTokenType.TokenType.NEWLINE:
+ if _previous().get_type() == ESCTokenType.TokenType.NEWLINE \
+ or _previous().get_type() == ESCTokenType.TokenType.DEDENT:
return
match _peek().get_type():
+ ESCTokenType.TokenType.COLON,\
+ ESCTokenType.TokenType.GLOBAL,\
ESCTokenType.TokenType.VAR,\
ESCTokenType.TokenType.IF,\
ESCTokenType.TokenType.WHILE,\
+ ESCTokenType.TokenType.PASS,\
+ ESCTokenType.TokenType.STOP,\
+ ESCTokenType.TokenType.QUESTION_BANG,\
+ ESCTokenType.TokenType.BREAK,\
+ ESCTokenType.TokenType.DONE,\
ESCTokenType.TokenType.RETURN:
return
diff --git a/addons/escoria-core/game/core-scripts/esc/compiler/esc_resolver.gd b/addons/escoria-core/game/core-scripts/esc/compiler/esc_resolver.gd
index 2b32b35..d356b85 100644
--- a/addons/escoria-core/game/core-scripts/esc/compiler/esc_resolver.gd
+++ b/addons/escoria-core/game/core-scripts/esc/compiler/esc_resolver.gd
@@ -1,8 +1,8 @@
## Resolves script variables to ensure that scoping rules are obeyed.
##
## The class will throw errors if scoping rules are broken or otherwise not followed.
-extends RefCounted
class_name ESCResolver
+extends RefCounted
var _interpreter
@@ -136,7 +136,7 @@ func visit_while_stmt(stmt: ESCGrammarStmts.While):
## #### Returns[br]
## [br]
## Returns nothing.
-func visit_pass_stmt(stmt: ESCGrammarStmts.Pass):
+func visit_pass_stmt(_stmt: ESCGrammarStmts.Pass):
pass
@@ -151,7 +151,7 @@ func visit_pass_stmt(stmt: ESCGrammarStmts.Pass):
## #### Returns[br]
## [br]
## Returns nothing.
-func visit_stop_stmt(stmt: ESCGrammarStmts.Stop):
+func visit_stop_stmt(_stmt: ESCGrammarStmts.Stop):
pass
@@ -186,7 +186,7 @@ func visit_var_stmt(stmt: ESCGrammarStmts.Var):
## #### Returns[br]
## [br]
## Returns nothing.
-func visit_global_stmt(stmt: ESCGrammarStmts.Global):
+func visit_global_stmt(_stmt: ESCGrammarStmts.Global):
pass
@@ -237,7 +237,7 @@ func visit_break_stmt(stmt: ESCGrammarStmts.Break):
## #### Returns[br]
## [br]
## Returns nothing.
-func visit_done_stmt(stmt: ESCGrammarStmts.Done):
+func visit_done_stmt(_stmt: ESCGrammarStmts.Done):
pass
@@ -270,7 +270,7 @@ func visit_dialog_stmt(stmt: ESCGrammarStmts.Dialog):
## #### Returns[br]
## [br]
## Returns nothing.
-func visit_literal_expr(expr: ESCGrammarExprs.Literal):
+func visit_literal_expr(_expr: ESCGrammarExprs.Literal):
pass
diff --git a/addons/escoria-core/game/core-scripts/esc/compiler/esc_scanner.gd b/addons/escoria-core/game/core-scripts/esc/compiler/esc_scanner.gd
index 08642a9..6591c48 100644
--- a/addons/escoria-core/game/core-scripts/esc/compiler/esc_scanner.gd
+++ b/addons/escoria-core/game/core-scripts/esc/compiler/esc_scanner.gd
@@ -3,8 +3,8 @@
## This is the first link in the ASHES compiler toolchain, and takes in ASHES
## script as text in order to provide a list of tokens to be handled by the
## ASHES parser.
-extends RefCounted
class_name ESCScanner
+extends RefCounted
## In ASHES, an identifier starting with `$` is interpreted as a lookup in
diff --git a/addons/escoria-core/game/core-scripts/esc/compiler/esc_script_builder.gd b/addons/escoria-core/game/core-scripts/esc/compiler/esc_script_builder.gd
index 46ba408..26dacce 100644
--- a/addons/escoria-core/game/core-scripts/esc/compiler/esc_script_builder.gd
+++ b/addons/escoria-core/game/core-scripts/esc/compiler/esc_script_builder.gd
@@ -1,7 +1,7 @@
## Convenience class to help build scripts in code for use with the ASHES compiler
## toolchain. Loosely follows the Builder pattern.
-extends RefCounted
class_name ESCScriptBuilder
+extends RefCounted
# Not really a "Builder" pattern per se, but helps with readability.
diff --git a/addons/escoria-core/game/core-scripts/esc/compiler/esc_token.gd b/addons/escoria-core/game/core-scripts/esc/compiler/esc_token.gd
index ec95d98..bd99d73 100644
--- a/addons/escoria-core/game/core-scripts/esc/compiler/esc_token.gd
+++ b/addons/escoria-core/game/core-scripts/esc/compiler/esc_token.gd
@@ -3,11 +3,11 @@
##
## This class contains any information required by the parser but also carries
## with it associated information useful for debugging and tracing purposes.
-extends RefCounted
class_name ESCToken
+extends RefCounted
-var _tokenType: int: # ESCScanner.TokenType enum
+var _token_type: int: # ESCScanner.TokenType enum
get = get_type
var _lexeme: String:
get = get_lexeme
@@ -38,8 +38,8 @@ var _filename: String:
## #### Returns[br]
## [br]
## Returns nothing.
-func init(tokenType: int, lexeme: String, literal, source: String, line: int, filename: String) -> void:
- _tokenType = tokenType
+func init(token_type: int, lexeme: String, literal, source: String, line: int, filename: String) -> void:
+ _token_type = token_type
_lexeme = lexeme
_literal = literal
_source = source
@@ -85,7 +85,7 @@ func get_source() -> String:
## [br]
## Returns the type of token this is; will be a value from `ESCTokenType.TokenType`. (`int`)
func get_type() -> int:
- return _tokenType
+ return _token_type
## The literal value of the token, if it exists.[br]
@@ -141,4 +141,4 @@ func get_filename() -> String:
func _to_string() -> String:
- return ESCTokenType.get_token_type_name(_tokenType) + " " + str(_lexeme) + " " + (str(_literal) if _literal else "")
+ return ESCTokenType.get_token_type_name(_token_type) + " " + str(_lexeme) + " " + (str(_literal) if _literal else "")
diff --git a/addons/escoria-core/game/core-scripts/esc/esc_action_manager.gd b/addons/escoria-core/game/core-scripts/esc/esc_action_manager.gd
index 7bf4a37..8e5c596 100644
--- a/addons/escoria-core/game/core-scripts/esc/esc_action_manager.gd
+++ b/addons/escoria-core/game/core-scripts/esc/esc_action_manager.gd
@@ -1,11 +1,7 @@
## Manages actions currently being carried out.
## @MANAGER
-extends Resource
class_name ESCActionManager
-
-
-## ESCPlayer resource
-const ESCPlayer = preload("res://addons/escoria-core/game/core-scripts/esc_player.gd")
+extends Resource
## The current action verb was changed.[br]
@@ -39,10 +35,10 @@ signal action_input_state_changed
## (I) -> AWAITING_VERB_OR_ITEM -> AWAITING_ITEM -> AWAITING_TARGET_ITEM -> COMPLETED -> (E)[br]
## or[br]
## (I) -> AWAITING_VERB_OR_ITEM -> AWAITING_VERB -> AWAITING_VERB_CONFIRMATION -> COMPLETED -> (E)
-enum ACTION_INPUT_STATE {
+enum ActionInputState {
AWAITING_VERB_OR_ITEM, ## Initial state
AWAITING_ITEM, ## After initial state, verb is defined
- AWAITING_TARGET_ITEM, ## Item defined requires combine, waiting for target
+ AWAITING_TARGET_ITEM, ## Item defined requires a target object
AWAITING_VERB, ## After initial state, item is defined
AWAITING_VERB_CONFIRMATION, ## Item was defined first, next verb, need verb confirmation
COMPLETED ## Final state
@@ -65,6 +61,9 @@ enum ACTION {
# Basic required internal actions
+## ESCPlayer resource
+const ESCPlayer = preload("res://addons/escoria-core/game/core-scripts/esc_player.gd")
+
## Action (event) triggered when a character has reached a destination.
const ACTION_ARRIVED = "arrived"
@@ -85,7 +84,7 @@ var current_tool: ESCObject
var current_target: ESCObject
## Current action input state.
-var action_state = ACTION_INPUT_STATE.AWAITING_VERB_OR_ITEM:
+var action_state = ActionInputState.AWAITING_VERB_OR_ITEM:
set = set_action_input_state
@@ -103,7 +102,7 @@ var action_state = ACTION_INPUT_STATE.AWAITING_VERB_OR_ITEM:
## [br]
## Returns nothing.
func do(action: int, params: Array = [], can_interrupt: bool = false) -> void:
- if escoria.current_state == escoria.GAME_STATE.DEFAULT:
+ if escoria.current_state == escoria.GameState.DEFAULT:
match action:
ACTION.BACKGROUND_CLICK:
if can_interrupt:
@@ -172,6 +171,7 @@ func do(action: int, params: Array = [], can_interrupt: bool = false) -> void:
var trigger_id = params[0]
var object_id = params[1]
var trigger_in_verb = params[2]
+ var trigger_object := escoria.object_manager.get_object(trigger_id)
escoria.logger.info(
self,
"trigger_in on trigger %s activated by %s." % [
@@ -179,12 +179,17 @@ func do(action: int, params: Array = [], can_interrupt: bool = false) -> void:
object_id
]
)
- if trigger_in_verb in escoria.object_manager.get_object(trigger_id).events:
- escoria.event_manager.queue_event(
- escoria.object_manager.get_object(trigger_id).events[
- trigger_in_verb
- ]
+
+ if not _is_object_actionable(trigger_object):
+ escoria.logger.info(
+ self,
+ "Trigger %s is not actionable. Skipping trigger_in." % trigger_id
)
+ return
+
+ var trigger_in_event = _get_trigger_event(trigger_object, trigger_in_verb, object_id)
+ if trigger_in_event:
+ escoria.event_manager.queue_event(trigger_in_event)
else:
escoria.logger.info(
self,
@@ -195,6 +200,7 @@ func do(action: int, params: Array = [], can_interrupt: bool = false) -> void:
var trigger_id = params[0]
var object_id = params[1]
var trigger_out_verb = params[2]
+ var trigger_object := escoria.object_manager.get_object(trigger_id)
escoria.logger.info(
self,
"trigger_out on trigger %s activated by %s." % [
@@ -202,12 +208,21 @@ func do(action: int, params: Array = [], can_interrupt: bool = false) -> void:
object_id
]
)
- if trigger_out_verb in escoria.object_manager.get_object(trigger_id).events:
- escoria.event_manager.queue_event(
- escoria.object_manager.get_object(trigger_id).events[
- trigger_out_verb
- ]
+
+ if not _is_object_actionable(trigger_object):
+ escoria.logger.info(
+ self,
+ "Trigger %s is not actionable. Skipping trigger_out." % trigger_id
)
+ return
+
+ var trigger_out_event = _get_trigger_event(
+ trigger_object,
+ trigger_out_verb,
+ object_id
+ )
+ if trigger_out_event:
+ escoria.event_manager.queue_event(trigger_out_event)
else:
escoria.logger.info(
self,
@@ -220,12 +235,19 @@ func do(action: int, params: Array = [], can_interrupt: bool = false) -> void:
self,
"Action received: '%s' with params %s." % [action, params]
)
- elif escoria.current_state == escoria.GAME_STATE.WAIT:
+ elif escoria.current_state == escoria.GameState.WAIT:
pass
- elif escoria.current_state == escoria.GAME_STATE.LOADING:
+ elif escoria.current_state == escoria.GameState.LOADING:
pass
+func _get_trigger_event(trigger_object: ESCObject, trigger_verb: String, object_id: String):
+ if trigger_object.has_event_with_target(trigger_verb, object_id):
+ return trigger_object.get_event_with_target(trigger_verb, object_id)
+
+ return trigger_object.get_event_with_target(trigger_verb)
+
+
## Sets the current state of action input. ## Parameters[br]
## [br]
## #### Parameters[br]
@@ -242,7 +264,7 @@ func set_action_input_state(p_state) -> void:
action_input_state_changed.emit()
-## Sets the current action verb. ## Parameters[br]
+## Sets the current action verb.
## [br]
## #### Parameters[br]
## [br]
@@ -259,10 +281,10 @@ func set_current_action(action: String) -> void:
current_action = action
- if action_state == ACTION_INPUT_STATE.AWAITING_VERB_OR_ITEM:
- set_action_input_state(ACTION_INPUT_STATE.AWAITING_ITEM)
- elif action_state == ACTION_INPUT_STATE.AWAITING_VERB:
- set_action_input_state(ACTION_INPUT_STATE.AWAITING_VERB_CONFIRMATION)
+ if action_state == ActionInputState.AWAITING_VERB_OR_ITEM:
+ set_action_input_state(ActionInputState.AWAITING_ITEM)
+ elif action_state == ActionInputState.AWAITING_VERB:
+ set_action_input_state(ActionInputState.AWAITING_VERB_CONFIRMATION)
action_changed.emit()
@@ -278,7 +300,7 @@ func set_current_action(action: String) -> void:
## Returns nothing.
func clear_current_action() -> void:
set_current_action("")
- set_action_input_state(ACTION_INPUT_STATE.AWAITING_VERB_OR_ITEM)
+ set_action_input_state(ActionInputState.AWAITING_VERB_OR_ITEM)
action_changed.emit()
@@ -294,10 +316,10 @@ func clear_current_action() -> void:
func clear_current_tool() -> void:
current_tool = null
current_target = null
- if action_state == ACTION_INPUT_STATE.AWAITING_VERB:
- set_action_input_state(ACTION_INPUT_STATE.AWAITING_VERB_OR_ITEM)
- elif action_state == ACTION_INPUT_STATE.AWAITING_TARGET_ITEM:
- set_action_input_state(ACTION_INPUT_STATE.AWAITING_ITEM)
+ if action_state == ActionInputState.AWAITING_VERB:
+ set_action_input_state(ActionInputState.AWAITING_VERB_OR_ITEM)
+ elif action_state == ActionInputState.AWAITING_TARGET_ITEM:
+ set_action_input_state(ActionInputState.AWAITING_ITEM)
## Checks if the specified action is valid and returns the associated event; otherwise, we see if there's a "fallback" event and use that if necessary and, if not, we return no event as there's nothing to do. or there's a reason not to run an event.[br]
@@ -326,9 +348,9 @@ func _get_event_to_queue(
var event_to_return = null
- # If we're using an action which item requires to combine
+ # If the action makes this item wait for a second target object.
if target.node is ESCItem \
- and action in target.node.combine_when_selected_action_is_in:
+ and action in target.node.actions_requiring_target_object:
# Check if object is in inventory or is not required to be in inventory to be used
if escoria.inventory_manager.inventory_has(target.global_id) or not target.node.use_from_inventory_only:
@@ -343,28 +365,19 @@ func _get_event_to_queue(
do_combine = false
if do_combine:
- var action_name = action
- if combine_with.global_id:
- action_name += " " + combine_with.global_id
-
- var combine_name = action
- if combine_with.global_id:
- combine_name += " " + target.global_id
-
- if _has_event_with_target(target.events, action_name, combine_with.global_id):
- event_to_return = target.events[action_name]
-
- elif _has_event_with_target(combine_with.events, combine_name, target.global_id)\
+ if target.has_event_with_target(action, combine_with.global_id):
+ event_to_return = target.get_event_with_target(action, combine_with.global_id)
+ elif combine_with.has_event_with_target(action, target.global_id)\
and not combine_with.node.combine_is_one_way:
- event_to_return = combine_with.events[combine_name]
+ event_to_return = combine_with.get_event_with_target(action, target.global_id)
else:
# Check to see if there isn't a "fallback" action to
# run before we declare this a failure.
if escoria.action_default_script \
- and escoria.action_default_script.events.has(action):
+ and escoria.action_default_script.has_event_with_target(action):
- event_to_return = escoria.action_default_script.events[action]
+ event_to_return = escoria.action_default_script.get_event_with_target(action)
else:
var errors = [
"Attempted to execute action '%s' between item %s and item %s" % [
@@ -414,17 +427,14 @@ func _get_event_to_queue(
+ "but item must be in inventory."
)
else:
- if _check_target_has_proper_action(target, action):
-# ##SAVEGAME
-# if target.events[action].is_completed:
-# target.events[action].is_completed = false
-# target.events[action].from_statement_id = 0
- event_to_return = target.events[action]
+ if target.has_event_with_target(action):
+ # We only deal with the action here as long as it doesn't have a target associated with it.
+ event_to_return = target.get_event_with_target(action)
elif escoria.action_default_script \
- and escoria.action_default_script.events.has(action):
+ and escoria.action_default_script.has_event_with_target(action):
# If there's a "fallback" action to run, return it
- event_to_return = escoria.action_default_script.events[action]
+ event_to_return = escoria.action_default_script.get_event_with_target(action)
else:
escoria.logger.warn(
self,
@@ -438,21 +448,23 @@ func _get_event_to_queue(
return event_to_return
-## Check to make sure `target` contains the specific `action`. If `target` has an entry for `action` that also requires a target itself (e.g. `:use "wrench"`), then we return `false` as combinations are handled elsewhere.[br]
+## Check to make sure `target_object` contains the specific `action`. If `target_object` has an entry for `action` that also requires a target itself (e.g. `:use "wrench"`), then we return `false` as targeted item actions are handled elsewhere.[br]
+## [br]
+## (The "target" in `target_object` is of a different meaning than the optional "target" in an event.)
## [br]
## #### Parameters[br]
## [br]
## | Name | Type | Description | Required? |[br]
## |:-----|:-----|:------------|:----------|[br]
-## |target|`ESCObject`|`ESCObject` whose events we are to check to see if `action` has a corresponding event.|yes|[br]
+## |target_object|`ESCObject`|`ESCObject` whose events we are to check to see if `action` has a corresponding event.|yes|[br]
## |action|`String`|The action to check.|yes|[br]
## [br]
## #### Returns[br]
## [br]
## Returns a `bool` value. (`bool`)
-func _check_target_has_proper_action(target: ESCObject, action: String) -> bool:
- if target.events.has(action):
- if target.events[action].get_target():
+func _check_target_has_proper_action(target_object: ESCObject, action: String) -> bool:
+ if target_object.has_event_with_target(action):
+ if target_object.get_event_with_target(action).get_target():
return false
return true
@@ -460,26 +472,6 @@ func _check_target_has_proper_action(target: ESCObject, action: String) -> bool:
return false
-## Determines whether the specified events dictionary contains an event with the specified event name and event target, e.g. :give "filled_out_form".[br]
-## [br]
-## #### Parameters[br]
-## [br]
-## | Name | Type | Description | Required? |[br]
-## |:-----|:-----|:------------|:----------|[br]
-## |events_dict|`Dictionary`|dictionary with events to check.|yes|[br]
-## |event_name|`String`|the event name to search for.|yes|[br]
-## |event_target|`String`|the target for the specified event to check.|yes|[br]
-## [br]
-## #### Returns[br]
-## [br]
-## Returns nothing.
-func _has_event_with_target(events_dict: Dictionary, event_name: String, event_target: String):
- var event = events_dict.get(event_name)
- if event == null:
- return false
- return true
-
-
## Runs the specified event.[br]
## [br]
## #### Parameters[br]
@@ -523,7 +515,6 @@ func perform_walk(
destination,
is_fast: bool = false
) -> void:
- # Walk to Position2D.
if destination is Vector2:
var walk_context = ESCWalkContext.new(
null,
@@ -578,29 +569,9 @@ func perform_inputevent_on_object(
event: InputEvent,
default_action: bool = false
) -> void:
- """
- This algorithm:
- - validates the requested action
- - grabs the corresponding event for the action, if available
- - makes the player move to the clicked object location, if needed
- (if it is located in the room for example) and wait for reaching.
- - when reached, performs an action depending on current defined action
- * no current action defined: do nothing else
- * current action defined:
- * item requires no combination: perform the current action
- on the item
- * item requires combination: check the status of the combination
- A combination requires 3 elements to fulfill:
- 1/ a verb action
- 2/ a first "tool" (item to use)
- 3/ a second "tool" (item to use ON)
- Whatever the user inputs to fulfill the combination (this is
- determined by gamedev in his game.gd script)
- - combination not fulfilled: no not perform until fulfilled
- - combination fulfilled: perform the combination.
- * else do nothing, except if default_action is requested.
- In this case, perform the default_action on the item.
- """
+ # This validates the requested action, resolves the corresponding event,
+ # moves the player when needed, and only performs targeted item actions
+ # after verb + source item + target item have all been selected.
escoria.logger.info(
self,
@@ -612,30 +583,30 @@ func perform_inputevent_on_object(
var dont_interact = false
# We need to have the new action input state BEFORE initiating the player
- # move so we determine now if the object clicked will require a combination
+ # move so we determine now if the object clicked requires a target object
# depending on the used action verb.
var tool_just_set = _set_tool_and_action(obj, default_action)
- var need_combine = _check_item_needs_combine()
+ var requires_target_object = _check_item_requires_target_object()
# If the clicked item is not in the inventory and the current tool was not set,
# then this is our first item, make it the tool.
if (not escoria.inventory_manager.inventory_has(obj.global_id) and not current_tool) \
- or (current_tool and not need_combine):
+ or (current_tool and not requires_target_object):
current_tool = obj
- # Else, if we have a tool and combination required, this is our second item,
+ # Else, if we have a tool and a target is required, this is our second item,
# make it the target.
- elif need_combine and not tool_just_set:
+ elif requires_target_object and not tool_just_set:
current_target = obj
# Update the action input state
- if action_state == ACTION_INPUT_STATE.AWAITING_TARGET_ITEM and current_target:
- set_action_input_state(ACTION_INPUT_STATE.COMPLETED)
- elif action_state == ACTION_INPUT_STATE.AWAITING_ITEM and \
- not need_combine:
- set_action_input_state(ACTION_INPUT_STATE.COMPLETED)
- elif action_state == ACTION_INPUT_STATE.AWAITING_ITEM and \
- need_combine and not tool_just_set:
- set_action_input_state(ACTION_INPUT_STATE.AWAITING_TARGET_ITEM)
+ if action_state == ActionInputState.AWAITING_TARGET_ITEM and current_target:
+ set_action_input_state(ActionInputState.COMPLETED)
+ elif action_state == ActionInputState.AWAITING_ITEM and \
+ not requires_target_object:
+ set_action_input_state(ActionInputState.COMPLETED)
+ elif action_state == ActionInputState.AWAITING_ITEM and \
+ requires_target_object and not tool_just_set:
+ set_action_input_state(ActionInputState.AWAITING_TARGET_ITEM)
var event_to_queue: ESCGrammarStmts.Event = null
@@ -648,19 +619,19 @@ func perform_inputevent_on_object(
# If so, and if the object is not in the inventory, we need to run the arrived action.
elif current_action in ["", ACTION_WALK] and not escoria.inventory_manager.inventory_has(obj.global_id):
event_to_queue = _get_event_to_queue(ACTION_ARRIVED, obj)
- # If the current action is set and different from "walk"/unset, we need to check for combinations.
+ # If the current action is set and different from "walk"/unset, check for targeted actions.
elif not current_action in ["", ACTION_WALK]:
- # If clicked object needs a combination, and current target is set, then perform the combination.
- if need_combine and current_target:
+ # If the selected tool requires a target and a target is set, run the targeted action.
+ if requires_target_object and current_target:
event_to_queue = _get_event_to_queue(current_action, current_tool, current_target)
- # If clicked object needs a combination then we need to wait for the target.
- elif need_combine:
- set_action_input_state(ACTION_INPUT_STATE.AWAITING_TARGET_ITEM)
+ # If the selected tool requires a target, wait for the player to choose one.
+ elif requires_target_object:
+ set_action_input_state(ActionInputState.AWAITING_TARGET_ITEM)
# If object is in inventory make it current tool.
if escoria.inventory_manager.inventory_has(obj.global_id):
current_tool = obj
return
- # If clicked object doesn't need a combination, then we simply run the action.
+ # If clicked object doesn't need a target, then we simply run the action.
else:
event_to_queue = _get_event_to_queue(current_action, obj)
@@ -707,8 +678,8 @@ func perform_inputevent_on_object(
"Player could not reach destination coordinates %s. " % str(destination_position) \
+ "Any requested action for %s will not fire." % obj.global_id
)
- if escoria.event_manager.EVENT_CANT_REACH in obj.events:
- escoria.event_manager.queue_event(obj.events[escoria.event_manager.EVENT_CANT_REACH])
+ if obj.has_event_with_target(escoria.event_manager.EVENT_CANT_REACH):
+ escoria.event_manager.queue_event(obj.get_event_with_target(escoria.event_manager.EVENT_CANT_REACH))
else:
escoria.logger.info(
self,
@@ -723,6 +694,8 @@ func perform_inputevent_on_object(
func _telekinetic_applies_to(event: ESCGrammarStmts.Event) -> bool:
+ if event == null:
+ return false
if event.get_flags_with_conditions().has("TK"):
var tk_flag_condition = event.get_flags_with_conditions().get("TK")
@@ -772,7 +745,7 @@ func _set_tool_and_action(obj: ESCObject, default_action: bool):
# Check if current_action and current_tool are already set
if current_action and current_tool:
if not current_action in escoria.action_manager \
- .current_tool.node.combine_when_selected_action_is_in:
+ .current_tool.node.actions_requiring_target_object:
current_tool = obj
tool_just_set = true
elif default_action:
@@ -780,13 +753,13 @@ func _set_tool_and_action(obj: ESCObject, default_action: bool):
current_action = obj.node.default_action_inventory
else:
current_action = obj.node.default_action
- elif current_action in obj.node.combine_when_selected_action_is_in:
+ elif current_action in obj.node.actions_requiring_target_object:
current_tool = obj
tool_just_set = true
return tool_just_set
-## Checks if object requires a combination with another, according to currently selected action verb (or check with default action of the item).[br]
+## Checks if the current tool requires a target object for the selected action verb.[br]
## [br]
## #### Parameters[br]
## [br]
@@ -795,10 +768,10 @@ func _set_tool_and_action(obj: ESCObject, default_action: bool):
## #### Returns[br]
## [br]
## Returns a `bool` value. (`bool`)
-func _check_item_needs_combine() -> bool:
+func _check_item_requires_target_object() -> bool:
return current_action \
and current_tool \
- and current_action in current_tool.node.combine_when_selected_action_is_in
+ and current_action in current_tool.node.actions_requiring_target_object
## Makes the player character walk towards the clicked item. Returns the resulting walk context.[br]
diff --git a/addons/escoria-core/game/core-scripts/esc/esc_command_registry.gd b/addons/escoria-core/game/core-scripts/esc/esc_command_registry.gd
index fdea1ec..a5d5a3b 100644
--- a/addons/escoria-core/game/core-scripts/esc/esc_command_registry.gd
+++ b/addons/escoria-core/game/core-scripts/esc/esc_command_registry.gd
@@ -1,6 +1,6 @@
## A registry of ASHES command objects.
-extends RefCounted
class_name ESCCommandRegistry
+extends RefCounted
## The registry of registered commands.
@@ -54,5 +54,4 @@ func load_command(command_name: String) -> ESCBaseCommand:
func is_command_or_control_pressed(command_name: String) -> ESCBaseCommand:
if self.registry.has(command_name):
return self.registry[command_name]
- else:
- return self.load_command(command_name)
+ return self.load_command(command_name)
diff --git a/addons/escoria-core/game/core-scripts/esc/esc_compiler.gd b/addons/escoria-core/game/core-scripts/esc/esc_compiler.gd
index c029f47..5ed051f 100644
--- a/addons/escoria-core/game/core-scripts/esc/esc_compiler.gd
+++ b/addons/escoria-core/game/core-scripts/esc/esc_compiler.gd
@@ -1,6 +1,6 @@
## Compiler for the ASHES language.
-extends Resource
class_name ESCCompiler
+extends Resource
## This must match `ESCProjectSettingsManager.COMMAND_DIRECTORIES`.
@@ -140,10 +140,21 @@ func _compiler_shim(source: String, filename: String = "", associated_global_id:
if not had_error:
for ps in parsed_statements:
- var event_name = ps.get_event_name()
- if ps.get_target() != null:
- event_name += " " + ps.get_target_name()
- script.events[event_name] = ps
+ if script.has_event_with_target(
+ ps.get_event_name(),
+ ps.get_target_name()
+ ):
+ ESCSafeLogging.log_error(
+ self,
+ "Duplicate event '%s' with target '%s'." % [
+ ps.get_event_name(),
+ ps.get_target_name()
+ ]
+ )
+ had_error = true
+ continue
+
+ script.events.add(ps)
return script
@@ -184,7 +195,7 @@ func load_esc_file(path: String, associated_global_id: String = "") -> ESCScript
## #### Returns[br]
## [br]
## Returns a `ESCScript` value. (`ESCScript`)
-func compile(script: String, path: String = "") -> ESCScript:
+func compile(script: String, _path: String = "") -> ESCScript:
return _compiler_shim(script)
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 47fda29..a1e35dc 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
@@ -4,8 +4,8 @@
## the foreground channel _front, but additional event queues can be added as required.
## Additionally, events can be scheduled to be queued in the future.
## @MANAGER
-extends Node
class_name ESCEventManager
+extends Node
## Emitted when the event has begun execution.[br]
@@ -111,18 +111,15 @@ var events_queue: Dictionary = {
## Currently running event in background channels.
var _running_events: Dictionary = {}
+## Runtime interpreters currently owned by the event manager, keyed by channel.
+var _runtime_interpreters: Dictionary = {}
+
## Those commands that are currently running per channel.
var _running_commands: Dictionary = {}
-## Channel currently being processed.
-var _current_channel: String = ""
-
## Whether an event can be played on a specific channel.
var _channels_state: Dictionary = {}
-## Whether we're currently waiting for an async event to complete, per channel.
-var _yielding: Dictionary = {}
-
## Whether we're currently changing the scene.
var _changing_scene: bool = false: set = set_changing_scene
@@ -171,15 +168,10 @@ func _ready():
## [br]
## Returns nothing.
func _process(delta: float) -> void:
- var channel_yielding: bool
-
for channel_name in events_queue.keys():
- channel_yielding = _yielding.get(channel_name, false)
-
- if events_queue[channel_name].size() == 0 or channel_yielding:
+ if events_queue[channel_name].size() == 0:
continue
if is_channel_free(channel_name):
- _current_channel = channel_name
_channels_state[channel_name] = false
_running_events[channel_name] = \
events_queue[channel_name].pop_front()
@@ -193,15 +185,15 @@ func _process(delta: float) -> void:
if not _running_events[channel_name].source.is_empty()
else "(unknown)"
)
- if not _running_events[channel_name].is_connected(
- "finished", _on_event_finished
+ if not _running_events[channel_name].finished.is_connected(
+ _on_event_finished.bind(channel_name)
):
_running_events[channel_name].finished.connect(
_on_event_finished.bind(channel_name),
CONNECT_ONE_SHOT
)
- if not _running_events[channel_name].is_connected(
- "interrupted", _on_event_finished
+ if not _running_events[channel_name].interrupted.is_connected(
+ _on_event_finished.bind(channel_name)
):
_running_events[channel_name].interrupted.connect(
_on_event_finished.bind(channel_name),
@@ -231,27 +223,9 @@ func _process(delta: float) -> void:
#var rc = _running_events[channel_name].run()
#escoria.interpreter.reset()
#var resolver: ESCResolver = ESCResolver.new(escoria.interpreter)
- var interpreter: ESCInterpreter = ESCInterpreterFactory.create_interpreter()
- var resolver: ESCResolver = ESCResolver.new(interpreter)
var event = _running_events[channel_name]
- escoria.logger.trace(
- self,
- "Processing event '%s' from script '%s'." \
- % [
- event.get_name().get_lexeme(),
- event.get_name().get_filename() if event.get_name().get_filename() else "<internal>"
- ]
- )
-
- resolver.resolve(event)
-
- var rc = await interpreter.interpret(event)
-
- #if rc is GDScriptFunctionState:
- #_yielding[channel_name] = true
- #rc = await (rc, "completed")
- #_yielding[channel_name] = false
+ call_deferred("_run_event_on_channel", channel_name, event)
for event in self.scheduled_events:
(event as ESCScheduledEvent).timeout -= delta
@@ -260,6 +234,32 @@ func _process(delta: float) -> void:
self.events_queue[CHANNEL_FRONT].append(event.event)
+func _run_event_on_channel(channel_name: String, event: ESCGrammarStmts.Event) -> void:
+ var interpreter: ESCInterpreter = ESCInterpreterFactory.create_runtime_interpreter(channel_name)
+ _runtime_interpreters[channel_name] = interpreter
+ var resolver: ESCResolver = ESCResolver.new(interpreter)
+
+ escoria.logger.trace(
+ self,
+ "Processing event '%s' from script '%s'." \
+ % [
+ event.get_name().get_lexeme(),
+ event.get_name().get_filename() if event.get_name().get_filename() else "<internal>"
+ ]
+ )
+
+ resolver.resolve(event)
+ await interpreter.interpret(event)
+
+ # Runtime interpreters are owned per channel run. Clean up the local
+ # instance once interpretation has concluded without touching any newer
+ # interpreter another concurrent channel run may have registered.
+ interpreter.cleanup()
+
+ if _runtime_interpreters.get(channel_name) == interpreter:
+ _runtime_interpreters.erase(channel_name)
+
+
## Queues a new event based on input from an ASHES command, most likely `queue_event`.[br]
## [br]
## #### Parameters[br]
@@ -281,23 +281,24 @@ func queue_event_from_esc(script_object: ESCScript, event: String,
return ESCExecution.RC_WONT_QUEUE
if channel == CHANNEL_FRONT:
- queue_event(script_object.events[event])
+ queue_event(script_object.get_event_with_target(event))
else:
queue_background_event(
channel,
- script_object.events[event]
+ script_object.get_event_with_target(event)
)
+
if block:
if channel == CHANNEL_FRONT:
var rc = await self.event_finished
while rc[1] != event:
rc = await self.event_finished
return rc[0]
- else:
- var rc = await self.background_event_finished
- while rc[1] != event and rc[2] != channel:
- rc = await self.background_event_finished
- return rc[0]
+
+ var rc = await self.background_event_finished
+ while rc[1] != event or rc[2] != channel:
+ rc = await self.background_event_finished
+ return rc[0]
return ESCExecution.RC_OK
@@ -335,12 +336,13 @@ func queue_event(event: ESCGrammarStmts.Event, force: bool = false, as_first = f
escoria.logger.debug(self, message % [event.get_event_name(), CHANNEL_FRONT])
return
- elif _is_event_running(event, CHANNEL_FRONT):
+
+ if _is_event_running(event, CHANNEL_FRONT):
# Don't queue the same event if it's already running.
escoria.logger.debug(
self,
"Event %s already running in channel '%s'. Won't be queued."
- % [event.get_event_name(), CHANNEL_FRONT]
+ % [event.get_event_name(), CHANNEL_FRONT]
)
return
@@ -388,27 +390,10 @@ func queue_background_event(channel_name: String, event: ESCGrammarStmts.Event)
if not channel_name in events_queue:
events_queue[channel_name] = []
- # Don't queue the same event more than once in a row.
- var last_event = _get_last_event_queued(channel_name)
-
- # Check the queue first to see if appending the event will result in
- # consecutive occurrences of the event. If not, be sure to check if the same
- # event is currently running.
- if last_event != null and last_event.get_event_name() == event.get_event_name():
- var message = "Event '%s' is already the most-recently queued event in channel '%s'." + \
- " Won't be queued again."
-
- escoria.logger.debug(self, message % [event.get_event_name(), channel_name])
- return
- elif _is_event_running(event, CHANNEL_FRONT):
- # Don't queue the same event if it's already running.
- escoria.logger.debug(
- self,
- "Event %s already running in channel '%s'. Won't be queued."
- % [event.get_event_name(), channel_name]
- )
-
- return
+ # Background channels are fed by explicit ASHES commands, so repeated queue
+ # requests are intentional. This includes back-to-back enqueues of the same
+ # event name and enqueuing the same event again while an earlier run is
+ # already active on the channel.
events_queue[channel_name].append(event)
@@ -482,8 +467,23 @@ func interrupt(exceptions: PackedStringArray = [], stop_walking = true) -> void:
## [br]
## Returns nothing.
func interrupt_channel(channel_name: String) -> void:
- for command in _running_commands.get(channel_name, []):
- command.interrupt()
+ var running_event: ESCGrammarStmts.Event = _running_events.get(channel_name, null)
+
+ # Interrupt the channel's running event directly so any in-flight command is
+ # reached even if command bookkeeping has not yet been updated for this frame.
+ if running_event != null:
+ escoria.logger.debug(
+ self,
+ "Interrupting running event %s in channel %s..."
+ % [running_event.get_event_name(), channel_name]
+ )
+ running_event.interrupt()
+ _channels_state[channel_name] = true
+
+ # Clear any queued follow-up events on the same channel so the interrupt has
+ # the same effect as the broader interrupt path, but scoped to one channel.
+ if events_queue.has(channel_name):
+ events_queue[channel_name].clear()
## Clears the event queues.[br]
@@ -563,10 +563,6 @@ func set_changing_scene(p_is_changing_scene: bool) -> void:
])
-# This probably won't work since _current_channel could have changed after
-# a yielding command resumes. Also the event itself isn't logged, just the command,
-# creating a problem.
-
## Adds a currently-running command to the current channel.[br]
## [br]
## #### Parameters[br]
@@ -579,10 +575,13 @@ func set_changing_scene(p_is_changing_scene: bool) -> void:
## [br]
## Returns nothing.
func add_running_command(command: ESCCommand) -> void:
- if _running_commands.get(_current_channel, []) == []:
- _running_commands[_current_channel] = [command]
+ if command.channel_name.is_empty():
+ return
+
+ if _running_commands.get(command.channel_name, []) == []:
+ _running_commands[command.channel_name] = [command]
else:
- _running_commands[_current_channel].append(command)
+ _running_commands[command.channel_name].append(command)
## Removes the specified command from the current channel.[br]
@@ -597,8 +596,11 @@ func add_running_command(command: ESCCommand) -> void:
## [br]
## Returns nothing.
func running_command_finished(command: ESCCommand) -> void:
- if command in _running_commands[_current_channel]:
- _running_commands[_current_channel].erase(command)
+ if command.channel_name.is_empty():
+ return
+
+ if command in _running_commands.get(command.channel_name, []):
+ _running_commands[command.channel_name].erase(command)
## The event finished running.[br]
diff --git a/addons/escoria-core/game/core-scripts/esc/esc_globals_manager.gd b/addons/escoria-core/game/core-scripts/esc/esc_globals_manager.gd
index 61c1e38..e9b86af 100644
--- a/addons/escoria-core/game/core-scripts/esc/esc_globals_manager.gd
+++ b/addons/escoria-core/game/core-scripts/esc/esc_globals_manager.gd
@@ -3,8 +3,8 @@
## The ASHES global state is basically simply a dictionary of keys with
## values. Values can be bool, integer or strings.
## @MANAGER
-extends Resource
class_name ESCGlobalsManager
+extends Resource
## Emitted when a global has changed.[br]
@@ -123,6 +123,19 @@ func get_global(key: String):
return null
+## Returns a snapshot copy of all currently stored globals.[br]
+## [br]
+## #### Parameters[br]
+## [br]
+## None.
+## [br]
+## #### Returns[br]
+## [br]
+## Returns a `Dictionary` containing the current global state. (`Dictionary`)
+func get_globals() -> Dictionary:
+ return _globals.duplicate(true)
+
+
## Filters the globals and return all matching keys and their values as a dictionary. Check out [the Godot docs](https://docs.godotengine.org/en/stable/classes/class_string.html#class-string-method-match) for the pattern format.[br]
## [br]
## #### Parameters[br]
diff --git a/addons/escoria-core/game/core-scripts/esc/esc_inventory_manager.gd b/addons/escoria-core/game/core-scripts/esc/esc_inventory_manager.gd
index 944aead..a6016ce 100644
--- a/addons/escoria-core/game/core-scripts/esc/esc_inventory_manager.gd
+++ b/addons/escoria-core/game/core-scripts/esc/esc_inventory_manager.gd
@@ -1,7 +1,7 @@
## A manager for inventory objects.
## @MANAGER
-extends Resource
class_name ESCInventoryManager
+extends Resource
## Checks whether the player has an inventory item.[br]
diff --git a/addons/escoria-core/game/core-scripts/esc/esc_object_manager.gd b/addons/escoria-core/game/core-scripts/esc/esc_object_manager.gd
index 047fcab..de2e671 100644
--- a/addons/escoria-core/game/core-scripts/esc/esc_object_manager.gd
+++ b/addons/escoria-core/game/core-scripts/esc/esc_object_manager.gd
@@ -1,7 +1,7 @@
## A manager for ESC objects.
## @MANAGER
-extends Resource
class_name ESCObjectManager
+extends Resource
## Reserved camera object.
@@ -94,6 +94,23 @@ func _init() -> void:
current_room_key = ESCRoomObjectsKey.new()
+## Clears all room-specific object and terrain state while preserving reserved
+## objects managed by Escoria itself.[br]
+## [br]
+## #### Parameters[br]
+## [br]
+## None.
+## [br]
+## #### Returns[br]
+## [br]
+## Returns nothing.
+func reset_game_state() -> void:
+ room_objects.clear()
+ room_objects.push_back(reserved_objects_container)
+ room_terrains.clear()
+ current_room_key = ESCRoomObjectsKey.new()
+
+
## Updates which object manager room is to be treated as the currently active one.[br]
## [br]
## #### Parameters[br]
@@ -133,7 +150,6 @@ func set_current_room(room: ESCRoom) -> void:
## Returns nothing.
func register_object(object: ESCObject, room: ESCRoom = null, force: bool = false, \
auto_unregister: bool = true) -> void:
-
if object.global_id.is_empty():
object.global_id = str(object.node.get_path()).split("/root/", false)[0]
object.node.global_id = object.global_id
@@ -193,7 +209,7 @@ func register_object(object: ESCObject, room: ESCRoom = null, force: bool = fals
return
# Object exists in room, set it to is last state (if different from
# "default")
- elif object.node is ESCItem and _object_exists_in_room(object, room_key):
+ if object.node is ESCItem and _object_exists_in_room(object, room_key):
# Object is already known, set its state to last known state
object.set_state(get_object(object.global_id).state)
@@ -201,16 +217,26 @@ func register_object(object: ESCObject, room: ESCRoom = null, force: bool = fals
# forcing the registration, since we don't know if this object will be
# overwritten ("forced") in the future and, if it is, if it's set to
# auto-unregister or not. In most cases, objects are set to auto unregister.
- if object.node.tree_exited.is_connected(unregister_object):
- object.node.tree_exited.disconnect(unregister_object)
+ if not object.unregister_object_callback.is_null() and \
+ object.node.tree_exited.is_connected(object.unregister_object_callback):
+ object.node.tree_exited.disconnect(object.unregister_object_callback)
if force:
+ var existing_object: ESCObject = _get_room_objects_objects(room_key).get(object.global_id)
+ if existing_object != null and is_instance_valid(existing_object.node):
+ if existing_object.node.tree_exited.is_connected(
+ existing_object.unregister_object_callback
+ ):
+ existing_object.node.tree_exited.disconnect(
+ existing_object.unregister_object_callback
+ )
# If this ID already exists and we're about to overwrite it, do the
# safe thing and unregister the old object first
unregister_object_by_global_id(object.global_id, room_key)
if auto_unregister:
- object.node.tree_exited.connect(unregister_object.bind(object, room_key))
+ object.unregister_object_callback = unregister_object.bind(object, room_key)
+ object.node.tree_exited.connect(object.unregister_object_callback)
if "is_interactive" in object.node and object.node.is_interactive:
object.interactive = true
@@ -352,13 +378,13 @@ func get_object(global_id: String, room: ESCRoom = null) -> ESCObject:
if global_id in RESERVED_OBJECTS:
if reserved_objects_container.objects.has(global_id):
return reserved_objects_container.objects[global_id]
- else:
- escoria.logger.warn(
- self,
- "Reserved object with global id %s not found in object manager!"
- % global_id
- )
- return null
+
+ escoria.logger.warn(
+ self,
+ "Reserved object with global id %s not found in object manager!"
+ % global_id
+ )
+ return null
var room_key: ESCRoomObjectsKey
@@ -382,24 +408,24 @@ func get_object(global_id: String, room: ESCRoom = null) -> ESCObject:
if objects.has(global_id):
return objects[global_id]
- else:
- escoria.logger.warn(
- self,
- "Object with global id %s in room instance (%s, %s) not found. This can be safely ignored if a room was being searched for."
- % [global_id, room_key.room_global_id, room_key.room_instance_id]
- )
- if escoria.inventory_manager.inventory_has(global_id):
- # item is in the inventory and may be registered to a different room
- for single_room in room_objects:
- # these are arrays of the objects still registered for each room
- if single_room.objects.has(global_id):
- escoria.logger.info(
- self,
- "Object with global id %s found in room instance (%s, %s) through the inventory."
- % [global_id, room_key.room_global_id, room_key.room_instance_id]
- )
- return single_room.objects[global_id]
- return null
+
+ escoria.logger.warn(
+ self,
+ "Object with global id %s in room instance (%s, %s) not found. This can be safely ignored if a room was being searched for."
+ % [global_id, room_key.room_global_id, room_key.room_instance_id]
+ )
+ if escoria.inventory_manager.inventory_has(global_id):
+ # item is in the inventory and may be registered to a different room
+ for single_room in room_objects:
+ # these are arrays of the objects still registered for each room
+ if single_room.objects.has(global_id):
+ escoria.logger.info(
+ self,
+ "Object with global id %s found in room instance (%s, %s) through the inventory."
+ % [global_id, room_key.room_global_id, room_key.room_instance_id]
+ )
+ return single_room.objects[global_id]
+ return null
## Removes an object from the registry.[br]
@@ -422,7 +448,7 @@ func unregister_object(object: ESCObject, room_key: ESCRoomObjectsKey) -> void:
escoria.logger.debug(
self,
"Unable to unregister object. " +
- "Object with global ID %s room (%s, %s) not found. If this was "
+ "Object with global ID '%s' room (%s, %s) not found. If this was "
% [
"?" if object == null else object.global_id,
room_key.room_global_id,
@@ -430,7 +456,6 @@ func unregister_object(object: ESCObject, room_key: ESCRoomObjectsKey) -> void:
] +
"part of a 'forced' registration, ignore this warning."
)
-
return
var room_objects = _get_room_objects_objects(room_key)
@@ -701,3 +726,31 @@ func _erase_room(room_key: ESCRoomObjectsKey) -> void:
if _compare_container_to_key(room_container, room_key):
room_objects.erase(room_container)
return
+
+
+## Disconnect all existing items from registered ESCObjects for the given room.
+## [br]
+## #### Parameters[br]
+## [br]
+## | Name | Type | Description | Required? |[br]
+## |:-----|:-----|:------------|:----------|[br]
+## |room_key|`ESCRoomObjectsKey`|The key representing the desired room in the object manager array|yes|[br]
+## [br]
+## #### Returns[br]
+## [br]
+## Returns nothing.
+func disconnect_tree_exit_for_room_items(room_key: ESCRoomObjectsKey) -> void:
+ #var _room_objects = _get_room_objects_objects(room_key)
+ var i: int = 0
+ for room_container in room_objects:
+ if room_container.room_global_id == room_key.room_global_id \
+ and room_container.room_instance_id == room_key.room_instance_id:
+ for object in room_container.objects:
+ var ro: ESCObject = room_objects[i].objects[object]
+ if is_instance_valid(ro.node) and \
+ ro.node.tree_exited.is_connected(ro.unregister_object_callback):
+ ro.node.tree_exited.disconnect(ro.unregister_object_callback)
+ break
+ else:
+ i += 1
+ continue
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 1a077a9..60042f7 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
@@ -1,7 +1,7 @@
## A manager for rooms in a game.
## @MANAGER
-extends Resource
class_name ESCRoomManager
+extends Resource
## The room manager scene.
## Manages room loading and keeps in memory
@@ -116,6 +116,23 @@ func change_scene_to_file(room_path: String, enable_automatic_transitions: bool)
room_scene.add_child(escoria.game_scene)
room_scene.move_child(escoria.game_scene, 0)
room_scene.game = escoria.game_scene
+
+ # If the scene we're loading is the same as the current one, disconnect
+ # the tree_exit signal on the existing items (that was connected when
+ # items got registered in Object Manager) so that objects for new items
+ # of the new room don't get unregistered.
+ var current_scene: Node = escoria.main.current_scene
+ var new_room_global_id: String = room_scene.global_id \
+ if not room_scene.global_id.is_empty() else room_scene.name
+ if is_instance_valid(current_scene):
+ var current_room_global_id: String = \
+ current_scene.global_id if not current_scene.global_id.is_empty() \
+ else current_scene.name
+ if new_room_global_id == current_room_global_id:
+ escoria.object_manager.disconnect_tree_exit_for_room_items(
+ escoria.object_manager.current_room_key
+ )
+
escoria.main.set_scene(room_scene)
# We know the scene has been loaded. Make its global ID available for
@@ -341,7 +358,7 @@ func _perform_script_events(room: ESCRoom) -> int:
get_class())
escoria.event_manager.queue_event(
- script_transition_out_compiled.events[escoria.event_manager.EVENT_TRANSITION_OUT],
+ script_transition_out_compiled.get_event_with_target(escoria.event_manager.EVENT_TRANSITION_OUT),
true
)
@@ -381,14 +398,6 @@ func _perform_script_events(room: ESCRoom) -> int:
if not is_instance_valid(room.player):
room.player = room.player_scene.instantiate()
room.add_child(room.player)
- escoria.object_manager.register_object(
- ESCObject.new(
- room.player.global_id,
- room.player
- ),
- room,
- true
- )
if escoria.globals_manager.has(
escoria.room_manager.GLOBAL_ANIMATION_RESOURCES
@@ -424,12 +433,19 @@ func _perform_script_events(room: ESCRoom) -> int:
# Add new camera to scene being prepared.
if room.player_camera:
- room.remove_child(room.player_camera)
+ room.remove_child(room.player_camera) # This unregisters the camera from object manager
room.player_camera.queue_free()
var new_player_camera: ESCCamera = escoria.resource_cache.get_resource(
CAMERA_SCENE_PATH
).instantiate()
- new_player_camera.register()
+ escoria.object_manager.register_object(
+ ESCObject.new(
+ ESCObjectManager.CAMERA,
+ new_player_camera
+ ),
+ null,
+ true
+ )
room.player_camera = new_player_camera
# We must first set the camera limits, and then worry about subsequent
@@ -530,10 +546,10 @@ func _perform_script_events(room: ESCRoom) -> int:
var script_transition_in = escoria.esc_compiler.compile(transition_in_script.build())
escoria.event_manager.queue_event(
- script_transition_in.events[escoria.event_manager.EVENT_TRANSITION_IN]
+ script_transition_in.get_event_with_target(escoria.event_manager.EVENT_TRANSITION_IN)
)
- if not escoria.current_state == escoria.GAME_STATE.LOADING:
+ if not escoria.current_state == escoria.GameState.LOADING:
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)
@@ -593,14 +609,15 @@ func _run_script_event(event_name: String, room: ESCRoom):
room.compiled_script = \
escoria.esc_compiler.load_esc_file(room.esc_script)
- if room.compiled_script.events.has(event_name):
+ if room.compiled_script.has_event_with_target(event_name):
+ var event = room.compiled_script.get_event_with_target(event_name)
escoria.logger.debug(
self,
"Queuing room script event %s " % event_name +
"composed of %s statements."
- % room.compiled_script.events[event_name].get_num_statements_in_block()
+ % event.get_num_statements_in_block()
)
- escoria.event_manager.queue_event(room.compiled_script.events[event_name], true)
+ escoria.event_manager.queue_event(event, true)
return true
- else:
- return false
+
+ return false
diff --git a/addons/escoria-core/game/core-scripts/esc/types/esc_base_command.gd b/addons/escoria-core/game/core-scripts/esc/types/esc_base_command.gd
index c46714d..e7f27e5 100644
--- a/addons/escoria-core/game/core-scripts/esc/types/esc_base_command.gd
+++ b/addons/escoria-core/game/core-scripts/esc/types/esc_base_command.gd
@@ -1,8 +1,8 @@
## Abstract base class for every ESC command.
##
## Extending classes have to override the configure and run function
-extends Resource
class_name ESCBaseCommand
+extends Resource
## The filename from which the relevant command is being called, if available.
@@ -11,6 +11,12 @@ var filename: String = ""
## The line number from the file the relevant command is being called from.
var line_number: int = 0
+## Whether the command is allowed to be ran in a room's :ready event during a
+## savegame loading. This is especially the case for sound control commands,
+## for which the Save Manager resumes from the recorded position.[br]
+## Set this to `false` in the `_init()` method of such commands when necessary.
+var run_in_ready_allowed_during_savegame_loading: bool = true
+
## A descriptor (contained in `ESCCommandArgumentDescriptor`) of the arguments of this command.[br]
## [br]
@@ -60,7 +66,7 @@ func validate(arguments: Array) -> bool:
## #### Returns[br]
## [br]
## Returns a `int` value. (`int`)
-func run(command_params: Array) -> int:
+func run(_command_params: Array) -> int:
raise_error(self, "Command %s did not override run. Please implement a run() function." % get_command_name())
return 0
diff --git a/addons/escoria-core/game/core-scripts/esc/types/esc_camera_base_command.gd b/addons/escoria-core/game/core-scripts/esc/types/esc_camera_base_command.gd
index 54af190..88088a8 100644
--- a/addons/escoria-core/game/core-scripts/esc/types/esc_camera_base_command.gd
+++ b/addons/escoria-core/game/core-scripts/esc/types/esc_camera_base_command.gd
@@ -6,8 +6,8 @@
## [br]
## None.
## [br]
-extends ESCBaseCommand
class_name ESCCameraBaseCommand
+extends ESCBaseCommand
## Generates a log entry when attempting to move the camera to an invalid position.[br]
diff --git a/addons/escoria-core/game/core-scripts/esc/types/esc_command.gd b/addons/escoria-core/game/core-scripts/esc/types/esc_command.gd
index 4a5cb76..1008a14 100644
--- a/addons/escoria-core/game/core-scripts/esc/types/esc_command.gd
+++ b/addons/escoria-core/game/core-scripts/esc/types/esc_command.gd
@@ -1,8 +1,8 @@
## Used to properly setup and execute commands, i.e. those that extend `ESCBaseCommand`.
##
## Despite its name, `ESCCommand` is more of a container and orchestrator than an actual command.
-extends ESCStatement
class_name ESCCommand
+extends ESCStatement
## The name of this command.
@@ -11,10 +11,15 @@ var name: String
## Parameters for this command
var parameters: Array = []
+## Channel where this command's owning event is running.
+var channel_name: String = ""
+
## The token generated by the parser containing info for debugging (e.g. line number,
## script filename, etc.).
var parser_token: ESCToken = null
+var _running_command_impl: ESCBaseCommand = null
+
## A `Dictionary` containing the data needed when saving a game.[br]
## [br]
@@ -85,36 +90,50 @@ func _command_exists() -> bool:
## Returns a `int` value. (`int`)
func run() -> int:
var command_object = escoria.command_registry.load_command(self.name)
+ _running_command_impl = command_object
_decorate_for_debugging(command_object)
if command_object == null:
+ _running_command_impl = null
return ESCExecution.RC_ERROR
- else:
- var argument_descriptor = command_object.configure()
- _decorate_for_debugging(argument_descriptor)
+ var argument_descriptor = command_object.configure()
- var prepared_arguments = argument_descriptor.prepare_arguments(
- self.parameters
- )
+ _decorate_for_debugging(argument_descriptor)
+
+ var prepared_arguments = argument_descriptor.prepare_arguments(
+ self.parameters
+ )
- if command_object.validate(prepared_arguments):
+ if command_object.validate(prepared_arguments):
+ if escoria.save_manager.is_loading_game \
+ and escoria.event_manager.get_running_event(escoria.event_manager.CHANNEL_FRONT).get_event_name() == escoria.event_manager.EVENT_READY \
+ and not command_object.run_in_ready_allowed_during_savegame_loading:
escoria.logger.debug(
self,
- "Running command %s with parameters %s."
+ "Skipped command %s with parameters %s because it is not allowed to be ran from :ready event during savegame load."
% [self.name, prepared_arguments]
)
- escoria.event_manager.add_running_command(self)
- var rc = await command_object.run(prepared_arguments)
- escoria.event_manager.running_command_finished(self)
- escoria.logger.debug(
- self,
- "[%s] Return code: %d." % [self.name, rc]
- )
- return rc
- else:
- return ESCExecution.RC_ERROR
+ _running_command_impl = null
+ return ESCExecution.RC_WONT_QUEUE
+ escoria.logger.debug(
+ self,
+ "Running command %s with parameters %s."
+ % [self.name, prepared_arguments]
+ )
+ escoria.event_manager.add_running_command(self)
+ var rc = await command_object.run(prepared_arguments)
+ escoria.event_manager.running_command_finished(self)
+ _running_command_impl = null
+ escoria.logger.debug(
+ self,
+ "[%s] Return code: %d." % [self.name, rc]
+ )
+ return rc
+
+ _running_command_impl = null
+ return ESCExecution.RC_ERROR
## This function interrupts the command. If it was not started, it will not run. If it had already started, the execution will be considered as finished immediately and finish. If it had already finished, nothing will happen.[br]
@@ -128,9 +147,8 @@ func run() -> int:
## Returns nothing.
func interrupt():
_is_interrupted = true
- var command = escoria.command_registry.is_command_or_control_pressed(self.name)
- if command.has_method("interrupt"):
- command.interrupt()
+ if _running_command_impl and _running_command_impl.has_method("interrupt"):
+ _running_command_impl.interrupt()
## Override of built-in _to_string function to display the statement.[br]
## [br]
diff --git a/addons/escoria-core/game/core-scripts/esc/types/esc_command_argument_descriptor.gd b/addons/escoria-core/game/core-scripts/esc/types/esc_command_argument_descriptor.gd
index 44b3b77..8367f49 100644
--- a/addons/escoria-core/game/core-scripts/esc/types/esc_command_argument_descriptor.gd
+++ b/addons/escoria-core/game/core-scripts/esc/types/esc_command_argument_descriptor.gd
@@ -1,6 +1,6 @@
## Describes the arguments of commands that extend `ESCBaseCommand`.
-extends RefCounted
class_name ESCCommandArgumentDescriptor
+extends RefCounted
## As the get_type command was deprecated with Godot 2.x w we need a way to determine
diff --git a/addons/escoria-core/game/core-scripts/esc/types/esc_dialog.gd b/addons/escoria-core/game/core-scripts/esc/types/esc_dialog.gd
index 5d48a98..032696f 100644
--- a/addons/escoria-core/game/core-scripts/esc/types/esc_dialog.gd
+++ b/addons/escoria-core/game/core-scripts/esc/types/esc_dialog.gd
@@ -1,6 +1,6 @@
## Represents a dialog in Escoria.
-extends ESCStatement
class_name ESCDialog
+extends ESCStatement
## Avatar used in the dialog, if any.
@@ -12,6 +12,9 @@ var timeout: int = 0
## The dialog option to select when timeout is reached.
var timeout_option: int = 0
+## Total number of options authored in this dialog, including currently hidden options.
+var authored_options_count: int = 0
+
## A list of `ESCDialogOption`s.
var options: Array
@@ -32,7 +35,11 @@ func is_valid() -> bool:
"Avatar scene not found: %s." % self.avatar
)
return false
- if self.timeout_option > self.options.size() \
+ var option_count := self.authored_options_count
+ if option_count == 0:
+ option_count = self.options.size()
+
+ if self.timeout_option > option_count \
or self.timeout_option < 0:
escoria.logger.error(
self,
@@ -43,6 +50,33 @@ func is_valid() -> bool:
return true
+## Returns the currently visible option configured as the timeout default, if any.[br]
+## [br]
+## #### Parameters[br]
+## [br]
+## None.
+## [br]
+## #### Returns[br]
+## [br]
+## Returns the currently visible timeout option as an `ESCDialogOption`, or `null` if the configured option is not visible.
+func get_timeout_option() -> ESCDialogOption:
+ var has_source_option_indexes := false
+
+ for option in self.options:
+ if option.source_option_index > 0:
+ has_source_option_indexes = true
+
+ if option.source_option_index == self.timeout_option:
+ return option
+
+ if not has_source_option_indexes \
+ and self.timeout_option > 0 \
+ and self.timeout_option <= self.options.size():
+ return self.options[self.timeout_option - 1]
+
+ return null
+
+
## Run this dialog. TODO: Although this method overrides its parent version, the return type here does NOT match the parent's signature. Consider either changing the parent's return type to be a `Variant`, or doing something to ensure greater consistency.[br]
## [br]
## #### Parameters[br]
@@ -58,7 +92,7 @@ func run():
"Starting dialog."
)
- escoria.current_state = escoria.GAME_STATE.DIALOG
+ escoria.current_state = escoria.GameState.DIALOG
if !escoria.dialog_player:
escoria.dialog_player = escoria.main.current_scene.get_node(
@@ -75,6 +109,6 @@ func run():
# If this is the case and the current level of dialog has a parent, it means
# it is still yielding and so will be shown again.
- escoria.current_state = escoria.GAME_STATE.DEFAULT
+ escoria.current_state = escoria.GameState.DEFAULT
return option
diff --git a/addons/escoria-core/game/core-scripts/esc/types/esc_dialog_option.gd b/addons/escoria-core/game/core-scripts/esc/types/esc_dialog_option.gd
index e3701e5..8737dbc 100644
--- a/addons/escoria-core/game/core-scripts/esc/types/esc_dialog_option.gd
+++ b/addons/escoria-core/game/core-scripts/esc/types/esc_dialog_option.gd
@@ -1,17 +1,23 @@
## A single option used as part of a dialog.
##
## `ESCDialog` makes use of these when assembling an actual dialog in Escoria.
-extends ESCStatement
class_name ESCDialogOption
+extends ESCStatement
## Option text displayed in the HUD.
var option: String:
get = get_translated_option
+## Explicit translation key for the option text.
+var translation_key: String = ""
+
## Maps back to the parsed source option.
var source_option
+## One-based index of this option in its authored dialog block.
+var source_option_index: int = -1
+
## Whether this option is valid.
var _is_valid: bool:
set = set_is_valid,
@@ -28,6 +34,14 @@ var _is_valid: bool:
## [br]
## Returns the translated version of the option, if one exists; otherwise, the default text is returned. (`String`)
func get_translated_option() -> String:
+ if not translation_key.is_empty():
+ var translated_text = tr(translation_key)
+
+ if translation_key != translated_text:
+ return translated_text
+
+ return option
+
# Check if text has a key
if ":" in option:
var splitted_text = option.split(":")
diff --git a/addons/escoria-core/game/core-scripts/esc/types/esc_event.gd b/addons/escoria-core/game/core-scripts/esc/types/esc_event.gd
index 19a0075..bf9e92c 100644
--- a/addons/escoria-core/game/core-scripts/esc/types/esc_event.gd
+++ b/addons/escoria-core/game/core-scripts/esc/types/esc_event.gd
@@ -12,18 +12,8 @@
## run once the room is visible.[br]
## - `:use <global id>` : Called from the current item when it is used with the item
## with specified by `<global id>`.
-extends ESCStatement
class_name ESCEvent
-
-## Regex identifying an ESC event.
-const REGEX = \
- '^:(?<name>[^|]+)( \\|\\s*(?<flags>( ' + \
- '(TK|NO_TT|NO_UI|NO_SAVE)' + \
- ')+))?$'
-
-## Prefix to identify this as an ESC event.
-const PREFIX = ":"
-
+extends ESCStatement
## Valid event flags:[br]
## - `TK`: stands for "telekinetic". It means the player won't walk over to
@@ -43,6 +33,14 @@ enum FLAGS {
NO_SAVE = 8
}
+## Regex identifying an ESC event.
+const REGEX = \
+ '^:(?<name>[^|]+)( \\|\\s*(?<flags>( ' + \
+ '(TK|NO_TT|NO_UI|NO_SAVE)' + \
+ ')+))?$'
+
+## Prefix to identify this as an ESC event.
+const PREFIX = ":"
## Name of the event.
var name: String
diff --git a/addons/escoria-core/game/core-scripts/esc/types/esc_events_container.gd b/addons/escoria-core/game/core-scripts/esc/types/esc_events_container.gd
new file mode 100644
index 0000000..0ef313e
--- /dev/null
+++ b/addons/escoria-core/game/core-scripts/esc/types/esc_events_container.gd
@@ -0,0 +1,52 @@
+## Container for storing events in Escoria, providing a consistent way to provide
+## visibility and access to events.
+class_name ESCEventsContainer
+extends RefCounted
+
+
+## The list of events being tracked.
+var events: Array = []
+
+
+## Adds an event to the container.[br]
+##[br]
+## #### Parameters[br]
+##[br]
+## - event: the event to be stored
+func add(event) -> void:
+ events.append(event)
+
+
+## Determines whether the specified events list contains an event with the[br]
+## specified event name and event target, e.g. `:give "filled_out_form"`[br]
+##[br]
+## #### Parameters[br]
+##[br]
+## - event_name: the event name to search for[br]
+## - event_target: the target for the specified event to check; may be null[br]
+##[br]
+## *Returns* true iff events contains an event matching both event_name and event_target
+func has_event_with_target(event_name: String, event_target = null) -> bool:
+ return is_instance_valid(get_event_with_target(event_name, event_target))
+
+
+## Returns the event matching the specified event name and target, e.g. `:give "filled_out_form"`[br]
+## if it exists; returns null otherwise.[br]
+##[br]
+## #### Parameters[br]
+##[br]
+## - event_name: the event name to search for[br]
+## - event_target: the target for the specified event to check; may be null[br]
+##[br]
+## *Returns* the event in `events` iff `events` contains an event matching both `event_name` and `event_target`;[br]
+## returns null otherwise.
+func get_event_with_target(event_name: String, event_target = null):
+ for event in events:
+ if event.get_event_name() == event_name:
+ if event_target:
+ if event.get_target_name() == event_target:
+ return event
+ else:
+ if not event.get_target_name():
+ return event
+ return null
diff --git a/addons/escoria-core/game/core-scripts/esc/types/esc_events_container.gd.uid b/addons/escoria-core/game/core-scripts/esc/types/esc_events_container.gd.uid
new file mode 100644
index 0000000..2559148
--- /dev/null
+++ b/addons/escoria-core/game/core-scripts/esc/types/esc_events_container.gd.uid
@@ -0,0 +1 @@
+uid://ct6ek3jk6spbq
diff --git a/addons/escoria-core/game/core-scripts/esc/types/esc_execution.gd b/addons/escoria-core/game/core-scripts/esc/types/esc_execution.gd
index 21641e7..917895c 100644
--- a/addons/escoria-core/game/core-scripts/esc/types/esc_execution.gd
+++ b/addons/escoria-core/game/core-scripts/esc/types/esc_execution.gd
@@ -1,6 +1,6 @@
## Class with enum containing the return codes returned by ASHES script functions.
-extends Resource
class_name ESCExecution
+extends Resource
## Execution result values.
## Return codes handled by events.[br]
diff --git a/addons/escoria-core/game/core-scripts/esc/types/esc_object.gd b/addons/escoria-core/game/core-scripts/esc/types/esc_object.gd
index 64d3596..eb975ae 100644
--- a/addons/escoria-core/game/core-scripts/esc/types/esc_object.gd
+++ b/addons/escoria-core/game/core-scripts/esc/types/esc_object.gd
@@ -1,7 +1,10 @@
## Represents an object that is able to be handled by Escoria.
-extends RefCounted
class_name ESCObject
+extends RefCounted
+const ESC_EVENTS_CONTAINER_SCRIPT := preload(
+ "res://addons/escoria-core/game/core-scripts/esc/types/esc_events_container.gd"
+)
## Default object state.
const STATE_DEFAULT: String = "default"
@@ -21,12 +24,15 @@ var interactive: bool = true: get = _get_interactive, set = _set_interactive
var state: String = STATE_DEFAULT:
get = get_state
-## The events registered with the object.
-var events: Dictionary = {}
+## The events registered with the object
+var events = ESC_EVENTS_CONTAINER_SCRIPT.new()
## The node representing the object in the scene.
var node: Node
+## Variable that stores the Callable method to unregister the object from Object Manager
+var unregister_object_callback: Callable
+
## Initializes the ESCObject with a global id and node.[br]
## [br]
## #### Parameters[br]
@@ -142,8 +148,8 @@ func is_active() -> bool:
func _get_interactive() -> bool:
if is_instance_valid(self.node) and "is_interactive" in self.node:
return self.node.is_interactive
- else:
- return true
+
+ return true
## Sets the interactive value in the node.[br]
@@ -177,7 +183,7 @@ func _set_interactive(value: bool):
func get_save_data() -> Dictionary:
var save_data: Dictionary = {}
- if self.global_id == "player" and not is_instance_valid(self.node):
+ if self.node is ESCPlayer and not is_instance_valid(self.node):
return save_data
save_data["active"] = self.active
@@ -185,18 +191,59 @@ func get_save_data() -> Dictionary:
save_data["state"] = self.state
if is_instance_valid(self.node):
+ if self.node is ESCItem:
+ if self.node.animations != null:
+ save_data["animations_resource_path"] = (self.node as ESCItem).animations.resource_path
+ var animation_player = (self.node as ESCItem).get_animation_player()
+ if is_instance_valid(animation_player):
+ save_data["current_animation"] = animation_player.get_current_animation()
+
if self.node.get("is_movable") and self.node.is_movable:
save_data["global_transform"] = self.node.global_transform
save_data["last_deg"] = wrapi(self.node._movable._get_angle() - 90 + 1, 0, 360)
save_data["last_dir"] = self.node._movable.last_dir
+ save_data["speed"] = self.node.speed
if self.node.has_method("get_custom_data"):
save_data["custom_data"] = self.node.get_custom_data()
- if self.global_id in ["_music", "_sound", "_ambient"] and self.node.get("state"):
+ if self.global_id in [ESCObjectManager.MUSIC, ESCObjectManager.SOUND, ESCObjectManager.AMBIENT] and self.node.get("state"):
save_data["state"] = self.node.get("state")
- save_data["playback_position"] = self.node.get_playback_position()
+ if ESCProjectSettingsManager.get_setting(
+ ESCProjectSettingsManager.SAVE_SOUNDS_PLAYBACK_POSITION
+ ):
+ save_data["playback_position"] = self.node.get_playback_position()
- if self.global_id == "_camera":
+ if self.global_id == ESCObjectManager.CAMERA:
save_data["target"] = self.node.get("_follow_target").global_id
+ var camera_limit_id = escoria.main.get_camera_limit_id_for_room(escoria.main.current_scene)
+ if camera_limit_id != null:
+ save_data["limit_id"] = camera_limit_id
return save_data
+
+
+## Determines whether the specified events list contains an event with the[br]
+## specified event name and event target, e.g. `:give "filled_out_form"`[br]
+##[br]
+## #### Parameters[br]
+##[br]
+## - event_name: the event name to search for[br]
+## - event_target: the target for the specified event to check; may be null[br]
+##[br]
+## *Returns* true iff events contains an event matching both event_name and event_target
+func has_event_with_target(event_name: String, event_target = null) -> bool:
+ return events.has_event_with_target(event_name, event_target)
+
+
+## Returns the event matching the specified event name and target, e.g. `:give "filled_out_form"`[br]
+## if it exists; returns null otherwise.[br]
+##[br]
+## #### Parameters[br]
+##[br]
+## - event_name: the event name to search for[br]
+## - event_target: the target for the specified event to check; may be null[br]
+##[br]
+## *Returns* the event in `events` iff `events` contains an event matching both `event_name` and `event_target`;[br]
+## returns null otherwise.
+func get_event_with_target(event_name: String, event_target = null):
+ return events.get_event_with_target(event_name, event_target)
diff --git a/addons/escoria-core/game/core-scripts/esc/types/esc_room_container.gd b/addons/escoria-core/game/core-scripts/esc/types/esc_room_container.gd
index 591d2b5..4c5bb80 100644
--- a/addons/escoria-core/game/core-scripts/esc/types/esc_room_container.gd
+++ b/addons/escoria-core/game/core-scripts/esc/types/esc_room_container.gd
@@ -1,7 +1,7 @@
## Abstract base class for a container of Escoria entities specific to a room
## to be stored in and used by the Escoria object manager.
-extends RefCounted
class_name ESCRoomContainer
+extends RefCounted
## Designates whether the objects contained in this container are all reserved objects.
diff --git a/addons/escoria-core/game/core-scripts/esc/types/esc_room_objects.gd b/addons/escoria-core/game/core-scripts/esc/types/esc_room_objects.gd
index 4a617ce..e798e8e 100644
--- a/addons/escoria-core/game/core-scripts/esc/types/esc_room_objects.gd
+++ b/addons/escoria-core/game/core-scripts/esc/types/esc_room_objects.gd
@@ -1,6 +1,6 @@
## Container for a room's `ESCObject`s stored in the object manager.
-extends ESCRoomContainer
class_name ESCRoomObjects
+extends ESCRoomContainer
## The hash of objects registered to the room.
diff --git a/addons/escoria-core/game/core-scripts/esc/types/esc_room_objects_key.gd b/addons/escoria-core/game/core-scripts/esc/types/esc_room_objects_key.gd
index b6f5ce4..0d303d0 100644
--- a/addons/escoria-core/game/core-scripts/esc/types/esc_room_objects_key.gd
+++ b/addons/escoria-core/game/core-scripts/esc/types/esc_room_objects_key.gd
@@ -1,7 +1,7 @@
## Simple pair container to store a room's identifying information for use in
## the object manager.
-extends RefCounted
class_name ESCRoomObjectsKey
+extends RefCounted
## Contains the `global_id` of the room being represented by this key.
diff --git a/addons/escoria-core/game/core-scripts/esc/types/esc_room_terrains.gd b/addons/escoria-core/game/core-scripts/esc/types/esc_room_terrains.gd
index 153a49c..cefac5b 100644
--- a/addons/escoria-core/game/core-scripts/esc/types/esc_room_terrains.gd
+++ b/addons/escoria-core/game/core-scripts/esc/types/esc_room_terrains.gd
@@ -1,6 +1,6 @@
## Container for `NavigationPolygon`s stored in the object manager.
-extends ESCRoomContainer
class_name ESCRoomTerrains
+extends ESCRoomContainer
## The hash of terrains registered to the room.
diff --git a/addons/escoria-core/game/core-scripts/esc/types/esc_scheduled_event.gd b/addons/escoria-core/game/core-scripts/esc/types/esc_scheduled_event.gd
index 736f241..8053366 100644
--- a/addons/escoria-core/game/core-scripts/esc/types/esc_scheduled_event.gd
+++ b/addons/escoria-core/game/core-scripts/esc/types/esc_scheduled_event.gd
@@ -1,6 +1,6 @@
## Represents an event that is scheduled to run sometime in the future.
-extends RefCounted
class_name ESCScheduledEvent
+extends RefCounted
## The event to run when timeout is reached.
diff --git a/addons/escoria-core/game/core-scripts/esc/types/esc_script.gd b/addons/escoria-core/game/core-scripts/esc/types/esc_script.gd
index efca0f8..ba5b7d9 100644
--- a/addons/escoria-core/game/core-scripts/esc/types/esc_script.gd
+++ b/addons/escoria-core/game/core-scripts/esc/types/esc_script.gd
@@ -1,11 +1,49 @@
## Represents a compiled ASHES script.
-extends Resource
class_name ESCScript
+extends Resource
+
+const ESC_EVENTS_CONTAINER_SCRIPT := preload(
+ "res://addons/escoria-core/game/core-scripts/esc/types/esc_events_container.gd"
+)
+
+## The events registered with the script.
+var events = ESC_EVENTS_CONTAINER_SCRIPT.new()
+
+##############
+# New interpreter stuff
+var parsed_events = []
-## A dictionary of `ESCEvent`s contained in this script.
-var events: Dictionary
## The name of the ASHES file parsed for this script, if this script was in fact
## loaded from a file (as opposed to being from an internal string).
var filename: String = ""
+
+##############
+
+
+## Determines whether the specified events list contains an event with the[br]
+## specified event name and event target, e.g. `:give "filled_out_form"`[br]
+##[br]
+## #### Parameters[br]
+##[br]
+## - event_name: the event name to search for[br]
+## - event_target: the target for the specified event to check; may be null[br]
+##[br]
+## *Returns* true iff events contains an event matching both event_name and event_target
+func has_event_with_target(event_name: String, event_target = null) -> bool:
+ return events.has_event_with_target(event_name, event_target)
+
+
+## Returns the event matching the specified event name and target, e.g. `:give "filled_out_form"`[br]
+## if it exists; returns null otherwise.[br]
+##[br]
+## #### Parameters[br]
+##[br]
+## - event_name: the event name to search for[br]
+## - event_target: the target for the specified event to check; may be null[br]
+##[br]
+## *Returns* the event in `events` iff `events` contains an event matching both `event_name` and `event_target`;[br]
+## returns null otherwise.
+func get_event_with_target(event_name: String, event_target = null):
+ return events.get_event_with_target(event_name, event_target)
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 345dd28..5a8e800 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
@@ -5,8 +5,8 @@
## newer ASHES scripting language used by Escoria. Although this class is extended
## to facilitate the execution of actual commands and dialogs, the name may be
## a bit misleading and may eventually be renamed or refactored.
-extends RefCounted
class_name ESCStatement
+extends RefCounted
## Emitted when the event has finished running.[br]
@@ -136,7 +136,7 @@ func run() -> int:
)
if rc == ESCExecution.RC_REPEAT:
return await self.run()
- elif rc != ESCExecution.RC_OK:
+ if rc != ESCExecution.RC_OK:
final_rc = rc
current_statement.is_completed = true
break