Event flags implementation (#382)

* Added event flags
* Added transition ESC command
* Also edited .gitignore to ignore .translation files
* docs: Automatic update of API docs

Co-authored-by: StraToN <StraToN@users.noreply.github.com>
This commit is contained in:
Julian Murgia
2021-09-07 09:13:09 +02:00
committed by GitHub
parent 903422960a
commit b4bf5b82d6
51 changed files with 1071 additions and 305 deletions

View File

@@ -173,7 +173,6 @@ func _test_event_flags() -> bool:
: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"))
@@ -200,12 +199,6 @@ func _test_event_flags() -> bool:
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

View File

@@ -1,8 +1,12 @@
# `change_scene path run_events`
# `change_scene path [disable_automatic_transition] [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.
# Loads a new scene, specified by "path".
# The `disable_automatic_transition` is a boolean (default false) can be set
# to true to disable automatic transitions between scenes, to allow you
# to control your transitions manually using the `transition` command.
# 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
@@ -13,8 +17,8 @@ class_name ChangeSceneCommand
func configure() -> ESCCommandArgumentDescriptor:
return ESCCommandArgumentDescriptor.new(
1,
[TYPE_STRING, TYPE_BOOL],
[null, true]
[TYPE_STRING, TYPE_BOOL, TYPE_BOOL],
[null, false, true]
)
@@ -42,9 +46,11 @@ func validate(arguments: Array) -> bool:
# 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]
escoria.logger.info(
"Changing scene to %s (disable_automatic_transition = %s, run_events = %s)" % [
command_params[0],
command_params[1],
command_params[2]
])
if escoria.main.current_scene:
@@ -53,9 +59,10 @@ func run(command_params: Array) -> int:
escoria.main.current_scene.global_id,
true
)
escoria.main.scene_transition.fade_out()
yield(escoria.main.scene_transition, "transition_done")
if !command_params[1]:
escoria.main.scene_transition.transition_out()
yield(escoria.main.scene_transition, "transition_done")
escoria.inputs_manager.clear_stack()
@@ -85,7 +92,7 @@ func run(command_params: Array) -> int:
escoria.main.set_scene(room_scene)
if "esc_script" in room_scene and room_scene.esc_script \
and command_params[1]:
and command_params[2]:
var script = escoria.esc_compiler.load_esc_file(
room_scene.esc_script
@@ -99,8 +106,9 @@ func run(command_params: Array) -> int:
if rc[0] != ESCExecution.RC_OK:
return rc[0]
escoria.main.scene_transition.fade_in()
yield(escoria.main.scene_transition, "transition_done")
if !command_params[1]:
escoria.main.scene_transition.transition_in()
yield(escoria.main.scene_transition, "transition_done")
if script.events.has("ready"):
escoria.event_manager.queue_event(script.events["ready"])
@@ -110,6 +118,11 @@ func run(command_params: Array) -> int:
if rc[0] != ESCExecution.RC_OK:
return rc[0]
else:
if !command_params[1]:
escoria.main.scene_transition.transition_in()
yield(escoria.main.scene_transition, "transition_done")
# Clear queued resources
escoria.resource_cache.clear()

View File

@@ -0,0 +1,45 @@
# `transition transition_name in|out`
#
# Performs a transition in our out manually.
#
# @ESC
extends ESCBaseCommand
class_name TransitionCommand
# 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.main.scene_transition.has_transition(arguments[0]):
escoria.logger.report_errors(
"transition: argument invalid",
[
"transition with name '%s' doesn't exist" % arguments[0]
]
)
return false
if not arguments[1] in ["in", "out"]:
escoria.logger.report_errors(
"transition: argument invalid",
[
"'in' or 'out' expected, but got '%s'" % arguments[1]
]
)
return false
return .validate(arguments)
# Run the command
func run(command_params: Array) -> int:
var transition_player = escoria.main.scene_transition
transition_player.call("transition_%s" % command_params[1], command_params[0])
var animation_finished = yield(transition_player, "transition_done")
return ESCExecution.RC_OK

View File

@@ -12,8 +12,8 @@ class_name ESCEvent
# Regex identifying an ESC event
const REGEX = \
'^:(?<name>[^|]+)( \\|(?<flags>( ' + \
'(TK|NO_TT|NO_HUD|NO_SAVE|CUT_BLACK|LEAVE_BLACK)' + \
'^:(?<name>[^|]+)( \\|\\s*(?<flags>( ' + \
'(TK|NO_TT|NO_HUD|NO_SAVE)' + \
')+))?$'
@@ -28,19 +28,11 @@ const REGEX = \
# 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
FLAG_NO_SAVE = 8
}
@@ -74,10 +66,6 @@ func _init(event_string: String):
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,

