ESC compiler rewrite
Splits the former ESC_Runner and ESC_Level_Runner into multiple dedicated managers. Authored-by: Dennis Ploeger <develop@dieploegers.de>
This commit is contained in:
@@ -133,6 +133,16 @@ func set_escoria_main_settings():
|
||||
|
||||
ProjectSettings.set_setting("application/run/main_scene", "res://addons/escoria-core/game/main_scene.tscn")
|
||||
|
||||
if not ProjectSettings.has_setting("escoria/main/command_directories"):
|
||||
ProjectSettings.set_setting("escoria/main/command_directories", [
|
||||
"res://addons/escoria-core/game/core-scripts/esc/commands"
|
||||
])
|
||||
ProjectSettings.add_property_info({
|
||||
"name": "escoria/main/command_directories",
|
||||
"type": TYPE_ARRAY,
|
||||
})
|
||||
|
||||
|
||||
if !ProjectSettings.has_setting("escoria/main/text_lang"):
|
||||
ProjectSettings.set_setting("escoria/main/text_lang", TranslationServer.get_locale())
|
||||
var text_lang_property_info = {
|
||||
@@ -168,6 +178,17 @@ func set_escoria_debug_settings():
|
||||
if !ProjectSettings.has_setting("escoria/debug/development_lang"):
|
||||
ProjectSettings.set_setting("escoria/debug/development_lang", "en")
|
||||
|
||||
# Assure log level preference
|
||||
if not ProjectSettings.has_setting("escoria/debug/log_level"):
|
||||
ProjectSettings.set_setting("escoria/debug/log_level", "ERROR")
|
||||
var property_info = {
|
||||
"name": "escoria/debug/log_level",
|
||||
"type": TYPE_STRING,
|
||||
"hint": PROPERTY_HINT_ENUM,
|
||||
"hint_string": "ERROR,WARNING,INFO,DEBUG"
|
||||
}
|
||||
ProjectSettings.add_property_info(property_info)
|
||||
|
||||
|
||||
func set_escoria_internal_settings():
|
||||
if !ProjectSettings.has_setting("escoria/internals/save_data"):
|
||||
|
||||
@@ -198,7 +198,9 @@ func walk_stop(pos):
|
||||
# orient towards the defined interaction direction set on the object (if any)
|
||||
if walk_context.has("target_object") \
|
||||
and walk_context.target_object.player_orients_on_arrival \
|
||||
and escoria.esc_runner.get_interactive(walk_context.target_object.global_id):
|
||||
and escoria.object_manager.get_object(
|
||||
walk_context.target_object.global_id
|
||||
).interactive:
|
||||
var orientation = walk_context["target_object"].interaction_direction
|
||||
last_dir = orientation
|
||||
parent.animation_sprite.play(parent.animations.idles[orientation][0])
|
||||
@@ -209,11 +211,6 @@ func walk_stop(pos):
|
||||
pose_scale = parent.animations.idles[last_dir][1]
|
||||
update_terrain()
|
||||
|
||||
if walk_context != null:
|
||||
escoria.esc_level_runner.finished(walk_context)
|
||||
escoria.esc_level_runner.finished()
|
||||
# walk_context = null
|
||||
|
||||
yield(parent.animation_sprite, "animation_finished")
|
||||
escoria.logger.info(parent.global_id + " arrived at " + str(walk_context))
|
||||
parent.emit_signal("arrived", walk_context)
|
||||
|
||||
@@ -0,0 +1,295 @@
|
||||
extends Control
|
||||
|
||||
|
||||
func _test_basic() -> bool:
|
||||
var esc = """
|
||||
:test
|
||||
# first group
|
||||
>
|
||||
say player "Test"
|
||||
# Second group
|
||||
> [test]
|
||||
say player "Test2 BLANK"
|
||||
say player "Test3" [test2]
|
||||
# Third group
|
||||
>
|
||||
say player "Test4"
|
||||
# Fourth group
|
||||
>
|
||||
say player "Test5"
|
||||
say player "Test 6"
|
||||
"""
|
||||
var script = escoria.esc_compiler.compile(esc.split("\n"))
|
||||
|
||||
var subject = script
|
||||
assert(subject is ESCScript)
|
||||
|
||||
subject = script.events.keys()
|
||||
assert(subject.size() == 1)
|
||||
assert(subject[0] == "test")
|
||||
|
||||
subject = script.events["test"].statements
|
||||
assert(subject.size() == 2)
|
||||
|
||||
subject = script.events["test"].statements[0]
|
||||
assert(subject is ESCGroup)
|
||||
assert(subject.statements.size() == 4)
|
||||
|
||||
subject = script.events["test"].statements[0].statements[0]
|
||||
assert(subject is ESCCommand)
|
||||
assert(subject.name == "say")
|
||||
assert(subject.parameters.size() == 2)
|
||||
assert(subject.parameters[0] == "player")
|
||||
assert(subject.parameters[1] == "Test")
|
||||
|
||||
subject = script.events["test"].statements[0].statements[1]
|
||||
assert(subject is ESCGroup)
|
||||
assert(subject.conditions.size() == 1)
|
||||
assert(subject.conditions[0] is ESCCondition)
|
||||
assert(subject.conditions[0].flag == "test")
|
||||
|
||||
subject = script.events["test"].statements[0].statements[1].statements[0]
|
||||
assert(subject is ESCCommand)
|
||||
assert(subject.name == "say")
|
||||
assert(subject.parameters.size() == 2)
|
||||
assert(subject.parameters[0] == "player")
|
||||
assert(subject.parameters[1] == "Test2 BLANK")
|
||||
|
||||
subject = script.events["test"].statements[0].statements[2]
|
||||
assert(subject is ESCCommand)
|
||||
assert(subject.name == "say")
|
||||
assert(subject.parameters.size() == 2)
|
||||
assert(subject.parameters[0] == "player")
|
||||
assert(subject.parameters[1] == "Test3")
|
||||
assert(subject.conditions.size() == 1)
|
||||
assert(subject.conditions[0].flag == "test2")
|
||||
|
||||
subject = script.events["test"].statements[0].statements[3]
|
||||
assert(subject is ESCGroup)
|
||||
assert(subject.statements.size() == 1)
|
||||
|
||||
subject = script.events["test"].statements[1]
|
||||
assert(subject is ESCGroup)
|
||||
assert(subject.statements.size() == 2)
|
||||
|
||||
subject = script.events["test"].statements[1].statements[1]
|
||||
assert(subject is ESCCommand)
|
||||
assert(subject.name == "say")
|
||||
assert(subject.parameters[1] == "Test 6")
|
||||
|
||||
return true
|
||||
|
||||
|
||||
func _test_conditions() -> bool:
|
||||
var esc = """
|
||||
:test
|
||||
say player "Test" [flag]
|
||||
say player "Test" [flag1,flag2]
|
||||
say player "Test" [!flag]
|
||||
say player "Test" [i/flag]
|
||||
say player "Test" [i/flag,flag]
|
||||
say player "Test" [i/flag,flag,!flag2]
|
||||
say player "Test" [eq flag 3]
|
||||
say player "Test" [eq flag 3,gt flag 5]
|
||||
say player "Test" [!eq flag 3]
|
||||
"""
|
||||
var script = escoria.esc_compiler.compile(esc.split("\n"))
|
||||
|
||||
var subject = script.events["test"].statements[0]
|
||||
assert(subject is ESCCommand)
|
||||
assert(subject.conditions.size() == 1)
|
||||
|
||||
subject = script.events["test"].statements[0].conditions[0]
|
||||
assert(subject.flag == "flag")
|
||||
assert(not subject.negated)
|
||||
assert(not subject.inventory)
|
||||
assert(subject.comparison == ESCCondition.COMPARISON_NONE)
|
||||
|
||||
subject = script.events["test"].statements[1].conditions
|
||||
assert(subject.size() == 2)
|
||||
assert(subject[0].flag == "flag1")
|
||||
assert(subject[1].flag == "flag2")
|
||||
|
||||
subject = script.events["test"].statements[2].conditions
|
||||
assert(subject.size() == 1)
|
||||
assert(subject[0].flag == "flag")
|
||||
assert(subject[0].negated)
|
||||
|
||||
subject = script.events["test"].statements[3].conditions
|
||||
assert(subject.size() == 1)
|
||||
assert(subject[0].flag == "flag")
|
||||
assert(subject[0].inventory)
|
||||
|
||||
subject = script.events["test"].statements[4].conditions
|
||||
assert(subject.size() == 2)
|
||||
assert(subject[0].flag == "flag")
|
||||
assert(subject[0].inventory)
|
||||
assert(subject[1].flag == "flag")
|
||||
assert(not subject[1].inventory)
|
||||
|
||||
subject = script.events["test"].statements[5].conditions
|
||||
assert(subject.size() == 3)
|
||||
assert(subject[0].flag == "flag")
|
||||
assert(subject[0].inventory)
|
||||
assert(subject[1].flag == "flag")
|
||||
assert(not subject[1].inventory)
|
||||
assert(subject[2].flag == "flag2")
|
||||
assert(not subject[2].inventory)
|
||||
assert(subject[2].negated)
|
||||
|
||||
subject = script.events["test"].statements[6].conditions
|
||||
assert(subject.size() == 1)
|
||||
assert(subject[0].flag == "flag")
|
||||
assert(subject[0].comparison == ESCCondition.COMPARISON_EQ)
|
||||
assert(subject[0].comparison_value == 3)
|
||||
|
||||
subject = script.events["test"].statements[7].conditions
|
||||
assert(subject.size() == 2)
|
||||
assert(subject[0].flag == "flag")
|
||||
assert(subject[0].comparison == ESCCondition.COMPARISON_EQ)
|
||||
assert(subject[0].comparison_value == 3)
|
||||
assert(subject[1].flag == "flag")
|
||||
assert(subject[1].comparison == ESCCondition.COMPARISON_GT)
|
||||
assert(subject[1].comparison_value == 5)
|
||||
|
||||
subject = script.events["test"].statements[8].conditions
|
||||
assert(subject.size() == 1)
|
||||
assert(subject[0].flag == "flag")
|
||||
assert(subject[0].comparison == ESCCondition.COMPARISON_EQ)
|
||||
assert(subject[0].comparison_value == 3)
|
||||
assert(subject[0].negated)
|
||||
|
||||
return true
|
||||
|
||||
|
||||
func _test_event_flags() -> bool:
|
||||
var esc = """
|
||||
:test | TK
|
||||
:test2 | TK NO_TT
|
||||
:test3 | TK NO_TT NO_HUD
|
||||
:test4 | TK NO_TT CUT_BLACK
|
||||
"""
|
||||
var script = escoria.esc_compiler.compile(esc.split("\n"))
|
||||
|
||||
var subject = script.events
|
||||
assert(subject.keys().size() == 4)
|
||||
assert("test" in subject.keys())
|
||||
assert("test2" in subject.keys())
|
||||
assert("test3" in subject.keys())
|
||||
assert("test4" in subject.keys())
|
||||
|
||||
subject = script.events["test"]
|
||||
assert(subject.name == "test")
|
||||
assert(subject.flags & ESCEvent.FLAG_TK != 0)
|
||||
assert(subject.flags & ESCEvent.FLAG_NO_TT == 0)
|
||||
|
||||
subject = script.events["test2"]
|
||||
assert(subject.name == "test2")
|
||||
assert(subject.flags & ESCEvent.FLAG_TK != 0)
|
||||
assert(subject.flags & ESCEvent.FLAG_NO_TT != 0)
|
||||
|
||||
subject = script.events["test3"]
|
||||
assert(subject.name == "test3")
|
||||
assert(subject.flags & ESCEvent.FLAG_TK != 0)
|
||||
assert(subject.flags & ESCEvent.FLAG_NO_TT != 0)
|
||||
assert(subject.flags & ESCEvent.FLAG_NO_HUD != 0)
|
||||
|
||||
subject = script.events["test4"]
|
||||
assert(subject.name == "test4")
|
||||
assert(subject.flags & ESCEvent.FLAG_TK != 0)
|
||||
assert(subject.flags & ESCEvent.FLAG_NO_TT != 0)
|
||||
assert(subject.flags & ESCEvent.FLAG_NO_HUD == 0)
|
||||
assert(subject.flags & ESCEvent.FLAG_CUT_BLACK != 0)
|
||||
return true
|
||||
|
||||
|
||||
func _test_dialog() -> bool:
|
||||
var esc = """
|
||||
:test
|
||||
?
|
||||
- "Option 1"
|
||||
say player "test"
|
||||
say player "testb"
|
||||
say player "testb?"
|
||||
- "Option 2" [flag]
|
||||
say player "test2"
|
||||
?
|
||||
- "Suboption 1"
|
||||
say player "test21"
|
||||
- "Suboption 2"
|
||||
say player "test22"
|
||||
!
|
||||
- "Option 3"
|
||||
>
|
||||
say player "test3"
|
||||
!
|
||||
"""
|
||||
var script = escoria.esc_compiler.compile(esc.split("\n"))
|
||||
|
||||
var subject = script.events["test"].statements
|
||||
assert(subject.size() == 1)
|
||||
|
||||
assert(subject[0] is ESCDialog)
|
||||
assert(subject[0].options.size() == 3)
|
||||
|
||||
subject = script.events["test"].statements[0].options[0]
|
||||
assert(subject is ESCDialogOption)
|
||||
assert(subject.option == "Option 1")
|
||||
|
||||
subject = script.events["test"].statements[0].options[0].statements
|
||||
assert(subject.size() == 3)
|
||||
assert(subject[0] is ESCCommand)
|
||||
assert(subject[0].name == "say")
|
||||
assert(subject[0].parameters.size() == 2)
|
||||
assert(subject[1] is ESCCommand)
|
||||
assert(subject[1].name == "say")
|
||||
assert(subject[1].parameters.size() == 2)
|
||||
assert(subject[1].parameters[1] == "testb")
|
||||
assert(subject[2] is ESCCommand)
|
||||
assert(subject[2].name == "say")
|
||||
assert(subject[2].parameters.size() == 2)
|
||||
assert(subject[2].parameters[1] == "testb?")
|
||||
|
||||
subject = script.events["test"].statements[0].options[1]
|
||||
assert(subject is ESCDialogOption)
|
||||
assert(subject.option == "Option 2")
|
||||
assert(subject.conditions.size() == 1)
|
||||
assert(subject.conditions[0].flag == "flag")
|
||||
|
||||
subject = script.events["test"].statements[0].options[1].statements
|
||||
assert(subject.size() == 2)
|
||||
assert(subject[0] is ESCCommand)
|
||||
assert(subject[0].name == "say")
|
||||
assert(subject[0].parameters.size() == 2)
|
||||
|
||||
assert(subject[1] is ESCDialog)
|
||||
assert(subject[1].options.size() == 2)
|
||||
|
||||
subject = script.events["test"].statements[0].options[2]
|
||||
assert(subject is ESCDialogOption)
|
||||
assert(subject.option == "Option 3")
|
||||
|
||||
subject = script.events["test"].statements[0].options[2].statements
|
||||
assert(subject.size() == 1)
|
||||
assert(subject[0] is ESCGroup)
|
||||
assert(subject[0].statements.size() == 1)
|
||||
assert(subject[0].statements[0] is ESCCommand)
|
||||
assert(subject[0].statements[0].parameters.size() == 2)
|
||||
|
||||
return true
|
||||
|
||||
|
||||
func _on_BasicFunctionality_pressed():
|
||||
$VBoxContainer/VBoxContainer/BasicFunctionality.pressed = self._test_basic()
|
||||
|
||||
|
||||
func _on_Conditions_pressed():
|
||||
$VBoxContainer/VBoxContainer/Conditions.pressed = self._test_conditions()
|
||||
|
||||
|
||||
func _on_EventFlags_pressed():
|
||||
$VBoxContainer/VBoxContainer/EventFlags.pressed = self._test_event_flags()
|
||||
|
||||
|
||||
func _on_Dialog_pressed():
|
||||
$VBoxContainer/VBoxContainer/Dialog.pressed = self._test_dialog()
|
||||
@@ -0,0 +1,58 @@
|
||||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://addons/escoria-core/game/core-scripts/esc/_test/test_esc_compiler.gd" type="Script" id=1]
|
||||
|
||||
[node name="Testsuite" type="Control"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
script = ExtResource( 1 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="."]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_right = 1.0
|
||||
margin_bottom = 1.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer"]
|
||||
margin_right = 1281.0
|
||||
margin_bottom = 172.0
|
||||
|
||||
[node name="BasicFunctionality" type="CheckButton" parent="VBoxContainer/VBoxContainer"]
|
||||
margin_right = 1281.0
|
||||
margin_bottom = 40.0
|
||||
text = "Basic Functionality"
|
||||
align = 1
|
||||
|
||||
[node name="Conditions" type="CheckButton" parent="VBoxContainer/VBoxContainer"]
|
||||
margin_top = 44.0
|
||||
margin_right = 1281.0
|
||||
margin_bottom = 84.0
|
||||
text = "Check conditions"
|
||||
align = 1
|
||||
|
||||
[node name="EventFlags" type="CheckButton" parent="VBoxContainer/VBoxContainer"]
|
||||
margin_top = 88.0
|
||||
margin_right = 1281.0
|
||||
margin_bottom = 128.0
|
||||
text = "Check event flags"
|
||||
align = 1
|
||||
|
||||
[node name="Dialog" type="CheckButton" parent="VBoxContainer/VBoxContainer"]
|
||||
margin_top = 132.0
|
||||
margin_right = 1281.0
|
||||
margin_bottom = 172.0
|
||||
text = "Check dialogs"
|
||||
align = 1
|
||||
|
||||
[connection signal="pressed" from="VBoxContainer/VBoxContainer/BasicFunctionality" to="." method="_on_BasicFunctionality_pressed"]
|
||||
[connection signal="pressed" from="VBoxContainer/VBoxContainer/Conditions" to="." method="_on_Conditions_pressed"]
|
||||
[connection signal="pressed" from="VBoxContainer/VBoxContainer/EventFlags" to="." method="_on_EventFlags_pressed"]
|
||||
[connection signal="pressed" from="VBoxContainer/VBoxContainer/Dialog" to="." method="_on_Dialog_pressed"]
|
||||
@@ -0,0 +1,47 @@
|
||||
# `accept_input [ALL|NONE|SKIP]`
|
||||
#
|
||||
# What type of input does the game accept. ALL is the default, SKIP allows
|
||||
# skipping of dialog but nothing else, NONE denies all input. Including opening
|
||||
# the menu etc. SKIP and NONE also disable autosaves.
|
||||
#
|
||||
# *Note* that SKIP gets reset to ALL when the event is done, but NONE persists.
|
||||
# This allows you to create cut scenes with SKIP where the dialog can be
|
||||
# skipped, but also initiate locked#### down cutscenes with accept_input
|
||||
# NONE in :setup and accept_input ALL later in :ready.
|
||||
#
|
||||
# @STUB
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
class_name AcceptInputCommand
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
1,
|
||||
[TYPE_STRING],
|
||||
["ALL"]
|
||||
)
|
||||
|
||||
|
||||
# Validate wether the given arguments match the command descriptor
|
||||
func validate(arguments: Array):
|
||||
if not arguments[0] in ["ALL", "NONE", "SKIP"]:
|
||||
escoria.logger.report_errors(
|
||||
"accept_input: invalid parameter",
|
||||
[
|
||||
"%s is not a valid parameter value (ALL, NONE, SKIP)" %\
|
||||
arguments[0]
|
||||
]
|
||||
)
|
||||
return false
|
||||
return .validate(arguments)
|
||||
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
escoria.logger.report_errors(
|
||||
"accept_input: command not implemented",
|
||||
[]
|
||||
)
|
||||
return ESCExecution.RC_ERROR
|
||||
46
addons/escoria-core/game/core-scripts/esc/commands/anim.gd
Normal file
46
addons/escoria-core/game/core-scripts/esc/commands/anim.gd
Normal file
@@ -0,0 +1,46 @@
|
||||
# `anim object name [reverse]`
|
||||
#
|
||||
# Executes the animation specificed with the "name" parameter on the object,
|
||||
# without blocking. The next command in the event will be executed immediately
|
||||
# after. Optional parameters:
|
||||
#
|
||||
# * reverse: plays the animation in reverse when true
|
||||
#
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
class_name AnimCommand
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
2,
|
||||
[TYPE_STRING, TYPE_STRING, TYPE_BOOL],
|
||||
[null, null, false]
|
||||
)
|
||||
|
||||
|
||||
# Validate wether the given arguments match the command descriptor
|
||||
func validate(arguments: Array):
|
||||
if not escoria.object_manager.objects.has(arguments[0]):
|
||||
escoria.logger.report_errors(
|
||||
"anim: invalid object",
|
||||
[
|
||||
"Object with global id %s not found." % arguments[0]
|
||||
]
|
||||
)
|
||||
return false
|
||||
return .validate(arguments)
|
||||
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
var obj = escoria.object_manager.objects[command_params[0]]
|
||||
var anim_id = command_params[1]
|
||||
var reverse = command_params[2]
|
||||
var animator = (obj.node as ESCItem).get_animation_player()
|
||||
if reverse:
|
||||
animator.play_backwards(anim_id)
|
||||
else:
|
||||
animator.play(anim_id)
|
||||
return ESCExecution.RC_OK
|
||||
@@ -0,0 +1,44 @@
|
||||
# `camera_push target [time] [type]`
|
||||
#
|
||||
# Push camera to `target`. Target must have camera_pos set. If it's of type
|
||||
# Camera2D, its zoom will be used as well as position. `type` is any of the
|
||||
# Tween.TransitionType values without the prefix, eg. LINEAR, QUART or CIRC;
|
||||
# defaults to QUART. A `time` value of 0 will set the camera immediately.
|
||||
#
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
class_name CameraPushCommand
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
1,
|
||||
[TYPE_STRING, [TYPE_REAL, TYPE_INT], TYPE_STRING],
|
||||
[null, 1, "QUAD"]
|
||||
)
|
||||
|
||||
|
||||
# Validate wether the given arguments match the command descriptor
|
||||
func validate(arguments: Array):
|
||||
if not escoria.object_manager.objects.has(arguments[0]):
|
||||
escoria.logger.report_errors(
|
||||
"camera_push: invalid object",
|
||||
[
|
||||
"Object global id %s not found" % arguments[0]
|
||||
]
|
||||
)
|
||||
return false
|
||||
|
||||
return .validate(arguments)
|
||||
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
(escoria.object_manager.get_object("camera").node as ESCCamera)\
|
||||
.push(
|
||||
escoria.object_manager.get_object(command_params[0]).node,
|
||||
command_params[1],
|
||||
command_params[2]
|
||||
)
|
||||
return ESCExecution.RC_OK
|
||||
@@ -0,0 +1,40 @@
|
||||
# `camera_set_limits camlimits_id`
|
||||
# Sets the camera limits to the one defined under `camlimits_id` in ESCRoom's
|
||||
# camera_limits array.
|
||||
# - camlimits_id : int : id of the camera limits to apply (defined in ESCRoom's
|
||||
# camera_limits array)
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
class_name CameraSetLimitsCommand
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
1,
|
||||
[TYPE_INT],
|
||||
[null]
|
||||
)
|
||||
|
||||
|
||||
# Validate wether the given arguments match the command descriptor
|
||||
func validate(arguments: Array):
|
||||
if not escoria.main.current_scene.camera_limits.size() < arguments[0]:
|
||||
escoria.logger.report_errors(
|
||||
"camera_set_limits: invalid limits id",
|
||||
[
|
||||
"Limit id %d is bigger than limits array size %d" % [
|
||||
arguments[0],
|
||||
escoria.main.current_scene.camera_limits.size()
|
||||
]
|
||||
]
|
||||
)
|
||||
return false
|
||||
|
||||
return .validate(arguments)
|
||||
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
escoria.main.set_camera_limits(command_params[0])
|
||||
return ESCExecution.RC_OK
|
||||
@@ -0,0 +1,28 @@
|
||||
# `camera_set_pos speed x y`
|
||||
#
|
||||
# Moves the camera to a position defined by "x" and "y", at the speed defined
|
||||
# by "speed" in pixels per second. If speed is 0, camera is teleported to the
|
||||
# position.
|
||||
#
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
class_name CameraSetPosCommand
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
3,
|
||||
[[TYPE_REAL, TYPE_INT], TYPE_INT, TYPE_INT],
|
||||
[null, null, null]
|
||||
)
|
||||
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
(escoria.object_manager.get_object("camera").node as ESCCamera)\
|
||||
.set_target(
|
||||
Vector2(command_params[1], command_params[2]),
|
||||
command_params[0]
|
||||
)
|
||||
return ESCExecution.RC_OK
|
||||
@@ -0,0 +1,42 @@
|
||||
# `camera_set_target speed object`
|
||||
#
|
||||
# Configures the camera to set the target to the given `object`using `speed`
|
||||
# as speed limit.
|
||||
# This is the default behavior (default follow object is "player").
|
||||
#
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
class_name CameraSetTargetCommand
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
2,
|
||||
[[TYPE_REAL, TYPE_INT], TYPE_STRING],
|
||||
[null, null]
|
||||
)
|
||||
|
||||
|
||||
# Validate wether the given arguments match the command descriptor
|
||||
func validate(arguments: Array):
|
||||
if not escoria.object_manager.objects.has(arguments[1]):
|
||||
escoria.logger.report_errors(
|
||||
"camera_set_pos: invalid object",
|
||||
[
|
||||
"Object with global id %s not found" % arguments[1]
|
||||
]
|
||||
)
|
||||
return false
|
||||
|
||||
return .validate(arguments)
|
||||
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
(escoria.object_manager.get_object("camera").node as ESCCamera)\
|
||||
.set_target(
|
||||
escoria.object_manager.get_object(command_params[1]).node,
|
||||
command_params[0]
|
||||
)
|
||||
return ESCExecution.RC_OK
|
||||
@@ -0,0 +1,29 @@
|
||||
# `camera_set_zoom magnitude [time]`
|
||||
#
|
||||
# Zooms the camera in/out to the desired `magnitude`. Values larger than 1 zooms
|
||||
# the camera out, and smaller values zooms in, relative to the default value
|
||||
# of 1. An optional `time` in seconds controls how long it takes for the camera
|
||||
# to zoom into position.
|
||||
#
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
class_name CameraSetZoomCommand
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
1,
|
||||
[[TYPE_REAL, TYPE_INT], [TYPE_REAL, TYPE_INT]],
|
||||
[null, 0.0]
|
||||
)
|
||||
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
(escoria.object_manager.get_object("camera").node as ESCCamera)\
|
||||
.set_camera_zoom(
|
||||
command_params[0],
|
||||
command_params[1]
|
||||
)
|
||||
return ESCExecution.RC_OK
|
||||
@@ -0,0 +1,42 @@
|
||||
# `camera_set_zoom_height pixels [time]
|
||||
#
|
||||
# Zooms the camera in/out to the desired `pixels` height.
|
||||
# An optional `time` in seconds controls how long it takes for the camera
|
||||
# to zoom into position.
|
||||
#
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
class_name CameraSetZoomHeightCommand
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
1,
|
||||
[TYPE_INT, [TYPE_INT, TYPE_REAL]],
|
||||
[null, 0.0]
|
||||
)
|
||||
|
||||
|
||||
# Validate wether the given arguments match the command descriptor
|
||||
func validate(arguments: Array):
|
||||
if arguments[0] < 0:
|
||||
escoria.logger.report_errors(
|
||||
"camera_set_zoom_height: invalid height",
|
||||
[
|
||||
"Can't zoom to a negative height %d" % arguments[0]
|
||||
]
|
||||
)
|
||||
return false
|
||||
|
||||
return .validate(arguments)
|
||||
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
(escoria.object_manager.get_object("camera").node as ESCCamera)\
|
||||
.set_camera_zoom(
|
||||
command_params[0] / escoria.game_size.y,
|
||||
command_params[1]
|
||||
)
|
||||
return ESCExecution.RC_OK
|
||||
@@ -0,0 +1,30 @@
|
||||
# `camera_shift x y [time] [type]`
|
||||
#
|
||||
# Shift camera by `x` and `y` pixels over `time` seconds. `type` is any of the
|
||||
# Tween.TransitionType values without the prefix, eg. LINEAR, QUART or CIRC;
|
||||
# defaults to QUART.
|
||||
#
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
class_name CameraShiftCommand
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
2,
|
||||
[TYPE_INT, TYPE_INT, [TYPE_INT, TYPE_REAL], TYPE_STRING],
|
||||
[null, null, 1, "QUAD"]
|
||||
)
|
||||
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
(escoria.object_manager.get_object("camera").node as ESCCamera)\
|
||||
.shift(
|
||||
command_params[0],
|
||||
command_params[1],
|
||||
command_params[2],
|
||||
command_params[3]
|
||||
)
|
||||
return ESCExecution.RC_OK
|
||||
@@ -0,0 +1,132 @@
|
||||
# `change_scene path run_events`
|
||||
#
|
||||
# Loads a new scene, specified by "path". The `run_events` variable is a
|
||||
# boolean (default true) which you never want to set manually! It's there only
|
||||
# to benefit save games, so they don't conflict with the scene's events.
|
||||
#
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
class_name ChangeSceneCommand
|
||||
|
||||
|
||||
# An array of scenes that have already been loaded
|
||||
var readied_scenes: Array = []
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
1,
|
||||
[TYPE_STRING, TYPE_BOOL],
|
||||
[null, true]
|
||||
)
|
||||
|
||||
|
||||
# Validate wether the given arguments match the command descriptor
|
||||
func validate(arguments: Array) -> bool:
|
||||
if not ResourceLoader.exists(arguments[0]):
|
||||
escoria.logger.report_errors(
|
||||
"change_scene: Invalid scene",
|
||||
["Scene %s was not found" % arguments[0]]
|
||||
)
|
||||
return false
|
||||
if not ResourceLoader.exists(
|
||||
ProjectSettings.get_setting("escoria/ui/game_scene")
|
||||
):
|
||||
escoria.logger.report_errors(
|
||||
"change_scene: Game scene not found",
|
||||
[
|
||||
"The path set in 'ui/game_scene' was not found: %s" % \
|
||||
ProjectSettings.get_setting("escoria/ui/game_scene")
|
||||
]
|
||||
)
|
||||
return false
|
||||
return .validate(arguments)
|
||||
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
escoria.logger.info("Changing scene to %s (run_events = %s)" % [
|
||||
command_params[0],
|
||||
command_params[1]
|
||||
])
|
||||
|
||||
if escoria.main.current_scene:
|
||||
escoria.globals_manager.set_global(
|
||||
"ESC_LAST_SCENE",
|
||||
escoria.main.current_scene.global_id,
|
||||
true
|
||||
)
|
||||
|
||||
escoria.main.scene_transition.fade_out()
|
||||
yield(escoria.main.scene_transition, "transition_done")
|
||||
|
||||
escoria.main_menu_instance.hide()
|
||||
|
||||
var res_room = escoria.resource_cache.get_resource(command_params[0])
|
||||
var res_game = escoria.resource_cache.get_resource(
|
||||
ProjectSettings.get_setting("escoria/ui/game_scene")
|
||||
)
|
||||
|
||||
# Load game scene
|
||||
var game_scene = res_game.instance()
|
||||
if not game_scene:
|
||||
escoria.logger.report_errors(
|
||||
"ChangeSceneCommand.run: Failed loading game scene",
|
||||
[
|
||||
"Failed loading scene %s" % \
|
||||
ProjectSettings.get_setting("escoria/ui/game_scene")
|
||||
]
|
||||
)
|
||||
|
||||
# Load room scene
|
||||
var room_scene = res_room.instance()
|
||||
if room_scene:
|
||||
room_scene.add_child(game_scene)
|
||||
room_scene.move_child(game_scene, 0)
|
||||
escoria.main.set_scene(room_scene)
|
||||
|
||||
if "esc_script" in room_scene and room_scene.esc_script \
|
||||
and command_params[1]:
|
||||
|
||||
var script = escoria.esc_compiler.load_esc_file(
|
||||
room_scene.esc_script
|
||||
)
|
||||
|
||||
if script.events.has("setup"):
|
||||
escoria.event_manager.queue_event(script.events["setup"])
|
||||
var rc = yield(escoria.event_manager, "event_finished")
|
||||
while rc[1] != "setup":
|
||||
rc = yield(escoria.event_manager, "event_finished")
|
||||
if rc[0] != ESCExecution.RC_OK:
|
||||
return rc[0]
|
||||
|
||||
# If scene was never visited, add "ready" event to the events stack
|
||||
if not command_params[0] in self.readied_scenes \
|
||||
and script.events.has("ready"):
|
||||
escoria.event_manager.queue_event(script.events["ready"])
|
||||
var rc = yield(escoria.event_manager, "event_finished")
|
||||
while rc[1] != "ready":
|
||||
rc = yield(escoria.event_manager, "event_finished")
|
||||
if rc[0] != ESCExecution.RC_OK:
|
||||
return rc[0]
|
||||
|
||||
escoria.main.scene_transition.fade_in()
|
||||
yield(escoria.main.scene_transition, "transition_done")
|
||||
|
||||
self.readied_scenes.append(command_params[0])
|
||||
|
||||
# Clear queued resources
|
||||
escoria.resource_cache.clear()
|
||||
|
||||
escoria.inputs_manager.hotspot_focused = ""
|
||||
else:
|
||||
escoria.logger.report_errors(
|
||||
"ChangeSceneCommand.run: Failed loading room scene",
|
||||
[
|
||||
"Failed loading scene %s" % command_params[0]
|
||||
]
|
||||
)
|
||||
return ESCExecution.RC_ERROR
|
||||
|
||||
return ESCExecution.RC_OK
|
||||
73
addons/escoria-core/game/core-scripts/esc/commands/custom.gd
Normal file
73
addons/escoria-core/game/core-scripts/esc/commands/custom.gd
Normal file
@@ -0,0 +1,73 @@
|
||||
# `custom object node func_name [params]`
|
||||
#
|
||||
# Calls the function `func_name` of the node `node` of object `object` with
|
||||
# the optional `params`. This is a blocking function
|
||||
#
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
class_name CustomCommand
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
3,
|
||||
[TYPE_STRING, TYPE_STRING, TYPE_STRING, TYPE_ARRAY],
|
||||
[null, null, null, []]
|
||||
)
|
||||
|
||||
|
||||
# Validate wether the given arguments match the command descriptor
|
||||
func validate(arguments: Array):
|
||||
if not escoria.object_manager.objects.has(arguments[0]):
|
||||
escoria.logger.report_errors(
|
||||
"custom: invalid object",
|
||||
[
|
||||
"Object with global id %s not found" % arguments[0]
|
||||
]
|
||||
)
|
||||
return false
|
||||
elif not escoria.object_manager.get_object(arguments[0]).node.has_node(
|
||||
arguments[1]
|
||||
):
|
||||
escoria.logger.report_errors(
|
||||
"custom: invalid node",
|
||||
[
|
||||
"Object with global id %s has no node %s" % [
|
||||
arguments[0],
|
||||
arguments[1],
|
||||
]
|
||||
]
|
||||
)
|
||||
return false
|
||||
elif not escoria.object_manager.get_object(arguments[0]).node\
|
||||
.get_node(
|
||||
arguments[1]
|
||||
)\
|
||||
.has_method(
|
||||
arguments[2]
|
||||
):
|
||||
escoria.logger.report_errors(
|
||||
"custom: invalid function",
|
||||
[
|
||||
"Object with global id %s and node %s has no function %s" % [
|
||||
arguments[0],
|
||||
arguments[1],
|
||||
arguments[2],
|
||||
]
|
||||
]
|
||||
)
|
||||
return false
|
||||
return .validate(arguments)
|
||||
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
var object = escoria.object_manager.get_object(
|
||||
command_params[0]
|
||||
)
|
||||
object.node.get_node(command_params[1]).call(
|
||||
command_params[2],
|
||||
command_params[3]
|
||||
)
|
||||
return ESCExecution.RC_OK
|
||||
@@ -0,0 +1,49 @@
|
||||
# `cut_scene object name [reverse]`
|
||||
#
|
||||
# Executes the animation specificed with the "name" parameter on the object,
|
||||
# blocking. The next command in the event will be executed when the animation
|
||||
# is finished playing. Optional parameters:
|
||||
#
|
||||
# * reverse plays the animation in reverse when true
|
||||
#
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
class_name CutSceneCommand
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
2,
|
||||
[TYPE_STRING, TYPE_STRING, TYPE_BOOL],
|
||||
[null, null, false]
|
||||
)
|
||||
|
||||
|
||||
# Validate wether the given arguments match the command descriptor
|
||||
func validate(arguments: Array):
|
||||
if not escoria.object_manager.objects.has(arguments[0]):
|
||||
escoria.logger.report_errors(
|
||||
"anim: invalid object",
|
||||
[
|
||||
"Object with global id %s not found." % arguments[0]
|
||||
]
|
||||
)
|
||||
return false
|
||||
return .validate(arguments)
|
||||
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
var obj = escoria.object_manager.objects[command_params[0]]
|
||||
var anim_id = command_params[1]
|
||||
var reverse = command_params[2]
|
||||
var animator = (obj.node as ESCItem).get_animation_player()
|
||||
if reverse:
|
||||
animator.play_backwards(anim_id)
|
||||
else:
|
||||
animator.play(anim_id)
|
||||
var animation_finished = yield(animator, "animation_finished")
|
||||
while animation_finished != anim_id:
|
||||
animation_finished = yield(animator, "animation_finished")
|
||||
return ESCExecution.RC_OK
|
||||
22
addons/escoria-core/game/core-scripts/esc/commands/debug.gd
Normal file
22
addons/escoria-core/game/core-scripts/esc/commands/debug.gd
Normal file
@@ -0,0 +1,22 @@
|
||||
# `debug string [string2 ...]`
|
||||
#
|
||||
# Takes 1 or more strings, prints them to the console.
|
||||
#
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
class_name DebugCommand
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
1,
|
||||
[TYPE_STRING],
|
||||
[""]
|
||||
)
|
||||
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
escoria.logger.debug("debug command issued", command_params)
|
||||
return ESCExecution.RC_OK
|
||||
@@ -0,0 +1,40 @@
|
||||
# `dec_global name value`
|
||||
#
|
||||
# Subtracts the value from global with given "name". Value and global must
|
||||
# both be integers.
|
||||
#
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
class_name DecGlobalCommand
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
2,
|
||||
[TYPE_STRING, TYPE_INT],
|
||||
[null, 0]
|
||||
)
|
||||
|
||||
|
||||
# Validate wether the given arguments match the command descriptor
|
||||
func validate(arguments: Array):
|
||||
if not escoria.globals_manager.get(arguments[0]) is int:
|
||||
escoria.logger.report_errors(
|
||||
"dec_global: invalid global",
|
||||
[
|
||||
"Global %s didn't have an integer value." % arguments[0]
|
||||
]
|
||||
)
|
||||
return false
|
||||
return .validate(arguments)
|
||||
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
escoria.globals_manager.set_global(
|
||||
command_params[0],
|
||||
escoria.globals_manager.get_global(command_params[0]) - \
|
||||
command_params[1]
|
||||
)
|
||||
return ESCExecution.RC_OK
|
||||
@@ -0,0 +1,36 @@
|
||||
# `enable_terrain node_name`
|
||||
# Enable the ESCTerrain's NavigationPolygonInstance defined by given node name.
|
||||
# Disables previously activated NavigationPolygonInstance.
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
class_name EnableTerrainCommand
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
1,
|
||||
[TYPE_STRING],
|
||||
[null]
|
||||
)
|
||||
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
var name : String = command_params[0]
|
||||
if escoria.room_terrain.has_node(name):
|
||||
var new_active_navigation_instance = \
|
||||
escoria.room_terrain.get_node(name)
|
||||
escoria.room_terrain.current_active_navigation_instance.enabled = false
|
||||
escoria.room_terrain.current_active_navigation_instance = \
|
||||
new_active_navigation_instance
|
||||
escoria.room_terrain.current_active_navigation_instance.enabled = true
|
||||
return ESCExecution.RC_OK
|
||||
else:
|
||||
escoria.logger.report_errors(
|
||||
"EnableTerrainCommand.run: Can not find terrain node",
|
||||
[
|
||||
"Terrain node %s could not be found" % name
|
||||
]
|
||||
)
|
||||
return ESCExecution.RC_ERROR
|
||||
@@ -0,0 +1,29 @@
|
||||
# `game_over continue_enabled show_credits`
|
||||
#
|
||||
# Ends the game. Use the "continue_enabled" parameter to enable or disable the
|
||||
# continue button in the main menu afterwards. The "show_credits" parameter
|
||||
# loads the ui/end_credits scene if true. You can configure it to your regular
|
||||
# credits scene if you want.
|
||||
#
|
||||
# @STUB
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
class_name GameOverCommand
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
0,
|
||||
[TYPE_BOOL, TYPE_BOOL],
|
||||
[false, true]
|
||||
)
|
||||
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
escoria.logger.report_errors(
|
||||
"game_over: command not implemented",
|
||||
[]
|
||||
)
|
||||
return ESCExecution.RC_ERROR
|
||||
@@ -0,0 +1,48 @@
|
||||
# `inc_global name value`
|
||||
#
|
||||
# Adds the value to global with given "name". Value and global must both be
|
||||
# integers.
|
||||
#
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
class_name IncGlobalCommand
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
2,
|
||||
[TYPE_STRING, TYPE_INT],
|
||||
[null, 0]
|
||||
)
|
||||
|
||||
|
||||
# Validate wether the given arguments match the command descriptor
|
||||
func validate(arguments: Array):
|
||||
if not escoria.globals_manager.has(arguments[0]):
|
||||
escoria.logger.report_errors(
|
||||
"inc_global: invalid global",
|
||||
[
|
||||
"Global %s does not exist." % arguments[0]
|
||||
]
|
||||
)
|
||||
return false
|
||||
if not escoria.globals_manager.get(arguments[0]) is int:
|
||||
escoria.logger.report_errors(
|
||||
"inc_global: invalid global",
|
||||
[
|
||||
"Global %s didn't have an integer value." % arguments[0]
|
||||
]
|
||||
)
|
||||
return false
|
||||
return .validate(arguments)
|
||||
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
escoria.globals_manager.set_global(
|
||||
command_params[0],
|
||||
escoria.globals_manager.get_global(command_params[0]) +\
|
||||
command_params[1]
|
||||
)
|
||||
return ESCExecution.RC_OK
|
||||
@@ -0,0 +1,22 @@
|
||||
# `inventory_add item`
|
||||
#
|
||||
# Add an item to the inventory
|
||||
#
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
class_name InventoryAddCommand
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
1,
|
||||
[TYPE_STRING],
|
||||
[null]
|
||||
)
|
||||
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
escoria.inventory_manager.add_item(command_params[0])
|
||||
return ESCExecution.RC_OK
|
||||
@@ -0,0 +1,22 @@
|
||||
# `inventory_remove item`
|
||||
#
|
||||
# Remove an item from the inventory.
|
||||
#
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
class_name InventoryRemoveCommand
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
1,
|
||||
[TYPE_STRING],
|
||||
[null]
|
||||
)
|
||||
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
escoria.inventory_manager.remove_item(command_params[0])
|
||||
return ESCExecution.RC_OK
|
||||
@@ -0,0 +1,28 @@
|
||||
# `play_snd object file [loop]`
|
||||
#
|
||||
# Plays the sound specificed with the "file" parameter on the object, without
|
||||
# blocking. You can play background sounds, eg. during scene changes, with
|
||||
# `play_snd bg_snd res://...`
|
||||
#
|
||||
# @STUB
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
class_name PlaySndCommand
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
2,
|
||||
[TYPE_STRING, TYPE_STRING, TYPE_BOOL],
|
||||
[null, null, false]
|
||||
)
|
||||
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
escoria.logger.report_errors(
|
||||
"play_snd: command not implemented",
|
||||
[]
|
||||
)
|
||||
return ESCExecution.RC_ERROR
|
||||
@@ -0,0 +1,42 @@
|
||||
# `queue_animation object animation`
|
||||
#
|
||||
# Similar to queue_resource, queues the resources necessary to have an
|
||||
# animation loaded on an item. The resource paths are taken from the item
|
||||
# placeholders.
|
||||
#
|
||||
# @STUB
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
class_name QueueAnimationCommand
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
2,
|
||||
[TYPE_STRING, TYPE_STRING],
|
||||
[null, null]
|
||||
)
|
||||
|
||||
|
||||
# Validate wether the given arguments match the command descriptor
|
||||
func validate(arguments: Array):
|
||||
if not escoria.object_manager.objects.has(arguments[0]):
|
||||
escoria.logger.report_errors(
|
||||
"queue_animation: invalid first object",
|
||||
[
|
||||
"Object with global id %s not found" % arguments[0]
|
||||
]
|
||||
)
|
||||
return false
|
||||
# TODO: Check if animation is valid
|
||||
return .validate(arguments)
|
||||
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
escoria.logger.report_errors(
|
||||
"queue_animation: command not implemented",
|
||||
[]
|
||||
)
|
||||
return ESCExecution.RC_ERROR
|
||||
@@ -0,0 +1,41 @@
|
||||
# `queue_resource path [front_of_queue]`
|
||||
#
|
||||
# Queues the load of a resource in a background thread. The `path` must be a
|
||||
# full path inside your game, for example "res://scenes/next_scene.tscn". The
|
||||
# "front_of_queue" parameter is optional (default value false), to put the
|
||||
# resource in the front of the queue. Queued resources are cleared when a
|
||||
# change scene happens (but after the scene is loaded, meaning you can queue
|
||||
# resources that belong to the next scene).
|
||||
#
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
class_name QueueResourceCommand
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
1,
|
||||
[],
|
||||
[null, false]
|
||||
)
|
||||
|
||||
|
||||
# Validate wether the given arguments match the command descriptor
|
||||
func validate(arguments: Array) -> bool:
|
||||
if not ResourceLoader.exists(arguments[0]):
|
||||
escoria.logger.report_errors(
|
||||
"queue_resource: Invalid resource",
|
||||
["Resource %s was not found" % arguments[0]]
|
||||
)
|
||||
return false
|
||||
return .validate(arguments)
|
||||
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
escoria.resource_cache.queue_resource(
|
||||
command_params[0],
|
||||
command_params[1]
|
||||
)
|
||||
return ESCExecution.RC_OK
|
||||
22
addons/escoria-core/game/core-scripts/esc/commands/repeat.gd
Normal file
22
addons/escoria-core/game/core-scripts/esc/commands/repeat.gd
Normal file
@@ -0,0 +1,22 @@
|
||||
# `repeat`
|
||||
#
|
||||
# Restarts the execution of the current scope at the start. A scope can be a
|
||||
# group or an event.
|
||||
#
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
class_name RepeatCommand
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
0,
|
||||
[],
|
||||
[]
|
||||
)
|
||||
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
return ESCExecution.RC_CANCEL
|
||||
85
addons/escoria-core/game/core-scripts/esc/commands/say.gd
Normal file
85
addons/escoria-core/game/core-scripts/esc/commands/say.gd
Normal file
@@ -0,0 +1,85 @@
|
||||
# `say object text [type] [avatar]`
|
||||
#
|
||||
# Runs the specified string as a dialog said by the object. Blocks execution
|
||||
# until the dialog finishes playing. Optional parameters:
|
||||
#
|
||||
# * "type" determines the type of dialog UI to use. Default value is "default"
|
||||
# * "avatar" determines the avatar to use for the dialog. Default value is
|
||||
# "default"
|
||||
#
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
class_name SayCommand
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
2,
|
||||
[TYPE_STRING, TYPE_STRING, TYPE_STRING, TYPE_STRING],
|
||||
[
|
||||
null,
|
||||
null,
|
||||
ProjectSettings.get_setting("escoria/ui/default_dialog_scene")\
|
||||
.get_file().get_basename(),
|
||||
"default"
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
|
||||
var dict : Dictionary
|
||||
var dialog_scene_name = ProjectSettings.get_setting(
|
||||
"escoria/ui/default_dialog_scene"
|
||||
)
|
||||
|
||||
if dialog_scene_name.empty():
|
||||
escoria.logger.report_errors(
|
||||
"say()",
|
||||
[
|
||||
"Project setting 'escoria/ui/default_dialog_scene' is not set.",
|
||||
"Please set a default dialog scene."
|
||||
]
|
||||
)
|
||||
return ESCExecution.RC_ERROR
|
||||
|
||||
var file = dialog_scene_name.get_file()
|
||||
var extension = dialog_scene_name.get_extension()
|
||||
dialog_scene_name = file.rstrip("." + extension)
|
||||
|
||||
# Manage specific dialog scene
|
||||
if command_params.size() > 2:
|
||||
dialog_scene_name = command_params[2]
|
||||
|
||||
# Manage translation/voice lines keys in the form of:
|
||||
# line_key:"Default line text"
|
||||
# If a line_key exists, we'll set it a label as it will automatically be
|
||||
# translated
|
||||
var dialog_key_line = command_params[1].split(":", true, 1)
|
||||
if dialog_key_line.size() > 1:
|
||||
dialog_key_line[1] = dialog_key_line[1].trim_prefix("\"")
|
||||
|
||||
dict = {
|
||||
"key": dialog_key_line[0],
|
||||
"line": dialog_key_line[1] if dialog_key_line.size() > 1 \
|
||||
else dialog_key_line[0],
|
||||
"ui": dialog_scene_name
|
||||
}
|
||||
|
||||
escoria.current_state = escoria.GAME_STATE.DIALOG
|
||||
|
||||
if !escoria.dialog_player:
|
||||
escoria.logger.report_errors(
|
||||
"No dialog player registered",
|
||||
[
|
||||
"No dialog player was registered and the say command was" +
|
||||
"encountered."
|
||||
]
|
||||
)
|
||||
return ESCExecution.RC_ERROR
|
||||
|
||||
escoria.dialog_player.say(command_params[0], dict)
|
||||
yield(escoria.dialog_player, "dialog_line_finished")
|
||||
return ESCExecution.RC_OK
|
||||
@@ -0,0 +1,53 @@
|
||||
# `sched_event time object event`
|
||||
#
|
||||
# Schedules the execution of an "event" found in "object" in a time in seconds.
|
||||
# If another event is running at the time, execution starts when the running
|
||||
# event ends.
|
||||
#
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
class_name SchedEventCommand
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
3,
|
||||
[TYPE_INT, TYPE_STRING, TYPE_STRING],
|
||||
[null, null, null]
|
||||
)
|
||||
|
||||
|
||||
# Validate wether the given arguments match the command descriptor
|
||||
func validate(arguments: Array):
|
||||
if not escoria.object_manager.objects.has(arguments[1]):
|
||||
escoria.logger.report_errors(
|
||||
"sched_event: invalid object",
|
||||
[
|
||||
"Object with global id %s not found" % arguments[1]
|
||||
]
|
||||
)
|
||||
return false
|
||||
elif not escoria.object_manager.get_object(arguments[1]).events\
|
||||
.has(arguments[2]):
|
||||
escoria.logger.report_errors(
|
||||
"sched_event: invalid object event",
|
||||
[
|
||||
"Object with global id %s has no event %s" % [
|
||||
arguments[1],
|
||||
arguments[2],
|
||||
]
|
||||
]
|
||||
)
|
||||
return false
|
||||
return .validate(arguments)
|
||||
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
escoria.event_manager.schedule_event(
|
||||
escoria.object_manager.get_object(command_params[1])\
|
||||
.events[command_params[2]],
|
||||
command_params[0]
|
||||
)
|
||||
return ESCExecution.RC_OK
|
||||
@@ -0,0 +1,37 @@
|
||||
# `set_active object value`
|
||||
#
|
||||
# Changes the "active" state of the object, value can be true or false.
|
||||
# Inactive objects are hidden in the scene.
|
||||
#
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
class_name SetActiveCommand
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
2,
|
||||
[TYPE_STRING, TYPE_BOOL],
|
||||
[null, null]
|
||||
)
|
||||
|
||||
|
||||
# Validate wether the given arguments match the command descriptor
|
||||
func validate(arguments: Array):
|
||||
if not escoria.object_manager.objects.has(arguments[0]):
|
||||
escoria.logger.report_errors(
|
||||
"set_active: invalid object",
|
||||
[
|
||||
"Object with global id %s not found" % arguments[0]
|
||||
]
|
||||
)
|
||||
return false
|
||||
return .validate(arguments)
|
||||
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
escoria.object_manager.get_object(command_params[0]).active = \
|
||||
command_params[1]
|
||||
return ESCExecution.RC_OK
|
||||
@@ -0,0 +1,45 @@
|
||||
# `set_angle object degrees`
|
||||
#
|
||||
# Turns object to a degrees angle without animations. 0 sets object facing
|
||||
# forward, 90 sets it 90 degrees clockwise ("east") etc. When turning to the
|
||||
# destination angle, animations are played if they're defined in animations.
|
||||
#
|
||||
# object must be player or interactive. degrees must be between [0, 360] or an
|
||||
# error is reported.
|
||||
#
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
class_name SetAngleCommand
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
2,
|
||||
[TYPE_STRING, TYPE_INT],
|
||||
[null, true]
|
||||
)
|
||||
|
||||
|
||||
# Validate wether the given arguments match the command descriptor
|
||||
func validate(arguments: Array):
|
||||
if not escoria.object_manager.objects.has(arguments[0]):
|
||||
escoria.logger.report_errors(
|
||||
"set_angle: invalid object",
|
||||
[
|
||||
"Object with global id %s not found" % arguments[0]
|
||||
]
|
||||
)
|
||||
return false
|
||||
return .validate(arguments)
|
||||
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
# HACK Countering the fact that angle_to_point() function gives
|
||||
# angle against X axis not Y, we need to check direction using (angle-90°).
|
||||
# Since the ESC command already gives the right angle, we add 90.
|
||||
escoria.object_manager.get_object(command_params[0]).node\
|
||||
.set_angle(int(command_params[1] + 90))
|
||||
return ESCExecution.RC_OK
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
# `set_global name value`
|
||||
#
|
||||
# Changes the value of the global "name" with the value. Value can be "true",
|
||||
# "false" or an integer.
|
||||
#
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
class_name SetGlobalCommand
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
2,
|
||||
[TYPE_STRING, [TYPE_INT, TYPE_BOOL, TYPE_STRING]],
|
||||
[null, null]
|
||||
)
|
||||
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
escoria.globals_manager.set_global(command_params[0], command_params[1])
|
||||
return ESCExecution.RC_OK
|
||||
@@ -0,0 +1,27 @@
|
||||
# `set_globals pattern value`
|
||||
#
|
||||
# Changes the value of multiple globals using a wildcard pattern, where "*"
|
||||
# matches zero or more arbitrary characters and "?" matches any single
|
||||
# character except a period (".").
|
||||
#
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
class_name SetGlobalsCommand
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
2,
|
||||
[TYPE_STRING, [TYPE_BOOL, TYPE_STRING, TYPE_INT]],
|
||||
[null, null]
|
||||
)
|
||||
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
escoria.globals_manager.set_global_wildcard(
|
||||
command_params[0],
|
||||
command_params[1]
|
||||
)
|
||||
return ESCExecution.RC_OK
|
||||
@@ -0,0 +1,28 @@
|
||||
# `set_hud_visible visible`
|
||||
#
|
||||
# If you have a cutscene like sequence where the player doesn't have control,
|
||||
# and you also have HUD elements visible, use this to hide the HUD. You want
|
||||
# to do that because it explicitly signals the player that there is no control
|
||||
# over the game at the moment. "visible" is true or false.
|
||||
#
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
class_name SetHudVisibleCommand
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
1,
|
||||
[TYPE_BOOL],
|
||||
[null]
|
||||
)
|
||||
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
if command_params[0]:
|
||||
escoria.main.current_scene.game.show_ui()
|
||||
else:
|
||||
escoria.main.current_scene.game.hide_ui()
|
||||
return ESCExecution.RC_OK
|
||||
@@ -0,0 +1,36 @@
|
||||
# `set_interactive object value`
|
||||
#
|
||||
# Sets whether or not an object should be interactive.
|
||||
#
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
class_name SetInteractiveCommand
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
2,
|
||||
[TYPE_STRING, TYPE_BOOL],
|
||||
[null, null]
|
||||
)
|
||||
|
||||
|
||||
# Validate wether the given arguments match the command descriptor
|
||||
func validate(arguments: Array):
|
||||
if not escoria.object_manager.objects.has(arguments[0]):
|
||||
escoria.logger.report_errors(
|
||||
"set_interactive: invalid object",
|
||||
[
|
||||
"Object with global id %s not found" % arguments[0]
|
||||
]
|
||||
)
|
||||
return false
|
||||
return .validate(arguments)
|
||||
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
escoria.object_manager.get_object(command_params[0]).interactive = \
|
||||
command_params[1]
|
||||
return ESCExecution.RC_OK
|
||||
@@ -0,0 +1,50 @@
|
||||
# `set_sound_state player sound loop`
|
||||
#
|
||||
# Change the sound playing on `player` to `sound` with optional looping if
|
||||
# `loop` is true.
|
||||
# Valid players are "bg_music" and "bg_sound".
|
||||
# Aside from paths to sound or music files, the values *off* and *default*.
|
||||
# *default* is the default value.
|
||||
# are also valid for `sound`
|
||||
#
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
class_name SetSoundStateCommand
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
1,
|
||||
[TYPE_STRING, TYPE_STRING, TYPE_BOOL],
|
||||
[null, "default", false]
|
||||
)
|
||||
|
||||
|
||||
# Validate wether the given arguments match the command descriptor
|
||||
func validate(arguments: Array):
|
||||
if not arguments[0] in ["bg_music", "bg_sound"]:
|
||||
escoria.logger.report_errors(
|
||||
"SetSoundStateCommand.validate: invalid player",
|
||||
[
|
||||
"Player %s is invalid found" % arguments[0]
|
||||
]
|
||||
)
|
||||
return false
|
||||
if not arguments[1] in ["default", "off"] \
|
||||
or not ResourceLoader.exists(arguments[1]):
|
||||
escoria.logger.report_errors(
|
||||
"SetSoundStateCommand.validate: invalid sound",
|
||||
[
|
||||
"Sound %s is invalid or not found" % arguments[1]
|
||||
]
|
||||
)
|
||||
return false
|
||||
return .validate(arguments)
|
||||
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
escoria.main.get_node(command_params[0])\
|
||||
.set_state(command_params[1], command_params[2])
|
||||
return ESCExecution.RC_OK
|
||||
@@ -0,0 +1,34 @@
|
||||
# `set_speed object speed`
|
||||
#
|
||||
# Sets how fast object moves. Speed is an integer.
|
||||
#
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
class_name SetSpeedCommand
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
2,
|
||||
[TYPE_STRING, TYPE_INT],
|
||||
[null, null]
|
||||
)
|
||||
|
||||
# Validate wether the given arguments match the command descriptor
|
||||
func validate(arguments: Array):
|
||||
if not escoria.object_manager.objects.has(arguments[0]):
|
||||
escoria.logger.report_errors(
|
||||
"set_speed: invalid object",
|
||||
[
|
||||
"Object with global id %s not found" % arguments[0]
|
||||
]
|
||||
)
|
||||
return false
|
||||
return .validate(arguments)
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
(escoria.object_manager.objects[command_params[0]].node as ESCItem).\
|
||||
set_speed(command_params[1])
|
||||
return ESCExecution.RC_OK
|
||||
@@ -0,0 +1,41 @@
|
||||
# `set_state object state [immediate]`
|
||||
#
|
||||
# Changes the state of an object, and executes the state animation if present.
|
||||
# The command can be used to change the appearance of an item or a player
|
||||
# character.
|
||||
# If `immediate` is set to true, the animation is run directly
|
||||
#
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
class_name SetStateCommand
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
2,
|
||||
[TYPE_STRING, TYPE_STRING, TYPE_BOOL],
|
||||
[null, null, false]
|
||||
)
|
||||
|
||||
|
||||
# Validate wether the given arguments match the command descriptor
|
||||
func validate(arguments: Array):
|
||||
if not escoria.object_manager.objects.has(arguments[0]):
|
||||
escoria.logger.report_errors(
|
||||
"set_state: invalid object",
|
||||
[
|
||||
"Object %s not found." % arguments[0]
|
||||
]
|
||||
)
|
||||
return false
|
||||
return .validate(arguments)
|
||||
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
(escoria.object_manager.objects[command_params[0]] as ESCObject).set_state(
|
||||
command_params[1],
|
||||
command_params[2]
|
||||
)
|
||||
return ESCExecution.RC_OK
|
||||
50
addons/escoria-core/game/core-scripts/esc/commands/slide.gd
Normal file
50
addons/escoria-core/game/core-scripts/esc/commands/slide.gd
Normal file
@@ -0,0 +1,50 @@
|
||||
# `slide object1 object2 [speed]`
|
||||
#
|
||||
# Moves object1 towards the position of object2, at the speed determined by
|
||||
# object1's "speed" property, unless overridden. This command is non-blocking.
|
||||
# It does not respect the room's navigation polygons, so you can move items
|
||||
# where the player can't walk.
|
||||
#
|
||||
# @STUB
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
class_name SlideCommand
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
2,
|
||||
[TYPE_STRING, TYPE_STRING, TYPE_INT],
|
||||
[null, null, null]
|
||||
)
|
||||
|
||||
|
||||
# Validate wether the given arguments match the command descriptor
|
||||
func validate(arguments: Array):
|
||||
if not escoria.object_manager.objects.has(arguments[0]):
|
||||
escoria.logger.report_errors(
|
||||
"slide: invalid first object",
|
||||
[
|
||||
"Object with global id %s not found" % arguments[0]
|
||||
]
|
||||
)
|
||||
return false
|
||||
if not escoria.object_manager.objects.has(arguments[1]):
|
||||
escoria.logger.report_errors(
|
||||
"slide: invalid second object",
|
||||
[
|
||||
"Object with global id %s not found" % arguments[0]
|
||||
]
|
||||
)
|
||||
return false
|
||||
return .validate(arguments)
|
||||
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
escoria.logger.report_errors(
|
||||
"slide: command not implemented",
|
||||
[]
|
||||
)
|
||||
return ESCExecution.RC_ERROR
|
||||
@@ -0,0 +1,50 @@
|
||||
# `slide_block object1 object2 [speed]`
|
||||
#
|
||||
# Moves object1 towards the position of object2, at the speed determined by
|
||||
# object1's "speed" property, unless overridden. This command is blocking.
|
||||
# It does not respect the room's navigation polygons, so you can move items
|
||||
# where the player can't walk.
|
||||
#
|
||||
# @STUB
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
class_name SlideBlockCommand
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
2,
|
||||
[TYPE_STRING, TYPE_STRING, TYPE_INT],
|
||||
[null, null, null]
|
||||
)
|
||||
|
||||
|
||||
# Validate wether the given arguments match the command descriptor
|
||||
func validate(arguments: Array):
|
||||
if not escoria.object_manager.objects.has(arguments[0]):
|
||||
escoria.logger.report_errors(
|
||||
"slide_block: invalid first object",
|
||||
[
|
||||
"Object with global id %s not found" % arguments[0]
|
||||
]
|
||||
)
|
||||
return false
|
||||
if not escoria.object_manager.objects.has(arguments[1]):
|
||||
escoria.logger.report_errors(
|
||||
"slide_block: invalid second object",
|
||||
[
|
||||
"Object with global id %s not found" % arguments[0]
|
||||
]
|
||||
)
|
||||
return false
|
||||
return .validate(arguments)
|
||||
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
escoria.logger.report_errors(
|
||||
"slide_block: command not implemented",
|
||||
[]
|
||||
)
|
||||
return ESCExecution.RC_ERROR
|
||||
61
addons/escoria-core/game/core-scripts/esc/commands/spawn.gd
Normal file
61
addons/escoria-core/game/core-scripts/esc/commands/spawn.gd
Normal file
@@ -0,0 +1,61 @@
|
||||
# `spawn path [object2]`
|
||||
#
|
||||
# Instances a scene determined by "path", and places in the position of
|
||||
# object2 (object2 is optional)
|
||||
#
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
class_name SpawnCommand
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
1,
|
||||
[TYPE_STRING, TYPE_STRING],
|
||||
[null, null]
|
||||
)
|
||||
|
||||
|
||||
# Validate wether the given arguments match the command descriptor
|
||||
func validate(arguments: Array):
|
||||
if not ResourceLoader.exists(arguments[0]):
|
||||
escoria.logger.report_errors(
|
||||
"spawn: invalid scene path",
|
||||
[
|
||||
"Scene with path %s not found" % arguments[0]
|
||||
]
|
||||
)
|
||||
return false
|
||||
if arguments[1] and not escoria.object_manager.objects.has(arguments[1]):
|
||||
escoria.logger.report_errors(
|
||||
"spawn: invalid object",
|
||||
[
|
||||
"Object with global id %s not found" % arguments[1]
|
||||
]
|
||||
)
|
||||
return false
|
||||
return .validate(arguments)
|
||||
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
var res_scene = escoria.resource_cache.get_resource(command_params[0])
|
||||
|
||||
# Load room scene
|
||||
var scene = res_scene.instance()
|
||||
if scene:
|
||||
escoria.main.get_node("/root").add_child(scene)
|
||||
if command_params[1]:
|
||||
var obj = escoria.object_manager.get_object(command_params[1])
|
||||
scene.set_position(obj.get_global_position())
|
||||
escoria.inputs_manager.hotspot_focused = false
|
||||
else:
|
||||
escoria.logger.report_errors(
|
||||
"spawn: Invalid scene",
|
||||
[
|
||||
"Failed loading scene %s" % command_params[0]
|
||||
]
|
||||
)
|
||||
|
||||
return ESCExecution.RC_OK
|
||||
21
addons/escoria-core/game/core-scripts/esc/commands/stop.gd
Normal file
21
addons/escoria-core/game/core-scripts/esc/commands/stop.gd
Normal file
@@ -0,0 +1,21 @@
|
||||
# `stop`
|
||||
#
|
||||
# Stops the event's execution.
|
||||
#
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
class_name StopCommand
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
0,
|
||||
[],
|
||||
[]
|
||||
)
|
||||
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
return ESCExecution.RC_CANCEL
|
||||
@@ -0,0 +1,50 @@
|
||||
# `teleport object1 object2 [angle]`
|
||||
#
|
||||
# Sets the position of object1 to the position of object2. By default,
|
||||
# object2's interact_angle is used to turn object1, but angle will override
|
||||
# this. Useful for doors and such with an interact_angle you don't always want
|
||||
# to adhere to when re-entering a room.
|
||||
#
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
class_name TeleportCommand
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
2,
|
||||
[TYPE_STRING, TYPE_STRING, TYPE_INT],
|
||||
[null, null, null]
|
||||
)
|
||||
|
||||
|
||||
# Validate wether the given arguments match the command descriptor
|
||||
func validate(arguments: Array):
|
||||
if not escoria.object_manager.objects.has(arguments[0]):
|
||||
escoria.logger.report_errors(
|
||||
"teleport: invalid first object",
|
||||
[
|
||||
"Object with global id %s not found" % arguments[0]
|
||||
]
|
||||
)
|
||||
return false
|
||||
if not escoria.object_manager.objects.has(arguments[1]):
|
||||
escoria.logger.report_errors(
|
||||
"teleport: invalid second object",
|
||||
[
|
||||
"Object with global id %s not found" % arguments[0]
|
||||
]
|
||||
)
|
||||
return false
|
||||
return .validate(arguments)
|
||||
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
escoria.object_manager.get_object(command_params[0]).node\
|
||||
.teleport(
|
||||
escoria.object_manager.get_object(command_params[1]).node,
|
||||
command_params[2]
|
||||
)
|
||||
return ESCExecution.RC_OK
|
||||
@@ -0,0 +1,44 @@
|
||||
# `turn_to object degrees`
|
||||
#
|
||||
# Turns object to a degrees angle with a directions animation.
|
||||
#
|
||||
# 0 sets object facing forward, 90 sets it 90 degrees clockwise ("east") etc.
|
||||
# When turning to the destination angle, animations are played if they're
|
||||
# defined in animations. object must be player or interactive. degrees must
|
||||
# be between [0, 360] or an error is reported.
|
||||
#
|
||||
# @STUB
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
class_name TurnToCommand
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
2,
|
||||
[TYPE_STRING, TYPE_INT],
|
||||
[null, true]
|
||||
)
|
||||
|
||||
|
||||
# Validate wether the given arguments match the command descriptor
|
||||
func validate(arguments: Array):
|
||||
if not escoria.object_manager.objects.has(arguments[0]):
|
||||
escoria.logger.report_errors(
|
||||
"turn_to: invalid object",
|
||||
[
|
||||
"Object with global id %s not found" % arguments[0]
|
||||
]
|
||||
)
|
||||
return false
|
||||
return .validate(arguments)
|
||||
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
escoria.logger.report_errors(
|
||||
"turn_to: command not implemented",
|
||||
[]
|
||||
)
|
||||
return ESCExecution.RC_ERROR
|
||||
22
addons/escoria-core/game/core-scripts/esc/commands/wait.gd
Normal file
22
addons/escoria-core/game/core-scripts/esc/commands/wait.gd
Normal file
@@ -0,0 +1,22 @@
|
||||
# `wait seconds`
|
||||
#
|
||||
# Blocks execution of the current script for a number of seconds specified by the "seconds" parameter.
|
||||
#
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
class_name WaitCommand
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
1,
|
||||
[TYPE_INT],
|
||||
[null]
|
||||
)
|
||||
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
yield(escoria.get_tree().create_timer(command_params[0]), "timeout")
|
||||
return ESCExecution.RC_OK
|
||||
45
addons/escoria-core/game/core-scripts/esc/commands/walk.gd
Normal file
45
addons/escoria-core/game/core-scripts/esc/commands/walk.gd
Normal file
@@ -0,0 +1,45 @@
|
||||
# `walk object1 object2 [speed]`
|
||||
#
|
||||
# Walks, using the walk animation, object1 towards the position of object2,
|
||||
# at the speed determined by object1's "speed" property,
|
||||
# unless overridden. This command is non-blocking.
|
||||
#
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
class_name WalkCommand
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
2,
|
||||
[TYPE_STRING, TYPE_STRING, TYPE_INT],
|
||||
[null, null, null]
|
||||
)
|
||||
|
||||
|
||||
# Validate wether the given arguments match the command descriptor
|
||||
func validate(arguments: Array):
|
||||
if not escoria.object_manager.objects.has(arguments[0]):
|
||||
escoria.logger.report_errors(
|
||||
"walk: invalid first object",
|
||||
[
|
||||
"Object with global id %s not found" % arguments[0]
|
||||
]
|
||||
)
|
||||
return false
|
||||
if not escoria.object_manager.objects.has(arguments[1]):
|
||||
escoria.logger.report_errors(
|
||||
"walk: invalid second object",
|
||||
[
|
||||
"Object with global id %s not found" % arguments[0]
|
||||
]
|
||||
)
|
||||
return false
|
||||
return .validate(arguments)
|
||||
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
escoria.do("walk", command_params)
|
||||
return ESCExecution.RC_OK
|
||||
@@ -0,0 +1,49 @@
|
||||
# `walk_block object1 object2 [speed]`
|
||||
#
|
||||
# Walks, using the walk animation, object1 towards the position of object2,
|
||||
# at the speed determined by object1's "speed" property,
|
||||
# unless overridden. This command is blocking.
|
||||
#
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
class_name WalkBlockCommand
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
2,
|
||||
[TYPE_STRING, TYPE_STRING, TYPE_INT],
|
||||
[null, null, null]
|
||||
)
|
||||
|
||||
|
||||
# Validate wether the given arguments match the command descriptor
|
||||
func validate(arguments: Array):
|
||||
if not escoria.object_manager.objects.has(arguments[0]):
|
||||
escoria.logger.report_errors(
|
||||
"walk_block: invalid first object",
|
||||
[
|
||||
"Object with global id %s not found" % arguments[0]
|
||||
]
|
||||
)
|
||||
return false
|
||||
if not escoria.object_manager.objects.has(arguments[1]):
|
||||
escoria.logger.report_errors(
|
||||
"walk_block: invalid second object",
|
||||
[
|
||||
"Object with global id %s not found" % arguments[0]
|
||||
]
|
||||
)
|
||||
return false
|
||||
return .validate(arguments)
|
||||
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
escoria.do("walk", command_params)
|
||||
yield(
|
||||
(escoria.object_manager.objects[command_params[0]].node as ESCItem),
|
||||
"arrived"
|
||||
)
|
||||
return ESCExecution.RC_OK
|
||||
@@ -0,0 +1,38 @@
|
||||
# `walk_to_pos player x y`
|
||||
#
|
||||
# Makes the `player` walk to the position `x`/`y`.
|
||||
#
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
class_name WalkToPosCommand
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
3,
|
||||
[TYPE_STRING, TYPE_INT, TYPE_INT],
|
||||
[null, null, null]
|
||||
)
|
||||
|
||||
|
||||
# Validate wether the given arguments match the command descriptor
|
||||
func validate(arguments: Array):
|
||||
if not escoria.object_manager.objects.has(arguments[0]):
|
||||
escoria.logger.report_errors(
|
||||
"walk_to_pos: invalid first object",
|
||||
[
|
||||
"Object with global id %s not found" % arguments[0]
|
||||
]
|
||||
)
|
||||
return false
|
||||
return .validate(arguments)
|
||||
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
escoria.do("walk", [
|
||||
command_params[0],
|
||||
Vector2(command_params[1], command_params[2])
|
||||
])
|
||||
return ESCExecution.RC_OK
|
||||
@@ -0,0 +1,42 @@
|
||||
# `walk_to_pos_block player x y`
|
||||
#
|
||||
# Makes the `player` walk to the position `x`/`y`. This is a blocking command.
|
||||
#
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
class_name WalkToPosBlockCommand
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
3,
|
||||
[TYPE_STRING, TYPE_INT, TYPE_INT],
|
||||
[null, null, null]
|
||||
)
|
||||
|
||||
|
||||
# Validate wether the given arguments match the command descriptor
|
||||
func validate(arguments: Array):
|
||||
if not escoria.object_manager.objects.has(arguments[0]):
|
||||
escoria.logger.report_errors(
|
||||
"walk_to_pos_block: invalid first object",
|
||||
[
|
||||
"Object with global id %s not found" % arguments[0]
|
||||
]
|
||||
)
|
||||
return false
|
||||
return .validate(arguments)
|
||||
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
escoria.do("walk", [
|
||||
command_params[0],
|
||||
Vector2(command_params[1], command_params[2])
|
||||
])
|
||||
yield(
|
||||
(escoria.object_manager.objects[command_params[0]].node as ESCItem),
|
||||
"arrived"
|
||||
)
|
||||
return ESCExecution.RC_OK
|
||||
188
addons/escoria-core/game/core-scripts/esc/esc_action_manager.gd
Normal file
188
addons/escoria-core/game/core-scripts/esc/esc_action_manager.gd
Normal file
@@ -0,0 +1,188 @@
|
||||
# Manages currently carried out actions
|
||||
extends Object
|
||||
class_name ESCActionManager
|
||||
|
||||
|
||||
# The current action was changed
|
||||
signal action_changed
|
||||
|
||||
|
||||
# Current verb used
|
||||
var current_action : String = "" setget set_current_action
|
||||
|
||||
# Current tool (ESCItem/ESCInventoryItem) used
|
||||
var current_tool: ESCObject
|
||||
|
||||
|
||||
# Set the current action
|
||||
func set_current_action(action : String):
|
||||
if action != current_action:
|
||||
clear_current_tool()
|
||||
|
||||
current_action = action
|
||||
emit_signal("action_changed")
|
||||
|
||||
|
||||
# Clear the current action
|
||||
func clear_current_action():
|
||||
set_current_action("")
|
||||
|
||||
|
||||
# Clear the current tool
|
||||
func clear_current_tool():
|
||||
current_tool = null
|
||||
|
||||
|
||||
# Activates the action for given params
|
||||
#
|
||||
# #### Parameters
|
||||
#
|
||||
# - action String Action to execute (defined in attached ESC file and in
|
||||
# action verbs UI) eg: arrived, use, look, pickup...
|
||||
# - target: Target ESC object
|
||||
# - combine_with: ESC object to combine with
|
||||
func activate(
|
||||
action: String,
|
||||
target: ESCObject,
|
||||
combine_with: ESCObject = null
|
||||
) -> int:
|
||||
escoria.logger.info("Activated action %s on %s" % [action, target])
|
||||
|
||||
# If we're using an action which item requires to combine
|
||||
if target.node is ESCItem\
|
||||
and action in target.node.combine_if_action_used_among:
|
||||
# Check if object must be in inventory to be used
|
||||
if target.node.use_from_inventory_only:
|
||||
if escoria.inventory_manager.inventory_has(target.global_id):
|
||||
# Player has item in inventory, we check the element to use on
|
||||
if combine_with:
|
||||
var do_combine = true
|
||||
if combine_with.node is ESCItem \
|
||||
and combine_with.node.use_from_inventory_only\
|
||||
and not escoria.inventory_manager.inventory_has(
|
||||
combine_with.global_id
|
||||
):
|
||||
do_combine = false
|
||||
|
||||
if do_combine:
|
||||
var target_event = "%s %s" % [
|
||||
action,
|
||||
combine_with.global_id
|
||||
]
|
||||
var combine_with_event = "%s %s" % [
|
||||
action,
|
||||
target.global_id
|
||||
]
|
||||
if target.events.has(target_event):
|
||||
escoria.event_manager.queue_event(target.events[
|
||||
target_event
|
||||
])
|
||||
var event_returned = yield(
|
||||
escoria.event_manager,
|
||||
"event_finished"
|
||||
)
|
||||
while event_returned[1] != target_event:
|
||||
event_returned = yield(
|
||||
escoria.event_manager,
|
||||
"event_finished"
|
||||
)
|
||||
if event_returned[0] == ESCExecution.RC_OK:
|
||||
escoria.action_manager\
|
||||
.clear_current_action()
|
||||
return event_returned[0]
|
||||
elif combine_with.events.has(combine_with_event)\
|
||||
and not combine_with.node.combine_is_one_way:
|
||||
escoria.event_manager.queue_event(
|
||||
combine_with.events[
|
||||
combine_with_event
|
||||
]
|
||||
)
|
||||
var event_returned = yield(
|
||||
escoria.event_manager,
|
||||
"event_finished"
|
||||
)
|
||||
while event_returned[1] != combine_with_event:
|
||||
event_returned = yield(
|
||||
escoria.event_manager,
|
||||
"event_finished"
|
||||
)
|
||||
if event_returned[0] == ESCExecution.RC_OK:
|
||||
escoria.action_manager\
|
||||
.clear_current_action()
|
||||
return event_returned[0]
|
||||
else:
|
||||
var errors = [
|
||||
"Attempted to execute action %s between item %s and item %s" % [
|
||||
action,
|
||||
target.global_id,
|
||||
combine_with.global_id
|
||||
]
|
||||
]
|
||||
if combine_with.node.combine_is_one_way:
|
||||
errors.append(
|
||||
"Reason: %s's item interaction " +\
|
||||
"is one-way." % combine_with.global_id
|
||||
)
|
||||
escoria.logger.report_warnings(
|
||||
"ESCActionManager.activate: Invalid action",
|
||||
errors
|
||||
)
|
||||
|
||||
return ESCExecution.RC_ERROR
|
||||
else:
|
||||
escoria.logger.report_warnings(
|
||||
"ESCActionManager.activate: Invalid action on item",
|
||||
[
|
||||
"Trying to combine object %s with %s, "+
|
||||
"but %s is not in inventory." % [
|
||||
target.global_id,
|
||||
combine_with.global_id,
|
||||
combine_with.global_id
|
||||
]
|
||||
]
|
||||
)
|
||||
return ESCExecution.RC_ERROR
|
||||
else:
|
||||
# We're missing a target here.
|
||||
# Tell the Label to add a conjunction and wait for another
|
||||
# click to add the target to p_param. Until then, return
|
||||
current_tool = target
|
||||
return ESCExecution.RC_OK
|
||||
else:
|
||||
escoria.logger.report_warnings(
|
||||
"ESCActionManager.activate: Invalid action on item",
|
||||
[
|
||||
"Trying to run %s on object %s, "+
|
||||
"but item must be in inventory." % [
|
||||
action,
|
||||
target.global_id
|
||||
]
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
if target.events.has(action):
|
||||
escoria.event_manager.queue_event(target.events[action])
|
||||
var event_returned = yield(
|
||||
escoria.event_manager,
|
||||
"event_finished"
|
||||
)
|
||||
while event_returned[1] != action:
|
||||
event_returned = yield(
|
||||
escoria.event_manager,
|
||||
"event_finished"
|
||||
)
|
||||
if event_returned[0] == ESCExecution.RC_OK:
|
||||
escoria.action_manager.clear_current_action()
|
||||
return event_returned[0]
|
||||
else:
|
||||
escoria.logger.report_warnings(
|
||||
"ESCActionManager.activate: Invalid action",
|
||||
[
|
||||
"Event for action %s on object %s not found." % [
|
||||
action,
|
||||
target.global_id
|
||||
]
|
||||
]
|
||||
)
|
||||
return ESCExecution.RC_ERROR
|
||||
@@ -0,0 +1,47 @@
|
||||
# A registry of ESC command objects
|
||||
extends Object
|
||||
class_name ESCCommandRegistry
|
||||
|
||||
|
||||
# The registry of registered commands
|
||||
var registry: Dictionary = {}
|
||||
|
||||
|
||||
# Load a command by its name
|
||||
#
|
||||
# #### Parameters
|
||||
#
|
||||
# - command_name: Name of command to load
|
||||
# **Returns** The command object
|
||||
func load_command(command_name: String) -> ESCBaseCommand:
|
||||
for command_directory in ProjectSettings.get(
|
||||
"escoria/main/command_directories"
|
||||
):
|
||||
if ResourceLoader.exists("%s/%s.gd" % [command_directory, command_name]):
|
||||
registry[command_name] = load(
|
||||
"%s/%s.gd" % [command_directory, command_name]
|
||||
).new()
|
||||
return registry[command_name]
|
||||
|
||||
escoria.logger.report_errors(
|
||||
"ESCCommandRegistry.load_command: Command not found",
|
||||
[
|
||||
"No command class could be found for command %s" %
|
||||
command_name
|
||||
]
|
||||
)
|
||||
|
||||
return null
|
||||
|
||||
|
||||
# Retrieve a command from the command registry
|
||||
#
|
||||
# #### Parameters
|
||||
#
|
||||
# - command_name: The name of the command
|
||||
# **Returns** The command object
|
||||
func get_command(command_name: String) -> ESCBaseCommand:
|
||||
if self.registry.has(command_name):
|
||||
return self.registry[command_name]
|
||||
else:
|
||||
return self.load_command(command_name)
|
||||
@@ -1,545 +1,220 @@
|
||||
extends Node
|
||||
"""
|
||||
ESC files:
|
||||
Lines beginning with ":" such as :push, :say are EVENTS.
|
||||
Lines in between are usually the ESC API functions calls. They are called COMMANDS.
|
||||
# Compiler of the ESC language
|
||||
extends Object
|
||||
class_name ESCCompiler
|
||||
|
||||
|
||||
Steps
|
||||
compile_script(path/to/esc) : called once
|
||||
> compile(path/to/esc, errors) : called once
|
||||
> read_events() : called once
|
||||
> create an ESCState, initialized with 1st line
|
||||
> for each line in ESCState that corresponds to an event (:event), create a new level
|
||||
> add_level(state, level, errors)
|
||||
> for each state.line that belongs to same group (same indentation), create a command
|
||||
> read_cmd(state, level, errors)
|
||||
> get the token in state.line : this is the actual command (say, teleport, etc.)
|
||||
> get the parameters next to the token
|
||||
> create an ESCCommand, check it and push it into level array
|
||||
> create an ESCEvent with the level created
|
||||
> add it to the returned Dictionary of events
|
||||
In the end, the ESCState has read all lines in the file and is deleted
|
||||
Returned value is a Dictionary { event name : ESCEvent}
|
||||
And ESCEvent.level is an array of ESCCommand
|
||||
"""
|
||||
# A RegEx for comment lines
|
||||
const COMMENT_REGEX = '^\\s*#.*$'
|
||||
|
||||
# A RegEx for empty lines
|
||||
const EMPTY_REGEX = '^\\s*$'
|
||||
|
||||
# A RegEx for finding out the indent of a line
|
||||
const INDENT_REGEX = '^(?<indent>\\s*)'
|
||||
|
||||
|
||||
# The currently compiled event
|
||||
var _current_event = null
|
||||
|
||||
var commands = {
|
||||
"accept_input": { "min_args": 1, "types": [TYPE_STRING] },
|
||||
"autosave": { "min_args": 0 },
|
||||
"anim": { "min_args": 2, "types": [TYPE_STRING, TYPE_STRING, TYPE_BOOL, TYPE_BOOL, TYPE_BOOL] },
|
||||
"camera_push": { "min_args": 1, "types": [TYPE_STRING] },
|
||||
"camera_set_drag_margin_enabled": { "min_args": 2, "types": [TYPE_BOOL, TYPE_BOOL] },
|
||||
"camera_set_limits": { "min_args": 1, "types": [TYPE_INT]},
|
||||
"camera_set_pos": { "min_args": 3, "types": [TYPE_REAL, TYPE_INT, TYPE_INT] },
|
||||
"camera_set_target": { "min_args": 1, "types": [TYPE_REAL] },
|
||||
"camera_set_zoom": { "min_args": 1, "types": [TYPE_REAL] },
|
||||
"camera_set_zoom_height": { "min_args": 1, "types": [TYPE_INT] },
|
||||
"camera_shift": { "min_args": 2, "types": [TYPE_INT, TYPE_INT] },
|
||||
"change_scene": { "min_args": 1, "types": [TYPE_STRING, TYPE_BOOL] },
|
||||
"custom": { "min_args": 2, "types": [TYPE_STRING, TYPE_STRING] },
|
||||
"cut_scene": { "min_args": 2, "types": [TYPE_STRING, TYPE_STRING, TYPE_BOOL, TYPE_BOOL, TYPE_BOOL] },
|
||||
"debug": { "min_args": 1 },
|
||||
"dec_global": { "min_args": 2, "types": [TYPE_STRING, TYPE_INT] },
|
||||
# "dialog_config": { "min_args": 3, "types": [TYPE_STRING, TYPE_BOOL, TYPE_BOOL] },
|
||||
"enable_terrain": { "min_args": 1, "types": [TYPE_STRING]},
|
||||
"game_over": { "min_args": 1, "types": [TYPE_BOOL] },
|
||||
"inc_global": { "min_args": 2, "types": [TYPE_STRING, TYPE_INT] },
|
||||
"inventory_add": { "min_args": 1 },
|
||||
"inventory_remove": { "min_args": 1 },
|
||||
"inventory_display": { "min_args": 1, "types": [TYPE_BOOL] },
|
||||
"jump": { "min_args": 1 },
|
||||
"label": { "min_args": 1 },
|
||||
"set_sound_state": { "min_args": 2, "types": [TYPE_STRING, TYPE_STRING, TYPE_BOOL] },
|
||||
"queue_animation": { "min_args": 2, "types": [TYPE_STRING, TYPE_STRING, TYPE_BOOL] },
|
||||
"queue_resource": { "min_args": 1, "types": [TYPE_STRING, TYPE_BOOL] },
|
||||
"repeat": true,
|
||||
"set_state": { "min_args": 2, "types": [TYPE_STRING, TYPE_STRING, TYPE_BOOL] },
|
||||
"set_hud_visible": { "min_args": 1, "types": [TYPE_BOOL]},
|
||||
"say": { "min_args": 2 },
|
||||
"sched_event": { "min_args": 3, "types": [TYPE_REAL, TYPE_STRING, TYPE_STRING] },
|
||||
"set_active": { "min_args": 2, "types": [TYPE_STRING, TYPE_BOOL] },
|
||||
"set_angle": { "min_args": 2, "types": [TYPE_STRING, TYPE_INT] },
|
||||
"set_global": { "min_args": 2, "types": [TYPE_STRING, TYPE_STRING] },
|
||||
"set_globals": { "min_args": 2, "types": [TYPE_STRING, TYPE_BOOL] },
|
||||
"set_interactive": { "min_args": 2, "types": [TYPE_STRING, TYPE_BOOL] },
|
||||
"set_speed": { "min_args": 2, "types": [TYPE_STRING, TYPE_INT] },
|
||||
"slide": { "min_args": 2 },
|
||||
"slide_block": { "min_args": 2 },
|
||||
"spawn": { "min_args": 1 },
|
||||
"stop": true,
|
||||
"superpose_scene": { "min_args": 1, "types": [TYPE_STRING, TYPE_BOOL] },
|
||||
"teleport": { "min_args": 2, "types": [TYPE_STRING, TYPE_STRING, TYPE_INT] },
|
||||
"teleport_pos": { "min_args": 3 },
|
||||
"turn_to": { "min_args": 2 },
|
||||
"wait": true,
|
||||
"walk": { "min_args": 2 },
|
||||
"walk_block": { "min_args": 2 },
|
||||
"walk_to_pos": { "min_args": 3},
|
||||
"walk_to_pos_block": { "min_args": 3},
|
||||
|
||||
"%": { "alias": "label", "min_args": 1},
|
||||
"?": { "alias": "dialog"},
|
||||
"!": { "alias": "end_dialog", "min_args": 0 },
|
||||
">": { "alias": "branch"},
|
||||
}
|
||||
# A stack of groups currently compiling
|
||||
var _groups_stack = []
|
||||
|
||||
# Commands that can be called only by the ESC debug prompt
|
||||
var debug_commands = {
|
||||
"get_active": { "min_args": 1, "types": [TYPE_STRING] },
|
||||
"get_global": { "min_args": 1, "types": [TYPE_STRING] },
|
||||
"get_interactive": { "min_args": 1, "types": [TYPE_STRING] },
|
||||
"get_state": { "min_args": 1, "types": [TYPE_STRING] },
|
||||
}
|
||||
# A stack of dialogs currently compiling
|
||||
var _dialogs_stack = []
|
||||
|
||||
# Loads a Dictionary of actions from a file, given its path.
|
||||
func load_esc_file(esc_file_path : String) -> Dictionary:
|
||||
var f = File.new()
|
||||
if !f.file_exists(esc_file_path):
|
||||
escoria.logger.report_errors("esc_compiler.gd:load_esc_file()", ["File " + esc_file_path + " not found."])
|
||||
return {}
|
||||
return compile_script(esc_file_path)
|
||||
# A stack of dialog options currently compiling
|
||||
var _dialogs_option_stack = []
|
||||
|
||||
# Loads the parameter script file. Can be either GDScript of ESC type.
|
||||
# Returns the Dictionary of actions loaded from the file.
|
||||
func compile_script(p_path : String) -> Dictionary:
|
||||
var ev_table
|
||||
# Script is GDScript
|
||||
if p_path.find(".gd") != -1:
|
||||
var res = ResourceLoader.load(p_path)
|
||||
if res == null:
|
||||
return {}
|
||||
ev_table = res.new().get_events()
|
||||
else: # Script is ESC
|
||||
var errors = []
|
||||
ev_table = compile(p_path, errors)
|
||||
if errors.size() > 0:
|
||||
escoria.logger.call_deferred("report_errors", p_path, errors)
|
||||
return ev_table
|
||||
|
||||
func check_command(commands_list : Dictionary, cmd : esctypes.ESCCommand, state : esctypes.ESCState, errors : Array):
|
||||
if !(cmd.name in commands_list):
|
||||
errors.push_back("line "+str(state.line_count)+": command "+cmd.name+" not valid.")
|
||||
return false
|
||||
# A pointer to the current container (group, dialog option)
|
||||
# that should get the current command
|
||||
var _command_container = []
|
||||
|
||||
var cmd_data = commands_list[cmd.name]
|
||||
if typeof(cmd_data) == TYPE_BOOL:
|
||||
return true
|
||||
# The currently identified indent
|
||||
var _current_indent = 0
|
||||
|
||||
if "alias" in cmd_data:
|
||||
cmd.name = cmd_data.alias
|
||||
|
||||
if "min_args" in cmd_data:
|
||||
if cmd.params.size() < cmd_data.min_args:
|
||||
errors.push_back("line "+str(state.line_count)+": command "+cmd.name+" takes "+str(cmd_data.min_args)+" parameters ("+str(cmd.params.size())+" were given).")
|
||||
return false
|
||||
|
||||
var ret = true
|
||||
if "types" in cmd_data:
|
||||
var i = 0
|
||||
for t in cmd_data.types:
|
||||
if i >= cmd.params.size():
|
||||
break
|
||||
if t == TYPE_BOOL:
|
||||
if cmd.params[i] == "true":
|
||||
cmd.params[i] = true
|
||||
elif cmd.params[i] == "false":
|
||||
cmd.params[i] = false
|
||||
else:
|
||||
errors.push_back("line " + str(state.line_count) + ": Invalid parameter " + cmd.params[i] + " for command " + cmd.name + ". Must be 'true' or 'false'.")
|
||||
ret = false
|
||||
if t == TYPE_INT:
|
||||
if not cmd.params[i].is_valid_integer():
|
||||
errors.push_back("line " + str(state.line_count) + ": Invalid parameter " + cmd.params[i] + " for command " + cmd.name + ". Expected integer.")
|
||||
cmd.params[i] = int(cmd.params[i])
|
||||
if t == TYPE_REAL:
|
||||
if not cmd.params[i].is_valid_float():
|
||||
errors.push_back("line " + str(state.line_count) + ": Invalid parameter " + cmd.params[i] + " for command " + cmd.name + ". Expected float.")
|
||||
cmd.params[i] = float(cmd.params[i])
|
||||
i+=1
|
||||
return ret
|
||||
|
||||
# Check that the given command exists and respects the right number of parameters
|
||||
func check_normal_command(cmd : esctypes.ESCCommand, state : esctypes.ESCState, errors : Array):
|
||||
return check_command(commands, cmd, state, errors)
|
||||
|
||||
func check_debug_command(cmd : esctypes.ESCCommand, state : esctypes.ESCState, errors : Array):
|
||||
return check_command(debug_commands, cmd, state, errors)
|
||||
|
||||
# Fills the given "state" with the next line read from the file
|
||||
func read_line(state : esctypes.ESCState) -> void:
|
||||
while true:
|
||||
if _eof_reached(state.file):
|
||||
state.line = null
|
||||
return
|
||||
else:
|
||||
state.line = _get_line(state.file)
|
||||
state.line_count += 1
|
||||
if !is_comment(state.line):
|
||||
return
|
||||
|
||||
# Returns true if line is a comment (starting with #)
|
||||
func is_comment(line : String) -> bool:
|
||||
for i in range(0, line.length()):
|
||||
var c = line[i]
|
||||
if c == "#":
|
||||
return true
|
||||
if c != " " && c != "\t":
|
||||
return false
|
||||
return true
|
||||
|
||||
# Returns the position of the first non-blank character in given line string
|
||||
func get_indent(line : String):
|
||||
for i in range(0, line.length()):
|
||||
if line[i] != " " && line[i] != "\t":
|
||||
return i
|
||||
|
||||
# If the given line string is a event (begins with ":"), returns its name
|
||||
# Else, return false
|
||||
func is_event(line : String):
|
||||
var trimmed = trim(line)
|
||||
if trimmed.find(":") == 0:
|
||||
return trimmed.substr(1, trimmed.length()-1)
|
||||
return false
|
||||
|
||||
# Returns true if the given string is a flag (ie. "[.+]")
|
||||
func is_flags(tk : String) -> bool:
|
||||
var trimmed = trim(tk)
|
||||
if trimmed.find("[") == 0 && trimmed.find("]") == trimmed.length()-1:
|
||||
return true
|
||||
return false
|
||||
|
||||
# Reads each line contained in the state (ESCState) (updates state.line)
|
||||
# While the new line belongs to the same group, creates an ESCCommand from the current state
|
||||
func add_level(state : esctypes.ESCState, level : Array, errors : Array):
|
||||
read_line(state)
|
||||
while state.line != null:
|
||||
if is_event(state.line):
|
||||
return
|
||||
var ind_level = get_indent(state.line)
|
||||
if ind_level < state.indent:
|
||||
return
|
||||
if ind_level > state.indent:
|
||||
errors.push_back("line "+str(state.line_count)+": invalid indentation for group")
|
||||
read_line(state)
|
||||
continue
|
||||
|
||||
read_cmd(state, level, errors)
|
||||
|
||||
func add_dialog(state : esctypes.ESCState, level : Array, errors : Array):
|
||||
read_line(state)
|
||||
|
||||
while typeof(state.line) != typeof(null):
|
||||
if is_event(state.line):
|
||||
return
|
||||
|
||||
var ind_level = get_indent(state.line)
|
||||
|
||||
if ind_level < state.indent:
|
||||
return
|
||||
|
||||
if ind_level > state.indent:
|
||||
errors.push_back("line "+str(state.line_count)+": invalid indentation for dialog")
|
||||
read_line(state)
|
||||
continue
|
||||
|
||||
read_dialog_option(state, level, errors)
|
||||
|
||||
func get_token(line : String, p_from : int, line_count : int, errors : Array) -> int:
|
||||
while p_from < line.length():
|
||||
if line[p_from] == " " || line[p_from] == "\t":
|
||||
p_from += 1
|
||||
else:
|
||||
break
|
||||
if p_from >= line.length():
|
||||
return -1
|
||||
var tk_end
|
||||
if line[p_from] == "[":
|
||||
tk_end = line.find("]", p_from)
|
||||
if tk_end == -1:
|
||||
errors.push_back("line "+str(line_count)+": unterminated flags")
|
||||
tk_end += 1
|
||||
elif line[p_from] == "\"":
|
||||
tk_end = line.find("\"", p_from+1)
|
||||
if tk_end == -1:
|
||||
errors.push_back("line "+str(line_count)+": unterminated quotes, line '"+line+"'")
|
||||
else:
|
||||
tk_end = p_from
|
||||
while tk_end < line.length():
|
||||
if line[tk_end] == ":":
|
||||
var ntk = get_token(line, tk_end+1, line_count, errors)
|
||||
tk_end = ntk
|
||||
break
|
||||
if line[tk_end] == " " || line[tk_end] == "\t":
|
||||
break
|
||||
tk_end += 1
|
||||
return tk_end
|
||||
|
||||
# Remove blank characters around p_str
|
||||
func trim(p_str : String) -> String:
|
||||
while p_str.length() && (p_str[0] == " " || p_str[0] == "\t"):
|
||||
p_str = p_str.substr(1, p_str.length()-1)
|
||||
while p_str.length() && p_str[p_str.length()-1] == " " || p_str[p_str.length()-1] == "\t":
|
||||
p_str = p_str.substr(0, p_str.length()-1)
|
||||
|
||||
if p_str[0] == "\"":
|
||||
p_str = p_str.substr(1, p_str.length()-1)
|
||||
if p_str[p_str.length()-1] == "\"":
|
||||
p_str = p_str.substr(0, p_str.length()-1)
|
||||
return p_str
|
||||
|
||||
# Parses a flags string (usually defined by '[.*]') and fills the flags_list array
|
||||
# and ifs variable (Dictionary containing all ifs conditions)
|
||||
func parse_flags(p_flags : String, flags_list : Array, ifs : Dictionary):
|
||||
var from = 1
|
||||
while true:
|
||||
var next = p_flags.find(",", from)
|
||||
var flag
|
||||
if next == -1:
|
||||
flag = p_flags.substr(from, (p_flags.length()-1) - from)
|
||||
else:
|
||||
flag = p_flags.substr(from, next - from)
|
||||
flag = trim(flag)
|
||||
var list = []
|
||||
|
||||
if flag[0] == "!":
|
||||
list.push_back(true)
|
||||
flag = trim(flag.substr(1, flag.length()-1))
|
||||
if flag.find("inv-") == 0:
|
||||
ifs["if_not_inv"].push_back(trim(flag).substr(4, flag.length()-1))
|
||||
elif flag.find("a/") == 0:
|
||||
ifs["if_not_active"].push_back(trim(flag).substr(2, flag.length() - 1))
|
||||
elif flag.substr(0, 3) in ["eq ", "gt ", "lt "]:
|
||||
var elems = flag.split(" ", true, 2)
|
||||
var comparison = "ne" if elems[0] == "eq" else "le" if elems[0] == "gt" else "ge"
|
||||
ifs["if_" + comparison].push_back([elems[1], elems[2]])
|
||||
else:
|
||||
ifs["if_false"].push_back(trim(flag))
|
||||
else:
|
||||
list.push_back(false)
|
||||
if flag.find("inv-") == 0:
|
||||
ifs["if_inv"].push_back(trim(flag).substr(4, flag.length()-1))
|
||||
elif flag.find("a/") == 0:
|
||||
ifs["if_active"].push_back(trim(flag).substr(2, flag.length() - 1))
|
||||
elif flag.substr(0, 3) in ["eq ", "gt ", "lt "]:
|
||||
var elems = flag.split(" ", true, 2)
|
||||
ifs["if_" + elems[0]].push_back([elems[1], elems[2]])
|
||||
else:
|
||||
ifs["if_true"].push_back(trim(flag))
|
||||
|
||||
if flag.find(":") >= 0:
|
||||
var pos = flag.substr(0, flag.find(":"))
|
||||
var inv = flag.substr(0, pos)
|
||||
inv = trim(inv)
|
||||
list.push_back(inv)
|
||||
flag = flag.substr(pos, flag.length() - pos)
|
||||
elif flag.find("inv-") == 0:
|
||||
flag = trim(flag).substr(4, flag.length()-1)
|
||||
list.push_back("i")
|
||||
else:
|
||||
list.push_back("g")
|
||||
|
||||
list.push_back(trim(flag))
|
||||
# printt("adding flag ", list)
|
||||
flags_list.push_back(list)
|
||||
if next == -1:
|
||||
return
|
||||
from = next+1
|
||||
|
||||
func read_dialog_option(state : esctypes.ESCState, level : Array, errors : Array):
|
||||
var tk_end = get_token(state.line, 0, state.line_count, errors)
|
||||
var tk = trim(state.line.substr(0, tk_end))
|
||||
if tk != "*" && tk != "-":
|
||||
errors.append("line "+str(state.line_count)+": Invalid dialog option")
|
||||
read_line(state)
|
||||
return
|
||||
|
||||
# Remove inline comments
|
||||
var comment_idx = state.line.find("#")
|
||||
if comment_idx > -1:
|
||||
state.line = state.line.substr(0, comment_idx)
|
||||
|
||||
tk_end += 1
|
||||
# var c_start = state.line.find("\"", 0)
|
||||
var c_end = state.line.find_last("\"")
|
||||
var q_end = state.line.find("[", c_end)
|
||||
var q_flags = null
|
||||
#printt("flags before", q_flags)
|
||||
if q_end == -1:
|
||||
q_end = state.line.length()
|
||||
else:
|
||||
var f_end = state.line.find("]", q_end)
|
||||
if f_end == -1:
|
||||
errors.append("line "+str(state.line_count)+": unterminated flags")
|
||||
else:
|
||||
f_end += 1
|
||||
q_flags = state.line.substr(q_end, f_end - q_end)
|
||||
var question = trim(state.line.substr(tk_end, q_end - tk_end))
|
||||
var cmd = { "name": "*", "params": [question, []] }
|
||||
|
||||
if q_flags:
|
||||
var ifs = {
|
||||
"if_true": [], "if_false": [], "if_inv": [], "if_not_inv": [],
|
||||
"if_active": [], "if_not_active": [],
|
||||
"if_eq": [], "if_ne": [], # string and integer comparison
|
||||
"if_gt": [], "if_ge": [], "if_lt": [], "if_le": [] # integer comparison
|
||||
func _init():
|
||||
# Assure command list preference
|
||||
if not ProjectSettings.has_setting("escoria/esc/command_paths"):
|
||||
ProjectSettings.set_setting("escoria/esc/command_paths", [
|
||||
"res://addons/escoria-core/game/core-scripts/esc/commands"
|
||||
])
|
||||
var property_info = {
|
||||
"name": "escoria/esc/command_paths",
|
||||
"type": TYPE_STRING_ARRAY
|
||||
}
|
||||
var flag_list = []
|
||||
parse_flags(q_flags, flag_list, ifs)
|
||||
for key in ifs:
|
||||
if ifs[key].size():
|
||||
cmd.conditions[key] = ifs[key]
|
||||
if flag_list.size():
|
||||
cmd.flags = flag_list
|
||||
|
||||
state.indent += 1
|
||||
add_level(state, cmd.params[1], errors)
|
||||
state.indent -= 1
|
||||
|
||||
level.push_back(cmd)
|
||||
|
||||
# Read an ESCState and converts it to ESCCommand
|
||||
# then puts it into level (Array of ESCCommand)
|
||||
func read_cmd(state : esctypes.ESCState, level : Array, errors : Array):
|
||||
var params = []
|
||||
var from = 0
|
||||
var tk_end = get_token(state.line, from, state.line_count, errors)
|
||||
var ifs = {
|
||||
"if_true": [], "if_false": [], "if_inv": [], "if_not_inv": [],
|
||||
"if_active": [], "if_not_active": [],
|
||||
"if_eq": [], "if_ne": [], # string and integer comparison
|
||||
"if_gt": [], "if_ge": [], "if_lt": [], "if_le": [] # integer comparison
|
||||
}
|
||||
var flags = []
|
||||
while tk_end != -1:
|
||||
var tk = trim(state.line.substr(from, tk_end - from))
|
||||
from = tk_end + 1
|
||||
if is_flags(tk):
|
||||
parse_flags(tk, flags, ifs)
|
||||
else:
|
||||
params.push_back(tk)
|
||||
tk_end = get_token(state.line, from, state.line_count, errors)
|
||||
|
||||
if params.size() == 0:
|
||||
errors.append("line "+str(state.line_count)+": Invalid command.")
|
||||
read_line(state)
|
||||
return
|
||||
|
||||
var cmd = esctypes.ESCCommand.new(params[0])
|
||||
|
||||
if params[0] == ">":
|
||||
cmd.params = []
|
||||
state.indent += 1
|
||||
add_level(state, cmd.params, errors)
|
||||
state.indent -= 1
|
||||
elif params[0] == "?":
|
||||
params.remove(0)
|
||||
var dialog_params = []
|
||||
state.indent += 1
|
||||
add_dialog(state, dialog_params, errors)
|
||||
cmd.params = params
|
||||
cmd.params.insert(0, dialog_params)
|
||||
state.indent -= 1
|
||||
elif params[0] == "*":
|
||||
errors.push_back("line "+str(state.line_count)+": Invalid command: dialog option outside dialog")
|
||||
read_line(state)
|
||||
return
|
||||
else:
|
||||
params.remove(0)
|
||||
|
||||
# Remove inline comments
|
||||
var comment_idx = params.find("#")
|
||||
if comment_idx > -1:
|
||||
params.resize(comment_idx)
|
||||
|
||||
cmd.params = params
|
||||
read_line(state)
|
||||
|
||||
for key in ifs:
|
||||
if ifs[key].size():
|
||||
cmd.conditions[key] = ifs[key]
|
||||
|
||||
if flags.size():
|
||||
cmd.flags = flags
|
||||
ProjectSettings.add_property_info(property_info)
|
||||
|
||||
var errors_before = errors.duplicate()
|
||||
var valid = check_normal_command(cmd, state, errors)
|
||||
if valid:
|
||||
level.push_back(cmd)
|
||||
|
||||
# Load an ESC file from a file resource
|
||||
func load_esc_file(path: String) -> ESCScript:
|
||||
escoria.logger.debug("Parsing file %s" % path)
|
||||
if File.new().file_exists(path):
|
||||
var file = File.new()
|
||||
file.open(path, File.READ)
|
||||
var lines = []
|
||||
while not file.eof_reached():
|
||||
lines.append(file.get_line())
|
||||
return self.compile(lines)
|
||||
else:
|
||||
var debug_valid = check_debug_command(cmd, state, errors)
|
||||
if debug_valid:
|
||||
errors.clear()
|
||||
level.push_back(cmd)
|
||||
escoria.logger.report_errors(
|
||||
"Can not find ESC file",
|
||||
[
|
||||
"File %s could not be found" % path
|
||||
]
|
||||
)
|
||||
return null
|
||||
|
||||
# Read events from f (Dictionary or File) into ret Dictionary
|
||||
func read_events(f, ret : Dictionary, errors : Array):
|
||||
#var state = { "file": f, "line": _get_line(f), "indent": 0, "line_count": 0 }
|
||||
var state = esctypes.ESCState.new(f, _get_line(f), 0, 0)
|
||||
|
||||
while state.line != null:
|
||||
if is_comment(state.line):
|
||||
read_line(state)
|
||||
continue
|
||||
var ev = is_event(state.line)
|
||||
if typeof(ev) != typeof(null):
|
||||
var level = []
|
||||
var abort = add_level(state, level, errors)
|
||||
var ev_flags = []
|
||||
if ev is String:
|
||||
if "|" in ev:
|
||||
var ev_split = ev.split("|", true, 1)
|
||||
ev = ev_split[0]
|
||||
ev = ev.strip_edges()
|
||||
if ev_split.size() > 1:
|
||||
ev_split[1] = ev_split[1].strip_edges()
|
||||
ev_flags = ev_split[1].split(" ")
|
||||
# Compiles an array of ESC script strings to an ESCScript
|
||||
func compile(lines: Array) -> ESCScript:
|
||||
var script = ESCScript.new()
|
||||
if lines.size() > 0:
|
||||
var events = self._compile(lines)
|
||||
for event in events:
|
||||
script.events[event.name] = event
|
||||
|
||||
return script
|
||||
|
||||
|
||||
# Compile an array of ESC script lines into an array of ESC objects
|
||||
func _compile(lines: Array) -> Array:
|
||||
|
||||
var comment_regex = RegEx.new()
|
||||
comment_regex.compile(COMMENT_REGEX)
|
||||
var empty_regex = RegEx.new()
|
||||
empty_regex.compile(EMPTY_REGEX)
|
||||
var indent_regex = RegEx.new()
|
||||
indent_regex.compile(INDENT_REGEX)
|
||||
|
||||
ret[ev] = esctypes.ESCEvent.new(ev, level, Array(ev_flags))
|
||||
if abort:
|
||||
return abort
|
||||
|
||||
# If f is a File, returns the next line as String (or null)
|
||||
# If f is a Dictionary, returns the next line from f.lines
|
||||
func _get_line(f):
|
||||
if f is Dictionary:
|
||||
if f.line >= f.lines.size():
|
||||
return null
|
||||
var line = f.lines[f.line]
|
||||
f.line += 1
|
||||
#printt("reading line ", line)
|
||||
return line
|
||||
else:
|
||||
return f.get_line()
|
||||
|
||||
func _eof_reached(f):
|
||||
if typeof(f) == typeof({}):
|
||||
return f.line >= f.lines.size()
|
||||
else:
|
||||
return f.eof_reached()
|
||||
|
||||
func compile_str(p_str : String, errors : Array):
|
||||
var f = { "line": 0, "lines": p_str.split("\n") }
|
||||
|
||||
#printt("esc compile str ", f)
|
||||
|
||||
var ret = {}
|
||||
read_events(f, ret, errors)
|
||||
|
||||
#printt("returning ", p_fname, ret)
|
||||
return ret
|
||||
|
||||
# Returns a Dictionary of events read from p_fname filename
|
||||
func compile(p_fname : String, errors : Array) -> Dictionary:
|
||||
var f = File.new()
|
||||
f.open(p_fname, File.READ)
|
||||
if !f.is_open():
|
||||
return {}
|
||||
|
||||
var ret = {}
|
||||
read_events(f, ret, errors)
|
||||
|
||||
#printt("returning ", p_fname, ret)
|
||||
return ret
|
||||
var event_regex = RegEx.new()
|
||||
event_regex.compile(ESCEvent.REGEX)
|
||||
var command_regex = RegEx.new()
|
||||
command_regex.compile(ESCCommand.REGEX)
|
||||
var dialog_regex = RegEx.new()
|
||||
dialog_regex.compile(ESCDialog.REGEX)
|
||||
var dialog_end_regex = RegEx.new()
|
||||
dialog_end_regex.compile(ESCDialog.END_REGEX)
|
||||
var dialog_option_regex = RegEx.new()
|
||||
dialog_option_regex.compile(ESCDialogOption.REGEX)
|
||||
var group_regex = RegEx.new()
|
||||
group_regex.compile(ESCGroup.REGEX)
|
||||
|
||||
var returned = []
|
||||
|
||||
while lines.size() > 0:
|
||||
var line = lines.pop_front()
|
||||
escoria.logger.debug("Parsing line %s" % line)
|
||||
if comment_regex.search(line) or empty_regex.search(line):
|
||||
# Ignore comments and empty lines
|
||||
escoria.logger.debug("Line is empty or a comment. Skipping.")
|
||||
continue
|
||||
var indent = \
|
||||
escoria.utils.get_re_group(
|
||||
indent_regex.search(line),
|
||||
"indent"
|
||||
).length()
|
||||
|
||||
if event_regex.search(line):
|
||||
var event = ESCEvent.new(line)
|
||||
escoria.logger.debug("Line is the event %s" % event.name)
|
||||
var event_lines = []
|
||||
while lines.size() > 0:
|
||||
var next_line = lines.pop_front()
|
||||
if not event_regex.search(next_line):
|
||||
event_lines.append(next_line)
|
||||
else:
|
||||
lines.push_front(next_line)
|
||||
break
|
||||
if event_lines.size() > 0:
|
||||
escoria.logger.debug(
|
||||
"Compiling the next %d lines into the event" % \
|
||||
event_lines.size()
|
||||
)
|
||||
event.statements = self._compile(event_lines)
|
||||
returned.append(event)
|
||||
elif group_regex.search(line):
|
||||
var group = ESCGroup.new(line)
|
||||
escoria.logger.debug("Line is a group")
|
||||
var group_lines = []
|
||||
while lines.size() > 0:
|
||||
var next_line = lines.pop_front()
|
||||
var next_line_indent = \
|
||||
escoria.utils.get_re_group(
|
||||
indent_regex.search(next_line),
|
||||
"indent"
|
||||
).length()
|
||||
if next_line_indent > indent:
|
||||
group_lines.append(next_line)
|
||||
else:
|
||||
lines.push_front(next_line)
|
||||
break
|
||||
if group_lines.size() > 0:
|
||||
escoria.logger.debug(
|
||||
"Compiling the next %d lines into the group" % \
|
||||
group_lines.size()
|
||||
)
|
||||
group.statements = self._compile(group_lines)
|
||||
returned.append(group)
|
||||
elif dialog_regex.search(line):
|
||||
var dialog = ESCDialog.new(line)
|
||||
escoria.logger.debug("Line is a dialog")
|
||||
var dialog_lines = []
|
||||
while lines.size() > 0:
|
||||
var next_line = lines.pop_front()
|
||||
var end_line = dialog_end_regex.search(next_line)
|
||||
if end_line and \
|
||||
escoria.utils.get_re_group(
|
||||
end_line,
|
||||
"indent"
|
||||
).length() == indent:
|
||||
break
|
||||
else:
|
||||
dialog_lines.append(next_line)
|
||||
if dialog_lines.size() > 0:
|
||||
escoria.logger.debug(
|
||||
"Compiling the next %d lines into the dialog" % \
|
||||
dialog_lines.size()
|
||||
)
|
||||
dialog.options = self._compile(dialog_lines)
|
||||
# Remove the end line from the stack
|
||||
lines.pop_front()
|
||||
returned.append(dialog)
|
||||
elif dialog_option_regex.search(line):
|
||||
var dialog_option = ESCDialogOption.new(line)
|
||||
escoria.logger.debug(
|
||||
"Line is the dialog option %s" % \
|
||||
dialog_option.option
|
||||
)
|
||||
var dialog_option_lines = []
|
||||
while lines.size() > 0:
|
||||
var next_line = lines.pop_front()
|
||||
var next_line_indent = \
|
||||
escoria.utils.get_re_group(
|
||||
indent_regex.search(next_line),
|
||||
"indent"
|
||||
).length()
|
||||
if next_line_indent > indent:
|
||||
dialog_option_lines.append(next_line)
|
||||
else:
|
||||
lines.push_front(next_line)
|
||||
break
|
||||
if dialog_option_lines.size() > 0:
|
||||
escoria.logger.debug(
|
||||
"Compiling the next %d lines into the event" % \
|
||||
dialog_option_lines.size()
|
||||
)
|
||||
dialog_option.statements = self._compile(dialog_option_lines)
|
||||
returned.append(dialog_option)
|
||||
elif command_regex.search(line):
|
||||
var command = ESCCommand.new(line)
|
||||
escoria.logger.debug("Line is the command %s" % command.name)
|
||||
returned.append(command)
|
||||
else:
|
||||
escoria.logger.report_errors(
|
||||
"Invalid ESC line detected",
|
||||
[
|
||||
"Line couldn't be compiled: %s" % line
|
||||
]
|
||||
)
|
||||
return returned
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
# A manager for running events
|
||||
extends Node
|
||||
class_name ESCEventManager
|
||||
|
||||
|
||||
# Emitted when the event did finish running
|
||||
signal event_finished(event_name, return_code)
|
||||
|
||||
|
||||
# A queue of events to run
|
||||
var events_queue: Array = []
|
||||
|
||||
# A list of currently scheduled events
|
||||
var scheduled_events: Array = []
|
||||
|
||||
|
||||
# Handle the events queue and scheduled events
|
||||
func _process(delta: float) -> void:
|
||||
if events_queue.size() > 0:
|
||||
var running_event = events_queue.pop_front()
|
||||
# TODO: Handle event flags
|
||||
if not running_event.is_connected(
|
||||
"finished", self, "_on_event_finished"
|
||||
):
|
||||
running_event.connect(
|
||||
"finished",
|
||||
self,
|
||||
"_on_event_finished",
|
||||
[running_event]
|
||||
)
|
||||
running_event.run()
|
||||
for event in self.scheduled_events:
|
||||
(event as ESCScheduledEvent).timeout -= delta
|
||||
if (event as ESCScheduledEvent).timeout <= 0:
|
||||
self.scheduled_events.erase(event)
|
||||
self.events_queue.append(event)
|
||||
|
||||
|
||||
# Queue a new event to run
|
||||
func queue_event(event: ESCEvent) -> void:
|
||||
events_queue.append(event)
|
||||
|
||||
|
||||
# Schedule an event to run after a timeout
|
||||
func schedule_event(event: ESCEvent, timeout: float) -> void:
|
||||
scheduled_events.append(ESCScheduledEvent.new(event, timeout))
|
||||
|
||||
|
||||
# The event finished running
|
||||
func _on_event_finished(return_code: int, event: ESCEvent) -> void:
|
||||
escoria.logger.debug(
|
||||
"Event %s ended with return code %d" % [event.name, return_code]
|
||||
)
|
||||
event.disconnect("finished", self, "_on_event_finished")
|
||||
match(return_code):
|
||||
ESCExecution.RC_CANCEL:
|
||||
self.scheduled_events = []
|
||||
self.events_queue = []
|
||||
return_code = ESCExecution.RC_OK
|
||||
emit_signal("event_finished", return_code, event.name)
|
||||
@@ -0,0 +1,90 @@
|
||||
# A resource that manages the ESC global states
|
||||
# The ESC global state is basically simply a dictionary of keys with
|
||||
# values. Values can be bool, integer or strings
|
||||
extends Resource
|
||||
class_name ESCGlobalsManager
|
||||
|
||||
|
||||
# Emitted when a global is changed
|
||||
signal global_changed(global, old_value, new_value)
|
||||
|
||||
|
||||
# A list of reserved globals which can not be overridden
|
||||
const RESERVED_GLOBALS = [
|
||||
"ESC_LAST_SCENE"
|
||||
]
|
||||
|
||||
|
||||
# The globals registry
|
||||
export(Dictionary) var _globals = {}
|
||||
|
||||
|
||||
# Check if a global was registered
|
||||
#
|
||||
# #### Parameters
|
||||
#
|
||||
# - key: The global key to check
|
||||
# **Returns** Wether the global was registered
|
||||
func has(key: String) -> bool:
|
||||
return _globals.has(key)
|
||||
|
||||
|
||||
# Get the current value of a global
|
||||
#
|
||||
# #### Parameters
|
||||
#
|
||||
# - key: The key of the global to return the value
|
||||
# **Returns** The value of the global
|
||||
func get_global(key: String):
|
||||
if _globals.has(key):
|
||||
return _globals[key]
|
||||
return null
|
||||
|
||||
|
||||
# Filter 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
|
||||
#
|
||||
# #### Parameters
|
||||
#
|
||||
# - pattern: The pattern that the keys have to match
|
||||
# **Returns** A dictionary of matching keys and their values
|
||||
func filter(pattern: String) -> Dictionary:
|
||||
var ret = {}
|
||||
for global_key in _globals.keys():
|
||||
if global_key.match(pattern):
|
||||
ret[global_key] = _globals[global_key]
|
||||
return ret
|
||||
|
||||
|
||||
# Set the value of a global
|
||||
#
|
||||
# #### Parameters
|
||||
#
|
||||
# - key: The key of the global to modify
|
||||
# - value: The new value
|
||||
func set_global(key: String, value, ignore_reserved: bool = false) -> void:
|
||||
if key in RESERVED_GLOBALS and not ignore_reserved:
|
||||
escoria.logger.report_errors(
|
||||
"ESCGlobalsManager.set_global: Can not override reserved global",
|
||||
[
|
||||
"Global key %s is reserved and can not be overridden" % key
|
||||
]
|
||||
)
|
||||
_globals[key] = value
|
||||
emit_signal("global_changed", key, _globals[key], value)
|
||||
|
||||
|
||||
# Set all globals that match the pattern to the value
|
||||
# Check out [the Godot docs](https://docs.godotengine.org/en/stable/classes/class_string.html#class-string-method-match)
|
||||
# for the pattern format
|
||||
#
|
||||
# #### Parameters
|
||||
#
|
||||
# - pattern: The wildcard pattern to match
|
||||
# - value: The new value
|
||||
func set_global_wildcard(pattern: String, value) -> void:
|
||||
for global_key in _globals.keys:
|
||||
if global_key.match(pattern):
|
||||
self.set_global(global_key, value)
|
||||
@@ -0,0 +1,50 @@
|
||||
# A manager for inventory objects
|
||||
extends Object
|
||||
class_name ESCInventoryManager
|
||||
|
||||
|
||||
# Check if the player has an inventory item
|
||||
#
|
||||
# #### Parameters
|
||||
#
|
||||
# - item: Inventory item id
|
||||
# **Returns** Wether the player has the inventory
|
||||
func inventory_has(item: String) -> bool:
|
||||
return escoria.globals_manager.has("i/%s" % item)
|
||||
|
||||
|
||||
# Get all inventory items
|
||||
# **Returns** The items in the inventory
|
||||
func items_in_inventory() -> Array:
|
||||
var items = []
|
||||
var filtered = escoria.globals_manager.filter("i/*")
|
||||
for glob in filtered.keys():
|
||||
if filtered[glob]:
|
||||
items.append(glob.rsplit("i/", false)[0])
|
||||
return items
|
||||
|
||||
|
||||
# Remove an item from the inventory
|
||||
#
|
||||
# #### Parameters
|
||||
#
|
||||
# - item: Inventory item id
|
||||
func remove_item(item: String):
|
||||
if not inventory_has(item):
|
||||
self.logger.report_errors(
|
||||
"ESCInventoryManager.remove_item: Error removing inventory item",
|
||||
[
|
||||
"Trying to remove non-existent item %s" % item
|
||||
]
|
||||
)
|
||||
else:
|
||||
escoria.globals_manager.set_global("i/%s" % item, false)
|
||||
|
||||
|
||||
# Add an item to the inventory
|
||||
#
|
||||
# #### Parameters
|
||||
#
|
||||
# - item: Inventory item id
|
||||
func add_item(item: String):
|
||||
escoria.globals_manager.set_global("i/%s" % item, true)
|
||||
@@ -0,0 +1,95 @@
|
||||
# A manager for ESC objects
|
||||
extends Node
|
||||
class_name ESCObjectManager
|
||||
|
||||
|
||||
const RESERVED_OBJECTS = [
|
||||
"bg_music"
|
||||
]
|
||||
|
||||
|
||||
# The hash of registered objects (the global id is the key)
|
||||
var objects: Dictionary = {}
|
||||
|
||||
|
||||
# Make active objects visible
|
||||
func _process(_delta):
|
||||
for object in objects:
|
||||
if (object as ESCObject).node:
|
||||
(object as ESCObject).node.visible = (object as ESCObject).active
|
||||
|
||||
|
||||
# Register the object in the manager
|
||||
#
|
||||
# #### Parameters
|
||||
#
|
||||
# - object: Obejct to register
|
||||
# - force: Register the object, even if it has already been registered
|
||||
func register_object(object: ESCObject, force: bool = false) -> void:
|
||||
if objects.has(object.global_id) and not force:
|
||||
escoria.logger.report_errors(
|
||||
"ESCObjectManager.register_object: Object already registered",
|
||||
[
|
||||
"Object with global id %s already registered" %
|
||||
object.global_id
|
||||
]
|
||||
)
|
||||
else:
|
||||
if not object.node.is_connected(
|
||||
"tree_exited",
|
||||
self,
|
||||
"unregister_object"
|
||||
):
|
||||
object.node.connect(
|
||||
"tree_exited",
|
||||
self,
|
||||
"unregister_object",
|
||||
[object]
|
||||
)
|
||||
|
||||
if "is_interactive" in object.node and object.node.is_interactive:
|
||||
object.interactive = true
|
||||
|
||||
if "esc_script" in object.node and not object.node.esc_script.empty():
|
||||
var script = escoria.esc_compiler.load_esc_file(
|
||||
object.node.esc_script
|
||||
)
|
||||
object.events = script.events
|
||||
|
||||
objects[object.global_id] = object
|
||||
|
||||
|
||||
# Check wether an object was registered
|
||||
#
|
||||
# #### Parameters
|
||||
#
|
||||
# - global_id: Global ID of object
|
||||
# **Returns** Wether the object exists in the object registry
|
||||
func has(global_id: String) -> bool:
|
||||
return objects.has(global_id)
|
||||
|
||||
|
||||
# Get the object from the object registry
|
||||
func get_object(global_id: String) -> ESCObject:
|
||||
if objects.has(global_id):
|
||||
return objects[global_id]
|
||||
else:
|
||||
escoria.logger.report_warnings(
|
||||
"Invalid object retrieved",
|
||||
[
|
||||
"Object with global id %s not found" % global_id
|
||||
]
|
||||
)
|
||||
return null
|
||||
|
||||
|
||||
# Remove an object from the registry
|
||||
#
|
||||
# #### Parameters
|
||||
#
|
||||
# - object: The object to unregister
|
||||
func unregister_object(object: ESCObject) -> void:
|
||||
if not escoria.inventory_manager.inventory_has(object.global_id) \
|
||||
and not object.global_id in RESERVED_OBJECTS:
|
||||
|
||||
objects.erase(object.global_id)
|
||||
@@ -1,747 +0,0 @@
|
||||
extends Node
|
||||
|
||||
"""
|
||||
This is the script that runs in background, checking for events in the events
|
||||
stack and executing them.
|
||||
Events are managed using 2 structures:
|
||||
- event_queue: a queue for scheduled events. On each iteration, every event
|
||||
in the queue is updated according time delta. If an event time occurs, it is run
|
||||
(see check_event_queue()).
|
||||
- levels_stack: stack of events to be run immediately (from an event in ESC file
|
||||
usually)
|
||||
"""
|
||||
|
||||
signal global_changed(global_name)
|
||||
signal inventory_changed
|
||||
signal open_inventory
|
||||
signal saved
|
||||
signal run_event(ev_name, ev_data)
|
||||
signal event_done(ev_name)
|
||||
signal music_volume_changed
|
||||
signal action_changed
|
||||
signal paused(p_paused)
|
||||
|
||||
onready var resource_cache = load("res://addons/escoria-core/game/core-scripts/resource_queue.gd").new()
|
||||
onready var save_data = load("res://addons/escoria-core/game/core-scripts/save_data/save_data.gd").new()
|
||||
|
||||
# Cached scenes
|
||||
var scenes_cache_list : Array = []
|
||||
var scenes_cache : Dictionary = {} # this will eventually have everything in scenes_cache_list forever
|
||||
|
||||
# Event currently running
|
||||
var running_event
|
||||
# Events queue for timed events
|
||||
var event_queue : Array = []
|
||||
# Events stack
|
||||
var levels_stack : Array = []
|
||||
|
||||
var reserved_globals = [
|
||||
"ESC_LAST_SCENE"
|
||||
]
|
||||
# Dictionary of global variables
|
||||
var globals : Dictionary = {}
|
||||
|
||||
# Dictionary of active objects
|
||||
## Active == visible to the player
|
||||
## Inactive == invisible to the player
|
||||
var actives : Dictionary = {}
|
||||
# Dictionary of all objects
|
||||
## in the form : { "object global_id" : object }
|
||||
var objects : Dictionary = {}
|
||||
# Dictionary of all objects' states
|
||||
## in the form : { "object_name" : "state_name" }
|
||||
var states : Dictionary = {}
|
||||
var interactives : Dictionary = {}
|
||||
|
||||
# Array containing the event table for each registered object
|
||||
var objects_events_table : Dictionary
|
||||
|
||||
var continue_enabled : bool = true
|
||||
var loading_game : bool = false
|
||||
var game
|
||||
|
||||
# VERBS & TOOLS
|
||||
# to be used like this:
|
||||
# <current_action> <current_tool> with (target item or hotspot)
|
||||
# eg: "use" "wrench" (with) (target item or hotspot)
|
||||
|
||||
# Current verb used
|
||||
var current_action : String = "" setget set_current_action
|
||||
# Current tool (ESCItem/ESCInventoryItem) used
|
||||
var current_tool
|
||||
|
||||
## If true, we are accepting inputs
|
||||
#var accept_input : bool
|
||||
#enum ACCEPTABLE_INPUT {
|
||||
# INPUT_NONE
|
||||
#}
|
||||
|
||||
func _ready():
|
||||
save_data.start()
|
||||
|
||||
get_tree().set_auto_accept_quit(ProjectSettings.get('escoria/main/force_quit'))
|
||||
randomize()
|
||||
save_data.check_settings()
|
||||
var settings = save_data.load_settings(null)
|
||||
escoria.settings = parse_json(settings)
|
||||
escoria._on_settings_loaded(escoria.settings)
|
||||
|
||||
printt("Calling resource cache start")
|
||||
resource_cache.start()
|
||||
|
||||
# if !ProjectSettings.get_setting("escoria/platform/skip_cache"):
|
||||
# scenes_cache_list.push_back(ProjectSettings.get_setting("escoria/main/curtain"))
|
||||
# scenes_cache_list.push_back(ProjectSettings.get_setting("escoria/main/hud"))
|
||||
#
|
||||
# printt("Cache list ", [scenes_cache_list])
|
||||
# for s in scenes_cache_list:
|
||||
# if s != null:
|
||||
# resource_cache.queue_resource(s, false, true)
|
||||
set_process(true)
|
||||
|
||||
func _process(delta : float):
|
||||
check_event_queue(delta)
|
||||
run()
|
||||
check_autosave()
|
||||
|
||||
# Process the event queue
|
||||
func check_event_queue(delta : float):
|
||||
# Update every event's time in the queue
|
||||
for e in event_queue:
|
||||
if e.qe_time > 0:
|
||||
e.qe_time -= delta
|
||||
|
||||
# if !can_interact() or running_event:
|
||||
# return
|
||||
|
||||
var i = event_queue.size()
|
||||
while i:
|
||||
i -= 1
|
||||
var queued_next = event_queue[i]
|
||||
print(queued_next)
|
||||
# if queued_next.qe_time <= 0:
|
||||
# var obj = get_object(queued_next.qe_objname)
|
||||
# run_event(obj.event_table[queued_next.qe_event])
|
||||
# event_queue.remove(i)
|
||||
# break
|
||||
|
||||
func is_debug_command(p_event):
|
||||
if p_event["ev_name"] != "debug":
|
||||
return false
|
||||
if p_event["ev_level"].size() != 1:
|
||||
return false
|
||||
if !(p_event["ev_level"][0].name in escoria.esc_compiler.debug_commands):
|
||||
return false
|
||||
return true
|
||||
|
||||
# Called by run_game()
|
||||
func run_event(p_event):
|
||||
"""
|
||||
Run an event
|
||||
"""
|
||||
if is_debug_command(p_event):
|
||||
return run_debug_command(p_event)
|
||||
else:
|
||||
running_event = p_event
|
||||
add_level(p_event, true)
|
||||
|
||||
func run_debug_command(p_event):
|
||||
return callv(p_event["ev_level"][0].name, p_event["ev_level"][0].params)
|
||||
|
||||
func add_level(p_event, p_root : bool):
|
||||
"""
|
||||
Add an ESCEvent to events stack
|
||||
p_event: the ESCEvent
|
||||
p_root: bool
|
||||
"""
|
||||
levels_stack.push_back(instance_level(p_event, p_root))
|
||||
return esctypes.EVENT_LEVEL_STATE.CALL
|
||||
|
||||
func instance_level(p_event : esctypes.ESCEvent, p_root : bool):
|
||||
var new_level = {
|
||||
"ip": 0, # Current instruction id
|
||||
"instructions": p_event.ev_level, # List of instructions (commands)
|
||||
"waiting": false, # If true, wait for current command to be finished (esc_runner_level.finished())
|
||||
"break_stop": p_root,
|
||||
"labels": {},
|
||||
"flags": p_event.ev_flags
|
||||
}
|
||||
|
||||
for i in range(p_event.ev_level.size()):
|
||||
if p_event.ev_level[i].name == "label":
|
||||
var lname = p_event.ev_level[i].params[0]
|
||||
new_level.labels[lname] = i
|
||||
return new_level
|
||||
|
||||
func run():
|
||||
if levels_stack.size() == 0:
|
||||
# Constantly run in _process: we may have an empty levels_stack and no event
|
||||
if running_event:
|
||||
emit_signal("event_done", running_event.ev_name)
|
||||
running_event = null
|
||||
return
|
||||
|
||||
while levels_stack.size() > 0:
|
||||
var ret = run_top()
|
||||
if ret == esctypes.EVENT_LEVEL_STATE.YIELD:
|
||||
return
|
||||
if ret == esctypes.EVENT_LEVEL_STATE.BREAK:
|
||||
while levels_stack.size() > 0 && !(levels_stack[levels_stack.size()-1].break_stop):
|
||||
levels_stack.remove(levels_stack.size()-1)
|
||||
levels_stack.remove(levels_stack.size()-1)
|
||||
|
||||
func run_top():
|
||||
var top = levels_stack[levels_stack.size()-1]
|
||||
# printt("-----> TOP:", top)
|
||||
var ret = $esc_level_runner.resume(top)
|
||||
if ret == esctypes.EVENT_LEVEL_STATE.RETURN || ret == esctypes.EVENT_LEVEL_STATE.BREAK:
|
||||
levels_stack.remove(levels_stack.size()-1)
|
||||
return ret
|
||||
|
||||
func test(cmd):
|
||||
if "if_true" in cmd.conditions.keys():
|
||||
for flag in cmd.conditions.if_true:
|
||||
if !get_global(flag):
|
||||
return false
|
||||
if "if_false" in cmd.conditions.keys():
|
||||
for flag in cmd.conditions.if_false:
|
||||
if get_global(flag):
|
||||
return false
|
||||
if "if_inv" in cmd.conditions.keys():
|
||||
for flag in cmd.conditions.if_inv:
|
||||
if !inventory_has(flag):
|
||||
return false
|
||||
if "if_not_inv" in cmd.conditions.keys():
|
||||
for flag in cmd.conditions.if_not_inv:
|
||||
if inventory_has(flag):
|
||||
return false
|
||||
if "if_active" in cmd.conditions.keys():
|
||||
for flag in cmd.conditions.if_active:
|
||||
if not flag in actives or not actives[flag]:
|
||||
return false
|
||||
if "if_not_active" in cmd.conditions.keys():
|
||||
for flag in cmd.conditions.if_not_active:
|
||||
if flag in actives and actives[flag]:
|
||||
return false
|
||||
if "if_eq" in cmd.conditions.keys():
|
||||
for flag in cmd.conditions.if_eq:
|
||||
if !is_global_equal_to(flag[0], flag[1]):
|
||||
return false
|
||||
if "if_ne" in cmd.conditions.keys():
|
||||
for flag in cmd.conditions.if_ne:
|
||||
if is_global_equal_to(flag[0], flag[1]):
|
||||
return false
|
||||
if "if_gt" in cmd.conditions.keys():
|
||||
for flag in cmd.conditions.if_gt:
|
||||
if !is_global_greater_than(flag[0], flag[1]):
|
||||
return false
|
||||
if "if_ge" in cmd.conditions.keys():
|
||||
for flag in cmd.conditions.if_ge:
|
||||
if is_global_less_than(flag[0], flag[1]):
|
||||
return false
|
||||
if "if_lt" in cmd.conditions.keys():
|
||||
for flag in cmd.conditions.if_lt:
|
||||
if !is_global_less_than(flag[0], flag[1]):
|
||||
return false
|
||||
if "if_le" in cmd.conditions.keys():
|
||||
for flag in cmd.conditions.if_le:
|
||||
if is_global_greater_than(flag[0], flag[1]):
|
||||
return false
|
||||
return true
|
||||
|
||||
func inventory_has(p_obj):
|
||||
return get_global("i/"+p_obj)
|
||||
|
||||
func items_in_inventory():
|
||||
var items = []
|
||||
for glob in globals.keys():
|
||||
if glob.begins_with("i/") and globals[glob] == "true":
|
||||
items.push_back(glob.rsplit("i/", false)[0])
|
||||
return items
|
||||
|
||||
func get_global(name):
|
||||
# If no value or looks like boolean, return boolean for backwards compatibility
|
||||
if not name in globals or globals[name].to_lower() == "false":
|
||||
return false
|
||||
if globals[name].to_lower() == "true":
|
||||
return true
|
||||
return globals[name]
|
||||
|
||||
# Set global state 'name' to 'value' (can be true or false)
|
||||
#
|
||||
func set_global(name, val, force_change_reserved : bool = false):
|
||||
if name in reserved_globals and !force_change_reserved:
|
||||
escoria.logger.report_warnings("esc_runner.gd:set_global()",
|
||||
["Global " + name + " is reserved. Value not modified."])
|
||||
return
|
||||
globals[name] = val
|
||||
# printt("global changed at global_vm, emitting for ", name, val)
|
||||
emit_signal("global_changed", name)
|
||||
|
||||
func set_globals(pattern : String, val):
|
||||
for key in globals:
|
||||
if key.match(pattern):
|
||||
set_global(key, val)
|
||||
# globals[key] = val
|
||||
# emit_signal("global_changed", key)
|
||||
|
||||
func dec_global(name, diff):
|
||||
var global = get_global(name)
|
||||
global = int(global) if global else 0
|
||||
set_global(name, str(global - diff))
|
||||
|
||||
func inc_global(name, diff):
|
||||
var global = get_global(name)
|
||||
global = int(global) if global else 0
|
||||
set_global(name, str(global + diff))
|
||||
|
||||
func is_global_equal_to(name, val):
|
||||
var global = get_global(name)
|
||||
if global and val and global == val:
|
||||
return true
|
||||
|
||||
func is_global_greater_than(name, val):
|
||||
var global = get_global(name)
|
||||
if global and val and int(global) > int(val):
|
||||
return true
|
||||
|
||||
func is_global_less_than(name, val):
|
||||
var global = get_global(name)
|
||||
if global and val and int(global) < int(val):
|
||||
return true
|
||||
|
||||
func jump(p_label):
|
||||
while levels_stack.size() > 0:
|
||||
var top = levels_stack[levels_stack.size()-1]
|
||||
printt("top labels: ", top.labels, p_label)
|
||||
if p_label in top.labels:
|
||||
top.ip = top.labels[p_label]
|
||||
return
|
||||
else:
|
||||
if top.break_stop || levels_stack.size() == 1:
|
||||
escoria.logger.report_errors("esc_runner.gd:jump()",
|
||||
["ESC: Jump to inexisting label: " + p_label])
|
||||
levels_stack.remove(levels_stack.size()-1)
|
||||
break
|
||||
else:
|
||||
levels_stack.remove(levels_stack.size()-1)
|
||||
|
||||
func check_autosave():
|
||||
pass
|
||||
|
||||
func set_current_action(action : String):
|
||||
if ! action is String:
|
||||
escoria.logger.report_errors("esc_runner.gd",
|
||||
["Trying to set_current_action: " + str(typeof(action))])
|
||||
|
||||
if action != current_action:
|
||||
clear_current_tool()
|
||||
|
||||
current_action = action
|
||||
emit_signal("action_changed")
|
||||
|
||||
func clear_current_action():
|
||||
set_current_action("")
|
||||
|
||||
func clear_current_tool():
|
||||
current_tool = null
|
||||
|
||||
func change_scene(params, context, run_events=true):
|
||||
escoria.logger.info("Change scene to " + params[0] + " with run_events " + str(run_events))
|
||||
# check_cache()
|
||||
# main.clear_scene()
|
||||
# camera = null
|
||||
event_queue = []
|
||||
|
||||
escoria.main.scene_transition.fade_out()
|
||||
yield(escoria.main.scene_transition, "transition_done")
|
||||
|
||||
# Regular events need to be reset immediately, so we don't
|
||||
# accidentally `yield()` on them, for performance reasons.
|
||||
# This does not affect `stack` so execution is fine anyway.
|
||||
if running_event and running_event.ev_name != "load":
|
||||
emit_signal("event_done", running_event.ev_name)
|
||||
running_event = null
|
||||
|
||||
var res_room = resource_cache.get_resource(params[0])
|
||||
var res_game = resource_cache.get_resource(ProjectSettings.get_setting("escoria/ui/game_scene"))
|
||||
if !res_room:
|
||||
escoria.logger.report_errors("esc_runner.gd:change_scene()",
|
||||
["Resource not found: " + params[0]])
|
||||
if !res_game:
|
||||
escoria.logger.report_errors("esc_runner.gd:change_scene()",
|
||||
["Resource not found: " + ProjectSettings.get_setting("escoria/ui/game_scene")])
|
||||
|
||||
resource_cache.clear()
|
||||
|
||||
# Load game scene
|
||||
var game_scene = res_game.instance()
|
||||
if !game_scene:
|
||||
escoria.logger.report_errors("esc_runner.gd:change_scene()",
|
||||
["Failed loading scene " + ProjectSettings.get_setting("escoria/ui/game_scene")])
|
||||
|
||||
# Load room scene
|
||||
var room_scene = res_room.instance()
|
||||
if room_scene:
|
||||
room_scene.add_child(game_scene)
|
||||
room_scene.move_child(game_scene, 0)
|
||||
var events = escoria.main.set_scene(room_scene, run_events)
|
||||
|
||||
escoria.main.scene_transition.fade_in()
|
||||
yield(escoria.main.scene_transition, "transition_done")
|
||||
|
||||
# If scene was never visited, add "ready" event to the events stack
|
||||
if !scenes_cache.has(room_scene.global_id) \
|
||||
and "ready" in events:
|
||||
run_event(events["ready"])
|
||||
|
||||
# :setup is pretty much required in the code, but fortunately
|
||||
# we can help out with cases where one isn't necessary otherwise
|
||||
if not "setup" in events:
|
||||
var fake_setup = escoria.esc_compiler.compile_str(":setup\n")
|
||||
events["setup"] = fake_setup["setup"]
|
||||
# Finally we add the setup on to of the events stack so that it is ran first
|
||||
run_event(events["setup"])
|
||||
|
||||
escoria.inputs_manager.hotspot_focused = ""
|
||||
if !scenes_cache_list.has(params[0]):
|
||||
scenes_cache_list.push_back(params[0])
|
||||
scenes_cache[room_scene.global_id] = params[0]
|
||||
else:
|
||||
escoria.logger.report_errors("esc_runner.gd:change_scene()",
|
||||
["Failed loading scene " + params[0]])
|
||||
|
||||
if context != null:
|
||||
context.waiting = false
|
||||
|
||||
# Re-apply actives
|
||||
for active in actives:
|
||||
set_active(active, actives[active])
|
||||
|
||||
# cam_target = null
|
||||
# autosave_pending = true
|
||||
|
||||
|
||||
func superpose_scene(params, context, run_events=true):
|
||||
printt("superposing scene ", params[0], " with run_events ", run_events)
|
||||
# check_cache()
|
||||
# main.clear_scene()
|
||||
# camera = null
|
||||
# event_queue = []
|
||||
|
||||
# Regular events need to be reset immediately, so we don't
|
||||
# accidentally `yield()` on them, for performance reasons.
|
||||
# This does not affect `stack` so execution is fine anyway.
|
||||
if running_event and running_event.ev_name != "load":
|
||||
emit_signal("event_done", running_event.ev_name)
|
||||
running_event = null
|
||||
|
||||
var res_room = resource_cache.get_resource(params[0])
|
||||
var res_game = resource_cache.get_resource(ProjectSettings.get_setting("escoria/ui/game_scene"))
|
||||
if !res_room:
|
||||
escoria.logger.report_errors("esc_runner.gd:superpose_scene()",
|
||||
["Resource not found: " + params[0]])
|
||||
if !res_game:
|
||||
escoria.logger.report_errors("esc_runner.gd:superpose_scene()",
|
||||
["Resource not found: " + ProjectSettings.get_setting("escoria/ui/game_scene")])
|
||||
|
||||
resource_cache.clear()
|
||||
|
||||
# Load game scene
|
||||
var game_scene = res_game.instance()
|
||||
if !game_scene:
|
||||
escoria.logger.report_errors("esc_runner.gd:superpose_scene()",
|
||||
["Failed loading scene " + ProjectSettings.get_setting("escoria/ui/game_scene")])
|
||||
|
||||
# Load room scene
|
||||
var room_scene = res_room.instance()
|
||||
if room_scene:
|
||||
get_node("/root").add_child(room_scene)
|
||||
|
||||
var target = context.get("set_position")
|
||||
if target:
|
||||
if target is Vector2:
|
||||
room_scene.set_position(target)
|
||||
if target is String:
|
||||
var obj = get_object(target)
|
||||
room_scene.set_position(obj.get_global_position())
|
||||
|
||||
escoria.inputs_manager.hotspot_focused = false
|
||||
if !scenes_cache_list.has(params[0]):
|
||||
scenes_cache_list.push_back(params[0])
|
||||
if room_scene.get("global_id"):
|
||||
scenes_cache[room_scene.global_id] = params[0]
|
||||
else:
|
||||
scenes_cache[room_scene.name] = params[0]
|
||||
else:
|
||||
escoria.logger.report_errors("esc_runner.gd:superpose_scene()",
|
||||
["Failed loading scene " + params[0]])
|
||||
|
||||
if context != null:
|
||||
context.waiting = false
|
||||
|
||||
# Re-apply actives
|
||||
for active in actives:
|
||||
set_active(active, actives[active])
|
||||
|
||||
# cam_target = null
|
||||
# autosave_pending = true
|
||||
|
||||
|
||||
func run_game(actions : Dictionary):
|
||||
set_process(true)
|
||||
# `load` and `ready` are exclusive because you probably don't want to
|
||||
# reset the game state when a scene becomes ready, and `ready` is
|
||||
# redundant when `load`ing state anyway.
|
||||
# `start` is used only in your `escoria/platform/game_start_script` .esc
|
||||
# file to start the game.
|
||||
if "start" in actions:
|
||||
clear()
|
||||
run_event(actions["start"])
|
||||
escoria.main_menu_instance.hide()
|
||||
elif "load" in actions:
|
||||
clear()
|
||||
run_event(actions["load"])
|
||||
elif "ready" in actions:
|
||||
run_event(actions["ready"])
|
||||
|
||||
func clear():
|
||||
get_tree().call_group_flags(SceneTree.GROUP_CALL_DEFAULT, "game", "game_cleared")
|
||||
levels_stack = []
|
||||
globals = {}
|
||||
objects = {}
|
||||
states = {}
|
||||
actives = {}
|
||||
interactives = {}
|
||||
event_queue = []
|
||||
continue_enabled = true
|
||||
loading_game = false
|
||||
|
||||
|
||||
func register_object(name : String, val : Object, force : bool = false):
|
||||
if !name:
|
||||
escoria.logger.report_errors("esc_runner.gd:register_object()",
|
||||
["global_id not given for " + val.get_class() + " " + val.name])
|
||||
|
||||
if name in objects and not force:
|
||||
escoria.logger.report_errors("esc_runner.gd:register_object()",
|
||||
["Trying to register already registered object " + name + ": " \
|
||||
+ val.get_class() + " (" + val.name + ")"])
|
||||
|
||||
objects[name] = val
|
||||
|
||||
if not val.is_connected("tree_exited", self, "object_exit_scene"):
|
||||
val.connect("tree_exited", self, "object_exit_scene", [name])
|
||||
|
||||
# Most objects have states/animations, but don't count on it
|
||||
# if val.has_method("set_state"):
|
||||
if val is ESCItem or val is ESCPlayer:
|
||||
if name in states:
|
||||
set_state(name, [states[name], true])
|
||||
else:
|
||||
set_state(name, [esctypes.OBJ_DEFAULT_STATE])
|
||||
|
||||
if val is ESCItem:
|
||||
if val.is_interactive:
|
||||
set_interactive(name, true)
|
||||
|
||||
if val.get("esc_script") != null and !val.get("esc_script").empty():
|
||||
objects_events_table[name] = escoria.esc_compiler.load_esc_file(val.esc_script)
|
||||
|
||||
|
||||
func get_object(name):
|
||||
if !(name in objects):
|
||||
return null
|
||||
return objects[name]
|
||||
|
||||
|
||||
# Activates the action for given params
|
||||
# p_action String Action to execute (defined in attached ESC file and in action verbs UI)
|
||||
# - eg: arrived, use, look, pickup...
|
||||
# p_params Array
|
||||
# - 0 Object Target object
|
||||
func activate(p_action : String, p_param : Array):
|
||||
escoria.logger.info("Action " + p_action + " with params ", [p_param])
|
||||
# if p_param[0].global_id:
|
||||
# printt("("+p_param[0].global_id+")")
|
||||
var what = p_param[0]
|
||||
|
||||
# If we're using an action which item requires to combine
|
||||
if what is ESCItem and p_action in what.combine_if_action_used_among:
|
||||
# Check if object must be in inventory to be used
|
||||
if what is ESCItem and what.use_from_inventory_only:
|
||||
if !inventory_has(what.global_id):
|
||||
# TODO Either use fallback here, or run pickup action before use
|
||||
escoria.logger.report_warnings("esc_runner.gd:activate()",
|
||||
["Trying to " + p_action + " on object " + what.global_id
|
||||
+ " but item must be in inventory."])
|
||||
return esctypes.EVENT_LEVEL_STATE.YIELD
|
||||
else:
|
||||
|
||||
# Player has item in inventory, we check the element to use on
|
||||
if p_param.size() > 1:
|
||||
var combine_with = p_param[1]
|
||||
|
||||
var do_combine = false
|
||||
if combine_with is ESCItem and combine_with.use_from_inventory_only:
|
||||
if inventory_has(combine_with.global_id):
|
||||
do_combine = true
|
||||
else:
|
||||
do_combine = true
|
||||
|
||||
if do_combine:
|
||||
if objects_events_table[what.global_id].has(p_action + " " + combine_with.global_id):
|
||||
run_event(objects_events_table[what.global_id][p_action + " " + combine_with.global_id])
|
||||
return esctypes.EVENT_LEVEL_STATE.RETURN
|
||||
elif objects_events_table[combine_with.global_id].has(p_action + " " + what.global_id) \
|
||||
and !combine_with.combine_is_one_way:
|
||||
run_event(objects_events_table[combine_with.global_id][p_action + " " + what.global_id])
|
||||
return esctypes.EVENT_LEVEL_STATE.RETURN
|
||||
else:
|
||||
var errors = ["Attempted to execute inexisting action " + \
|
||||
p_action + " between item " + combine_with.global_id + " and item " + what.global_id]
|
||||
if combine_with.get("combine_is_one_way") != null \
|
||||
and combine_with.combine_is_one_way:
|
||||
errors.append("Reason: " + combine_with.global_id + "'s item interaction is one-way.")
|
||||
escoria.logger.report_warnings("esc_runner.gd:activate()", errors)
|
||||
|
||||
return esctypes.EVENT_LEVEL_STATE.YIELD
|
||||
else:
|
||||
# TODO Use fallback here
|
||||
pass
|
||||
|
||||
else:
|
||||
# We're missing a target here.
|
||||
# Tell the Label to add a conjunction and wait for another click
|
||||
# to add the target to p_param. Until then, return false.
|
||||
current_tool = what
|
||||
return esctypes.EVENT_LEVEL_STATE.YIELD
|
||||
|
||||
if what.global_id in objects_events_table:
|
||||
if p_action in objects_events_table[what.global_id]:
|
||||
run_event(objects_events_table[what.global_id][p_action])
|
||||
else:
|
||||
escoria.logger.report_warnings("esc_runner.gd:activate()",
|
||||
["Action '" + p_action + "' requested on object '" \
|
||||
+ what.global_id + "' but action doesn't exist in attached ESC file.",
|
||||
"TODO: manage fallbacks."])
|
||||
return esctypes.EVENT_LEVEL_STATE.RETURN
|
||||
else:
|
||||
escoria.logger.report_warnings("esc_runner.gd:activate()",
|
||||
["Action '" + p_action + "' requested on object '" + what.global_id \
|
||||
+ "' but object does not exist in objects_events_table.", \
|
||||
"Does object " + what.global_id + " have an attached ESC file?"])
|
||||
return esctypes.EVENT_LEVEL_STATE.RETURN
|
||||
return esctypes.EVENT_LEVEL_STATE.RETURN
|
||||
|
||||
|
||||
func get_state(name : String):
|
||||
return states[name]
|
||||
|
||||
|
||||
func get_active(name : String) -> bool:
|
||||
if actives.has(name):
|
||||
return actives[name]
|
||||
return false
|
||||
|
||||
"""
|
||||
Return the interactive object given its global_id.
|
||||
"""
|
||||
func get_interactive(global_id : String):
|
||||
if interactives.has(global_id):
|
||||
return interactives[global_id]
|
||||
return false
|
||||
|
||||
|
||||
"""
|
||||
Change an object state and play its animation (if it has one)
|
||||
p_params[] :
|
||||
- String state : the state name
|
||||
- bool immediate (default=false) : if true, the animation is not played and immediately goes to the last frame
|
||||
"""
|
||||
func set_state(global_id : String, p_params : Array):
|
||||
var obj = get_object(global_id)
|
||||
states[global_id] = p_params[0]
|
||||
var immediate : bool = false
|
||||
if p_params.size() > 1:
|
||||
immediate = p_params[1]
|
||||
|
||||
# A Hotspot can have a child item, if this item has an empty sprite
|
||||
# (the hotspot is there to get the user input)
|
||||
var animation_node
|
||||
if obj is ESCItem:
|
||||
#if obj.get("animation") != null:
|
||||
# animation_node = obj.get("animation")
|
||||
if obj.get_animation_player() != null:
|
||||
animation_node = obj.get_animation_player()
|
||||
|
||||
if animation_node:
|
||||
animation_node.stop()
|
||||
var actual_animator
|
||||
if animation_node is AnimationPlayer:
|
||||
actual_animator = animation_node
|
||||
elif animation_node is AnimatedSprite:
|
||||
actual_animator = animation_node.frames
|
||||
|
||||
if actual_animator.has_animation(p_params[0]):
|
||||
if !immediate:
|
||||
animation_node.play(p_params[0])
|
||||
else:
|
||||
# The animation is not played, we directly set it at its last frame
|
||||
if animation_node is AnimatedSprite:
|
||||
animation_node.animation = p_params[0]
|
||||
else:
|
||||
animation_node.current_animation = p_params[0]
|
||||
var animation = actual_animator.get_animation(p_params[0])
|
||||
var animation_length = animation.length
|
||||
animation_node.seek(animation_length)
|
||||
escoria.logger.info("Item " + obj.global_id + " changed state to: " + p_params[0])
|
||||
|
||||
"""
|
||||
When object is active, it is VISIBLE.
|
||||
When object is inactive, it is HIDDEN.
|
||||
"""
|
||||
func set_active(name : String, active):
|
||||
actives[name] = active
|
||||
if objects.has(name) and is_instance_valid(objects[name]):
|
||||
if objects[name] is ESCInventoryItem:
|
||||
return
|
||||
|
||||
if active:
|
||||
objects[name].show()
|
||||
else:
|
||||
objects[name].hide()
|
||||
|
||||
"""
|
||||
When object is interactive, it can be focused
|
||||
When object is not interactive, it cannot be focused and used
|
||||
"""
|
||||
func set_interactive(name : String, active):
|
||||
interactives[name] = active
|
||||
|
||||
|
||||
|
||||
"""
|
||||
Callback called by ESCItems when it emits "tree_exit", ie. removed from scene.
|
||||
Item is kept in objects[] array if it is in inventory.
|
||||
"""
|
||||
func object_exit_scene(name : String):
|
||||
# If object is in inventory, save it before it's destroyed so we still have
|
||||
# its data in objects[]
|
||||
if inventory_has(name):
|
||||
objects[name] = objects[name].duplicate()
|
||||
else:
|
||||
if name != "bg_music":
|
||||
escoria.logger.info("Object " + name + " removed from scene.")
|
||||
objects.erase(name)
|
||||
|
||||
|
||||
func check_obj(name, cmd):
|
||||
var obj = escoria.esc_runner.get_object(name)
|
||||
if obj == null:
|
||||
escoria.logger.report_errors("esc_runner.gd:check_obj()",
|
||||
["Global id "+name+" not found for " + cmd])
|
||||
return false
|
||||
return true
|
||||
|
||||
|
||||
@@ -1,773 +0,0 @@
|
||||
extends Node
|
||||
|
||||
# This script implements the ESCCommands contained in the ESCEvent.
|
||||
# TODO : this script should use "Command" pattern.
|
||||
|
||||
var current_context
|
||||
|
||||
|
||||
func finished(context = null):
|
||||
if context != null:
|
||||
context.waiting = false
|
||||
else:
|
||||
current_context.waiting = false
|
||||
|
||||
if escoria.current_state == escoria.GAME_STATE.WAIT:
|
||||
escoria.current_state = escoria.GAME_STATE.DEFAULT
|
||||
|
||||
|
||||
func resume(context):
|
||||
current_context = context
|
||||
if context.waiting:
|
||||
return esctypes.EVENT_LEVEL_STATE.YIELD
|
||||
var count = context.instructions.size()
|
||||
while context.ip < count:
|
||||
var top = escoria.esc_runner.levels_stack.size()
|
||||
var ret = run(context)
|
||||
context.ip += 1
|
||||
if top < escoria.esc_runner.levels_stack.size():
|
||||
return esctypes.EVENT_LEVEL_STATE.CALL
|
||||
if ret == esctypes.EVENT_LEVEL_STATE.YIELD:
|
||||
return esctypes.EVENT_LEVEL_STATE.YIELD
|
||||
if ret == esctypes.EVENT_LEVEL_STATE.CALL:
|
||||
return esctypes.EVENT_LEVEL_STATE.CALL
|
||||
if ret == esctypes.EVENT_LEVEL_STATE.BREAK:
|
||||
if context.break_stop:
|
||||
break
|
||||
else:
|
||||
return esctypes.EVENT_LEVEL_STATE.BREAK
|
||||
if ret == esctypes.EVENT_LEVEL_STATE.REPEAT:
|
||||
context.ip = 0
|
||||
if ret == esctypes.EVENT_LEVEL_STATE.JUMP:
|
||||
return esctypes.EVENT_LEVEL_STATE.JUMP
|
||||
context.ip = 0
|
||||
return esctypes.EVENT_LEVEL_STATE.RETURN
|
||||
|
||||
|
||||
func run(context):
|
||||
var cmd = context.instructions[context.ip]
|
||||
if cmd.name == "label":
|
||||
return esctypes.EVENT_LEVEL_STATE.RETURN
|
||||
if !escoria.esc_runner.test(cmd):
|
||||
return esctypes.EVENT_LEVEL_STATE.RETURN
|
||||
#print("name is ", cmd.name)
|
||||
#if !(cmd.name in self):
|
||||
# escoria.logger.report_errors("", ["Unexisting command "+cmd.name])
|
||||
return call(cmd.name, cmd.params)
|
||||
|
||||
|
||||
"""
|
||||
Automatically called when a dialog line is said.
|
||||
"""
|
||||
func dialog_line_finished() -> void:
|
||||
# escoria.esc_runner.get_node("esc_level_runner").finished()
|
||||
finished()
|
||||
escoria.dialog_player.is_speaking = false
|
||||
escoria.current_state = escoria.GAME_STATE.DEFAULT
|
||||
|
||||
|
||||
"""
|
||||
accept_input [ALL|NONE|SKIP]
|
||||
What type of input does the game accept. ALL is the default, SKIP allows skipping
|
||||
of dialog but nothing else, NONE denies all input. Including opening the menu etc.
|
||||
SKIP and NONE also disable autosaves. Note that SKIP gets reset to ALL when the
|
||||
event is done, but NONE persists. This allows you to create cut scenes with SKIP
|
||||
where the dialog can be skipped, but also initiate locked-down cutscenes with
|
||||
accept_input NONE in :setup and accept_input ALL later in :ready.
|
||||
"""
|
||||
func accept_input(command_params : Array):
|
||||
# var p_input = command_params[0]
|
||||
# var input = escoria.esc_runner.acceptable_inputs["INPUT_" + p_input]
|
||||
# escoria.esc_runner.set_accept_input(input)
|
||||
pass
|
||||
|
||||
|
||||
"""
|
||||
"""
|
||||
func autosave():
|
||||
# escoria.request_autosave()
|
||||
pass
|
||||
|
||||
|
||||
"""
|
||||
anim object name [reverse] [flip_x] [flip_y]
|
||||
Executes the animation specificed with the "name" parameter on the object,
|
||||
without blocking. The next command in the event will be executed immediately after.
|
||||
Optional parameters:
|
||||
reverse plays the animation in reverse when true
|
||||
flip_x flips the x axis of the object's sprites when true (object's root node needs to be Node2D)
|
||||
flip_y flips the y axis of the object's sprites when true (object's root node needs to be Node2D)
|
||||
"""
|
||||
func anim(command_params : Array):
|
||||
if !escoria.esc_runner.check_obj(command_params[0], "anim"):
|
||||
return esctypes.EVENT_LEVEL_STATE.RETURN
|
||||
private_play_animation(command_params)
|
||||
return esctypes.EVENT_LEVEL_STATE.RETURN
|
||||
|
||||
|
||||
"""
|
||||
Groups Commands can be grouped using the character ">" to start a group, and
|
||||
incrementing the indentation of the commands that belong to the group. Example:
|
||||
>
|
||||
set_global door_open true
|
||||
animation player pick_up
|
||||
# end of group
|
||||
"""
|
||||
func branch(command_params : Array):
|
||||
var branch_ev = esctypes.ESCEvent.new("branch", command_params, [])
|
||||
return escoria.esc_runner.add_level(branch_ev, false)
|
||||
|
||||
|
||||
"""
|
||||
camera_push target [time] [type]
|
||||
Push camera to target. Target must have camera_pos set.
|
||||
If it's of type Camera2D, its zoom will be used as well as position.
|
||||
- A time value of 0 will set the camera immediately.
|
||||
- type is any of the Tween.TransitionType values without the prefix, eg. LINEAR,
|
||||
QUART or CIRC; defaults to QUART.
|
||||
"""
|
||||
func camera_push(command_params : Array):
|
||||
var target = escoria.esc_runner.get_object(command_params[0])
|
||||
var time = command_params[1] if command_params.size() > 1 else 1
|
||||
var type = command_params[2] if command_params.size() > 2 else "QUAD"
|
||||
escoria.esc_runner.get_object("camera").push(target, time, type)
|
||||
|
||||
|
||||
"""
|
||||
camera_set_limits camlimits_id
|
||||
Sets the camera limits to the one defined under "camlimits_id" in ESCRoom's
|
||||
camera_limits array.
|
||||
- camlimits_id : int : id of the camera limits to apply (defined in ESCRoom's
|
||||
camera_limits array)
|
||||
"""
|
||||
func camera_set_limits(command_params : Array):
|
||||
escoria.main.set_camera_limits(command_params[0])
|
||||
|
||||
|
||||
"""
|
||||
camera_set_drag_margin_enabled horizontal_enabled vertical_enabled
|
||||
- horizontal_enabled : bool
|
||||
- vertical_enabled : bool are booleans for whether or not horizontal and vertical drag
|
||||
margins are enabled. You will likely want to set them false for advanced camera
|
||||
motions and true for regular gameplay and/or tracking NPCs.
|
||||
"""
|
||||
func camera_set_drag_margin_enabled(command_params : Array):
|
||||
var horizontal_enabled = command_params[0]
|
||||
var vertical_enabled = command_params[1]
|
||||
escoria.esc_runner.get_object("camera").set_drag_margin_enabled(horizontal_enabled, vertical_enabled)
|
||||
|
||||
|
||||
"""
|
||||
camera_set_pos speed x y
|
||||
Moves the camera to a position defined by "x" and "y", at the speed defined by
|
||||
"speed" in pixels per second. If speed is 0, camera is teleported to the position.
|
||||
"""
|
||||
func camera_set_pos(command_params : Array):
|
||||
var speed = command_params[0]
|
||||
var pos = Vector2(command_params[1], command_params[2])
|
||||
escoria.esc_runner.get_object("camera").set_target(pos, speed)
|
||||
|
||||
|
||||
"""
|
||||
camera_set_target speed object [object2 object3 ...]
|
||||
Configures the camera to follow 1 or more objects, using "speed" as speed limit.
|
||||
This is the default behavior (default follow object is "player").
|
||||
If there's more than 1 object, the camera follows the average position of all
|
||||
the objects specified.
|
||||
"""
|
||||
func camera_set_target(command_params : Array):
|
||||
var speed = command_params[0]
|
||||
var target = escoria.esc_runner.get_object(command_params[1])
|
||||
escoria.esc_runner.get_object("camera").set_target(target, speed)
|
||||
|
||||
|
||||
"""
|
||||
camera_set_zoom magnitude [time]
|
||||
Zooms the camera in/out to the desired magnitude. Values larger than 1 zooms
|
||||
the camera out, and smaller values zooms in, relative to the default value of 1.
|
||||
An optional time in seconds controls how long it takes for the camera to zoom
|
||||
into position.
|
||||
"""
|
||||
func camera_set_zoom(command_params : Array):
|
||||
var zoom_level = command_params[0]
|
||||
var speed = command_params[0] if command_params.size() > 1 else 0
|
||||
escoria.esc_runner.get_object("camera").set_camera_zoom(zoom_level, speed)
|
||||
|
||||
|
||||
"""
|
||||
camera_set_zoom_height pixels [time]
|
||||
Similar to the command above, but uses pixel height instead of magnitude to zoom.
|
||||
"""
|
||||
func camera_set_zoom_height(command_params : Array):
|
||||
var magnitude = command_params[0] / escoria.game_size.y
|
||||
var time = command_params[1] if command_params.size() > 1 else 0
|
||||
escoria.esc_runner.get_object("camera").set_camera_zoom(magnitude, float(time))
|
||||
|
||||
|
||||
"""
|
||||
camera_shift x y [time] [type]
|
||||
Shift camera by x and y pixels over time seconds.
|
||||
- type is any of the Tween.TransitionType values without the prefix, eg. LINEAR,
|
||||
QUART or CIRC; defaults to QUART.
|
||||
"""
|
||||
func camera_shift(command_params : Array):
|
||||
var x = command_params[0]
|
||||
var y = command_params[1]
|
||||
var time = command_params[2]
|
||||
var type = command_params[3] if command_params.size() > 3 else "QUAD"
|
||||
escoria.esc_runner.get_object("camera").shift(x, y, time, type)
|
||||
|
||||
|
||||
"""
|
||||
change_scene path [run_events]
|
||||
Loads a new scene, specified by "path".
|
||||
The run_events variable is a boolean (default true) which you never want to set
|
||||
manually! It's there only to benefit save games, so they don't conflict with the
|
||||
scene's events.
|
||||
"""
|
||||
func change_scene(command_params : Array):
|
||||
# Savegames must have events disabled, so saving the game adds a false to params
|
||||
var run_events = true
|
||||
if command_params.size() == 2:
|
||||
run_events = bool(command_params[1])
|
||||
|
||||
# looking for localized string format in scene. this should be somewhere else
|
||||
var sep = command_params[0].find(":\"")
|
||||
if sep >= 0:
|
||||
var path = command_params[0].substr(sep + 2, command_params[0].length() - (sep + 2))
|
||||
escoria.esc_runner.call_deferred("change_scene", [path], current_context, run_events)
|
||||
else:
|
||||
escoria.esc_runner.call_deferred("change_scene", command_params, current_context, run_events)
|
||||
|
||||
current_context.waiting = true
|
||||
return esctypes.EVENT_LEVEL_STATE.YIELD
|
||||
|
||||
|
||||
"""
|
||||
"""
|
||||
func custom():
|
||||
pass
|
||||
|
||||
|
||||
"""
|
||||
cut_scene object name [reverse] [flip_x] [flip_y]
|
||||
Executes the animation specificed with the "name" parameter on the object, BLOCKING.
|
||||
The next command in the event will be executed when the animation is finished
|
||||
playing.
|
||||
Optional parameters:
|
||||
- reverse plays the animation in reverse when true
|
||||
- flip_x flips the x axis of the object's sprites when true
|
||||
(object's root node needs to be Node2D)
|
||||
- flip_y flips the y axis of the object's sprites when true
|
||||
(object's root node needs to be Node2D)
|
||||
"""
|
||||
func cut_scene(command_params : Array):
|
||||
if !escoria.esc_runner.check_obj(command_params[0], "cut_scene"):
|
||||
return esctypes.EVENT_LEVEL_STATE.RETURN
|
||||
private_play_animation(command_params)
|
||||
return esctypes.EVENT_LEVEL_STATE.YIELD
|
||||
|
||||
|
||||
"""
|
||||
PRIVATE
|
||||
Play animation using parameters.
|
||||
Used by commands anim() and cut_scene()
|
||||
"""
|
||||
func private_play_animation(command_params : Array):
|
||||
var obj = escoria.esc_runner.get_object(command_params[0])
|
||||
var anim_id = command_params[1]
|
||||
var reverse = false
|
||||
if command_params.size() > 2:
|
||||
reverse = command_params[2]
|
||||
var flip = Vector2(1, 1)
|
||||
if command_params.size() > 3 && command_params[3]:
|
||||
flip.x = -1
|
||||
if command_params.size() > 4 && command_params[4]:
|
||||
flip.y = -1
|
||||
current_context.waiting = true
|
||||
obj.play_anim(anim_id, current_context, reverse, flip)
|
||||
|
||||
|
||||
"""
|
||||
debug string [string2 ...]
|
||||
Takes 1 or more strings, prints them to the console.
|
||||
"""
|
||||
func debug(command_params : Array):
|
||||
for p in command_params:
|
||||
printt(p)
|
||||
return esctypes.EVENT_LEVEL_STATE.RETURN
|
||||
|
||||
|
||||
"""
|
||||
dec_global name value
|
||||
Subtracts the value from global with given "name".
|
||||
Value and global must both be integers.
|
||||
"""
|
||||
func dec_global(command_params : Array):
|
||||
escoria.esc_runner.dec_global(command_params[0], command_params[1])
|
||||
return esctypes.EVENT_LEVEL_STATE.RETURN
|
||||
|
||||
|
||||
"""
|
||||
inc_global name value
|
||||
Adds the value to global with given "name".
|
||||
Value and global must both be integers.
|
||||
"""
|
||||
func inc_global(command_params : Array):
|
||||
escoria.esc_runner.inc_global(command_params[0], command_params[1])
|
||||
return esctypes.EVENT_LEVEL_STATE.RETURN
|
||||
|
||||
|
||||
"""
|
||||
Start a dialog choice.
|
||||
"""
|
||||
func dialog(command_params : Array):
|
||||
current_context.waiting = true
|
||||
current_context.in_dialog = true
|
||||
escoria.current_state = escoria.GAME_STATE.DIALOG
|
||||
if !escoria.dialog_player:
|
||||
escoria.dialog_player = escoria.main.current_scene.get_node("game/ui/dialog_layer/dialog_player")
|
||||
var options = command_params.slice(1, command_params.size())
|
||||
escoria.dialog_player.start_dialog_choices(command_params[0], options)
|
||||
return esctypes.EVENT_LEVEL_STATE.YIELD
|
||||
|
||||
|
||||
#func dialog_config():
|
||||
## escoria.esc_runner.dialog_config(params)
|
||||
## return esctypes.EVENT_LEVEL_STATE.RETURN
|
||||
# pass
|
||||
|
||||
|
||||
"""
|
||||
enable_terrain node_name
|
||||
Enable the ESCTerrain's NavigationPolygonInstance defined by given node name.
|
||||
Disables previously activated NavigationPolygonInstance.
|
||||
"""
|
||||
func enable_terrain(command_params : Array):
|
||||
var name : String = command_params[0]
|
||||
if escoria.room_terrain.has_node(name):
|
||||
var new_active_navigation_instance = escoria.room_terrain.get_node(name)
|
||||
escoria.room_terrain.current_active_navigation_instance.enabled = false
|
||||
escoria.room_terrain.current_active_navigation_instance = new_active_navigation_instance
|
||||
escoria.room_terrain.current_active_navigation_instance.enabled = true
|
||||
|
||||
"""
|
||||
"""
|
||||
func game_over(command_params : Array):
|
||||
pass
|
||||
|
||||
|
||||
"""
|
||||
Adds element in inventory.
|
||||
Usage: inventory_add my_item
|
||||
equivalent to: set_global i/my_item true
|
||||
"""
|
||||
func inventory_add(command_params : Array):
|
||||
set_global(["i/"+command_params[0], "true"])
|
||||
|
||||
|
||||
"""
|
||||
Removes element from inventory.
|
||||
Usage: inventory_remove my_item
|
||||
equivalent to: set_global i/my_item false
|
||||
"""
|
||||
func inventory_remove(command_params : Array):
|
||||
set_global(["i/"+command_params[0], "false"])
|
||||
|
||||
|
||||
"""
|
||||
inventory_open true/false
|
||||
Shows or hides inventory. Uses code in game.tscn scene, thus developed outside of Escoria.
|
||||
"""
|
||||
func inventory_display(command_params : Array):
|
||||
var display : bool = bool(command_params[0])
|
||||
if display:
|
||||
escoria.main.current_scene.game.open_inventory()
|
||||
else:
|
||||
escoria.main.current_scene.game.close_inventory()
|
||||
|
||||
|
||||
"""
|
||||
jump label_name
|
||||
Jump to label_name block. This is used to build more complex dialog trees.
|
||||
Labels must be defined at the same level as the 'jump' command, using either
|
||||
'label label_name' command or '% label_name'.
|
||||
"""
|
||||
func jump(command_params : Array):
|
||||
escoria.esc_runner.jump(command_params[0])
|
||||
return esctypes.EVENT_LEVEL_STATE.JUMP
|
||||
|
||||
|
||||
"""
|
||||
set_sound_state bg_music|bg_sound off|default|<path/to/music.file> true|false
|
||||
"""
|
||||
func set_sound_state(command_params : Array):
|
||||
var snd_player = command_params[0]
|
||||
var snd_id = command_params[1]
|
||||
var loop = false
|
||||
if command_params.size() == 3 and command_params[2]:
|
||||
loop = true
|
||||
escoria.main.get_node(snd_player).set_state(snd_id, loop)
|
||||
return esctypes.EVENT_LEVEL_STATE.RETURN
|
||||
|
||||
|
||||
"""
|
||||
queue_animation object animation
|
||||
"""
|
||||
func queue_animation(command_params : Array):
|
||||
pass
|
||||
|
||||
|
||||
"""
|
||||
queue_resource path [front_of_queue]
|
||||
Queues the load of a resource in a background thread. The path must be a full
|
||||
path inside your game, for example "res://scenes/next_scene.tscn".
|
||||
The "front_of_queue" parameter is optional (default value false), to put the
|
||||
resource in the front of the queue. Queued resources are cleared when a change
|
||||
scene happens (but after the scene is loaded, meaning you can queue resources
|
||||
that belong to the next scene).
|
||||
"""
|
||||
func queue_resource(command_params : Array):
|
||||
var path : String = command_params[0]
|
||||
var in_front : bool = command_params[1] if command_params.size() > 1 else false
|
||||
escoria.esc_runner.resource_cache.queue_resource(path, in_front)
|
||||
|
||||
|
||||
"""
|
||||
repeat
|
||||
Restarts the execution of the current scope at the start. A scope can be a group
|
||||
or an event.
|
||||
"""
|
||||
func repeat(command_params : Array):
|
||||
return esctypes.EVENT_LEVEL_STATE.REPEAT
|
||||
|
||||
|
||||
"""
|
||||
say speaker_id "text_to_say" [dialog_ui_name]
|
||||
Make a character say one line.
|
||||
- dialog_ui_name String if set, uses the dialog UI by its name as defined
|
||||
in game.tscn/dialog_layer/dialog_player
|
||||
"""
|
||||
func say(command_params : Array) -> esctypes:
|
||||
current_context.waiting = true
|
||||
|
||||
var dict : Dictionary
|
||||
var dialog_scene_name = ProjectSettings.get_setting("escoria/ui/default_dialog_scene")
|
||||
|
||||
if dialog_scene_name.empty():
|
||||
escoria.logger.report_errors("level_esc_runners.gd:say()",
|
||||
["Project setting 'escoria/ui/default_dialog_scene' is not set.",
|
||||
"Please set a default dialog scene."])
|
||||
var file = dialog_scene_name.get_file()
|
||||
var extension = dialog_scene_name.get_extension()
|
||||
dialog_scene_name = file.rstrip("." + extension)
|
||||
|
||||
# Manage specific dialog scene
|
||||
if command_params.size() > 2:
|
||||
dialog_scene_name = command_params[2]
|
||||
|
||||
# Manage translation/voice lines keys in the form of :
|
||||
# line_key:"Default line text"
|
||||
# If a line_key exists, we'll set it a label as it will automatically be
|
||||
# translated
|
||||
var dialog_key_line = command_params[1].split(":", true, 1)
|
||||
if dialog_key_line.size() > 1:
|
||||
dialog_key_line[1] = dialog_key_line[1].trim_prefix("\"")
|
||||
|
||||
dict = {
|
||||
"key": dialog_key_line[0],
|
||||
"line": dialog_key_line[1] if dialog_key_line.size() > 1 else dialog_key_line[0],
|
||||
"ui": dialog_scene_name
|
||||
#"ui": "dialog_label"
|
||||
#"ui": "dialog_box_inset"
|
||||
}
|
||||
escoria.current_state = escoria.GAME_STATE.DIALOG
|
||||
if !escoria.dialog_player:
|
||||
escoria.dialog_player = escoria.main.current_scene.get_node("game/ui/dialog_layer/dialog_player")
|
||||
escoria.dialog_player.say(command_params[0], dict)
|
||||
return esctypes.EVENT_LEVEL_STATE.YIELD
|
||||
|
||||
|
||||
"""
|
||||
set_active global_id true/false
|
||||
Sets object as active or inactive. Active objects are displayed in scene and
|
||||
respond to inputs. Inactives are hidden.
|
||||
"""
|
||||
func set_active(command_params : Array):
|
||||
if !escoria.esc_runner.check_obj(command_params[0], "set_active"):
|
||||
return esctypes.EVENT_LEVEL_STATE.RETURN
|
||||
var name : String = command_params[0]
|
||||
var value = command_params[1]
|
||||
escoria.esc_runner.set_active(name, value)
|
||||
|
||||
"""
|
||||
set_angle object_id angle_degrees
|
||||
Set the angle of an object.
|
||||
"""
|
||||
func set_angle(command_params : Array):
|
||||
if !escoria.esc_runner.check_obj(command_params[0], "set_angle"):
|
||||
return esctypes.EVENT_LEVEL_STATE.RETURN
|
||||
var obj = escoria.esc_runner.get_object(command_params[0])
|
||||
# HACK Countering the fact that angle_to_point() function gives
|
||||
# angle against X axis not Y, we need to check direction using (angle-90°).
|
||||
# Since the ESC command already gives the right angle, we add 90.
|
||||
obj.set_angle(int(command_params[1] + 90))
|
||||
return esctypes.EVENT_LEVEL_STATE.RETURN
|
||||
|
||||
|
||||
"""
|
||||
set_state object_id state_name
|
||||
Set object state to state_name. States are recorded in escoria.states[].
|
||||
If the object has an animation named 'state_name', Escoria plays it.
|
||||
"""
|
||||
func set_state(command_params : Array):
|
||||
var global_id : String = command_params[0]
|
||||
var p_params : Array = command_params.slice(1, command_params.size())
|
||||
escoria.esc_runner.set_state(global_id, p_params)
|
||||
|
||||
|
||||
"""
|
||||
set_hud_visible true/false
|
||||
Hides the UI. Uses code in game.tscn scene, thus developed outside of Escoria.
|
||||
"""
|
||||
func set_hud_visible(command_params : Array):
|
||||
if command_params[0]:
|
||||
escoria.main.current_scene.game.show_ui()
|
||||
else:
|
||||
escoria.main.current_scene.game.hide_ui()
|
||||
|
||||
|
||||
"""
|
||||
"""
|
||||
func sched_event(command_params : Array):
|
||||
pass
|
||||
|
||||
|
||||
"""
|
||||
set_global global_variable value
|
||||
Sets a global variable value. Value can be string, integer or boolean.
|
||||
"""
|
||||
func set_global(command_params : Array):
|
||||
var name : String = command_params[0]
|
||||
var value = command_params[1]
|
||||
escoria.esc_runner.set_global(name, value)
|
||||
|
||||
|
||||
"""
|
||||
set_globals pattern value
|
||||
Changes the value of multiple globals using a wildcard pattern.
|
||||
Example:
|
||||
# clears the inventory
|
||||
set_globals i/* false
|
||||
"""
|
||||
func set_globals(command_params : Array):
|
||||
var pattern : String = command_params[0]
|
||||
var val = command_params[1]
|
||||
escoria.esc_runner.set_globals(pattern, val)
|
||||
|
||||
|
||||
"""
|
||||
set_interactive global_id true/false
|
||||
Sets object as interactive or not. Interactive objects can be pointed and
|
||||
interacted with.
|
||||
"""
|
||||
func set_interactive(command_params : Array):
|
||||
var global_id : String = command_params[0]
|
||||
var value = command_params[1]
|
||||
escoria.esc_runner.set_interactive(global_id, value)
|
||||
|
||||
|
||||
"""
|
||||
set_speed global_id speed_value
|
||||
Sets the speed of object defined by 'global_id' to 'speed_value'
|
||||
"""
|
||||
func set_speed(command_params : Array):
|
||||
if !escoria.esc_runner.check_obj(command_params[0], "set_speed"):
|
||||
return esctypes.EVENT_LEVEL_STATE.RETURN
|
||||
|
||||
var global_id : String = command_params[0]
|
||||
var speed_value = command_params[1]
|
||||
escoria.get_object(global_id).set_speed(speed_value)
|
||||
|
||||
|
||||
"""
|
||||
"""
|
||||
func slide(command_params : Array):
|
||||
pass
|
||||
|
||||
|
||||
"""
|
||||
"""
|
||||
func slide_to_pos(command_params : Array):
|
||||
pass
|
||||
|
||||
|
||||
"""
|
||||
"""
|
||||
func slide_block(command_params : Array):
|
||||
pass
|
||||
|
||||
|
||||
"""
|
||||
"""
|
||||
func slide_to_pos_block(command_params : Array):
|
||||
pass
|
||||
|
||||
|
||||
"""
|
||||
spawn path [object2]
|
||||
Instances a scene determined by "path", and places in the position of object2
|
||||
(object2 is optional)
|
||||
"""
|
||||
func spawn(command_params : Array):
|
||||
superpose_scene(command_params)
|
||||
|
||||
"""
|
||||
stop
|
||||
Stops the execution of the current script when it reaches the 'stop' instruction.
|
||||
Usually used in the end of commands blocks.
|
||||
"""
|
||||
func stop(command_params : Array):
|
||||
return esctypes.EVENT_LEVEL_STATE.BREAK
|
||||
|
||||
|
||||
"""
|
||||
superpose_scene path [run_events]
|
||||
Loads a new scene, specified by "path" and displays it OVER the current one.
|
||||
This is useful to display puzzle scenes over the current room, so that you don't
|
||||
loose any progression and continuity.
|
||||
- path String Path to the scene to superpose.
|
||||
- run_events Boolean (default true) which you never want to set
|
||||
manually! It's there only to benefit save games, so they don't conflict with the
|
||||
scene's events.
|
||||
"""
|
||||
func superpose_scene(command_params : Array):
|
||||
# Savegames must have events disabled, so saving the game adds a false to params
|
||||
var run_events = true
|
||||
if command_params.size() == 2:
|
||||
if command_params[1] in ["true", "false"]:
|
||||
run_events = true if command_params[1] == "true" else false
|
||||
else:
|
||||
current_context["set_position"] = command_params[1]
|
||||
|
||||
# looking for localized string format in scene. this should be somewhere else
|
||||
var sep = command_params[0].find(":\"")
|
||||
if sep >= 0:
|
||||
var path = command_params[0].substr(sep + 2, command_params[0].length() - (sep + 2))
|
||||
escoria.esc_runner.call_deferred("superpose_scene", [path], current_context, run_events)
|
||||
else:
|
||||
escoria.esc_runner.call_deferred("superpose_scene", command_params, current_context, run_events)
|
||||
|
||||
current_context.waiting = true
|
||||
return esctypes.EVENT_LEVEL_STATE.YIELD
|
||||
|
||||
|
||||
"""
|
||||
teleport obj1 obj2 [angle_degrees]
|
||||
Teleports obj1 at obj2's position. If angle_degrees is set (int), sets obj1's
|
||||
angle to angle_degrees.
|
||||
"""
|
||||
func teleport(command_params : Array):
|
||||
if !escoria.esc_runner.check_obj(command_params[0], "teleport"):
|
||||
return esctypes.EVENT_LEVEL_STATE.RETURN
|
||||
if !escoria.esc_runner.check_obj(command_params[1], "teleport"):
|
||||
return esctypes.EVENT_LEVEL_STATE.RETURN
|
||||
|
||||
var angle
|
||||
if command_params.size() > 2:
|
||||
angle = int(command_params[2])
|
||||
|
||||
escoria.esc_runner.get_object(command_params[0]) \
|
||||
.teleport(escoria.esc_runner.get_object(command_params[1]), angle)
|
||||
return esctypes.EVENT_LEVEL_STATE.RETURN
|
||||
|
||||
|
||||
"""
|
||||
teleport obj1 x y [angle_degrees]
|
||||
Teleports obj1 at (x,y). If angle_degrees is set (int), sets obj1's
|
||||
angle to angle_degrees.
|
||||
"""
|
||||
func teleport_pos(command_params : Array):
|
||||
if !escoria.esc_runner.check_obj(command_params[0], "teleport"):
|
||||
return esctypes.EVENT_LEVEL_STATE.RETURN
|
||||
var x = command_params[1]
|
||||
var y = command_params[2]
|
||||
|
||||
var angle
|
||||
if command_params.size() > 2:
|
||||
angle = int(command_params[3])
|
||||
|
||||
escoria.esc_runner.get_object(command_params[0]).teleport(Vector2(x,y), angle)
|
||||
return esctypes.EVENT_LEVEL_STATE.RETURN
|
||||
|
||||
|
||||
"""
|
||||
"""
|
||||
func turn_to(command_params : Array):
|
||||
pass
|
||||
|
||||
|
||||
"""
|
||||
Wait for given time in seconds.
|
||||
Usage: wait time_in_seconds
|
||||
"""
|
||||
func wait(command_params : Array):
|
||||
escoria.current_state = escoria.GAME_STATE.WAIT
|
||||
var time = float(command_params[0])
|
||||
if time <= 0:
|
||||
return esctypes.EVENT_LEVEL_STATE.RETURN
|
||||
# get_tree().call_group_flags(SceneTree.GROUP_CALL_DEFAULT, "game", "wait", time, p_level)
|
||||
escoria.main.wait(command_params, current_context)
|
||||
current_context.waiting = true
|
||||
return esctypes.EVENT_LEVEL_STATE.YIELD
|
||||
|
||||
|
||||
"""
|
||||
walk object_id1 object_id2
|
||||
Make object1 walk towards object2. This command is not blocking (user input not disabled)
|
||||
"""
|
||||
func walk(command_params : Array):
|
||||
current_context.waiting = false
|
||||
escoria.do("walk", command_params)
|
||||
return esctypes.EVENT_LEVEL_STATE.RETURN
|
||||
|
||||
|
||||
"""
|
||||
walk_block object_id1 object_id2
|
||||
Make object1 walk towards object2. This command is blocking (user input disabled)
|
||||
"""
|
||||
func walk_block(command_params : Array):
|
||||
current_context.waiting = true
|
||||
escoria.do("walk", command_params)
|
||||
return esctypes.EVENT_LEVEL_STATE.YIELD
|
||||
|
||||
|
||||
"""
|
||||
walk_to_pos object_id1 pos_x pos_y
|
||||
Make object1 walk towards object2. This command is not blocking (user input not disabled)
|
||||
"""
|
||||
func walk_to_pos(command_params : Array):
|
||||
current_context.waiting = false
|
||||
var destination_pos = Vector2(command_params[1], command_params[2])
|
||||
escoria.do("walk", [command_params[0], destination_pos])
|
||||
return esctypes.EVENT_LEVEL_STATE.RETURN
|
||||
|
||||
"""
|
||||
walk_to_pos_block object_id1 pos_x pos_y
|
||||
Make object1 walk towards object2. This command is blocking (user input disabled)
|
||||
"""
|
||||
func walk_to_pos_block(command_params : Array):
|
||||
current_context.waiting = true
|
||||
var destination_pos = Vector2(command_params[1], command_params[2])
|
||||
escoria.do("walk", [command_params[0], destination_pos])
|
||||
return esctypes.EVENT_LEVEL_STATE.YIELD
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
# A base class for every ESC command.
|
||||
# Extending classes have to override the configure and run function
|
||||
extends Node
|
||||
class_name ESCBaseCommand
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
escoria.logger.error("Command %s did not override configure." % get_class())
|
||||
return ESCCommandArgumentDescriptor.new()
|
||||
|
||||
|
||||
# Validate wether the given arguments match the command descriptor
|
||||
func validate(arguments: Array) -> bool:
|
||||
return self.configure().validate(get_class(), arguments)
|
||||
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
escoria.logger.error("Command %s did not override run." % get_class())
|
||||
return 0
|
||||
124
addons/escoria-core/game/core-scripts/esc/types/esc_command.gd
Normal file
124
addons/escoria-core/game/core-scripts/esc/types/esc_command.gd
Normal file
@@ -0,0 +1,124 @@
|
||||
# An ESC command
|
||||
extends ESCStatement
|
||||
class_name ESCCommand
|
||||
|
||||
|
||||
# Regex matching command lines
|
||||
const REGEX = \
|
||||
'^(\\s*)(?<name>[^\\s]+)(\\s(?<parameters>([^\\[]|$)+))?' +\
|
||||
'(\\[(?<conditions>[^\\]]+)\\])?'
|
||||
|
||||
|
||||
# The name of this command
|
||||
var name: String
|
||||
|
||||
# Parameters of this command
|
||||
var parameters: Array = []
|
||||
|
||||
# A list of ESCConditions to run this command.
|
||||
# Conditions are combined using logical AND
|
||||
var conditions: Array = []
|
||||
|
||||
|
||||
# Create a command from a command string
|
||||
func _init(command_string):
|
||||
var command_regex = RegEx.new()
|
||||
command_regex.compile(REGEX)
|
||||
|
||||
if command_regex.search(command_string):
|
||||
for result in command_regex.search_all(command_string):
|
||||
if "name" in result.names:
|
||||
self.name = escoria.utils.get_re_group(result, "name")
|
||||
if "parameters" in result.names:
|
||||
# Split parameters by whitespace but allow quoted
|
||||
# parameters
|
||||
var quote_open = false
|
||||
var parameter_values = PoolStringArray([])
|
||||
var parsed_parameters = \
|
||||
escoria.utils.sanitize_whitespace(
|
||||
escoria.utils.get_re_group(
|
||||
result,
|
||||
"parameters"
|
||||
).strip_edges()
|
||||
)
|
||||
for parameter in parsed_parameters.split(" "):
|
||||
if parameter.begins_with('"') and parameter.ends_with('"'):
|
||||
parameters.append(
|
||||
parameter.substr(1, parameter.length() - 2)
|
||||
)
|
||||
elif parameter.begins_with('"'):
|
||||
quote_open = true
|
||||
parameter_values.append(parameter.substr(1))
|
||||
elif parameter.ends_with('"'):
|
||||
quote_open = false
|
||||
parameter_values.append(
|
||||
parameter.substr(0, len(parameter) - 1)
|
||||
)
|
||||
parameters.append(parameter_values.join(" "))
|
||||
parameter_values.resize(0)
|
||||
elif quote_open:
|
||||
parameter_values.append(parameter)
|
||||
else:
|
||||
parameters.append(parameter)
|
||||
if "conditions" in result.names:
|
||||
for condition in escoria.utils.get_re_group(
|
||||
result,
|
||||
"conditions"
|
||||
).split(","):
|
||||
self.conditions.append(
|
||||
ESCCondition.new(condition.strip_edges())
|
||||
)
|
||||
else:
|
||||
escoria.logger.report_errors(
|
||||
"Invalid command detected: %s" % command_string,
|
||||
[
|
||||
"Command regexp didn't match"
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
# Check, if conditions match
|
||||
func is_valid() -> bool:
|
||||
var command_found = false
|
||||
for base_path in ProjectSettings.get("escoria/esc/command_directories"):
|
||||
var command_path = "%s/%s.gd" % [
|
||||
base_path,
|
||||
self.name
|
||||
]
|
||||
if ResourceLoader.exists(command_path):
|
||||
command_found = true
|
||||
|
||||
if not command_found:
|
||||
escoria.logger.report_errors(
|
||||
"Invalid command detected: %s" % self.name,
|
||||
[
|
||||
"Command implementation not found in any command directory"
|
||||
]
|
||||
)
|
||||
return false
|
||||
|
||||
return .is_valid()
|
||||
|
||||
|
||||
# Run this command
|
||||
func run() -> int:
|
||||
var command_object = escoria.command_registry.get_command(self.name)
|
||||
if command_object == null:
|
||||
return ESCExecution.RC_ERROR
|
||||
else:
|
||||
var argument_descriptor = command_object.configure()
|
||||
var prepared_arguments = argument_descriptor.prepare_arguments(
|
||||
self.parameters
|
||||
)
|
||||
if argument_descriptor.validate(self.name, prepared_arguments):
|
||||
escoria.logger.debug("Running command %s with parameters %s" % [
|
||||
self.name,
|
||||
prepared_arguments
|
||||
])
|
||||
var rc = command_object.run(prepared_arguments)
|
||||
if rc is GDScriptFunctionState:
|
||||
rc = yield(rc, "completed")
|
||||
escoria.logger.debug("[%s] Return code: %d" % [self.name, rc])
|
||||
return rc
|
||||
else:
|
||||
return ESCExecution.RC_ERROR
|
||||
@@ -0,0 +1,90 @@
|
||||
# The descriptor of the arguments of an ESC command
|
||||
extends Object
|
||||
class_name ESCCommandArgumentDescriptor
|
||||
|
||||
|
||||
# Number of arguments the command expects
|
||||
var min_args: int = 0
|
||||
|
||||
# The types the arguments as TYPE_ constants. If the command is called with
|
||||
# more arguments than there are entries in the types array, the additional
|
||||
# arguments will be checked against the last entry of the types array.
|
||||
var types: Array = []
|
||||
|
||||
# The default values for the arguments
|
||||
var defaults: Array = []
|
||||
|
||||
|
||||
# Initialize the descriptor
|
||||
func _init(p_min_args: int = 0, p_types: Array = [], p_defaults: Array = []):
|
||||
min_args = p_min_args
|
||||
types = p_types
|
||||
defaults = p_defaults
|
||||
|
||||
|
||||
# Combine the default argument values with the given arguments
|
||||
func prepare_arguments(arguments: Array) -> Array:
|
||||
var complete_arguments = defaults
|
||||
|
||||
for index in range(arguments.size()):
|
||||
complete_arguments[index] = escoria.utils.get_typed_value(
|
||||
arguments[index]
|
||||
)
|
||||
|
||||
return complete_arguments
|
||||
|
||||
|
||||
# Validate wether the given arguments match the command descriptor
|
||||
func validate(command: String, arguments: Array) -> bool:
|
||||
if arguments.size() < self.min_args:
|
||||
escoria.logger.report_errors(
|
||||
"Invalid command arguments for command %s" % command,
|
||||
[
|
||||
"Arguments didn't match minimum size %d: %s" %
|
||||
self.min_args,
|
||||
arguments
|
||||
]
|
||||
)
|
||||
|
||||
for index in range(arguments.size()):
|
||||
if arguments[index] == null:
|
||||
# No type checking for null values
|
||||
continue
|
||||
var correct = false
|
||||
var types_index = index
|
||||
if types_index > types.size():
|
||||
types_index = types.size() - 1
|
||||
if not self.types[types_index] is Array:
|
||||
self.types[types_index] = [self.types[index]]
|
||||
for type in self.types[types_index]:
|
||||
if not correct:
|
||||
correct = self._is_type(arguments[index], type)
|
||||
|
||||
if not correct:
|
||||
escoria.logger.report_errors(
|
||||
"Argument type did not match descriptor for command %s" %
|
||||
command,
|
||||
[
|
||||
"Argument %d is of type %d. Expected %s" % [
|
||||
index,
|
||||
typeof(arguments[index]),
|
||||
PoolStringArray(
|
||||
self.types[types_index]
|
||||
).join(",")
|
||||
]
|
||||
]
|
||||
)
|
||||
|
||||
return true
|
||||
|
||||
|
||||
# Check wether the given argument is of the given type
|
||||
#
|
||||
# #### Parameters
|
||||
#
|
||||
# - argument: Argument to test
|
||||
# - type: Type to check
|
||||
# *Returns* Wether the argument is of the given type
|
||||
func _is_type(argument, type: int) -> bool:
|
||||
return typeof(argument) == type
|
||||
|
||||
130
addons/escoria-core/game/core-scripts/esc/types/esc_condition.gd
Normal file
130
addons/escoria-core/game/core-scripts/esc/types/esc_condition.gd
Normal file
@@ -0,0 +1,130 @@
|
||||
# A condition to run a command
|
||||
extends Object
|
||||
class_name ESCCondition
|
||||
|
||||
|
||||
# Valid comparison types
|
||||
enum {COMPARISON_NONE, COMPARISON_EQ, COMPARISON_GT, COMPARISON_LT}
|
||||
|
||||
|
||||
# Regex that matches condition lines
|
||||
const REGEX = \
|
||||
'^(?<is_negated>!)?(?<comparison>eq|gt|lt)? ?' +\
|
||||
'(?<is_inventory>i\/)?(?<flag>[^ ]+)( (?<comparison_value>.+))?$'
|
||||
|
||||
|
||||
const COMPARISON_DESCRIPTION = [
|
||||
"Checking if %s %s %s true%s",
|
||||
"Checking if %s %s %s equals %s",
|
||||
"Checking if %s %s %s greater than %s",
|
||||
"Checking if %s %s %s less than %s"
|
||||
]
|
||||
|
||||
|
||||
# Name of the flag compared
|
||||
var flag: String
|
||||
|
||||
# Wether this condition is negated
|
||||
var negated: bool = false
|
||||
|
||||
# Wether this condition is regarding an inventory item ("i/...")
|
||||
var inventory: bool = false
|
||||
|
||||
# An optional comparison type. Use the COMPARISON-Enum
|
||||
var comparison: int = COMPARISON_NONE
|
||||
|
||||
# The value used together with the comparison type
|
||||
var comparison_value
|
||||
|
||||
|
||||
# Create a new condition from an ESC condition string
|
||||
func _init(comparison_string: String):
|
||||
var comparison_regex = RegEx.new()
|
||||
comparison_regex.compile(
|
||||
REGEX
|
||||
)
|
||||
|
||||
if comparison_regex.search(comparison_string):
|
||||
for result in comparison_regex.search_all(comparison_string):
|
||||
if "is_negated" in result.names:
|
||||
self.negated = true
|
||||
if "comparison" in result.names:
|
||||
match escoria.utils.get_re_group(result, "comparison"):
|
||||
"eq": self.comparison = COMPARISON_EQ
|
||||
"gt": self.comparison = COMPARISON_GT
|
||||
"lt": self.comparison = COMPARISON_LT
|
||||
_: escoria.logger.report_errors(
|
||||
"Invalid comparison type detected: %s" %
|
||||
comparison_string,
|
||||
[
|
||||
"Comparison type %s unknown" %
|
||||
escoria.utils.get_re_group(
|
||||
result,
|
||||
"comparison"
|
||||
)
|
||||
]
|
||||
)
|
||||
if "comparison_value" in result.names:
|
||||
self.comparison_value = escoria.utils.get_typed_value(
|
||||
escoria.utils.get_re_group(
|
||||
result,
|
||||
"comparison_value"
|
||||
)
|
||||
)
|
||||
if "is_inventory" in result.names:
|
||||
self.inventory = true
|
||||
if "flag" in result.names:
|
||||
self.flag = escoria.utils.get_re_group(result, "flag")
|
||||
else:
|
||||
escoria.logger.report_errors(
|
||||
"Invalid comparison detected: %s" % comparison_string,
|
||||
[
|
||||
"Comparison regexp didn't match"
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
# Run this comparison against the globals
|
||||
func run() -> bool:
|
||||
var global_name = self.flag
|
||||
|
||||
escoria.logger.debug(
|
||||
COMPARISON_DESCRIPTION[self.comparison] % [
|
||||
"inventory item" if self.inventory else "global value",
|
||||
self.flag,
|
||||
"is not" if self.negated else "is",
|
||||
"" if self.comparison == COMPARISON_NONE else self.comparison_value
|
||||
]
|
||||
)
|
||||
|
||||
if self.inventory:
|
||||
global_name = "i/%s" % flag
|
||||
|
||||
var return_value = false
|
||||
|
||||
if self.comparison == COMPARISON_NONE and \
|
||||
escoria.globals_manager.has(global_name) and \
|
||||
escoria.globals_manager.get_global(global_name) is bool and \
|
||||
escoria.globals_manager.get_global(global_name):
|
||||
return_value = true
|
||||
elif self.comparison == COMPARISON_EQ and \
|
||||
escoria.globals_manager.get_global(global_name) == \
|
||||
self.comparison_value:
|
||||
return_value = true
|
||||
elif self.comparison == COMPARISON_GT and \
|
||||
escoria.globals_manager.get_global(global_name) > \
|
||||
self.comparison_value:
|
||||
return_value = true
|
||||
elif self.comparison == COMPARISON_LT and \
|
||||
escoria.globals_manager.get_global(global_name) < \
|
||||
self.comparison_value:
|
||||
return_value = true
|
||||
|
||||
if self.negated:
|
||||
return_value = not return_value
|
||||
|
||||
escoria.logger.debug(
|
||||
"It is" if return_value else "It isn't"
|
||||
)
|
||||
|
||||
return return_value
|
||||
@@ -0,0 +1,84 @@
|
||||
# An ESC dialog
|
||||
extends ESCStatement
|
||||
class_name ESCDialog
|
||||
|
||||
|
||||
# Regex that matches dialog lines
|
||||
const REGEX = \
|
||||
'^(\\s*)\\?( (?<type>[^ ]+))?( (?<avatar>[^ ]+))?' +\
|
||||
'( (?<timeout>[^ ]+))?( (?<timeout_option>.+))?$'
|
||||
|
||||
|
||||
# A Regex that matches the end of a dialog
|
||||
const END_REGEX = \
|
||||
'^(?<indent>\\s*)!.*$'
|
||||
|
||||
|
||||
# Dialog type
|
||||
var type: String = ""
|
||||
|
||||
# Avatar used in the dialog
|
||||
var avatar: String = ""
|
||||
|
||||
# Timeout until the timeout_option option is selected. Use 0 for no timeout
|
||||
var timeout: int = 0
|
||||
|
||||
# The dialog option to select when timeout is reached
|
||||
var timeout_option: int = 0
|
||||
|
||||
# A list of ESCDialogOptions
|
||||
var options: Array
|
||||
|
||||
|
||||
# Construct a dialog from a dialog string
|
||||
func _init(dialog_string: String):
|
||||
var dialog_regex = RegEx.new()
|
||||
dialog_regex.compile(REGEX)
|
||||
|
||||
if dialog_regex.search(dialog_string):
|
||||
for result in dialog_regex.search_all(dialog_string):
|
||||
if "type" in result.names:
|
||||
self.type = escoria.utils.get_re_group(result, "type")
|
||||
if "avatar" in result.names:
|
||||
self.avatar = escoria.utils.get_re_group(result, "avatar")
|
||||
if "timeout" in result.names:
|
||||
self.timeout = int(
|
||||
escoria.utils.get_re_group(result, "timeout")
|
||||
)
|
||||
if "timeout_option" in result.names:
|
||||
self.timeout_option = int(
|
||||
escoria.utils.get_re_group(result, "timeout_option")
|
||||
)
|
||||
else:
|
||||
escoria.logger.report_errors(
|
||||
"Invalid dialog detected: %s" % dialog_string,
|
||||
[
|
||||
"Dialog regexp didn't match"
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
# Dialogs have no conditions, just return true
|
||||
func is_valid() -> bool:
|
||||
return true
|
||||
|
||||
|
||||
# Run this dialog
|
||||
func run():
|
||||
escoria.logger.debug("Starting dialog")
|
||||
escoria.current_state = escoria.GAME_STATE.DIALOG
|
||||
if !escoria.dialog_player:
|
||||
escoria.dialog_player = escoria.main.current_scene.get_node(
|
||||
"game/ui/dialog_layer/dialog_player"
|
||||
)
|
||||
escoria.dialog_player.start_dialog_choices(self)
|
||||
var option = yield(
|
||||
escoria.dialog_player,
|
||||
"option_chosen"
|
||||
) as ESCDialogOption
|
||||
var rc = option.run()
|
||||
if rc is GDScriptFunctionState:
|
||||
rc = yield(rc, "completed")
|
||||
if rc != ESCExecution.RC_CANCEL:
|
||||
return self.run()
|
||||
return rc
|
||||
@@ -0,0 +1,49 @@
|
||||
# An option of an ESC dialog
|
||||
extends ESCStatement
|
||||
class_name ESCDialogOption
|
||||
|
||||
|
||||
# Regex that matches dialog option lines
|
||||
const REGEX = \
|
||||
'^[^-]*- "(?<option>[^"]+)"( \\[(?<conditions>[^\\]]+)\\])?$'
|
||||
|
||||
|
||||
# Option displayed in the HUD
|
||||
var option: String
|
||||
|
||||
# Conditions to show this dialog
|
||||
var conditions: Array = []
|
||||
|
||||
|
||||
# Create a dialog option from a string
|
||||
func _init(option_string: String):
|
||||
var option_regex = RegEx.new()
|
||||
option_regex.compile(REGEX)
|
||||
|
||||
if option_regex.search(option_string):
|
||||
for result in option_regex.search_all(option_string):
|
||||
if "option" in result.names:
|
||||
self.option = escoria.utils.get_re_group(result, "option")
|
||||
if "conditions" in result.names:
|
||||
for condition_text in escoria.utils.get_re_group(
|
||||
result,
|
||||
"conditions"
|
||||
).split(","):
|
||||
self.conditions.append(
|
||||
ESCCondition.new(condition_text.strip_edges())
|
||||
)
|
||||
else:
|
||||
escoria.logger.report_errors(
|
||||
"Invalid dialog option detected: %s" % option_string,
|
||||
[
|
||||
"Dialog option regexp didn't match"
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
# Check, if conditions match
|
||||
func is_valid() -> bool:
|
||||
for condition in self.conditions:
|
||||
if not (condition as ESCCondition).run():
|
||||
return false
|
||||
return true
|
||||
93
addons/escoria-core/game/core-scripts/esc/types/esc_event.gd
Normal file
93
addons/escoria-core/game/core-scripts/esc/types/esc_event.gd
Normal file
@@ -0,0 +1,93 @@
|
||||
# An event in the ESC language
|
||||
#
|
||||
# Events are triggered from various sources. Common events include
|
||||
#
|
||||
# * :setup Called every time when visiting a scene
|
||||
# * :ready Called the first time a scene is visited
|
||||
# * :use <global id> Called from the current item when it is used with the item
|
||||
# with the global id <global id>
|
||||
extends ESCStatement
|
||||
class_name ESCEvent
|
||||
|
||||
|
||||
# Regex identifying an ESC event
|
||||
const REGEX = \
|
||||
'^:(?<name>[^|]+)( \\|(?<flags>( ' + \
|
||||
'(TK|NO_TT|NO_HUD|NO_SAVE|CUT_BLACK|LEAVE_BLACK)' + \
|
||||
')+))?$'
|
||||
|
||||
|
||||
# Valid event flags
|
||||
# * TK: stands for "telekinetic". It means the player won't walk over to
|
||||
# the item to say the line.
|
||||
# * 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.
|
||||
# * NO_HUD: stands for "No HUD". It hides the HUD for the duration of the
|
||||
# event. Useful when you want something to look like a cut scene but not
|
||||
# disable input for skipping dialog.
|
||||
# * NO_SAVE: disables saving. Use this in cut scenes and anywhere a
|
||||
# badly-timed autosave would leave your game in a messed-up state.
|
||||
# * CUT_BLACK: applies only to `:setup`. It makes the screen go black
|
||||
# during the setup phase. You will probably see a quick black flash, so use
|
||||
# it only if you prefer it over the standard cut.
|
||||
# * LEAVE_BLACK: applies only to `:setup`. In case your `:ready` starts with
|
||||
# `cut_scene telon fade_in`, you must apply this flag or you will see a
|
||||
# flash of your new scene before going black again for the fade_in.
|
||||
enum {
|
||||
FLAG_TK = 1,
|
||||
FLAG_NO_TT = 2,
|
||||
FLAG_NO_HUD = 4,
|
||||
FLAG_NO_SAVE = 8,
|
||||
FLAG_CUT_BLACK = 16,
|
||||
FLAG_LEAVE_BLACK = 32
|
||||
}
|
||||
|
||||
|
||||
# Name of event
|
||||
var name: String
|
||||
|
||||
# Flags set to this event
|
||||
var flags: int = 0
|
||||
|
||||
|
||||
# Create a new event from an event line
|
||||
func _init(event_string: String):
|
||||
var event_regex = RegEx.new()
|
||||
event_regex.compile(REGEX)
|
||||
|
||||
if event_regex.search(event_string):
|
||||
for result in event_regex.search_all(event_string):
|
||||
if "name" in result.names:
|
||||
self.name = escoria.utils.get_re_group(result, "name") \
|
||||
.strip_edges()
|
||||
if "flags" in result.names:
|
||||
var _flags = escoria.utils.get_re_group(
|
||||
result,
|
||||
"flags"
|
||||
).strip_edges().split(" ")
|
||||
if "TK" in _flags:
|
||||
self.flags |= FLAG_TK
|
||||
if "NO_TT" in _flags:
|
||||
self.flags |= FLAG_NO_TT
|
||||
if "NO_HUD" in _flags:
|
||||
self.flags |= FLAG_NO_HUD
|
||||
if "NO_SAVE" in _flags:
|
||||
self.flags |= FLAG_NO_SAVE
|
||||
if "CUT_BLACK" in _flags:
|
||||
self.flags |= FLAG_CUT_BLACK
|
||||
if "LEAVE_BLACK" in _flags:
|
||||
self.flags |= FLAG_LEAVE_BLACK
|
||||
else:
|
||||
escoria.logger.report_errors(
|
||||
"Invalid event detected: %s" % event_string,
|
||||
[
|
||||
"Event regexp didn't match"
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
# Execute this statement and return its return code
|
||||
func run() -> int:
|
||||
escoria.logger.debug("Starting event %s" % name)
|
||||
return .run()
|
||||
@@ -0,0 +1,11 @@
|
||||
# Basic features and informations about ESC executions
|
||||
extends Object
|
||||
class_name ESCExecution
|
||||
|
||||
|
||||
# Return codes handled by events
|
||||
# * RC_OK: Event run okay
|
||||
# * RC_CANCEL: Cancel all scheduled and queued events
|
||||
# * RC_ERROR: Error running a command
|
||||
# * RC_REPEAT: Repeat the current scope from the beginning
|
||||
enum {RC_OK, RC_CANCEL, RC_ERROR, RC_REPEAT}
|
||||
36
addons/escoria-core/game/core-scripts/esc/types/esc_group.gd
Normal file
36
addons/escoria-core/game/core-scripts/esc/types/esc_group.gd
Normal file
@@ -0,0 +1,36 @@
|
||||
# A group of ESC commands
|
||||
extends ESCStatement
|
||||
class_name ESCGroup
|
||||
|
||||
|
||||
# A RegEx identifying a group
|
||||
const REGEX = '^([^>]*)>\\s*(\\[(?<conditions>[^\\]]+)\\])?$'
|
||||
|
||||
|
||||
# A list of ESCConditions to run this group
|
||||
# Conditions are combined using logical AND
|
||||
var conditions: Array = []
|
||||
|
||||
|
||||
# Construct an ESC group of an ESC script line
|
||||
func _init(group_string: String):
|
||||
var group_regex = RegEx.new()
|
||||
group_regex.compile(REGEX)
|
||||
|
||||
if group_regex.search(group_string):
|
||||
for result in group_regex.search_all(group_string):
|
||||
if "conditions" in result.names:
|
||||
for condition in escoria.utils.get_re_group(
|
||||
result,
|
||||
"conditions"
|
||||
).split(","):
|
||||
self.conditions.append(
|
||||
ESCCondition.new(condition.strip_edges())
|
||||
)
|
||||
else:
|
||||
escoria.logger.report_errors(
|
||||
"Invalid group detected: %s" % group_string,
|
||||
[
|
||||
"Group regexp didn't match"
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,72 @@
|
||||
# An object handled in Escoria
|
||||
extends Node
|
||||
class_name ESCObject
|
||||
|
||||
|
||||
# The global id of the object
|
||||
var global_id: String
|
||||
|
||||
# Wether the object is active (visible to the player)
|
||||
var active: bool = true setget _set_active
|
||||
|
||||
# Wether the object is interactive (clickable by the player)
|
||||
var interactive: bool = true
|
||||
|
||||
# The state of the object. If the object has a respective animation,
|
||||
# it will be played
|
||||
var state: String = "default"
|
||||
|
||||
# The events registered with the object
|
||||
var events: Dictionary = {}
|
||||
|
||||
# The node in the scene. Can be an ESCItem or an ESCCamera
|
||||
var node: Node
|
||||
|
||||
|
||||
func _init(p_global_id: String, p_node: Node):
|
||||
global_id = p_global_id
|
||||
node = p_node
|
||||
|
||||
|
||||
# Set the state and start a possible animation
|
||||
#
|
||||
# #### Parameters
|
||||
#
|
||||
# - p_state: State to set
|
||||
# - immediate: If true, skip directly to the end
|
||||
func set_state(p_state: String, immediate: bool = false):
|
||||
state = p_state
|
||||
|
||||
if node.has_method("get_animation_player"):
|
||||
var animation_node = node.get_animation_player()
|
||||
|
||||
if animation_node:
|
||||
animation_node.stop()
|
||||
var actual_animator
|
||||
if animation_node is AnimationPlayer:
|
||||
if animation_node.has_animation(p_state):
|
||||
if immediate:
|
||||
animation_node.current_animation = p_state
|
||||
animation_node.seek(
|
||||
animation_node.get_animation(p_state).length
|
||||
)
|
||||
else:
|
||||
animation_node.play(p_state)
|
||||
elif animation_node is AnimatedSprite:
|
||||
if animation_node.frames.has_animation(p_state):
|
||||
if immediate:
|
||||
animation_node.animation = p_state
|
||||
animation_node.frame = \
|
||||
animation_node.frames.get_frame_count(p_state)
|
||||
else:
|
||||
animation_node.play(p_state)
|
||||
|
||||
|
||||
# Set the active value, thus hiding or showing the object
|
||||
#
|
||||
# #### Parameters
|
||||
#
|
||||
# - value: Value to set
|
||||
func _set_active(value: bool):
|
||||
active = value
|
||||
self.node.visible = value
|
||||
@@ -0,0 +1,17 @@
|
||||
# An event that is scheduled to run later
|
||||
extends Object
|
||||
class_name ESCScheduledEvent
|
||||
|
||||
|
||||
# Event to run when timeout is reached
|
||||
var event: ESCEvent
|
||||
|
||||
|
||||
# The number of seconds until the event is run
|
||||
var timeout: float
|
||||
|
||||
|
||||
# Create a new scheduled event
|
||||
func _init(p_event: ESCEvent, p_timeout: float):
|
||||
self.event = p_event
|
||||
self.timeout = p_timeout
|
||||
@@ -0,0 +1,7 @@
|
||||
# A compiled ESC script
|
||||
extends Object
|
||||
class_name ESCScript
|
||||
|
||||
|
||||
# A dictionary of ESCEvents in this script
|
||||
var events: Dictionary
|
||||
@@ -0,0 +1,37 @@
|
||||
# A statement in an ESC file
|
||||
extends Object
|
||||
class_name ESCStatement
|
||||
|
||||
|
||||
# Emitted when the event did finish running
|
||||
signal finished(return_code)
|
||||
|
||||
|
||||
# The list of ESC commands
|
||||
var statements: Array = []
|
||||
|
||||
|
||||
# Check wether the statement should be run based on its conditions
|
||||
func is_valid() -> bool:
|
||||
for condition in self.conditions:
|
||||
if not (condition as ESCCondition).run():
|
||||
return false
|
||||
return true
|
||||
|
||||
|
||||
# Execute this statement and return its return code
|
||||
func run() -> int:
|
||||
var final_rc = ESCExecution.RC_OK
|
||||
for statement in statements:
|
||||
if statement.is_valid():
|
||||
var rc = statement.run()
|
||||
if rc is GDScriptFunctionState:
|
||||
rc = yield(rc, "completed")
|
||||
if rc == ESCExecution.RC_REPEAT:
|
||||
return self.run()
|
||||
elif rc != ESCExecution.RC_OK:
|
||||
final_rc = rc
|
||||
break
|
||||
|
||||
emit_signal("finished", final_rc)
|
||||
return final_rc
|
||||
@@ -60,7 +60,6 @@ func _enter_tree():
|
||||
add_child(area)
|
||||
|
||||
func _ready():
|
||||
# escoria.register_object(self)
|
||||
mouse_filter = MOUSE_FILTER_IGNORE
|
||||
area.connect("input_event", self, "manage_input")
|
||||
connect("gui_input", self, "manage_input_texturerect")
|
||||
|
||||
@@ -17,9 +17,6 @@ enum EDITOR_GAME_DEBUG_DISPLAY {
|
||||
export(EDITOR_GAME_DEBUG_DISPLAY) var editor_debug_mode = EDITOR_GAME_DEBUG_DISPLAY.NONE setget set_editor_debug_mode
|
||||
|
||||
|
||||
func _ready():
|
||||
escoria.esc_runner.connect("event_done", self, "_on_event_done")
|
||||
|
||||
|
||||
func set_editor_debug_mode(p_editor_debug_mode : int) -> void:
|
||||
editor_debug_mode = p_editor_debug_mode
|
||||
@@ -104,10 +101,6 @@ func show_ui():
|
||||
pass
|
||||
|
||||
|
||||
## EVENTS
|
||||
func _on_event_done(event_name: String):
|
||||
pass
|
||||
|
||||
|
||||
## FUNCTIONS BELOW THIS POINT DON'T NEED TO BE REIMPLEMENTED BY USER
|
||||
## (Although they can be, if required)
|
||||
|
||||
@@ -2,9 +2,6 @@ tool
|
||||
extends Area2D
|
||||
class_name ESCItem
|
||||
|
||||
func get_class():
|
||||
return "ESCItem"
|
||||
|
||||
"""
|
||||
ESCItem is a Sprite that defines an item, potentially interactive
|
||||
"""
|
||||
@@ -127,7 +124,13 @@ func _ready():
|
||||
|
||||
# Register and connect all elements to Escoria backoffice.
|
||||
if !Engine.is_editor_hint():
|
||||
escoria.register_object(self)
|
||||
escoria.object_manager.register_object(
|
||||
ESCObject.new(
|
||||
global_id,
|
||||
self
|
||||
),
|
||||
true
|
||||
)
|
||||
terrain = escoria.room_terrain
|
||||
|
||||
if !is_trigger:
|
||||
|
||||
@@ -2,16 +2,6 @@ extends Node
|
||||
|
||||
const OBJ_DEFAULT_STATE = "default"
|
||||
|
||||
## Custom nodes:
|
||||
#var ESCBackground = preload("res://addons/escoria-core/game/core-scripts/escbackground.gd")
|
||||
#var ESCItem = preload("res://addons/escoria-core/game/core-scripts/escitem.gd")
|
||||
#var ESCItemsInventory = preload("res://addons/escoria-core/game/core-scripts/items_inventory.gd")
|
||||
#var ESCInventoryItem = preload("res://addons/escoria-core/game/core-scripts/inventory_item.gd")
|
||||
#var ESCPlayer = preload("res://addons/escoria-core/game/core-scripts/escplayer.gd")
|
||||
#var ESCRoom = preload("res://addons/escoria-core/game/core-scripts/escroom.gd")
|
||||
#var ESCTerrain = preload("res://addons/escoria-core/game/core-scripts/escterrain.gd")
|
||||
#var ESCTriggerZone = preload("res://addons/escoria-core/game/core-scripts/esctriggerzone.gd")
|
||||
|
||||
enum EVENT_LEVEL_STATE {
|
||||
RETURN, # 0
|
||||
YIELD, # 1
|
||||
@@ -20,65 +10,3 @@ enum EVENT_LEVEL_STATE {
|
||||
CALL, # 4
|
||||
JUMP # 5
|
||||
}
|
||||
|
||||
|
||||
"""
|
||||
ESCState is a helper class used to read ESC files. Once the ESC file is read and
|
||||
decoded into ESCEvents and ESCCommands, the ESCState instance is removed.
|
||||
"""
|
||||
class ESCState:
|
||||
var file # File or Dictionary
|
||||
var line # String, can be null
|
||||
var indent : int
|
||||
var line_count : int
|
||||
|
||||
func _init(p_file, p_line, p_indent, p_line_count):
|
||||
file = p_file
|
||||
line = p_line
|
||||
indent = p_indent
|
||||
line_count = p_line_count
|
||||
|
||||
func _to_string():
|
||||
return """ESCState: {
|
||||
file: """ + file + """,
|
||||
line: """ + line + """,
|
||||
indent: """ + indent + """,
|
||||
line_count: """ + line_count + """
|
||||
}"""
|
||||
|
||||
|
||||
class ESCEvent:
|
||||
var ev_name : String
|
||||
var ev_level : Array
|
||||
var ev_flags : Array
|
||||
|
||||
func _init(p_name, p_level, p_flags):
|
||||
ev_name = p_name
|
||||
ev_level = p_level
|
||||
ev_flags = p_flags
|
||||
|
||||
func _to_string():
|
||||
return """ESCEvent: {
|
||||
ev_name: """ + ev_name + """,
|
||||
ev_level: """ + String(ev_level) + """,
|
||||
ev_flags: """ + String(ev_flags) + """
|
||||
}"""
|
||||
|
||||
|
||||
class ESCCommand:
|
||||
var name : String
|
||||
var params : Array
|
||||
var conditions : Dictionary
|
||||
var flags : Array
|
||||
|
||||
func _init(p_name):
|
||||
name = p_name
|
||||
params = []
|
||||
|
||||
func _to_string():
|
||||
return """ESCCommand: {
|
||||
name: """ + name + """,
|
||||
params: """ + String(params) + """,
|
||||
conditions: """ + String(conditions) + """,
|
||||
flags: """ + String(flags) + """
|
||||
}"""
|
||||
|
||||
@@ -82,7 +82,7 @@ func _ready():
|
||||
|
||||
# Connect the player to the event_done signal, so we can react to a finished
|
||||
# ":setup" event. In this case, we need to run update_terrain()
|
||||
escoria.esc_runner.connect("event_done", Movable, "update_terrain")
|
||||
escoria.event_manager.connect("event_finished", self, "update_terrain")
|
||||
|
||||
# assert(is_angle_in_interval(0, [340,40])) # true
|
||||
# assert(is_angle_in_interval(359, [340,40])) # true
|
||||
@@ -169,3 +169,5 @@ func set_angle(deg : int, immediate = true):
|
||||
func set_speed(speed_value : int) -> void:
|
||||
speed = speed_value
|
||||
|
||||
func update_terrain(rc: int, event_name: String) -> void:
|
||||
Movable.update_terrain(event_name)
|
||||
|
||||
@@ -39,11 +39,23 @@ func _ready():
|
||||
if player_scene:
|
||||
player = player_scene.instance()
|
||||
add_child(player)
|
||||
escoria.register_object(player)
|
||||
escoria.object_manager.register_object(
|
||||
ESCObject.new(
|
||||
player.global_id,
|
||||
player
|
||||
),
|
||||
true
|
||||
)
|
||||
game.get_node("camera").set_target(player)
|
||||
|
||||
if has_node("player_start"):
|
||||
escoria.register_object($player_start)
|
||||
escoria.object_manager.register_object(
|
||||
ESCObject.new(
|
||||
$player_start.name,
|
||||
$player_start
|
||||
),
|
||||
true
|
||||
)
|
||||
|
||||
if global_id.empty():
|
||||
global_id = name
|
||||
|
||||
@@ -21,7 +21,7 @@ func _ready():
|
||||
current_active_navigation_instance = n
|
||||
|
||||
if !Engine.is_editor_hint():
|
||||
escoria.register_object(self)
|
||||
escoria.room_terrain = self
|
||||
#path = ImagePathFinder.new()
|
||||
_update_texture()
|
||||
|
||||
|
||||
@@ -31,8 +31,9 @@ const ONE_LINE_HEIGHT = 16
|
||||
|
||||
|
||||
func _ready():
|
||||
escoria.call_deferred("register_object", self)
|
||||
escoria.esc_runner.connect("action_changed", self, "on_action_selected")
|
||||
if escoria.main.current_scene:
|
||||
escoria.main.current_scene.game.tooltip_node = self
|
||||
escoria.action_manager.connect("action_changed", self, "on_action_selected")
|
||||
|
||||
|
||||
func set_color(p_color : Color):
|
||||
@@ -62,7 +63,7 @@ func set_debug_mode(p_debug_mode : bool):
|
||||
|
||||
|
||||
func on_action_selected() -> void:
|
||||
current_action = escoria.esc_runner.current_action
|
||||
current_action = escoria.action_manager.current_action
|
||||
update_tooltip_text()
|
||||
|
||||
|
||||
|
||||
@@ -1,32 +1,98 @@
|
||||
# Logging
|
||||
onready var warning_is_reported : bool = false
|
||||
# Logging framework for Escoria
|
||||
extends Object
|
||||
class_name ESCLogger
|
||||
|
||||
|
||||
# The path of the ESC file that was reported last (used for removing
|
||||
# duplicate warnings
|
||||
var warning_path : String
|
||||
|
||||
func warning(string : String, args = []):
|
||||
var argsstr = str(args) if !args.empty() else ""
|
||||
printerr("(W)\t" + string + " \t" + argsstr)
|
||||
|
||||
# Valid log levels
|
||||
enum { LOG_ERROR, LOG_WARNING, LOG_INFO, LOG_DEBUG }
|
||||
|
||||
|
||||
# A map of log level names to log level ints
|
||||
var _level_map: Dictionary = {
|
||||
"ERROR": LOG_ERROR,
|
||||
"WARNING": LOG_WARNING,
|
||||
"INFO": LOG_INFO,
|
||||
"DEBUG": LOG_DEBUG,
|
||||
}
|
||||
|
||||
|
||||
# Log a debug message
|
||||
#
|
||||
# #### Parameters
|
||||
#
|
||||
# * string: Text to log
|
||||
# * args: Additional information
|
||||
func debug(string : String, args = []):
|
||||
if _get_log_level() >= LOG_DEBUG:
|
||||
var argsstr = str(args) if !args.empty() else ""
|
||||
printerr("(D)\t" + string + " \t" + argsstr)
|
||||
|
||||
|
||||
# Log an info message
|
||||
#
|
||||
# #### Parameters
|
||||
#
|
||||
# * string: Text to log
|
||||
# * args: Additional information
|
||||
func info(string : String, args = []):
|
||||
var argsstr = []
|
||||
if !args.empty():
|
||||
for arg in args:
|
||||
if arg is Array:
|
||||
for p in arg:
|
||||
argsstr.append(p.global_id)
|
||||
else:
|
||||
argsstr.append(str(arg))
|
||||
print("(I)\t" + string + " \t" + str(argsstr))
|
||||
|
||||
|
||||
if _get_log_level() >= LOG_INFO:
|
||||
var argsstr = []
|
||||
if !args.empty():
|
||||
for arg in args:
|
||||
if arg is Array:
|
||||
for p in arg:
|
||||
argsstr.append(p.global_id)
|
||||
else:
|
||||
argsstr.append(str(arg))
|
||||
print("(I)\t" + string + " \t" + str(argsstr))
|
||||
|
||||
|
||||
# Log a warning message
|
||||
#
|
||||
# #### Parameters
|
||||
#
|
||||
# * string: Text to log
|
||||
# * args: Additional information
|
||||
func warning(string : String, args = []):
|
||||
if _get_log_level() >= LOG_WARNING:
|
||||
var argsstr = str(args) if !args.empty() else ""
|
||||
printerr("(W)\t" + string + " \t" + argsstr)
|
||||
if ProjectSettings.get_setting("escoria/debug/terminate_on_warnings"):
|
||||
print_stack()
|
||||
assert(false)
|
||||
|
||||
|
||||
# Log an error message
|
||||
#
|
||||
# #### Parameters
|
||||
#
|
||||
# * string: Text to log
|
||||
# * args: Additional information
|
||||
func error(string : String, args = []):
|
||||
var argsstr = str(args) if !args.empty() else ""
|
||||
printerr("(E)\t" + string + " \t" + argsstr)
|
||||
if _get_log_level() >= LOG_ERROR:
|
||||
var argsstr = str(args) if !args.empty() else ""
|
||||
printerr("(E)\t" + string + " \t" + argsstr)
|
||||
if ProjectSettings.get_setting("escoria/debug/terminate_on_errors"):
|
||||
print_stack()
|
||||
assert(false)
|
||||
|
||||
|
||||
# Log a warning message about an ESC file
|
||||
#
|
||||
# #### Parameters
|
||||
#
|
||||
# * p_path: Path to the file
|
||||
# * warnings: Array of warnings to put out
|
||||
# * report_once: Additional messages about the same file will be ignored
|
||||
func report_warnings(p_path : String, warnings : Array, report_once = false) -> void:
|
||||
if p_path != warning_path:
|
||||
warning_is_reported = false
|
||||
var warning_is_reported = false
|
||||
if p_path == warning_path:
|
||||
warning_is_reported = true
|
||||
|
||||
if !warning_is_reported:
|
||||
var text = "Warnings in file "+p_path+"\n"
|
||||
@@ -41,6 +107,12 @@ func report_warnings(p_path : String, warnings : Array, report_once = false) ->
|
||||
warning_is_reported = true
|
||||
|
||||
|
||||
# Log an error message about an ESC file
|
||||
#
|
||||
# #### Parameters
|
||||
#
|
||||
# * p_path: Path to the file
|
||||
# * errors: Array of errors to put out
|
||||
func report_errors(p_path : String, errors : Array) -> void:
|
||||
var text = "Errors in file "+p_path+"\n"
|
||||
for e in errors:
|
||||
@@ -49,8 +121,9 @@ func report_errors(p_path : String, errors : Array) -> void:
|
||||
else:
|
||||
text += e+"\n"
|
||||
error(text)
|
||||
if ProjectSettings.get_setting("escoria/debug/terminate_on_errors"):
|
||||
print_stack()
|
||||
assert(false)
|
||||
# If your game stopped here, you may want to look at the Output tab and
|
||||
# check for the error that caused the game to stop.
|
||||
|
||||
|
||||
# Returns the currently set log level
|
||||
# **Returns** Log level as set in the configuration
|
||||
func _get_log_level() -> int:
|
||||
return _level_map[ProjectSettings.get_setting("escoria/debug/log_level")]
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
# A cache for resources
|
||||
extends Object
|
||||
class_name ResourceCache
|
||||
|
||||
var thread : Thread
|
||||
var mutex : Mutex
|
||||
var sem : Semaphore
|
||||
|
||||
#warning-ignore:unused_class_variable
|
||||
var time_max = 100 # msec
|
||||
|
||||
var queue : Array = []
|
||||
var pending : Dictionary = {}
|
||||
|
||||
@@ -137,6 +138,13 @@ func get_resource(path):
|
||||
return res
|
||||
else:
|
||||
_unlock("return")
|
||||
if not ProjectSettings.get_setting("escoria/platform/skip_cache"):
|
||||
var res = ResourceLoader.load(path)
|
||||
pending[path] = {
|
||||
"res": res,
|
||||
"permanent": true
|
||||
}
|
||||
return res
|
||||
return ResourceLoader.load(path)
|
||||
|
||||
func thread_process():
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
extends Script
|
||||
class_name ESCScript
|
||||
|
||||
func get_class():
|
||||
return "ESCScript"
|
||||
|
||||
func _init():
|
||||
pass
|
||||
@@ -8,3 +8,59 @@ func _get_deg_from_rad(rad_angle : float):
|
||||
deg = 0.0
|
||||
return deg
|
||||
|
||||
|
||||
# Get the content of a reg exp group by name
|
||||
#
|
||||
# #### Parameters
|
||||
#
|
||||
# - re_match: The RegExMatch object
|
||||
# - group: The name of the group
|
||||
# **Returns** The value of the named regex group in the match
|
||||
func get_re_group(re_match: RegExMatch, group: String) -> String:
|
||||
if group in re_match.names:
|
||||
return re_match.strings[re_match.names[group]]
|
||||
else:
|
||||
return ""
|
||||
|
||||
|
||||
# Return a string value in the correct infered type
|
||||
#
|
||||
# #### Parameters
|
||||
#
|
||||
# - value: The original value
|
||||
# **Returns** The typed value according to the type inference
|
||||
func get_typed_value(value: String):
|
||||
var regex_bool = RegEx.new()
|
||||
regex_bool.compile("^true|false$")
|
||||
var regex_float = RegEx.new()
|
||||
regex_float.compile("^[0-9]+\\.[0-9]+$")
|
||||
var regex_int = RegEx.new()
|
||||
regex_int.compile("^[0-9]+$")
|
||||
|
||||
if regex_float.search(value):
|
||||
return float(value)
|
||||
elif regex_int.search(value):
|
||||
return int(value)
|
||||
elif regex_bool.search(value.to_lower()):
|
||||
return true if value.to_lower() == "true" else false
|
||||
else:
|
||||
return str(value)
|
||||
|
||||
|
||||
# Sanitize use of whitespaces in a string. Removes double whitespaces
|
||||
# and converts tabs into space.
|
||||
#
|
||||
# #### Paramters
|
||||
#
|
||||
# - value: String to work on
|
||||
# **Returns** the string with sanitized whitespaces
|
||||
func sanitize_whitespace(value: String) -> String:
|
||||
var tab_regex = RegEx.new()
|
||||
tab_regex.compile("\\t")
|
||||
var double_regex = RegEx.new()
|
||||
double_regex.compile("\\s\\s+")
|
||||
return double_regex.sub(
|
||||
tab_regex.sub(value, " "),
|
||||
" ",
|
||||
true
|
||||
)
|
||||
|
||||
@@ -1,13 +1,36 @@
|
||||
extends Node
|
||||
|
||||
# Scripts
|
||||
onready var esc_compiler = $esc_compiler
|
||||
onready var logger = load("res://addons/escoria-core/game/core-scripts/log/logging.gd").new()
|
||||
onready var main = $main
|
||||
onready var esc_runner = $esc_runner
|
||||
onready var esc_level_runner = $esc_runner/esc_level_runner
|
||||
onready var inputs_manager = $inputs_manager
|
||||
onready var utils = load("res://addons/escoria-core/game/core-scripts/utils/utils.gd").new()
|
||||
onready var save_data = load("res://addons/escoria-core/game/core-scripts/save_data/save_data.gd").new()
|
||||
|
||||
# Logger used
|
||||
var logger: ESCLogger
|
||||
|
||||
# The inventory manager instance
|
||||
var inventory_manager: ESCInventoryManager
|
||||
|
||||
# The action manager instance
|
||||
var action_manager: ESCActionManager
|
||||
|
||||
# ESC compiler instance
|
||||
var esc_compiler: ESCCompiler
|
||||
|
||||
# ESC Event manager instance
|
||||
var event_manager: ESCEventManager
|
||||
|
||||
# ESC globals registry instance
|
||||
var globals_manager: ESCGlobalsManager
|
||||
|
||||
# ESC object manager instance
|
||||
var object_manager: ESCObjectManager
|
||||
|
||||
# ESC command registry instance
|
||||
var command_registry: ESCCommandRegistry
|
||||
|
||||
var resource_cache: ResourceCache
|
||||
|
||||
# INSTANCES
|
||||
var main_menu_instance
|
||||
@@ -57,66 +80,46 @@ var settings_default : Dictionary = {
|
||||
|
||||
|
||||
func _init():
|
||||
logger = load("res://addons/escoria-core/game/core-scripts/log/logging.gd").new()
|
||||
self.logger = ESCLogger.new()
|
||||
self.inventory_manager = ESCInventoryManager.new()
|
||||
self.action_manager = ESCActionManager.new()
|
||||
self.event_manager = ESCEventManager.new()
|
||||
self.globals_manager = ESCGlobalsManager.new()
|
||||
self.add_child(self.event_manager)
|
||||
self.object_manager = ESCObjectManager.new()
|
||||
self.command_registry = ESCCommandRegistry.new()
|
||||
self.esc_compiler = ESCCompiler.new()
|
||||
self.resource_cache = ResourceCache.new()
|
||||
self.resource_cache.start()
|
||||
|
||||
|
||||
func _ready():
|
||||
save_data.start()
|
||||
save_data.check_settings()
|
||||
var settings = save_data.load_settings(null)
|
||||
escoria.settings = parse_json(settings)
|
||||
escoria._on_settings_loaded(escoria.settings)
|
||||
|
||||
|
||||
##################################################################################
|
||||
|
||||
# Called by Main menu "start new game"
|
||||
func new_game():
|
||||
var actions = esc_compiler.load_esc_file(ProjectSettings.get_setting("escoria/main/game_start_script"))
|
||||
$esc_runner.run_game(actions)
|
||||
var script = self.esc_compiler.load_esc_file(
|
||||
ProjectSettings.get_setting("escoria/main/game_start_script")
|
||||
)
|
||||
event_manager.queue_event(script.events["start"])
|
||||
var rc = yield(event_manager, "event_finished")
|
||||
while rc[1] != "start":
|
||||
rc = yield(event_manager, "event_finished")
|
||||
|
||||
escoria.main.scene_transition.fade_in()
|
||||
yield(escoria.main.scene_transition, "transition_done")
|
||||
|
||||
|
||||
|
||||
"""
|
||||
Add object to the environement.
|
||||
"""
|
||||
func register_object(object : Object):
|
||||
var object_id
|
||||
if object.get("global_id"):
|
||||
object_id = object.global_id
|
||||
else:
|
||||
object_id = object.name
|
||||
|
||||
if object is ESCDialogsPlayer:
|
||||
dialog_player = object
|
||||
|
||||
if object is ESCPlayer:
|
||||
$esc_runner.register_object(object_id, object, true)
|
||||
|
||||
if object is Position2D:
|
||||
$esc_runner.register_object(object_id, object, true)
|
||||
if rc[0] != ESCExecution.RC_OK:
|
||||
self.logger.report_errors(
|
||||
"Start event of the start script returned unsuccessful: %d" % rc[0],
|
||||
[]
|
||||
)
|
||||
return
|
||||
|
||||
if object is ESCItem:
|
||||
$esc_runner.register_object(object_id, object, true)
|
||||
|
||||
if object is ESCTerrain:
|
||||
room_terrain = object
|
||||
|
||||
# if object is ESCBackground:
|
||||
# $esc_runner.register_object(object_id, object, true)
|
||||
|
||||
if object is ESCCamera:
|
||||
$esc_runner.register_object(object_id, object, true)
|
||||
|
||||
if object is ESCInventory:
|
||||
inventory = object
|
||||
|
||||
if object is ESCTooltip:
|
||||
if main.current_scene:
|
||||
main.current_scene.game.tooltip_node = object
|
||||
|
||||
if object is ESCBackgroundMusic:
|
||||
$esc_runner.register_object(object_id, object, true)
|
||||
|
||||
if object is ESCBackgroundSound:
|
||||
$esc_runner.register_object(object_id, object, true)
|
||||
|
||||
|
||||
|
||||
|
||||
"""
|
||||
Generic action function that runs an action on an element of the room (eg player walk)
|
||||
@@ -126,16 +129,21 @@ func do(action : String, params : Array = []) -> void:
|
||||
if current_state == GAME_STATE.DEFAULT:
|
||||
match action:
|
||||
"walk":
|
||||
# Reset current action.
|
||||
esc_runner.clear_current_action()
|
||||
self.action_manager.clear_current_action()
|
||||
|
||||
# Check moving object.
|
||||
if !escoria.esc_runner.check_obj(params[0], "escoria.do(walk)"):
|
||||
escoria.logger.report_errors("escoria.gd:do()",
|
||||
["Walk action requested on inexisting object: " + params[0]])
|
||||
if not self.object_manager.has(params[0]):
|
||||
self.logger.report_errors(
|
||||
"escoria.gd:do()",
|
||||
[
|
||||
"Walk action requested on inexisting object: %s "\
|
||||
% params[0]
|
||||
]
|
||||
)
|
||||
return
|
||||
|
||||
var moving_obj = escoria.esc_runner.get_object(params[0])
|
||||
var moving_obj = self.object_manager.get_object(params[0])\
|
||||
.node
|
||||
|
||||
# Walk to Position2D.
|
||||
if params[1] is Vector2:
|
||||
@@ -148,14 +156,19 @@ func do(action : String, params : Array = []) -> void:
|
||||
|
||||
# Walk to object from its id
|
||||
elif params[1] is String:
|
||||
if !escoria.esc_runner.check_obj(params[1], "escoria.do(walk)"):
|
||||
escoria.logger.report_errors("escoria.gd:do()",
|
||||
["Walk action requested TOWARDS inexisting object: " + params[1]])
|
||||
if not self.object_manager.has(params[1]):
|
||||
self.logger.report_errors(
|
||||
"escoria.gd:do()",
|
||||
[
|
||||
"Walk action requested TOWARDS " +\
|
||||
"inexisting object: %s" % params[1]
|
||||
]
|
||||
)
|
||||
return
|
||||
|
||||
var object = escoria.esc_runner.get_object(params[1])
|
||||
var object = self.object_manager.get_object(params[1])
|
||||
if object:
|
||||
var target_position : Vector2 = object.interact_position
|
||||
var target_position : Vector2 = object.node.interact_position
|
||||
var is_fast : bool = false
|
||||
if params.size() > 2 and params[2] == true:
|
||||
is_fast = true
|
||||
@@ -165,31 +178,40 @@ func do(action : String, params : Array = []) -> void:
|
||||
|
||||
"item_left_click":
|
||||
if params[0] is String:
|
||||
escoria.logger.info("escoria.do() : item_left_click on item ", [params[0]])
|
||||
var item = $esc_runner.get_object(params[0])
|
||||
self.logger.info("escoria.do() : item_left_click on item ", [params[0]])
|
||||
var item = self.object_manager.get_object(params[0])
|
||||
ev_left_click_on_item(item, params[1])
|
||||
|
||||
"item_right_click":
|
||||
if params[0] is String:
|
||||
escoria.logger.info("escoria.do() : item_right_click on item ", [params[0]])
|
||||
ev_left_click_on_item($esc_runner.get_object(params[0]), params[1], true)
|
||||
self.logger.info("escoria.do() : item_right_click on item ", [params[0]])
|
||||
var item = self.object_manager.get_object(params[0])
|
||||
ev_left_click_on_item(item, params[1], true)
|
||||
|
||||
"trigger_in":
|
||||
var trigger_id = params[0]
|
||||
var object_id = params[1]
|
||||
var trigger_in_verb = params[2]
|
||||
escoria.logger.info("escoria.do() : trigger_in " + trigger_id + " by " + object_id)
|
||||
esc_runner.run_event(esc_runner.objects_events_table[trigger_id][trigger_in_verb])
|
||||
self.logger.info("escoria.do() : trigger_in " + trigger_id + " by " + object_id)
|
||||
self.event_manager.queue_event(
|
||||
object_manager.get_object(trigger_id).events[
|
||||
trigger_in_verb
|
||||
]
|
||||
)
|
||||
|
||||
"trigger_out":
|
||||
var trigger_id = params[0]
|
||||
var object_id = params[1]
|
||||
var trigger_out_verb = params[2]
|
||||
escoria.logger.info("escoria.do() : trigger_out " + trigger_id + " by " + object_id)
|
||||
esc_runner.run_event(esc_runner.objects_events_table[trigger_id][trigger_out_verb])
|
||||
self.logger.info("escoria.do() : trigger_out " + trigger_id + " by " + object_id)
|
||||
self.event_manager.queue_event(
|
||||
object_manager.get_object(trigger_id).events[
|
||||
trigger_out_verb
|
||||
]
|
||||
)
|
||||
|
||||
_:
|
||||
escoria.logger.report_warnings("escoria.gd:do()",
|
||||
self.logger.report_warnings("escoria.gd:do()",
|
||||
["Action received:", action, "with params ", params])
|
||||
elif current_state == GAME_STATE.WAIT:
|
||||
pass
|
||||
@@ -204,25 +226,29 @@ func ev_left_click_on_item(obj, event, default_action = false):
|
||||
event :
|
||||
"""
|
||||
if obj is String:
|
||||
obj = esc_runner.objects[obj]
|
||||
escoria.logger.info(obj.global_id + " left-clicked with event ", [event])
|
||||
obj = object_manager.get_object(obj)
|
||||
self.logger.info(obj.global_id + " left-clicked with event ", [event])
|
||||
|
||||
var need_combine = false
|
||||
# Check if current_action and current_tool are already set
|
||||
if esc_runner.current_action:
|
||||
if esc_runner.current_tool:
|
||||
if esc_runner.current_action in esc_runner.current_tool.combine_if_action_used_among:
|
||||
if self.action_manager.current_action:
|
||||
if self.action_manager.current_tool:
|
||||
if self.action_manager.current_action in self.action_manager\
|
||||
.current_tool.node.combine_if_action_used_among:
|
||||
need_combine = true
|
||||
else:
|
||||
esc_runner.current_tool = obj
|
||||
self.action_manager.current_tool = obj
|
||||
else:
|
||||
if default_action:
|
||||
if esc_runner.inventory_has(obj.global_id):
|
||||
esc_runner.current_action = obj.default_action_inventory
|
||||
if self.inventory_manager.inventory_has(obj.global_id):
|
||||
self.action_manager.current_action = \
|
||||
obj.node.default_action_inventory
|
||||
else:
|
||||
esc_runner.current_action = obj.default_action
|
||||
elif esc_runner.current_action in obj.combine_if_action_used_among:
|
||||
esc_runner.current_tool = obj
|
||||
self.action_manager.current_action = \
|
||||
obj.node.default_action
|
||||
elif self.action_manager.current_action in \
|
||||
obj.node.combine_if_action_used_among:
|
||||
self.action_manager.current_tool = obj
|
||||
|
||||
|
||||
# Don't interact after player movement towards object (because object is inactive for example)
|
||||
@@ -230,33 +256,33 @@ func ev_left_click_on_item(obj, event, default_action = false):
|
||||
var destination_position : Vector2 = main.current_scene.player.global_position
|
||||
|
||||
# Create walk context
|
||||
var walk_context = {"fast": event.doubleclick, "target_object" : obj}
|
||||
var walk_context = {"fast": event.doubleclick, "target_object" : obj.node}
|
||||
|
||||
# If object not in inventory, player walks towards it
|
||||
if !esc_runner.inventory_has(obj.global_id):
|
||||
if not inventory_manager.inventory_has(obj.global_id):
|
||||
var clicked_object_has_interact_position = false
|
||||
|
||||
if esc_runner.get_interactive(obj.global_id):
|
||||
if object_manager.get_object(obj.global_id).interactive:
|
||||
# if obj.interact_positions.default != null:
|
||||
# destination_position = obj.interact_positions.default#.global_position
|
||||
# clicked_object_has_interact_position = true
|
||||
# else:
|
||||
# destination_position = obj.position
|
||||
if obj.get_interact_position() != null:
|
||||
destination_position = obj.get_interact_position()
|
||||
if obj.node.get_interact_position() != null:
|
||||
destination_position = obj.node.get_interact_position()
|
||||
clicked_object_has_interact_position = true
|
||||
else:
|
||||
destination_position = obj.position
|
||||
destination_position = obj.node.position
|
||||
else:
|
||||
destination_position = event.position
|
||||
dont_interact = true
|
||||
|
||||
# Use esc_runner for this?
|
||||
# Use ESC for this?
|
||||
var is_already_walking = main.current_scene.player.walk_to(destination_position, walk_context)
|
||||
|
||||
# Wait for the player to arrive before continuing with action.
|
||||
var context = yield(main.current_scene.player, "arrived")
|
||||
escoria.logger.info("Context arrived: ", [context])
|
||||
self.logger.info("Context arrived: ", [context])
|
||||
if context.has("target_object") and walk_context.has("target_object"):
|
||||
if (context.target_object.global_id != walk_context.target_object.global_id) \
|
||||
or (context.target_object.global_id == walk_context.target_object.global_id and is_already_walking):
|
||||
@@ -276,24 +302,32 @@ func ev_left_click_on_item(obj, event, default_action = false):
|
||||
# If player has arrived at the position he was supposed to reach so he can interact
|
||||
if player_global_pos == destination_position:
|
||||
# Manage exits
|
||||
if obj.is_exit and $esc_runner.current_action == "" or $esc_runner.current_action == "walk":
|
||||
var params = [obj]
|
||||
$esc_runner.activate("exit_scene", params)
|
||||
|
||||
if obj.node.is_exit and self.action_manager.current_action == "" \
|
||||
or self.action_manager.current_action == "walk":
|
||||
self.action_manager.activate("exit_scene", obj)
|
||||
else:
|
||||
# Manage movements towards object before activating it
|
||||
if $esc_runner.current_action == "" or $esc_runner.current_action == "walk":
|
||||
if self.action_manager.current_action == "" \
|
||||
or self.action_manager.current_action == "walk":
|
||||
if destination_position != clicked_position \
|
||||
and !esc_runner.inventory_has(obj.global_id):
|
||||
esc_runner.activate("arrived", [obj])
|
||||
and not inventory_manager.inventory_has(obj.global_id):
|
||||
self.action_manager.activate("arrived", obj)
|
||||
# Manage action on object
|
||||
elif $esc_runner.current_action != "" and $esc_runner.current_action != "walk":
|
||||
elif self.action_manager.current_action != "" and \
|
||||
self.action_manager.current_action != "walk":
|
||||
# If apply_interact, perform combine between items
|
||||
if need_combine:
|
||||
esc_runner.activate(esc_runner.current_action, [esc_runner.current_tool, obj])
|
||||
self.action_manager.activate(
|
||||
self.action_manager.current_action,
|
||||
self.action_manager.current_tool,
|
||||
obj
|
||||
)
|
||||
|
||||
else:
|
||||
esc_runner.activate(esc_runner.current_action, [obj])
|
||||
self.action_manager.activate(
|
||||
self.action_manager.current_action,
|
||||
obj
|
||||
)
|
||||
|
||||
# else:
|
||||
## escoria.fallback("")
|
||||
|
||||
@@ -1,24 +1,12 @@
|
||||
[gd_scene load_steps=7 format=2]
|
||||
[gd_scene load_steps=4 format=2]
|
||||
|
||||
[ext_resource path="res://addons/escoria-core/game/core-scripts/esc/esc_runner.gd" type="Script" id=1]
|
||||
[ext_resource path="res://addons/escoria-core/game/main.tscn" type="PackedScene" id=2]
|
||||
[ext_resource path="res://addons/escoria-core/game/escoria.gd" type="Script" id=3]
|
||||
[ext_resource path="res://addons/escoria-core/game/core-scripts/esc/esc_runner_level.gd" type="Script" id=4]
|
||||
[ext_resource path="res://addons/escoria-core/game/inputs_manager.gd" type="Script" id=5]
|
||||
[ext_resource path="res://addons/escoria-core/game/core-scripts/esc/esc_compiler.gd" type="Script" id=6]
|
||||
|
||||
[node name="escoria" type="Node"]
|
||||
script = ExtResource( 3 )
|
||||
|
||||
[node name="esc_compiler" type="Node" parent="."]
|
||||
script = ExtResource( 6 )
|
||||
|
||||
[node name="esc_runner" type="Node" parent="."]
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[node name="esc_level_runner" type="Node" parent="esc_runner"]
|
||||
script = ExtResource( 4 )
|
||||
|
||||
[node name="inputs_manager" type="Node" parent="."]
|
||||
script = ExtResource( 5 )
|
||||
|
||||
|
||||
@@ -15,98 +15,36 @@ var screen_ofs = Vector2(0, 0)
|
||||
onready var bg_music = $bg_music
|
||||
onready var scene_transition = $layers/curtain/scene_transition
|
||||
|
||||
func _ready():
|
||||
$layers/wait_timer.connect("timeout", self, "_on_wait_finished")
|
||||
|
||||
func set_scene(p_scene, run_events=true):
|
||||
"""
|
||||
Sets p_scene as current scene
|
||||
If run_events=true, plays the events defined in :setup event
|
||||
"""
|
||||
# Set the new current scene
|
||||
#
|
||||
# #### Parameters
|
||||
#
|
||||
# - p_scene: Current scene to set
|
||||
func set_scene(p_scene: Node):
|
||||
if !p_scene:
|
||||
escoria.logger.report_errors("main", ["Trying to set empty scene"])
|
||||
|
||||
if current_scene != null:
|
||||
clear_scene()
|
||||
|
||||
# get_node("/root").add_child(p_scene)
|
||||
|
||||
add_child(p_scene)
|
||||
|
||||
# Ensure we don't have a regular event running when changing scenes
|
||||
if escoria.esc_runner.running_event:
|
||||
assert(escoria.esc_runner.running_event.ev_name == "load")
|
||||
|
||||
var events : Dictionary = {}
|
||||
if "esc_script" in p_scene and p_scene.esc_script and run_events:
|
||||
events = escoria.esc_compiler.load_esc_file(p_scene.esc_script)
|
||||
|
||||
# # :setup is pretty much required in the code, but fortunately
|
||||
# # we can help out with cases where one isn't necessary otherwise
|
||||
# if not "setup" in events:
|
||||
# var fake_setup = escoria.esc_compiler.compile_str(":setup\n")
|
||||
# events["setup"] = fake_setup["setup"]
|
||||
#
|
||||
# escoria.esc_runner.run_event(events["setup"])
|
||||
# # We need to ensure that :setup event is finished before adding the next event.
|
||||
# var setup_done = false
|
||||
# while !setup_done:
|
||||
# var event_name = yield(escoria.esc_runner, "event_done")
|
||||
# if event_name == "setup":
|
||||
# setup_done = true
|
||||
#
|
||||
# # If scene was never visited, run "ready" event
|
||||
# if !escoria.esc_runner.scenes_cache.has(p_scene.global_id) \
|
||||
# and "ready" in events:
|
||||
# escoria.esc_runner.run_event(events["ready"])
|
||||
#
|
||||
move_child(p_scene, 0)
|
||||
|
||||
set_current_scene(p_scene, run_events)
|
||||
set_camera_limits()
|
||||
return events
|
||||
|
||||
func set_current_scene(p_scene, run_events=true):
|
||||
current_scene = p_scene
|
||||
$"/root".move_child(current_scene, 0)
|
||||
|
||||
# Loading a save game must set the scene but not run events
|
||||
if "events_path" in current_scene and current_scene.events_path and run_events:
|
||||
if escoria.esc_runner.game:
|
||||
# Having a game with `:setup` means we must wait for it to finish
|
||||
if "setup" in escoria.esc_runner.game:
|
||||
if not escoria.esc_runner.running_event:
|
||||
escoria.logger.report_errors("main.gd:set_current_scene()", ["escoria.esc_runner.game has setup but no running_event"])
|
||||
|
||||
if escoria.esc_runner.running_event.ev_name != "setup":
|
||||
escoria.logger.report_errors("main.gd:set_current_scene()", ["escoria.esc_runner.game has setup but it is not running: " + escoria.esc_runner.running_event.ev_name])
|
||||
|
||||
yield(escoria.esc_runner, "event_done")
|
||||
else:
|
||||
escoria.esc_compiler.load_file(current_scene.events_path)
|
||||
# For a new game, we must run `:setup` if available
|
||||
# and wait for it to finish
|
||||
if "setup" in escoria.esc_runner.game:
|
||||
escoria.esc_runner.run_event(escoria.esc_runner.game["setup"])
|
||||
yield(escoria.esc_runner, "event_done")
|
||||
|
||||
if not escoria.esc_runner.running_event:
|
||||
escoria.esc_runner.run_game()
|
||||
|
||||
escoria.esc_runner.register_object("_scene", p_scene, true) # Force overwrite of global
|
||||
|
||||
check_game_scene_methods()
|
||||
|
||||
set_camera_limits()
|
||||
|
||||
|
||||
func clear_scene():
|
||||
if current_scene == null:
|
||||
return
|
||||
|
||||
escoria.esc_runner.clear_current_action()
|
||||
escoria.esc_runner.clear_current_tool()
|
||||
# escoria.esc_runner.hover_clear_stack()
|
||||
# escoria.clear_inventory()
|
||||
escoria.action_manager.clear_current_action()
|
||||
escoria.action_manager.clear_current_tool()
|
||||
|
||||
last_scene_global_id = current_scene.global_id
|
||||
escoria.esc_runner.set_global("ESC_LAST_SCENE", last_scene_global_id, true)
|
||||
get_node("/root").remove_child(current_scene)
|
||||
remove_child(current_scene)
|
||||
current_scene.free()
|
||||
current_scene = null
|
||||
|
||||
@@ -116,9 +54,6 @@ func wait(params : Array, level):
|
||||
$layers/wait_timer.set_one_shot(true)
|
||||
$layers/wait_timer.start()
|
||||
|
||||
func _on_wait_finished():
|
||||
escoria.esc_level_runner.finished(wait_level)
|
||||
|
||||
|
||||
func set_camera_limits(camera_limit_id : int = 0):
|
||||
var limits = {}
|
||||
|
||||
@@ -10,4 +10,3 @@ func _ready():
|
||||
escoria.call_deferred("add_child", main_menu_scene)
|
||||
escoria.main_menu_instance = main_menu_scene
|
||||
|
||||
|
||||
|
||||
@@ -185,5 +185,11 @@ func _ready():
|
||||
target = Vector2(0, 0)
|
||||
|
||||
tween.connect("tween_completed", self, "target_reached")
|
||||
escoria.register_object(self)
|
||||
escoria.object_manager.register_object(
|
||||
ESCObject.new(
|
||||
self.name,
|
||||
self
|
||||
),
|
||||
true
|
||||
)
|
||||
|
||||
|
||||
@@ -1,76 +1,108 @@
|
||||
# Escoria dialog player
|
||||
tool
|
||||
extends ResourcePreloader
|
||||
class_name ESCDialogsPlayer
|
||||
|
||||
func get_class():
|
||||
return "ESCDialogsPlayer"
|
||||
|
||||
# This scene is in charge of ALL dialogs management :
|
||||
# - characters sayings
|
||||
# - player dialog options panel display/hiding and choices
|
||||
# Emitted when an answer as chosem
|
||||
#
|
||||
# ##### Parameters
|
||||
#
|
||||
# - option: The dialog option that was chosen
|
||||
signal option_chosen(option)
|
||||
|
||||
var path_to_dialog_scenes : String
|
||||
# Emitted when a dialog line was finished
|
||||
signal dialog_line_finished
|
||||
|
||||
|
||||
# Wether the player is currently speaking
|
||||
var is_speaking = false
|
||||
var dialog_ui = null
|
||||
var dialog_chooser_ui = null
|
||||
|
||||
# Reference to the dialog UI
|
||||
var _dialog_ui = null
|
||||
|
||||
# Reference to the dialog chooser UI
|
||||
var _dialog_chooser_ui = null
|
||||
|
||||
|
||||
# Register the dialog player and load the dialog resources
|
||||
func _ready():
|
||||
if !Engine.is_editor_hint():
|
||||
escoria.register_object(self)
|
||||
escoria.dialog_player = self
|
||||
preload_resources(ProjectSettings.get_setting("escoria/ui/dialogs_folder"))
|
||||
|
||||
func preload_resources(path : String):
|
||||
path_to_dialog_scenes = path
|
||||
|
||||
# Preload the dialog UI resources
|
||||
#
|
||||
# #### Parameters
|
||||
#
|
||||
# - path: Path where the actual dialog UI resources are located
|
||||
func preload_resources(path: String) -> void:
|
||||
var dialog_folder := Directory.new()
|
||||
if !path_to_dialog_scenes.empty() and dialog_folder.open(path_to_dialog_scenes) == OK:
|
||||
if !path.empty() and dialog_folder.open(path) == OK:
|
||||
dialog_folder.list_dir_begin()
|
||||
var file_name = dialog_folder.get_next()
|
||||
while file_name != "":
|
||||
if !dialog_folder.current_is_dir() and file_name.get_extension() == "tscn":
|
||||
if !dialog_folder.current_is_dir() \
|
||||
and file_name.get_extension() == "tscn":
|
||||
var extension = "." + file_name.get_extension()
|
||||
var basename = file_name.replace(extension, "")
|
||||
|
||||
if !has_resource(basename):
|
||||
var file_path = dialog_folder.get_current_dir() + "/" + file_name
|
||||
var file_path = "%s/%s" % [
|
||||
dialog_folder.get_current_dir(),
|
||||
file_name
|
||||
]
|
||||
var dialog_scene = load(file_path)
|
||||
|
||||
if dialog_scene != null:
|
||||
add_resource(basename, dialog_scene)
|
||||
file_name = dialog_folder.get_next()
|
||||
else:
|
||||
escoria.logger.report_errors("dialog_player.gd:preload_resources()",
|
||||
["An error occurred when trying to access the path: {_}.".format(path)])
|
||||
escoria.logger.report_errors(
|
||||
"dialog_player.gd:preload_resources()",
|
||||
[
|
||||
"An error occurred when trying to access the path: %s." % path
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
func say(character : String, params : Dictionary):
|
||||
# A short one line dialog
|
||||
#
|
||||
# #### Parameters
|
||||
#
|
||||
# - character: Character that is talking
|
||||
# - params: A dictionary of parameters. Currently only "line" is supported and
|
||||
# holds the line the character should say
|
||||
func say(character: String, params: Dictionary) -> void:
|
||||
is_speaking = true
|
||||
dialog_ui = get_resource(params.ui).instance()
|
||||
get_parent().add_child(dialog_ui)
|
||||
dialog_ui.say(character, params)
|
||||
_dialog_ui = get_resource(params.ui).instance()
|
||||
get_parent().add_child(_dialog_ui)
|
||||
_dialog_ui.say(character, params)
|
||||
yield(_dialog_ui, "dialog_line_finished")
|
||||
emit_signal("dialog_line_finished")
|
||||
|
||||
|
||||
func finish_fast():
|
||||
dialog_ui.finish_fast()
|
||||
# Called when a dialog line is skipped
|
||||
func finish_fast() -> void:
|
||||
_dialog_ui.finish_fast()
|
||||
|
||||
# Options:
|
||||
# type: (default value "default") the type of dialog menu to use. All types are in the "dd_player" scene.
|
||||
# avatar: (default value "default") the avatar to use in the dialog ui.
|
||||
# timeout: (default value 0) timeout to select an option. After the time has passed, the "timeout_option" will be selected automatically. If the value is 0, there's no timeout.
|
||||
# timeout_option: (default value 0) option selected when timeout is reached.
|
||||
func start_dialog_choices(answers : Array, options : Array):
|
||||
if answers.empty():
|
||||
escoria.logger.report_errors("dialog_player.gd:start_dialog_choices()", ["Received answers array was empty."])
|
||||
dialog_chooser_ui = get_resource("text_dialog_choice").instance()
|
||||
get_parent().add_child(dialog_chooser_ui)
|
||||
dialog_chooser_ui.set_answers(answers)
|
||||
|
||||
func play_dialog_option_chosen(level_to_run : Array):
|
||||
# escoria.esc_runner.finished(context)
|
||||
var ev_level = level_to_run
|
||||
var ev = esctypes.ESCEvent.new("dialog_choice_done", ev_level, [])
|
||||
escoria.esc_runner.add_level(ev, false)
|
||||
dialog_chooser_ui.hide()
|
||||
# stop()
|
||||
# Display a list of choices
|
||||
func start_dialog_choices(dialog: ESCDialog):
|
||||
if dialog.options.empty():
|
||||
escoria.logger.report_errors(
|
||||
"dialog_player.gd:start_dialog_choices()",
|
||||
["Received answers array was empty."]
|
||||
)
|
||||
_dialog_chooser_ui = get_resource("text_dialog_choice").instance()
|
||||
get_parent().add_child(_dialog_chooser_ui)
|
||||
|
||||
_dialog_chooser_ui.set_answers(dialog.options)
|
||||
|
||||
|
||||
# Called when an option was chosen
|
||||
func play_dialog_option_chosen(option: ESCDialogOption):
|
||||
emit_signal("option_chosen", option)
|
||||
_dialog_chooser_ui.hide()
|
||||
|
||||
|
||||
@@ -18,16 +18,18 @@ func _on_command_text_entered(p_command_str : String):
|
||||
var actual_command = ":debug\n" + p_command_str + "\n"
|
||||
|
||||
var errors = []
|
||||
var events = escoria.esc_compiler.compile_str(actual_command, errors)
|
||||
var script = escoria.esc_compiler.compile([
|
||||
":debug",
|
||||
p_command_str
|
||||
])
|
||||
|
||||
if errors.empty():
|
||||
#past_actions.text += str(events)
|
||||
var ret = escoria.esc_runner.run_event(events["debug"])
|
||||
if ret != null:
|
||||
past_actions.text += str(ret)
|
||||
else:
|
||||
# Display first error only
|
||||
past_actions.text += str(errors[0].split(":")[1].strip_edges())
|
||||
if script:
|
||||
escoria.event_manager.run(script.events["debug"])
|
||||
var ret = yield(escoria.event_manager, "event_finished")
|
||||
while ret[1] != "debug":
|
||||
ret = yield(escoria.event_manager, "event_finished")
|
||||
if not ret[0] == ESCExecution.RC_OK:
|
||||
past_actions.text += "Returned code: %d" % ret[0]
|
||||
|
||||
|
||||
func _on_event_done(event_name : String):
|
||||
|
||||
@@ -25,10 +25,10 @@ func _ready():
|
||||
# if !Engine.is_editor_hint():
|
||||
# return
|
||||
|
||||
for item_id in escoria.esc_runner.items_in_inventory():
|
||||
for item_id in escoria.inventory_manager.items_in_inventory():
|
||||
call_deferred("add_new_item_by_id", item_id)
|
||||
|
||||
escoria.register_object(self)
|
||||
escoria.inventory = self
|
||||
|
||||
if inventory_ui_container == null or inventory_ui_container.is_empty():
|
||||
escoria.logger.report_errors(self.get_path(), ["Items container is empty."])
|
||||
@@ -37,29 +37,44 @@ func _ready():
|
||||
items_ids_in_inventory[c.item_id] = c
|
||||
# c.connect("pressed", escoria.inputs_manager, "_on_inventory_item_pressed", [c.item_id])
|
||||
|
||||
escoria.esc_runner.connect("global_changed", self, "_on_escoria_global_changed")
|
||||
escoria.globals_manager.connect("global_changed", self, "_on_escoria_global_changed")
|
||||
|
||||
|
||||
# add item to Inventory UI using its id set in its scene
|
||||
func add_new_item_by_id(item_id : String) -> void:
|
||||
if item_id.begins_with("i/"):
|
||||
item_id = item_id.rsplit("i/", false)[0]
|
||||
if !items_ids_in_inventory.has(item_id):
|
||||
if !escoria.esc_runner.check_obj(item_id, "add_new_item_by_id"):
|
||||
escoria.logger.report_errors("inventory_ui.gd:add_new_item_by_id()",
|
||||
["Item global id '"+ item_id + "' does not exist.",
|
||||
"Check item's id in ESCORIA_ALL_ITEMS scene."])
|
||||
if !all_items.get_inventory_item(item_id):
|
||||
escoria.logger.report_errors("inventory_ui.gd:add_new_item_by_id()",
|
||||
["Item global id '"+ item_id + "' doesn't have corresponding inventory item.",
|
||||
"Check item's id in ESCORIA_ALL_ITEMS scene."])
|
||||
if not items_ids_in_inventory.has(item_id):
|
||||
if not escoria.object_manager.has(item_id):
|
||||
escoria.logger.report_errors(
|
||||
"inventory_ui.gd:add_new_item_by_id()",
|
||||
[
|
||||
"Item global id '%s' does not exist." % item_id,
|
||||
"Check item's id in ESCORIA_ALL_ITEMS scene."
|
||||
]
|
||||
)
|
||||
if not all_items.get_inventory_item(item_id):
|
||||
escoria.logger.report_errors(
|
||||
"inventory_ui.gd:add_new_item_by_id()",
|
||||
[
|
||||
"Item global id '%s' doesn't have a " +\
|
||||
"corresponding inventory item." % item_id,
|
||||
"Check item's id in ESCORIA_ALL_ITEMS scene."
|
||||
]
|
||||
)
|
||||
var item_inventory_button = all_items.get_inventory_item(item_id).duplicate()
|
||||
items_ids_in_inventory[item_id] = item_inventory_button
|
||||
get_node(inventory_ui_container).add_item(item_inventory_button)
|
||||
|
||||
# Add the item to inventory
|
||||
if !escoria.esc_runner.objects.has(item_id):
|
||||
escoria.esc_runner.register_object(item_id, item_inventory_button)
|
||||
if not escoria.object_manager.has(item_id):
|
||||
escoria.object_manager.register_object(
|
||||
ESCObject.new(
|
||||
item_id,
|
||||
item_inventory_button
|
||||
),
|
||||
true
|
||||
)
|
||||
item_inventory_button.visible = true
|
||||
|
||||
item_inventory_button.connect("mouse_left_inventory_item",
|
||||
@@ -94,17 +109,14 @@ func remove_item_by_id(item_id : String) -> void:
|
||||
item_inventory_button.queue_free()
|
||||
items_ids_in_inventory.erase(item_id)
|
||||
|
||||
func _on_escoria_global_changed(global : String) -> void:
|
||||
func _on_escoria_global_changed(global : String, old_value, new_value) -> void:
|
||||
if !global.begins_with("i/"):
|
||||
return
|
||||
var item = global.rsplit("i/", false)
|
||||
if item.size() == 1:
|
||||
if escoria.esc_runner.globals[global] == "true":
|
||||
if new_value:
|
||||
add_new_item_by_id(item[0])
|
||||
elif escoria.esc_runner.globals[global] == "false":
|
||||
remove_item_by_id(item[0])
|
||||
else:
|
||||
escoria.logger.report_warnings("inventory_ui.gd:_on_escoria_global_changed()", \
|
||||
["Inventory global " + global + " is neither 'true' nor 'false' (was " + escoria.esc_runner.globals[global] + "). "])
|
||||
remove_item_by_id(item[0])
|
||||
else:
|
||||
escoria.logger.report_errors("inventory_ui.gd:_on_escoria_global_changed()", ["Global must contain 1 item name.", "(received: " + global + ")"])
|
||||
|
||||
@@ -11,8 +11,10 @@ export var global_id = "bg_music"
|
||||
|
||||
func game_cleared():
|
||||
set_state("off", true)
|
||||
self.disconnect("tree_exited", escoria.esc_runner, "object_exit_scene")
|
||||
escoria.register_object(self)
|
||||
escoria.object_manager.register_object(
|
||||
ESCObject.new(global_id, self),
|
||||
true
|
||||
)
|
||||
|
||||
|
||||
func set_state(p_state, p_force = false):
|
||||
@@ -38,5 +40,8 @@ func set_state(p_state, p_force = false):
|
||||
stream.play()
|
||||
|
||||
func _ready():
|
||||
escoria.register_object(self)
|
||||
escoria.object_manager.register_object(
|
||||
ESCObject.new(global_id, self),
|
||||
true
|
||||
)
|
||||
|
||||
|
||||
@@ -11,7 +11,10 @@ export var global_id = "bg_sound"
|
||||
|
||||
func game_cleared():
|
||||
stream.stream = null
|
||||
escoria.register_object(self)
|
||||
escoria.object_manager.register_object(
|
||||
ESCObject.new(global_id, self),
|
||||
true
|
||||
)
|
||||
|
||||
|
||||
func set_state(p_state, p_force = false):
|
||||
@@ -38,4 +41,7 @@ func set_state(p_state, p_force = false):
|
||||
|
||||
|
||||
func _ready():
|
||||
escoria.register_object(self)
|
||||
escoria.object_manager.register_object(
|
||||
ESCObject.new(global_id, self),
|
||||
true
|
||||
)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
tool
|
||||
extends PanelContainer
|
||||
|
||||
signal dialog_line_started
|
||||
signal dialog_line_finished
|
||||
|
||||
export(String) var current_character setget set_current_character
|
||||
@@ -40,6 +41,7 @@ params: Dictionary
|
||||
"""
|
||||
func say(character : String, params : Dictionary) :
|
||||
show()
|
||||
emit_signal("dialog_line_started")
|
||||
set_current_character(character)
|
||||
|
||||
if !params["line"]:
|
||||
@@ -70,10 +72,8 @@ func _on_dialog_line_typed(object, key):
|
||||
$Timer.connect("timeout", self, "_on_dialog_finished")
|
||||
|
||||
func _on_dialog_finished():
|
||||
escoria.esc_level_runner.finished()
|
||||
escoria.dialog_player.is_speaking = false
|
||||
escoria.current_state = escoria.GAME_STATE.DEFAULT
|
||||
# emit_signal("dialog_line_finished")
|
||||
emit_signal("dialog_line_finished")
|
||||
queue_free()
|
||||
|
||||
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
extends Control
|
||||
|
||||
func _ready():
|
||||
pass
|
||||
|
||||
|
||||
func set_answers(answers_array : PoolStringArray):
|
||||
|
||||
func _on_answer1_gui_input(event):
|
||||
pass # Replace with function body.
|
||||
@@ -12,12 +12,11 @@ func _ready():
|
||||
c.queue_free()
|
||||
|
||||
|
||||
func set_answers(p_commands : Array):
|
||||
commands = p_commands
|
||||
var c = 0
|
||||
func set_answers(options : Array):
|
||||
commands = options
|
||||
for option in commands:
|
||||
var new_answer_label = RichTextLabel.new()
|
||||
new_answer_label.text = option.params[0]
|
||||
new_answer_label.text = option.option
|
||||
new_answer_label.fit_content_height = true
|
||||
new_answer_label.add_font_override("normal_font", font)
|
||||
|
||||
@@ -27,13 +26,10 @@ func set_answers(p_commands : Array):
|
||||
new_answer_label.connect("focus_exited", self, "_on_answer_focus_exited", [new_answer_label]) # Focus exited
|
||||
new_answer_label.connect("mouse_entered", self, "_on_answer_mouse_entered", [new_answer_label]) # Mouse entered
|
||||
new_answer_label.connect("mouse_exited", self, "_on_answer_mouse_exited", [new_answer_label]) # Mouse exited
|
||||
new_answer_label.connect("gui_input", self, "_on_answer_gui_input", [c]) # Clicks
|
||||
c += 1
|
||||
new_answer_label.connect("gui_input", self, "_on_answer_gui_input", [option]) # Clicks
|
||||
|
||||
func _on_answer_gui_input(event : InputEvent, answer_id : int):
|
||||
func _on_answer_gui_input(event : InputEvent, answer : ESCDialogOption):
|
||||
if event is InputEventMouseButton and event.is_pressed():
|
||||
var answer = commands[answer_id].params[1]
|
||||
printt(answer)
|
||||
escoria.dialog_player.play_dialog_option_chosen(answer)
|
||||
|
||||
func _on_answer_mouse_entered(answer_node : Node):
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
extends RichTextLabel
|
||||
|
||||
#signal dialog_line_started
|
||||
#signal dialog_line_finished
|
||||
signal dialog_line_started
|
||||
signal dialog_line_finished
|
||||
|
||||
onready var tween = $Tween
|
||||
onready var text_node = self
|
||||
@@ -28,12 +28,14 @@ params: Dictionary
|
||||
func say(character : String, params : Dictionary) :
|
||||
show()
|
||||
|
||||
emit_signal("dialog_line_started")
|
||||
|
||||
if !params["line"]:
|
||||
escoria.logger.report_errors("dialog_box_inset.gd:say()", ["No line field in params!"])
|
||||
return
|
||||
|
||||
# Position the RichTextLabel on the character's dialog position, if any.
|
||||
current_character = escoria.esc_runner.get_object(character)
|
||||
current_character = escoria.object_manager.get_object(character).node
|
||||
rect_position = current_character.get_node("dialog_position").get_global_transform_with_canvas().origin
|
||||
rect_position.x -= rect_size.x / 2
|
||||
|
||||
@@ -73,7 +75,7 @@ func _on_dialog_line_typed(object, key):
|
||||
|
||||
func _on_dialog_finished():
|
||||
current_character.stop_talking()
|
||||
escoria.esc_level_runner.finished()
|
||||
emit_signal("dialog_line_finished")
|
||||
escoria.dialog_player.is_speaking = false
|
||||
escoria.current_state = escoria.GAME_STATE.DEFAULT
|
||||
queue_free()
|
||||
|
||||
@@ -3,7 +3,7 @@ say player "It's a bottle."
|
||||
stop
|
||||
|
||||
:pickup
|
||||
inventory_add r9_bottle true
|
||||
inventory_add r9_bottle
|
||||
set_active r9_bottle_left false
|
||||
set_active r9_bottle_middle false
|
||||
set_active r9_bottle_right false
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
# Set player look left
|
||||
set_angle player 270
|
||||
stop
|
||||
> [!last_scene]
|
||||
> [!eq ESC_LAST_SCENE room2]
|
||||
teleport player player_start
|
||||
stop
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
:look
|
||||
> [! dialog_advance]
|
||||
say player ROOM1_look_wall_item_1:"I don't know what that stuff is."
|
||||
say player "I don't know what that stuff is."
|
||||
set_global dialog_advance 1
|
||||
stop
|
||||
> [eq dialog_advance 1]
|
||||
say player ROOM1_look_wall_item_2:"I REALLY don't know what that stuff is."
|
||||
say player "I REALLY don't know what that stuff is."
|
||||
set_global dialog_advance 2
|
||||
stop
|
||||
> [eq dialog_advance 2]
|
||||
say player ROOM1_look_wall_item_3:"No, SERIOUSLY, I have no idea what that is!"
|
||||
say player ROOM1_look_wall_item_4:"Please stop asking me that!"
|
||||
say player "No, SERIOUSLY, I have no idea what that is!"
|
||||
say player "Please stop asking me that!"
|
||||
stop
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user