View File

@@ -96,6 +96,12 @@ func perform_inputevent_on_object(
escoria.logger.info("%s left-clicked with event " % obj.global_id, [event])
var event_flags = 0
var has_current_action: bool = false
if obj.events.has(escoria.action_manager.current_action):
event_flags = obj.events[escoria.action_manager.current_action].flags
has_current_action = true
# Don't interact after player movement towards object
# (because object is inactive for example)
var dont_interact = false
@@ -105,20 +111,21 @@ func perform_inputevent_on_object(
# If clicked object not in inventory, player walks towards it
if not obj.node is ESCPlayer and \
not escoria.inventory_manager.inventory_has(obj.global_id):
var context = _walk_towards_object(
obj,
event.position,
event.doubleclick
)
if context is GDScriptFunctionState:
context = yield(_walk_towards_object(
not escoria.inventory_manager.inventory_has(obj.global_id) and \
(not has_current_action or not event_flags & ESCEvent.FLAG_TK):
var context = _walk_towards_object(
obj,
event.position,
event.doubleclick
), "completed")
destination_position = context.target_position
dont_interact = context.dont_interact_on_arrival
)
if context is GDScriptFunctionState:
context = yield(_walk_towards_object(
obj,
event.position,
event.doubleclick
), "completed")
destination_position = context.target_position
dont_interact = context.dont_interact_on_arrival
# If no interaction should happen after player has arrived, leave
# immediately.
@@ -131,6 +138,50 @@ func perform_inputevent_on_object(
# If player has arrived at the position he was supposed to reach
# so he can interact
if player_global_pos == destination_position:
# If NO_TT flag is active, hide tooltip and connect for
# event finished to show it back
if event_flags & ESCEvent.FLAG_NO_TT \
and not escoria.event_manager.is_connected(
"event_finished",
self,
"_on_no_tooltip_event_finished"
):
escoria.main.current_scene.game.tooltip_node.hide()
escoria.event_manager.connect(
"event_finished",
self,
"_on_no_tooltip_event_finished"
)
if event_flags & ESCEvent.FLAG_NO_HUD and \
not escoria.event_manager.is_connected(
"event_finished",
self,
"_on_no_hud_event_finished"
):
escoria.main.current_scene.game.hide_ui()
escoria.event_manager.connect(
"event_finished",
self,
"_on_no_hud_event_finished"
)
if event_flags & ESCEvent.FLAG_NO_SAVE and \
not escoria.event_manager.is_connected(
"event_finished",
self,
"_on_no_save_event_finished"
):
escoria.save_manager.save_enabled = false
escoria.event_manager.connect(
"event_finished",
self,
"_on_no_save_event_finished"
)
pass
# Manage exits
if obj.node.is_exit and escoria.action_manager.current_action \
in ["", "walk"]:
@@ -246,3 +297,63 @@ func _walk_towards_object(
walk_context.dont_interact_on_arrival = true
return context
# Called when an event having "NO_TT" flag is finished.
#
# ## Parameters
#
# - _return_code: The ESCExecution return code sent by the events manager.
# - _event_name: the name of the event
func _on_no_tooltip_event_finished(_return_code: int, _event_name: String):
escoria.main.current_scene.game.tooltip_node.show()
if escoria.event_manager.is_connected(
"event_finished",
self,
"_on_no_tooltip_event_finished"
):
escoria.event_manager.disconnect(
"event_finished",
self,
"_on_no_tooltip_event_finished"
)
# Called when an event having "NO_HUD" flag is finished.
#
# ## Parameters
#
# - _return_code: The ESCExecution return code sent by the events manager.
# - _event_name: the name of the event
func _on_no_hud_event_finished(_return_code: int, _event_name: String):
escoria.main.current_scene.game.show_ui()
if escoria.event_manager.is_connected(
"event_finished",
self,
"_on_no_hud_event_finished"
):
escoria.event_manager.disconnect(
"event_finished",
self,
"_on_no_hud_event_finished"
)
# Called when an event having "NO_SAVE" flag is finished.
#
# ## Parameters
#
# - _return_code: The ESCExecution return code sent by the events manager.
# - _event_name: the name of the event
func _on_no_save_event_finished(_return_code: int, _event_name: String):
escoria.save_manager.save_enabled = true
if escoria.event_manager.is_connected(
"event_finished",
self,
"_on_no_save_event_finished"
):
escoria.event_manager.disconnect(
"event_finished",
self,
"_on_no_save_event_finished"
)

View File

@@ -1,6 +1,9 @@
# Saves and loads savegame and settings files
class_name ESCSaveManager
# If true, saving a game is enabled. Else, saving is disabled
var save_enabled: bool = true
# Variable containing the saves folder obtained from Project Settings
var save_folder: String
@@ -65,6 +68,12 @@ func save_game_exists(id: int) -> bool:
# - id: integer suffix of the savegame file
# - p_savename: name of the savegame
func save_game(id: int, p_savename: String):
if not save_enabled:
escoria.logger.debug(
"esc_save_data_resources.gd",
["Save requested while saving is not possible. Save canceled."])
return
var save_game := ESCSaveGame.new()
save_game.escoria_version = escoria.ESCORIA_VERSION
save_game.game_version = ProjectSettings.get_setting(

View File

@@ -1,40 +1,68 @@
# A transition player for scene changes
extends ColorRect
# Emitted when the transition was played
signal transition_done
# The name of the transition to play
# The name of the default transition to play
export(
String,
"fade_black",
"fade_white",
"transition_in",
"transition_out"
"curtain"
) var transition_name: String
# Reference to the _AnimationPlayer_ node
onready var _anim_player := $AnimationPlayer
# Fade in when the scene is starting
func _ready() -> void:
fade_in()
transition_in()
# Fade out the transition
func fade_out() -> void:
_anim_player.play(transition_name)
# Transition out
#
# ## Parameters
#
# - p_transition_name: name of the transition to play (if empty string, uses
# the default transition)
func transition_out(p_transition_name: String = "") -> void:
if p_transition_name.empty():
_anim_player.play(transition_name)
else:
_anim_player.play(p_transition_name)
yield(_anim_player, "animation_finished")
emit_signal("transition_done")
_anim_player.seek(0.0)
# Fade in the transition
func fade_in() -> void:
# Plays the Fade animation and wait until it finishes
_anim_player.play_backwards(transition_name)
# Transition in
#
# ## Parameters
#
# - p_transition_name: name of the transition to play (if empty string, uses
# the default transition)
func transition_in(p_transition_name: String = "") -> void:
if p_transition_name.empty():
_anim_player.play_backwards(transition_name)
else:
_anim_player.play_backwards(p_transition_name)
yield(_anim_player, "animation_finished")
emit_signal("transition_done")
_anim_player.seek(0.0)
# Returns true whether the transition scene has a transition corresponding
# to name provided.
#
# ## Parameters
#
# - p_name: The name of the transition to test
#
# *Returns* true if a transition exists with given name.
func has_transition(p_name: String) -> bool:
return _anim_player.has_animation(p_name)

View File

@@ -1,8 +1,47 @@
[gd_scene load_steps=7 format=2]
[gd_scene load_steps=6 format=2]
[ext_resource path="res://addons/escoria-core/game/scenes/transitions/transition.gd" type="Script" id=1]
[ext_resource path="res://addons/escoria-core/game/scenes/transitions/shaders/transition.material" type="Material" id=2]
[sub_resource type="Animation" id=3]
resource_name = "curtain"
tracks/0/type = "value"
tracks/0/path = NodePath(".:material:shader_param/cutoff")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/keys = {
"times": PoolRealArray( 0, 1 ),
"transitions": PoolRealArray( 1, 1 ),
"update": 0,
"values": [ 0.0, 1.0 ]
}
tracks/1/type = "value"
tracks/1/path = NodePath(".:material:shader_param/color")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/keys = {
"times": PoolRealArray( 0 ),
"transitions": PoolRealArray( 1 ),
"update": 0,
"values": [ Color( 0, 0, 0, 1 ) ]
}
tracks/2/type = "value"
tracks/2/path = NodePath(".:modulate")
tracks/2/interp = 1
tracks/2/loop_wrap = true
tracks/2/imported = false
tracks/2/enabled = true
tracks/2/keys = {
"times": PoolRealArray( 0 ),
"transitions": PoolRealArray( 1 ),
"update": 0,
"values": [ Color( 1, 1, 1, 1 ) ]
}
[sub_resource type="Animation" id=1]
resource_name = "fade_black"
length = 0.5
@@ -18,6 +57,30 @@ tracks/0/keys = {
"update": 0,
"values": [ Color( 0, 0, 0, 0 ), Color( 0, 0, 0, 1 ) ]
}
tracks/1/type = "value"
tracks/1/path = NodePath(".:material:shader_param/cutoff")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/keys = {
"times": PoolRealArray( 0 ),
"transitions": PoolRealArray( 1 ),
"update": 0,
"values": [ 0.0 ]
}
tracks/2/type = "value"
tracks/2/path = NodePath(".:material:shader_param/color")
tracks/2/interp = 1
tracks/2/loop_wrap = true
tracks/2/imported = false
tracks/2/enabled = true
tracks/2/keys = {
"times": PoolRealArray( 0 ),
"transitions": PoolRealArray( 1 ),
"update": 0,
"values": [ Color( 0, 0, 0, 1 ) ]
}
[sub_resource type="Animation" id=2]
resource_name = "fade_white"
@@ -34,38 +97,33 @@ tracks/0/keys = {
"update": 0,
"values": [ Color( 1, 1, 1, 0 ), Color( 1, 1, 1, 1 ) ]
}
[sub_resource type="Animation" id=3]
resource_name = "transition_in"
tracks/0/type = "value"
tracks/0/path = NodePath(".:material:shader_param/cutoff")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/keys = {
"times": PoolRealArray( 0, 1 ),
"transitions": PoolRealArray( 1, 1 ),
tracks/1/type = "value"
tracks/1/path = NodePath(".:material:shader_param/cutoff")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/keys = {
"times": PoolRealArray( 0 ),
"transitions": PoolRealArray( 1 ),
"update": 0,
"values": [ 0.0, 1.0 ]
"values": [ 0.0 ]
}
[sub_resource type="Animation" id=4]
resource_name = "transition_out"
tracks/0/type = "value"
tracks/0/path = NodePath(".:material:shader_param/cutoff")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/keys = {
"times": PoolRealArray( 0, 1 ),
"transitions": PoolRealArray( 1, 1 ),
tracks/2/type = "value"
tracks/2/path = NodePath(".:material:shader_param/color")
tracks/2/interp = 1
tracks/2/loop_wrap = true
tracks/2/imported = false
tracks/2/enabled = true
tracks/2/keys = {
"times": PoolRealArray( 0 ),
"transitions": PoolRealArray( 1 ),
"update": 0,
"values": [ 1.0, 0.0 ]
"values": [ Color( 1, 1, 1, 1 ) ]
}
[node name="scene_transition" type="ColorRect"]
modulate = Color( 0, 0, 0, 0 )
material = ExtResource( 2 )
anchor_right = 1.0
anchor_bottom = 1.0
@@ -74,10 +132,9 @@ script = ExtResource( 1 )
__meta__ = {
"_edit_use_anchors_": false
}
transition_name = "transition_out"
transition_name = "curtain"
[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
anims/curtain = SubResource( 3 )
anims/fade_black = SubResource( 1 )
anims/fade_white = SubResource( 2 )
anims/transition_in = SubResource( 3 )
anims/transition_out = SubResource( 4 )

View File

@@ -178,6 +178,7 @@ func pause_game():
escoria.main.current_scene.show()
escoria.set_game_paused(false)
else:
$ui/pause_menu.set_save_enabled(escoria.save_manager.save_enabled)
$ui/pause_menu.show()
escoria.main.current_scene.game.get_node("camera").current = false
escoria.main.current_scene.game.hide_ui()

View File

@@ -159,6 +159,7 @@ func pause_game():
escoria.main.current_scene.game.show_ui()
escoria.main.current_scene.show()
else:
$ui/pause_menu.set_save_enabled(escoria.save_manager.save_enabled)
$ui/pause_menu.show()
escoria.main.current_scene.game.get_node("camera").current = false
escoria.main.current_scene.game.hide_ui()