From 8ef8a59a07e18c55db811f4053a20d2820159ab1 Mon Sep 17 00:00:00 2001 From: Carenalga Date: Sun, 11 Feb 2024 10:31:08 -0500 Subject: [PATCH] Documentation for Engine classes (#150) * First documentation annotations for Popochiu class Base description, signals, constants and public members documented. [upd] Documentation annotations of other classes in order to make them available to access from the Popochiu docs page. * Progress on documenting E public methods * Finish first pass of E documentation Comments added to all public methods and members. * Finish documentation for PopochiuSettings Progress on documenting PopochiuClickable. * Finish documentation for PopochiuClickable Restored class_name definition and extends to their previous code format because the one line approach was causing problems with showing the classes in the documentation. * Finish documentation for PopochiuInventoryItem Minor updates to Popochiu and PopochiuClickable docs. * Finish documentation for PopochiuRoom * Finish documentation for PopochiuProp, PopochiuHotspot and PopochiuWalkableArea * Finish documentation for PopochiuRegion [upd] Minor text order update for virtual methods. * Progress on documenting PopochiuCharacter * Progress in PopochiuCharacter documentation Update a typo when refering to Popochiu.queue outside popochiu.gd documentation comments. * Finish documentation for PopochiuCharacter * Finish documentation of PopochiuDialog * Finish documentation for PopochiuDialogOption. * Finish documentation for Data classes. PopochiuCharacterData, PopochiuInventoryItemData and PopochiuRoomData. --- .../engine/audio_manager/audio_cue.gd | 4 + .../engine/audio_manager/audio_manager.gd | 10 +- .../objects/character/popochiu_character.gd | 324 +++++++++++++++--- .../character/popochiu_character_data.gd | 18 +- .../objects/clickable/popochiu_clickable.gd | 97 ++++-- .../engine/objects/dialog/popochiu_dialog.gd | 77 +++-- .../objects/dialog/popochiu_dialog_option.gd | 39 ++- .../components/dialog_text/dialog_text.gd | 21 +- .../popochiu_graphic_interface.gd | 2 +- .../templates/9_verb/9_verb_commands.gd | 1 + .../templates/sierra/sierra_commands.gd | 1 + .../simple_click/simple_click_commands.gd | 1 + .../objects/hotspot/popochiu_hotspot.gd | 11 +- .../inventory_item/popochiu_inventory_item.gd | 137 +++++++- .../popochiu_inventory_item_data.gd | 18 +- .../engine/objects/popochiu_settings.gd | 54 ++- .../engine/objects/prop/popochiu_prop.gd | 46 ++- .../engine/objects/region/popochiu_region.gd | 96 ++++-- .../engine/objects/room/popochiu_room.gd | 199 +++++++---- .../engine/objects/room/popochiu_room.tscn | 1 + .../engine/objects/room/popochiu_room_data.gd | 42 ++- .../transition_layer/transition_layer.gd | 5 +- .../walkable_area/popochiu_walkable_area.gd | 33 +- .../engine/others/popochiu_save_load.gd | 9 +- addons/popochiu/engine/popochiu.gd | 313 +++++++++++++---- 25 files changed, 1197 insertions(+), 362 deletions(-) diff --git a/addons/popochiu/engine/audio_manager/audio_cue.gd b/addons/popochiu/engine/audio_manager/audio_cue.gd index 97241bf7d..dc81dd14b 100644 --- a/addons/popochiu/engine/audio_manager/audio_cue.gd +++ b/addons/popochiu/engine/audio_manager/audio_cue.gd @@ -1,6 +1,10 @@ @tool extends Resource class_name PopochiuAudioCue +## Used to play audio files with extra properties. +## +## You can set the pitch (with random values), volume, and audio bus. Whether it loops or not, or +## whether it is 2D positioned. @export var audio: AudioStream @export var loop := false : set = set_loop diff --git a/addons/popochiu/engine/audio_manager/audio_manager.gd b/addons/popochiu/engine/audio_manager/audio_manager.gd index 23146cd27..cef6b8fa2 100644 --- a/addons/popochiu/engine/audio_manager/audio_manager.gd +++ b/addons/popochiu/engine/audio_manager/audio_manager.gd @@ -1,10 +1,10 @@ -# Handles playing audio with AudioCues. -# -# TODO: Create AudioHandle so each AudioCue has its own AudioStreamPlayer... -# http://www.powerhoof.com/public/powerquestdocs/class_power_tools_1_1_quest_1_1_audio_handle.html -extends Node class_name PopochiuAudioManager +extends Node @warning_ignore("return_value_discarded") +## Handles playing audio with AudioCues. + +# TODO: Create AudioHandle so each AudioCue has its own AudioStreamPlayer... +# http://www.powerhoof.com/public/powerquestdocs/class_power_tools_1_1_quest_1_1_audio_handle.html const TEMP_PLAYER := "temporal" const AudioCue := preload('audio_cue.gd') diff --git a/addons/popochiu/engine/objects/character/popochiu_character.gd b/addons/popochiu/engine/objects/character/popochiu_character.gd index c44b36edd..0b1c874aa 100644 --- a/addons/popochiu/engine/objects/character/popochiu_character.gd +++ b/addons/popochiu/engine/objects/character/popochiu_character.gd @@ -2,41 +2,105 @@ @icon('res://addons/popochiu/icons/character.png') class_name PopochiuCharacter extends PopochiuClickable -## Any Object that can move, walk, navigate rooms, have an inventory, etc. -# TODO: Use a state machine - -enum FlipsWhen { NONE, LOOKING_RIGHT, LOOKING_LEFT } -enum Looking {UP, UP_RIGHT, RIGHT, DOWN_RIGHT, DOWN, DOWN_LEFT, LEFT, UP_LEFT} - -signal started_walk_to(character, start, end) +## Any object that can move, walk, navigate rooms, or have an inventory. + +## Determines when to flip the [b]$Sprite2D[/b] child. +enum FlipsWhen { + ## The [b]$Sprite2D[/b] child is not flipped. + NONE, + ## The [b]$Sprite2D[/b] child is flipped when the character is looking to the right. + LOOKING_RIGHT, + ## The [b]$Sprite2D[/b] child is flipped when the character is looking to the left. + LOOKING_LEFT +} +## Determines the direction the character is facing +enum Looking { + ## The character is facing up [code](0, -y)[/code]. + UP, + ## The character is facing up-right [code](x, -y)[/code]. + UP_RIGHT, + ## The character is facing right [code](x, 0)[/code]. + RIGHT, + ## The character is facing down-right [code](x, y)[/code]. + DOWN_RIGHT, + ## The character is facing down [code](0, y)[/code]. + DOWN, + ## The character is facing down-left [code](-x, y)[/code]. + DOWN_LEFT, + ## The character is facing left [code](-x, 0)[/code]. + LEFT, + ## The character is facing up-left [code](-x, -y)[/code]. + UP_LEFT +} + +## Emitted when the character starts walking. As parameters, it sends itself, the starting position +## and the ending position. [PopochiuRoom]s connect to this signal in order to make characters move +## inside them from one point to another. +signal started_walk_to(character: PopochiuCharacter, start: Vector2, end: Vector2) +## Emitted when the character is forced to stop while walking. signal stopped_walk +## Emitted when the character reaches the ending position when moving from one point to another. signal move_ended +## The [Color] in which the dialogue lines of the character are rendered. @export var text_color := Color.WHITE +## Depending on its value, the [b]$Sprite2D[/b] child will be flipped horizontally depending on +## which way the character is facing. If the value is [constant NONE], then the +## [b]$Sprite2D[/b] child won't be flipped. @export var flips_when: FlipsWhen = FlipsWhen.NONE -@export var voices := []: - set = set_voices # (Array, Dictionary) +## Array of [Dictionary] where each element has +## [code]{ emotion: String, variations: Array[PopochiuAudioCue] }[/code]. +## You can use this to define which [PopochiuAudioCue]s to play when the character speaks using a +## specific emotion. +@export var voices := [] : set = set_voices +## Whether the character should follow the player-controlled character (PC) when it moves through +## the room. @export var follow_player := false +## The offset between the player-controlled character (PC) and this character when it follows the +## former one. @export var follow_player_offset := Vector2(20,0) -@export var avatars := []: - set = set_avatars # (Array, Dictionary) +## Array of [Dictionary] where each element has [code]{ emotion: String, avatar: Texture }[/code]. +## You can use this to define which [Texture] to use as avatar for the character when it speaks +## using a specific emotion. +@export var avatars := [] : set = set_avatars +## The speed at which the character will move in pixels per frame. @export var walk_speed := 200.0 +## Whether the character can or not move. @export var can_move := true +## Whether the character ignores or not walkable areas. If [code]true[/code], the character will +## move to any point in the room clicked by players without taking into account the walkable areas +## in it. @export var ignore_walkable_areas := false +## Whether the character will move only when the frame changes on its animation. @export var anti_glide_animation: bool = false +# This category is used by the Aseprite Importer in order to allow the creation of a section in the +# Inspector for the character. @export_category("Aseprite") +## The stored position of the character. Used when [member anti_glide_animation] is +## [code]true[/code]. var position_stored = null +## Stores the [member PopochiuRoom.script_name] of the preiously visited [PopochiuRoom]. var last_room := '' +## The suffix text to add to animation names. var anim_suffix := '' +## Whether the character is or not moving through the room. var is_moving := false +## The current emotion used by the character. var emotion := '' +## var on_scaling_region: Dictionary = {} -var default_walk_speed: int -var default_scale: Vector2 +## Stores the default walk speed defined in [member walk_speed]. Used by [PopochiuRoom] when scaling +## the character if it is inside a [PopochiuRegion] that modifies the scale. +var default_walk_speed := 0 +## Stores the default scale. Used by [PopochiuRoom] when scaling the character if it is inside a +## [PopochiuRegion] that modifies the scale. +var default_scale := Vector2.ONE var _looking_dir: int = Looking.DOWN +## A to the [b]$DialogPos[/b] child. Used by the GUI to calculate where to render the dialogue lines +## said by the character when it speaks. @onready var dialog_pos: Marker2D = $DialogPos @@ -68,33 +132,50 @@ func _get_property_list(): #endregion #region Virtual #################################################################################### +## Use it to play the idle animation of the character. +## [i]Virtual[/i]. func _play_idle() -> void: play_animation('idle') +## Use it to play the walk animation of the character. +## [i]Virtual[/i]. func _play_walk(target_pos: Vector2) -> void: # Set the default parameters for play_animation() var animation_label = 'walk' var animation_fallback = 'idle' + play_animation(animation_label, animation_fallback) +## Use it to play the talk animation of the character. +## [i]Virtual[/i]. func _play_talk() -> void: play_animation('talk') +## Use it to play the grab animation of the character. +## [i]Virtual[/i]. func _play_grab() -> void: play_animation('grab') - #endregion #region Public ##################################################################################### +## Puts the character in the idle state by playing its idle animation, then waits for +## [code]0.2[/code] seconds. +## If the characer has a [b]$Sprite2D[/b] child, it makes it flip based on the [member flips_when] +## value. +## [br][i]This method is intended to be used inside a [method Popochiu.queue] of instructions.[/i] func queue_idle() -> Callable: return func (): await idle() +## Puts the character in the idle state by playing its idle animation, then waits for +## [code]0.2[/code] seconds. +## If the characer has a [b]$Sprite2D[/b] child, it makes it flip based on the [member flips_when] +## value. func idle() -> void: if E.cutscene_skipped: await get_tree().process_frame @@ -113,10 +194,17 @@ func idle() -> void: await get_tree().create_timer(0.2).timeout +## Makes the character move to [param target_pos] and plays its walk animation. +## If the characer has a [b]$Sprite2D[/b] child, it makes it flip based on the [member flips_when] +## value. +## [br][i]This method is intended to be used inside a [method Popochiu.queue] of instructions.[/i] func queue_walk(target_pos: Vector2) -> Callable: return func (): await walk(target_pos) +## Makes the character move to [param target_pos] and plays its walk animation. +## If the characer has a [b]$Sprite2D[/b] child, it makes it flip based on the [member flips_when] +## value. func walk(target_pos: Vector2) -> void: is_moving = true _looking_dir = Looking.LEFT if target_pos.x < position.x else Looking.RIGHT @@ -160,10 +248,13 @@ func take_turn(target_pos: Vector2): face_direction(target_pos) _play_walk(target_pos) +## Makes the character stop moving and emits [signal stopped_walk]. +## [br][i]This method is intended to be used inside a [method Popochiu.queue] of instructions.[/i] func queue_stop_walking() -> Callable: return func (): await stop_walking() - - + + +## Makes the character stop moving and emits [signal stopped_walk]. func stop_walking() -> void: is_moving = false @@ -172,55 +263,127 @@ func stop_walking() -> void: await get_tree().process_frame +## Makes the character to look up by setting [member _looking_dir] to [constant UP] and waits until +## [method idle] finishes. +## [br][i]This method is intended to be used inside a [method Popochiu.queue] of instructions.[/i] func queue_face_up() -> Callable: return func (): await face_up() +## Makes the character to look up by setting [member _looking_dir] to [constant UP] and waits until +## [method idle] finishes. func face_up() -> void: _looking_dir = Looking.UP await idle() +## Makes the character to look up and right by setting [member _looking_dir] to [constant UP_RIGHT] +## and waits until [method idle] finishes. +## [br][i]This method is intended to be used inside a [method Popochiu.queue] of instructions.[/i] func queue_face_up_right() -> Callable: return func (): await face_up_right() +## Makes the character to look up and right by setting [member _looking_dir] to [constant UP_RIGHT] +## and waits until [method idle] finishes. func face_up_right() -> void: _looking_dir = Looking.UP_RIGHT await idle() +## Makes the character to look right by setting [member _looking_dir] to [constant RIGHT] and waits +## until [method idle] finishes. +## [br][i]This method is intended to be used inside a [method Popochiu.queue] of instructions.[/i] +func queue_face_right() -> Callable: + return func (): await face_right() + + +## Makes the character to look right by setting [member _looking_dir] to [constant RIGHT] and waits +## until [method idle] finishes. +func face_right() -> void: + _looking_dir = Looking.RIGHT + await idle() + + +## Makes the character to look down and right by setting [member _looking_dir] to +## [constant DOWN_RIGHT] and waits until [method idle] finishes. +## [br][i]This method is intended to be used inside a [method Popochiu.queue] of instructions.[/i] +func queue_face_down_right() -> Callable: + return func (): await face_down_right() + + +## Makes the character to look down and right by setting [member _looking_dir] to +## [constant DOWN_RIGHT] and waits until [method idle] finishes. +func face_down_right() -> void: + _looking_dir = Looking.DOWN_RIGHT + await idle() + + +## Makes the character to look down by setting [member _looking_dir] to [constant DOWN] and waits +## until [method idle] finishes. +## [br][i]This method is intended to be used inside a [method Popochiu.queue] of instructions.[/i] func queue_face_down() -> Callable: return func (): await face_down() +## Makes the character to look down by setting [member _looking_dir] to [constant DOWN] and waits +## until [method idle] finishes. func face_down() -> void: _looking_dir = Looking.DOWN await idle() +## Makes the character to look down and left by setting [member _looking_dir] to +## [constant DOWN_LEFT] and waits until [method idle] finishes. +## [br][i]This method is intended to be used inside a [method Popochiu.queue] of instructions.[/i] +func queue_face_down_left() -> Callable: + return func (): await face_down_left() + + +## Makes the character to look down and left by setting [member _looking_dir] to +## [constant DOWN_LEFT] and waits until [method idle] finishes. +func face_down_left() -> void: + _looking_dir = Looking.DOWN_LEFT + await idle() + + +## Makes the character to look left by setting [member _looking_dir] to [constant LEFT] and waits +## until [method idle] finishes. +## [br][i]This method is intended to be used inside a [method Popochiu.queue] of instructions.[/i] func queue_face_left() -> Callable: return func (): await face_left() +## Makes the character to look left by setting [member _looking_dir] to [constant LEFT] and waits +## until [method idle] finishes. func face_left() -> void: _looking_dir = Looking.LEFT await idle() -func queue_face_right() -> Callable: - return func (): await face_right() +## Makes the character to look up and left by setting [member _looking_dir] to [constant UP_LEFT] +## and waits until [method idle] finishes. +## [br][i]This method is intended to be used inside a [method Popochiu.queue] of instructions.[/i] +func queue_face_up_left() -> Callable: + return func (): await face_up_left() -func face_right() -> void: - _looking_dir = Looking.RIGHT +## Makes the character to look up and left by setting [member _looking_dir] to [constant UP_LEFT] +## and waits until [method idle] finishes. +func face_up_left() -> void: + _looking_dir = Looking.UP_LEFT await idle() +## Makes the character face in the direction of the last clicked [PopochiuClickable], which is +## stored in [member Popochiu.clicked]. +## [br][i]This method is intended to be used inside a [method Popochiu.queue] of instructions.[/i] func queue_face_clicked() -> Callable: return func (): await face_clicked() +## Makes the character face in the direction of the last clicked [PopochiuClickable], which is +## stored in [member Popochiu.clicked]. func face_clicked() -> void: if E.clicked.global_position < global_position: if has_node('Sprite2D'): @@ -234,10 +397,19 @@ func face_clicked() -> void: await face_right() +## Calls [method _play_talk] and emits [signal character_spoke] sending itself as parameter, and the +## [param dialog] line to show on screen. You can specify the emotion to use with [param emo]. If an +## [AudioCue] is defined for the emotion, it is played. Once the talk animation finishes, the +## characters return to its idle state. +## [br][i]This method is intended to be used inside a [method Popochiu.queue] of instructions.[/i] func queue_say(dialog: String, emo := "") -> Callable: return func (): await say(dialog, emo) +## Calls [method _play_talk] and emits [signal character_spoke] sending itself as parameter, and the +## [param dialog] line to show on screen. You can specify the emotion to use with [param emo]. If an +## [AudioCue] is defined for the emotion, it is played. Once the talk animation finishes, the +## characters return to its idle state. func say(dialog: String, emo := "") -> void: if E.cutscene_skipped: await get_tree().process_frame @@ -271,10 +443,15 @@ func say(dialog: String, emo := "") -> void: G.unblock(true) +## Calls [method _play_grab] and waits until the [signal character_grab_done] is emitted, then goes +## back to [method idle]. +## [br][i]This method is intended to be used inside a [method Popochiu.queue] of instructions.[/i] func queue_grab() -> Callable: return func (): await grab() +## Calls [method _play_grab] and waits until the [signal character_grab_done] is emitted, then goes +## back to [method idle]. func grab() -> void: if E.cutscene_skipped: await get_tree().process_frame @@ -288,87 +465,110 @@ func grab() -> void: idle() +## Calls [method PopochiuClickable.hide_helpers] and then hides the `$DialogPos` child. func hide_helpers() -> void: super() - if is_instance_valid(dialog_pos): dialog_pos.hide() + if is_instance_valid(dialog_pos): + dialog_pos.hide() +## Calls [method PopochiuClickable.show_helpers] and then shows the `$DialogPos` child. func show_helpers() -> void: super() - if is_instance_valid(dialog_pos): dialog_pos.show() + + if is_instance_valid(dialog_pos): + dialog_pos.show() +## Makes the character walk to [param pos]. +## [br][i]This method is intended to be used inside a [method Popochiu.queue] of instructions.[/i] func queue_walk_to(pos: Vector2) -> Callable: return func(): await walk_to(pos) +## Makes the character walk to [param pos]. func walk_to(pos: Vector2) -> void: await walk(E.current_room.to_global(pos)) +## Makes the character walk to the last clicked [PopochiuClickable], which is stored in +## [member Popochiu.clicked]. You can set an [param offset] relative to the target position. +## [br][i]This method is intended to be used inside a [method Popochiu.queue] of instructions.[/i] func queue_walk_to_clicked(offset := Vector2.ZERO) -> Callable: return func (): await walk_to_clicked(offset) +## Makes the character walk to the last clicked [PopochiuClickable], which is stored in +## [member Popochiu.clicked]. You can set an [param offset] relative to the target position. func walk_to_clicked(offset := Vector2.ZERO) -> void: await _walk_to_node(E.clicked, offset) +## Makes the character walk to the [PopochiuProp] (in the current room) which +## [member PopochiuClickable.script_name] is equal to [param id]. You can set an [param offset] +## relative to the target position. +## [br][i]This method is intended to be used inside a [method Popochiu.queue] of instructions.[/i] func queue_walk_to_prop(id: String, offset := Vector2.ZERO) -> Callable: return func(): await walk_to_prop(id, offset) +## Makes the character walk to the [PopochiuProp] (in the current room) which +## [member PopochiuClickable.script_name] is equal to [param id]. You can set an [param offset] +## relative to the target position. func walk_to_prop(id: String, offset := Vector2.ZERO) -> void: await _walk_to_node(E.current_room.get_prop(id), offset) +## Makes the character walk to the [PopochiuHotspot] (in the current room) which +## [member PopochiuClickable.script_name] is equal to [param id]. You can set an [param offset] +## relative to the target position. +## [br][i]This method is intended to be used inside a [method Popochiu.queue] of instructions.[/i] func queue_walk_to_hotspot(id: String, offset := Vector2.ZERO) -> Callable: return func(): await walk_to_hotspot(id, offset) +## Makes the character walk to the [PopochiuHotspot] (in the current room) which +## [member PopochiuClickable.script_name] is equal to [param id]. You can set an [param offset] +## relative to the target position. func walk_to_hotspot(id: String, offset := Vector2.ZERO) -> void: await _walk_to_node(E.current_room.get_hotspot(id), offset) +## Makes the character walk to the [Marker2D] (in the current room) which [member Node.name] is +## equal to [param id]. You can set an [param offset] relative to the target position. +## [br][i]This method is intended to be used inside a [method Popochiu.queue] of instructions.[/i] func queue_walk_to_marker(id: String, offset := Vector2.ZERO) -> Callable: return func(): await walk_to_marker(id, offset) +## Makes the character walk to the [Marker2D] (in the current room) which [member Node.name] is +## equal to [param id]. You can set an [param offset] relative to the target position. func walk_to_marker(id: String, offset := Vector2.ZERO) -> void: await _walk_to_node(E.current_room.get_marker(id), offset) +## Sets [member emotion] to [param new_emotion] when in a [method Popochiu.queue]. func queue_set_emotion(new_emotion: String) -> Callable: return func(): emotion = new_emotion +## Sets [member ignore_walkable_areas] to [param new_value] when in a [method Popochiu.queue]. func queue_ignore_walkable_areas(new_value: bool) -> Callable: return func(): ignore_walkable_areas = new_value +## Plays the [param animation_label] animation. You can specify a fallback animation to play with +## [param animation_fallback] in case the former one doesn't exists. +## [br][i]This method is intended to be used inside a [method Popochiu.queue] of instructions.[/i] func queue_play_animation( animation_label: String, animation_fallback := 'idle', blocking := false ) -> Callable: return func(): await play_animation(animation_label, animation_fallback) -func queue_stop_animation(): - return func(): await stop_animation() - - -func queue_halt_animation(): - return func(): halt_animation() - - -func queue_pause_animation(): - return func(): pause_animation() - - -func queue_resume_animation(): - return func(): resume_animation() - - +## Plays the [param animation_label] animation. You can specify a fallback animation to play with +## [param animation_fallback] in case the former one doesn't exists. func play_animation(animation_label: String, animation_fallback := 'idle'): if not has_node("AnimationPlayer"): PopochiuUtils.print_error( @@ -397,6 +597,15 @@ func play_animation(animation_label: String, animation_fallback := 'idle'): _play_idle() +## Makes the animation that is currently playing to stop. Works only if it is looping and is not an +## idle animation. The animation stops when the current loop finishes. +## [br][i]This method is intended to be used inside a [method Popochiu.queue] of instructions.[/i] +func queue_stop_animation(): + return func(): await stop_animation() + + +## Makes the animation that is currently playing to stop. Works only if it is looping and is not an +## idle animation. The animation stops when the current loop finishes. func stop_animation(): # If the animation is not looping or is an idle one, do nothing if ( @@ -405,27 +614,53 @@ func stop_animation(): $AnimationPlayer.current_animation.begins_with('idle_') ): return - # save the loop mode, wait for the anim to be over as designed, then restore the mode + + # Save the loop mode, wait for the anim to be over as designed, then restore the mode var animation = $AnimationPlayer.get_animation($AnimationPlayer.current_animation) var animation_loop_mode = animation.loop_mode animation.loop_mode = Animation.LOOP_NONE + await $AnimationPlayer.animation_finished + _play_idle() animation.loop_mode = animation_loop_mode +## Immediately stops the animation that is currently playing by changing to the idle animation. +## [br][i]This method is intended to be used inside a [method Popochiu.queue] of instructions.[/i] +func queue_halt_animation(): + return func(): halt_animation() + + +## Immediately stops the animation that is currently playing by changing to the idle animation. func halt_animation(): _play_idle() +## Pauses the animation that is currently playing. +## [br][i]This method is intended to be used inside a [method Popochiu.queue] of instructions.[/i] +func queue_pause_animation(): + return func(): pause_animation() + + +## Pauses the animation that is currently playing. func pause_animation(): $AnimationPlayer.pause() +## Resumes the current animation (that was previously paused). +## [br][i]This method is intended to be used inside a [method Popochiu.queue] of instructions.[/i] +func queue_resume_animation(): + return func(): resume_animation() + + +## Resumes the current animation (that was previously paused). func resume_animation(): $AnimationPlayer.play() +## Makes the character look in the direction of [param destination]. The result is one of the values +## defined by [enum Looking]. func face_direction(destination: Vector2): # Get the vector from the origin to the destination. var vectX = destination.x - position.x @@ -460,6 +695,9 @@ func face_direction(destination: Vector2): _looking_dir = Looking.UP_LEFT +## Returns the [Texture] of the avatar defined for the [param emo] emotion. +## Returns [code]null[/code] if no avatar is found. If there is an avatar defined for the +## [code]""[/code] emotion, that one is returned by default. func get_avatar_for_emotion(emo := "") -> Texture: var texture: Texture = null @@ -474,13 +712,15 @@ func get_avatar_for_emotion(emo := "") -> Texture: return texture -#endregion - -#region SetGet ##################################################################################### +## Returns the [code]y[/code] value of the [b]$DialogPos[/b] [Marker2D] (the node that defines the +## position of the dialog lines said by the character when it talks). func get_dialog_pos() -> float: return $DialogPos.position.y +#endregion + +#region SetGet ##################################################################################### func set_voices(value: Array) -> void: voices = value diff --git a/addons/popochiu/engine/objects/character/popochiu_character_data.gd b/addons/popochiu/engine/objects/character/popochiu_character_data.gd index c5b416dd8..e6fd880e9 100644 --- a/addons/popochiu/engine/objects/character/popochiu_character_data.gd +++ b/addons/popochiu/engine/objects/character/popochiu_character_data.gd @@ -1,16 +1,25 @@ @icon('res://addons/popochiu/icons/character.png') class_name PopochiuCharacterData extends Resource +## This class is used to store information when saving and loading the game. It also ensures that +## the data remains throughout the game's execution. +## The identifier of the object used in scripts. @export var script_name := '' +## The path to the scene file to be used when adding the character to the game during runtime. @export_file("*.tscn") var scene := '' #region Virtual #################################################################################### +## Called when the game is saved. +## [i]Virtual[/i]. func _on_save() -> Dictionary: return {} +## Called when the game is loaded. The structure of [param data] is the same returned by +## [method _on_save]. +## [i]Virtual[/i]. func _on_load(_data: Dictionary) -> void: pass @@ -18,15 +27,14 @@ func _on_load(_data: Dictionary) -> void: #endregion #region Public ##################################################################################### -# Use this to save custom data for this PopochiuCharacter when saving the game. -# The Dictionary must contain only JSON supported types: bool, int, float, String. +## Use this to store custom data when saving the game. The returned [Dictionary] must contain only +## JSON supported types: [bool], [int], [float], [String]. func on_save() -> Dictionary: return _on_save() -# Called when the game is loaded. -# This Dictionary should has the same structure you defined for the returned -# one in on_save(). +## Called when the game is loaded. [param data] will have the same structure you defined for the +## returned [Dictionary] by [method _on_save]. func on_load(data: Dictionary) -> void: _on_load(data) diff --git a/addons/popochiu/engine/objects/clickable/popochiu_clickable.gd b/addons/popochiu/engine/objects/clickable/popochiu_clickable.gd index 342341e63..861a515b6 100644 --- a/addons/popochiu/engine/objects/clickable/popochiu_clickable.gd +++ b/addons/popochiu/engine/objects/clickable/popochiu_clickable.gd @@ -1,29 +1,52 @@ @tool class_name PopochiuClickable extends Area2D -## Allows to handle an Area2D that reacts to click events, and mouse entering, -## and exiting. - +## Handles an Area2D that reacts to mouse events. +## +## Is the base clase for [PopochiuProp], [PopochiuHotspot] and [PopochiuCharacter]. +## It has a property to determine when the object should render in front or back to other, another +## property that can be used to define the position to which characters will move to when moving +## to the item, and tow [CollisionPolygon2D] which are used to handle players interaction and +## handle scaling. + +## Used to allow devs to define the cursor type for the clickable. const CURSOR := preload('res://addons/popochiu/engine/cursor/cursor.gd') +## The identifier of the object used in scripts. @export var script_name := '' +## The text shown to players when the cursor hovers the object. @export var description := '' +## Whether the object will listen to interactions. @export var clickable := true +## The [code]y[/code] position of the baseline relative to the center of the object. @export var baseline := 0 : set = set_baseline +## The [Vector2] position where characters will move when aproaching the object. @export var walk_to_point := Vector2.ZERO : set = set_walk_to_point +## The cursor to use when the mouse hovers the object. @export var cursor: CURSOR.Type = CURSOR.Type.NONE +## Whether the object will be rendered always above other objects in the room. @export var always_on_top := false +## Stores the vertices to assign to the [b]InteractionPolygon[/b] child during runtime. This is used +## by [PopochiuRoom] to store the info in its [code].tscn[/code]. @export var interaction_polygon := PackedVector2Array() +## Stores the position to assign to the [b]InteractionPolygon[/b] child during runtime. This is used +## by [PopochiuRoom] to store the info in its [code].tscn[/code]. @export var interaction_polygon_position := Vector2.ZERO -var room: Node2D = null : set = set_room # It is a PopochiuRoom +## The [PopochiuRoom] to which the object belongs. +var room: Node2D = null : set = set_room +## The number of times this object has been left-clicked. var times_clicked := 0 +## The number of times this object has been right-clicked. var times_right_clicked := 0 -var editing_polygon := false +## The number of times this object has been middle-clicked. var times_middle_clicked := 0 -# NOTE Don't know if this will make sense, or if it this object should emit -# a signal about the click (command execution) -var last_click_button := -1 +## Used by the editor to know if the [b]InteractionPolygon[/b] child its being edited in Godot's +## 2D Canvas Editor. +var editing_polygon := false +## Stores the last [enum MouseButton] pressed on this object. +var last_click_button := -1 # NOTE Don't know if this will make sense, or if this object should +# emit a signal about the click (command execution). @onready var _description_code := description @@ -117,27 +140,32 @@ func _process(delta): #endregion #region Virtual #################################################################################### -## When the room this node belongs to has been added to the tree +## Called when the room this node belongs to has been added to the tree. +## [i]Virtual[/i]. func _on_room_set() -> void: pass -## When the node is clicked +## Called when the node is clicked. +## [i]Virtual[/i]. func _on_click() -> void: pass -## When the node is right clicked +## Called when the node is right clicked. +## [i]Virtual[/i]. func _on_right_click() -> void: pass -## When the node is middle clicked +## Called when the node is middle clicked. +## [i]Virtual[/i]. func _on_middle_click() -> void: pass -## When the node is clicked and there is an inventory item selected +## Called when the node is clicked and there is an inventory item selected. +## [i]Virtual[/i]. func _on_item_used(item: PopochiuInventoryItem) -> void: pass @@ -145,6 +173,8 @@ func _on_item_used(item: PopochiuInventoryItem) -> void: #endregion #region Public ##################################################################################### +## Used by the plugin to hide the visual helpers that show the [member baseline] and +## [member walk_to_point] in the 2D Canvas Editor when this node is unselected in the Scene panel. func hide_helpers() -> void: $BaselineHelper.hide() $WalkToHelper.hide() @@ -153,6 +183,9 @@ func hide_helpers() -> void: $InteractionPolygon.hide() +## Used by the plugin to make visible the visual helpers that show the [member baseline] and +## [member walk_to_point] of the object in the 2D Canvas Editor when the is selected in the +## Scene panel. func show_helpers() -> void: $BaselineHelper.show() $WalkToHelper.show() @@ -161,28 +194,35 @@ func show_helpers() -> void: $InteractionPolygon.show() +## Hides this Node. +## [br][i]This method is intended to be used inside a [method Popochiu.queue] of instructions.[/i] func queue_disable() -> Callable: return func (): await disable() -# Hides the Node and disables its interaction +## Hides this Node. func disable() -> void: self.visible = false await get_tree().process_frame +## Shows this Node. +## [br][i]This method is intended to be used inside a [method Popochiu.queue] of instructions.[/i] func queue_enable() -> Callable: return func (): await enable() -# Makes the Node visible and enables its interaction +## Shows this Node. func enable() -> void: self.visible = true await get_tree().process_frame +## Returns the [member description] of the node using [method Object.tr] if +## [member PopochiuSettings.use_translations] is [code]true[/code]. Otherwise, it returns just the +## value of [member description]. func get_description() -> String: if Engine.is_editor_hint(): if description.is_empty(): @@ -191,25 +231,38 @@ func get_description() -> String: return E.get_text(description) -## Called when the object is left clicked +## Returns the global position of [member walk_to_point]. +func get_walk_to_point() -> Vector2: + if Engine.is_editor_hint(): + return walk_to_point + elif is_inside_tree(): + return to_global(walk_to_point) + return walk_to_point + + +## Called when the object is left clicked. func on_click() -> void: _on_click() -## Called when the object is right clicked +## Called when the object is right clicked. func on_right_click() -> void: _on_right_click() -## Called when the object is middle clicked +## Called when the object is middle clicked. func on_middle_click() -> void: _on_middle_click() +## Called when an [param item] is used on this object. func on_item_used(item: PopochiuInventoryItem) -> void: await G.show_system_text("Can't USE %s here" % item.description) +## Triggers the proper GUI command for the clicked mouse button identified with [param button_idx], +## which can be [enum MouseButton].MOUSE_BUTTON_LEFT, [enum MouseButton].MOUSE_BUTTON_RIGHT or +## [enum MouseButton].MOUSE_BUTTON_MIDDLE. func handle_command(button_idx: int) -> void: var command: String = E.get_current_command_name().to_snake_case() var prefix := "on_%s" @@ -254,14 +307,6 @@ func set_walk_to_point(value: Vector2) -> void: get_node('WalkToHelper').position = value -func get_walk_to_point() -> Vector2: - if Engine.is_editor_hint(): - return walk_to_point - elif is_inside_tree(): - return to_global(walk_to_point) - return walk_to_point - - func set_room(value: Node2D) -> void: room = value diff --git a/addons/popochiu/engine/objects/dialog/popochiu_dialog.gd b/addons/popochiu/engine/objects/dialog/popochiu_dialog.gd index b3b418292..668646b2a 100644 --- a/addons/popochiu/engine/objects/dialog/popochiu_dialog.gd +++ b/addons/popochiu/engine/objects/dialog/popochiu_dialog.gd @@ -2,27 +2,38 @@ @icon('res://addons/popochiu/icons/dialog.png') class_name PopochiuDialog extends Resource -## For branching dialog, can have dialog options that trigger a script. +## A class for branching dialogs. The dialog options can be used to trigger events. -const PopochiuDialogOption := preload('popochiu_dialog_option.gd') - -@export var options := [] : set = set_options +## The identifier of the object used in scripts. @export var script_name := '' +## The array of [PopochiuDialogOption] to show on screen when the dialog is running. +@export var options: Array[PopochiuDialogOption] = [] : set = set_options #region Virtual #################################################################################### +## Called when the dialog starts. [b]You have to use an [code]await[/code] in this method in order +## to make the dialog to work properly[/b]. +## [i]Virtual[/i]. func _on_start() -> void: pass +## Called when the [param opt] dialog option is clicked. The [member PopochiuDialogOption.id] in +## [param opt] can be used to check which was the selected option. +## [i]Virtual[/i]. func _option_selected(opt: PopochiuDialogOption) -> void: pass +## Called when the game is saved. +## [i]Virtual[/i]. func _on_save() -> Dictionary: return {} +## Called when the game is loaded. The structure of [param data] is the same returned by +## [method _on_save]. +## [i]Virtual[/i]. func _on_load(_data: Dictionary) -> void: pass @@ -30,78 +41,88 @@ func _on_load(_data: Dictionary) -> void: #endregion #region Public ##################################################################################### +## Starts this dialog, then [method _on_start] is called. +## [br][i]This method is intended to be used inside a [method Popochiu.queue] of instructions.[/i] +func queue_start() -> Callable: + return func (): await start() + + +## Starts this dialog, then [method _on_start] is called. func start() -> void: # Start this dialog D.current_dialog = self await _start() -func queue_start() -> Callable: - return func (): await start() +## Stops the dialog (which makes the menu with the options to disappear). +## [br][i]This method is intended to be used inside a [method Popochiu.queue] of instructions.[/i] +func queue_stop() -> Callable: + return func (): await stop() +## Stops the dialog (which makes the menu with the options to disappear). func stop() -> void: D.finish_dialog() -func queue_stop() -> Callable: - return func (): await stop() - - +## Enables each [PopochiuDialogOption] which [member PopochiuDialogOption.id] matches each of the +## values in the [param ids] array. func turn_on_options(ids: Array) -> void: for id in ids: var opt: PopochiuDialogOption = get_option(id) if opt: opt.turn_on() +## Disables each [PopochiuDialogOption] which [member PopochiuDialogOption.id] matches each of the +## values in the [param ids] array. func turn_off_options(ids: Array) -> void: for id in ids: var opt: PopochiuDialogOption = get_option(id) if opt: opt.turn_off() +## Disables [b]forever[/b] each [PopochiuDialogOption] which [member PopochiuDialogOption.id] +## matches each of the values in the [param ids] array. func turn_off_forever_options(ids: Array) -> void: for id in ids: var opt: PopochiuDialogOption = get_option(id) if opt: opt.turn_off_forever() -## Use this to save custom data for this PopochiuDialog when saving the game. -## The Dictionary must contain only JSON supported types: bool, int, float, String. +## Use this to save custom data when saving the game. The returned [Dictionary] must contain only +## JSON supported types: [bool], [int], [float], [String]. func on_save() -> Dictionary: return _on_save() -## Called when the game is loaded. -## This Dictionary should has the same structure you defined for the returned one in _on_save(). +## Called when the game is loaded. [param data] will have the same structure you defined for the +## returned [Dictionary] by [method _on_save]. func on_load(data: Dictionary) -> void: _on_load(data) +## Returns the dilog option which [member PopochiuDialogOption.id] matches [param opt_id]. +func get_option(opt_id: String) -> PopochiuDialogOption: + for o in options: + if (o as PopochiuDialogOption).id == opt_id: + return o + return null + + #endregion #region SetGet ##################################################################################### -func set_options(value: Array) -> void: +func set_options(value: Array[PopochiuDialogOption]) -> void: options = value - for v in value.size(): - if not value[v]: + for idx in value.size(): + if not value[idx]: var new_opt: PopochiuDialogOption = PopochiuDialogOption.new() var id := 'Opt%d' % options.size() new_opt.id = id new_opt.text = 'Option %d' % options.size() - options[v] = new_opt - - notify_property_list_changed() - - -# Gets the option PopochiuDialogOption.id that matches opt_id -func get_option(opt_id: String) -> PopochiuDialogOption: - for o in options: - if (o as PopochiuDialogOption).id == opt_id: - return o - return null + options[idx] = new_opt #endregion diff --git a/addons/popochiu/engine/objects/dialog/popochiu_dialog_option.gd b/addons/popochiu/engine/objects/dialog/popochiu_dialog_option.gd index 4698c0f84..a039b26d9 100644 --- a/addons/popochiu/engine/objects/dialog/popochiu_dialog_option.gd +++ b/addons/popochiu/engine/objects/dialog/popochiu_dialog_option.gd @@ -1,28 +1,42 @@ @tool class_name PopochiuDialogOption extends Resource -# Each option in a dialog. -# ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ +## Each of the options in a [PopochiuDialog]. -@export var id := '' : set = set_id -@export var text := '' +## The identifier of the option. Use it when scripting. +@export var id := "" : set = set_id +## The text to show on screen for the option. +@export var text := "" +## The icon to show on screen for the option. @export var icon: Texture = null +## Whether this option is visible. @export var visible := true +## Whether this option is disabled. If [code]true[/code], the option won´t be rendered. @export var disabled := false +## Whether this option should be [b]always[/b] rendered as not previously selected. @export var always_on := false -# TODO: Store the localization code -var script_name := '' +## Stores the same value of the [member id] property. +var script_name := "" +## Whether the option was already been selected. If [code]true[/code], then the option's +## [member text] will be shown different in the options menu, so players know they already clicked +## the option. var used := false +## The number of times this options has been clicked. var used_times := 0 -# ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ VIRTUAL ░░░░ +#region Virtual #################################################################################### +## Called when the option is selected. +## [i]Virtual[/i]. func _on_selected() -> void: pass -# ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ PUBLIC ░░░░ +#endregion + +#region Public ##################################################################################### +## Makes the option visible. Won´t work if the option is [member disabled]. func turn_on() -> void: if disabled: return @@ -30,17 +44,24 @@ func turn_on() -> void: used = false +## Makes the option invisible. func turn_off() -> void: visible = false +## Disables the option by making [member disable] [code]true[/code]. func turn_off_forever() -> void: disabled = true -# ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ SET & GET ░░░░ +#endregion + +#region SetGet ##################################################################################### func set_id(value: String) -> void: id = value script_name = id resource_name = id + + +#endregion diff --git a/addons/popochiu/engine/objects/graphic_interface/components/dialog_text/dialog_text.gd b/addons/popochiu/engine/objects/graphic_interface/components/dialog_text/dialog_text.gd index a29648037..c99d23804 100644 --- a/addons/popochiu/engine/objects/graphic_interface/components/dialog_text/dialog_text.gd +++ b/addons/popochiu/engine/objects/graphic_interface/components/dialog_text/dialog_text.gd @@ -28,8 +28,7 @@ var _y_limit := 0.0 @onready var _continue_icon_tween: Tween = null -#region Godot -# ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ GODOT ░░░░ +#region Godot ###################################################################################### func _ready() -> void: set_meta(DFLT_SIZE, size) set_meta(DFLT_POSITION, position) @@ -65,17 +64,17 @@ func _input(event: InputEvent) -> void: disappear() else: stop() -#endregion -#region Public -# ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ PUBLIC ░░░░ +#endregion + +#region Public ##################################################################################### func play_text(props: Dictionary) -> void: var msg: String = E.get_text(props.text) _is_waiting_input = false _dialog_pos = props.position - # ==== Calculate the size of the node ====================================== + # ==== Calculate the size of the node ========================================================== # Create a RichTextLabel to calculate the resulting size of this node once # the whole text is shown var rt := RichTextLabel.new() @@ -133,7 +132,7 @@ func play_text(props: Dictionary) -> void: lbl.free() rt.free() - # ====================================== Calculate the size of the node ==== + # ========================================================== Calculate the size of the node ==== match E.current_dialog_style: 0: @@ -240,11 +239,11 @@ func disappear() -> void: func change_speed() -> void: _secs_per_character = E.current_text_speed -#endregion -#region Private -# ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ PRIVATE ░░░░ +#endregion + +#region Private #################################################################################### func _show_dialogue(chr: PopochiuCharacter, msg := '') -> void: if not visible: return @@ -343,4 +342,6 @@ func _on_dialog_style_changed() -> void: if E.current_dialog_style != 0 and E.current_dialog_style == used_when: wrap_width = size.x + + #endregion diff --git a/addons/popochiu/engine/objects/graphic_interface/popochiu_graphic_interface.gd b/addons/popochiu/engine/objects/graphic_interface/popochiu_graphic_interface.gd index ff35ca45d..2842ab3e7 100644 --- a/addons/popochiu/engine/objects/graphic_interface/popochiu_graphic_interface.gd +++ b/addons/popochiu/engine/objects/graphic_interface/popochiu_graphic_interface.gd @@ -1,5 +1,5 @@ -extends Control class_name PopochiuGraphicInterface +extends Control ## Handles the in-game Graphic Interface. var popups_stack := [] diff --git a/addons/popochiu/engine/objects/graphic_interface/templates/9_verb/9_verb_commands.gd b/addons/popochiu/engine/objects/graphic_interface/templates/9_verb/9_verb_commands.gd index 39f995f76..3e3a641b8 100644 --- a/addons/popochiu/engine/objects/graphic_interface/templates/9_verb/9_verb_commands.gd +++ b/addons/popochiu/engine/objects/graphic_interface/templates/9_verb/9_verb_commands.gd @@ -1,5 +1,6 @@ class_name NineVerbCommands extends PopochiuCommands +## Defines the commands and fallback methods for the 9 Verb GUI. enum Commands { WALK_TO, OPEN, PICK_UP, PUSH, CLOSE, LOOK_AT, PULL, GIVE, TALK_TO, USE diff --git a/addons/popochiu/engine/objects/graphic_interface/templates/sierra/sierra_commands.gd b/addons/popochiu/engine/objects/graphic_interface/templates/sierra/sierra_commands.gd index 3b129c9e7..a49f06e9d 100644 --- a/addons/popochiu/engine/objects/graphic_interface/templates/sierra/sierra_commands.gd +++ b/addons/popochiu/engine/objects/graphic_interface/templates/sierra/sierra_commands.gd @@ -1,5 +1,6 @@ class_name SierraCommands extends PopochiuCommands +## Defines the commands and fallback methods for the Sierra GUI. enum Commands { WALK, LOOK, INTERACT, TALK diff --git a/addons/popochiu/engine/objects/graphic_interface/templates/simple_click/simple_click_commands.gd b/addons/popochiu/engine/objects/graphic_interface/templates/simple_click/simple_click_commands.gd index 7626e8028..cbd7b573b 100644 --- a/addons/popochiu/engine/objects/graphic_interface/templates/simple_click/simple_click_commands.gd +++ b/addons/popochiu/engine/objects/graphic_interface/templates/simple_click/simple_click_commands.gd @@ -1,5 +1,6 @@ class_name SimpleClickCommands extends PopochiuCommands +## Defines the commands and fallback methods for the Simple-click/Context-sensitive GUI. ## Called when `E.command_fallback()` is triggered. diff --git a/addons/popochiu/engine/objects/hotspot/popochiu_hotspot.gd b/addons/popochiu/engine/objects/hotspot/popochiu_hotspot.gd index 0b05f2e30..89ad36462 100644 --- a/addons/popochiu/engine/objects/hotspot/popochiu_hotspot.gd +++ b/addons/popochiu/engine/objects/hotspot/popochiu_hotspot.gd @@ -2,9 +2,14 @@ @icon('res://addons/popochiu/icons/hotspot.png') class_name PopochiuHotspot extends PopochiuClickable -## Areas players can interact with. -## E.g. Something that is part of the Room's background (the sky, an entrance). - +## Areas players can interact with (i.e. something that is part of the room's background: the sky, +## an entrance to a cave, a forest in the distance). +## +## When selecting a Hotspot in the scene tree (Scene dock), Popochiu will enable three buttons in +## the Canvas Editor Menu: Baseline, Walk to, and Interaction. This can be used to select the child +## nodes that allow to modify the position of the [member PopochiuClickable.baseline], +## the position of the [member PopochiuClickable.walk_to_point], and the position and the polygon +## points of the [b]$InteractionPolygon[/b] child. #region Godot ###################################################################################### func _ready() -> void: diff --git a/addons/popochiu/engine/objects/inventory_item/popochiu_inventory_item.gd b/addons/popochiu/engine/objects/inventory_item/popochiu_inventory_item.gd index 9a2953b51..f5120e0e9 100644 --- a/addons/popochiu/engine/objects/inventory_item/popochiu_inventory_item.gd +++ b/addons/popochiu/engine/objects/inventory_item/popochiu_inventory_item.gd @@ -2,22 +2,32 @@ class_name PopochiuInventoryItem extends TextureRect ## An inventory item. +## +## Characters can collect these items and use them on things. They can also handle interactions and +## be used on other objects (i.e. [PopochiuClickable] or other inventory items). +## Used to allow devs to define the cursor type for the clickable. const CURSOR := preload('res://addons/popochiu/engine/cursor/cursor.gd') +## Emitted when the item is selected. signal selected(item) +## Emitted when the item is unselected (in most GUIs, this happens when right-clicking anywhere on +## the screen). signal unselected -@export var description := '' : get = get_description -@export var stack := false +## The identifier of the item used in scripts. @export var script_name := '' +## The text shown to players when the cursor hovers the item. +@export var description := '' : get = get_description +## The cursor to use when the mouse hovers the object. @export var cursor: CURSOR.Type = CURSOR.Type.USE -var amount := 1 + +## Whether this item is actually inside the inventory GUI. var in_inventory := false : set = set_in_inventory -# NOTE Don't know if this will make sense, or if it this object should emit -# a signal about the click (command execution) -var last_click_button := -1 +## Stores the last [enum MouseButton] pressed on this object. +var last_click_button := -1 # NOTE Don't know if this will make sense, or if it this object should +# emit a signal about the click (command execution) #region Godot ###################################################################################### @@ -30,32 +40,38 @@ func _ready(): #endregion #region Virtual #################################################################################### -## When the item is clicked in the Inventory +## Called when the item is clicked in the inventory GUI. +## [i]Virtual[/i]. func _on_click() -> void: pass -## When the item is right clicked in the Inventory +## Called when the item is right clicked in the inventory GUI. +## [i]Virtual[/i]. func _on_right_click() -> void: pass -## When the item is middle clicked in the Inventory +## Called when the item is middle clicked in the inventory GUI. +## [i]Virtual[/i]. func _on_middle_click() -> void: pass -## When the item is clicked and there is another inventory item selected +## When the item is clicked and there is another [param item] currently selected. +## [i]Virtual[/i]. func _on_item_used(item: PopochiuInventoryItem) -> void: pass -## Actions to excecute after the item is added to the Inventory +## Called after the item is added to the inventory. +## [i]Virtual[/i]. func _on_added_to_inventory() -> void: pass -## Actions to excecute when the item is discarded from the Inventory +## Called when the item is discarded from the inventory. +## [i]Virtual[/i]. func _on_discard() -> void: pass @@ -63,10 +79,33 @@ func _on_discard() -> void: #endregion #region Public ##################################################################################### +## Adds this item to the inventory. If [param animate] is [code]true[/code], the inventory GUI will +## show an animation as a feedback of this action. It will depend on the implementation of the +## inventory in the GUI. +## [br][i]This method is intended to be used inside a [method Popochiu.queue] of instructions.[/i] +## [br][br]Example of how to use it when interacting with a [PopochiuProp]: +## [codeblock] +## func on_click() -> void: +## E.queue([ +## C.queue_walk_to_clicked(), +## "Player: I'm gonna take this with me", +## I.Key.queue_add() +## ]) +## [/codeblock] func queue_add(animate := true) -> Callable: return func (): await add(animate) +## Adds this item to the inventory. If [param animate] is [code]true[/code], the inventory GUI will +## show an animation as a feedback of this action. It will depend on the implementation of the +## inventory in the GUI. +## [br][br]Example of how to use it when interacting with a [PopochiuProp]: +## [codeblock] +## func on_click() -> void: +## await C.walk_to_clicked() +## await C.player.say("I'm gonna take this with me") +## await I.Key.add() +## [/codeblock] func add(animate := true) -> void: if I.is_full(): printerr( @@ -94,20 +133,48 @@ func add(animate := true) -> void: await get_tree().process_frame +## Adds this item to the inventory and makes it the current selected item (the cursor will look like +## the item's texture). Pass [param animate] as [code]false[/code] if you do not want the inventory +## GUI to animate when the item is added. +## [br][i]This method is intended to be used inside a [method Popochiu.queue] of instructions.[/i] func queue_add_as_active(animate := true) -> Callable: return func (): await add_as_active(animate) +## Adds this item to the inventory and makes it the current selected item (the cursor will look like +## the item's texture). Pass [param animate] as [code]false[/code] if you do not want the inventory +## GUI to animate when the item is added. func add_as_active(animate := true) -> void: await add(animate) I.set_active_item(self, true) +## Removes the item from the inventory (its instance will be kept in memory). Pass [param animate] +## as [code]true[/code] if you want the inventory GUI to animate when the item is removed. +## [br][i]This method is intended to be used inside a [method Popochiu.queue] of instructions.[/i] +## [br][br]Example of how to use it when using an item on a [PopochiuProp]: +## [codeblock] +## func on_item_used(item: PopochiuInventoryItem) -> void: +## if item == I.ToyCar: +## E.queue([ +## "Player: Here is your toy car", +## I.ToyCar.queue_remove() +## ]) +## [/codeblock] func queue_remove(animate := false) -> Callable: return func (): await remove(animate) +## Removes the item from the inventory (its instance will be kept in memory). Pass [param animate] +## as [code]true[/code] if you want the inventory GUI to animate when the item is removed. +## [br][br]Example of how to use it when using an item on a [PopochiuProp]: +## [codeblock] +## func on_item_used(item: PopochiuInventoryItem) -> void: +## if item == I.ToyCar: +## await C.player.say("Here is your toy car") +## await I.ToyCar.remove() +## [/codeblock] func remove(animate := false) -> void: in_inventory = false @@ -121,6 +188,31 @@ func remove(animate := false) -> void: G.unblock() +## Replaces this inventory item by [param new_item]. Useful when combining items. +## [br][i]This method is intended to be used inside a [method Popochiu.queue] of instructions.[/i] +## [br][br]Example of how to use it when combining two inventory items: +## [codeblock] +## # This is the script of the InventoryItemHook.gd (I.Hook) +## func on_item_used(item: PopochiuInventoryItem) -> void: +## if item == I.Rope: +## E.queue([ +## I.Rope.queue_remove(), +## queue_replace(I.RopeWithHook) +## ]) +## [/codeblock] +func queue_replace(new_item: PopochiuInventoryItem) -> Callable: + return func (): await replace(new_item) + + +## Replaces this inventory item by [param new_item]. Useful when combining items. +## [br][br]Example of how to use it when combining two inventory items: +## [codeblock] +## # This is the script of the InventoryItemHook.gd (I.Hook) +## func on_item_used(item: PopochiuInventoryItem) -> void: +## if item == I.Rope: +## await I.Rope.remove() +## await replace(I.RopeWithHook) +## [/codeblock] func replace(new_item: PopochiuInventoryItem) -> void: in_inventory = false @@ -136,10 +228,17 @@ func replace(new_item: PopochiuInventoryItem) -> void: G.unblock() +# NOTE: Maybe this is not necessary since we can have the same with [method queue_remove]. +## Removes the item from the inventory (its instance will be kept in memory). Pass [param animate] +## as [code]true[/code] if you want the inventory GUI to animate when the item is removed. +## [br][i]This method is intended to be used inside a [method Popochiu.queue] of instructions.[/i] func queue_discard(animate := false) -> Callable: return func (): await discard(animate) +# NOTE: Maybe this is not necessary since we can have the same with [method remove]. +## Removes the item from the inventory (its instance will be kept in memory). Pass [param animate] +## as [code]true[/code] if you want the inventory GUI to animate when the item is removed. func discard(animate := false) -> void: _on_discard() @@ -149,33 +248,37 @@ func discard(animate := false) -> void: await remove(animate) -func set_active(ignore_block := false) -> void: +## Makes this item the current active item (the cursor will look like the item's texture). +func set_active(_ignore_block := false) -> void: #I.set_active_item(self, ignore_block) selected.emit(self) -## Called when the item is clicked in the Inventory +## Called when the item is clicked in the inventory. func on_click() -> void: _on_click() -## Called when the item is right clicked in the Inventory +## Called when the item is right clicked in the inventory. func on_right_click() -> void: _on_right_click() -## Called when the item is middle clicked in the Inventory +## Called when the item is middle clicked in the inventory. func on_middle_click() -> void: _on_middle_click() -## When the item is clicked and there is another inventory item selected +## Called when the item is clicked and there is another [param item] currently selected. func on_item_used(item: PopochiuInventoryItem) -> void: await G.show_system_text( 'Nothing happens when using %s in this item' % item.description ) +## Triggers the proper GUI command for the clicked mouse button identified with [param button_idx], +## which can be [enum MouseButton].MOUSE_BUTTON_LEFT, [enum MouseButton].MOUSE_BUTTON_RIGHT or +## [enum MouseButton].MOUSE_BUTTON_MIDDLE. func handle_command(button_idx: int) -> void: var command: String = E.get_current_command_name().to_snake_case() var suffix := "click" diff --git a/addons/popochiu/engine/objects/inventory_item/popochiu_inventory_item_data.gd b/addons/popochiu/engine/objects/inventory_item/popochiu_inventory_item_data.gd index fab468eb3..8e3beee0d 100644 --- a/addons/popochiu/engine/objects/inventory_item/popochiu_inventory_item_data.gd +++ b/addons/popochiu/engine/objects/inventory_item/popochiu_inventory_item_data.gd @@ -1,16 +1,25 @@ @icon('res://addons/popochiu/icons/inventory_item.png') class_name PopochiuInventoryItemData extends Resource +## This class is used to store information when saving and loading the game. It also ensures that +## the data remains throughout the game's execution. +## The identifier of the object used in scripts. @export var script_name := '' +## The path to the scene file to be used when adding the character to the game during runtime. @export_file("*.tscn") var scene := '' #region Virtual #################################################################################### +## Called when the game is saved. +## [i]Virtual[/i]. func _on_save() -> Dictionary: return {} +## Called when the game is loaded. The structure of [param data] is the same returned by +## [method _on_save]. +## [i]Virtual[/i]. func _on_load(_data: Dictionary) -> void: pass @@ -18,15 +27,14 @@ func _on_load(_data: Dictionary) -> void: #endregion #region Public ##################################################################################### -# Use this to save custom data for this PopochiuCharacter when saving the game. -# The Dictionary must contain only JSON supported types: bool, int, float, String. +## Use this to store custom data when saving the game. The returned [Dictionary] must contain only +## JSON supported types: [bool], [int], [float], [String]. func on_save() -> Dictionary: return _on_save() -# Called when the game is loaded. -# This Dictionary should has the same structure you defined for the returned -# one in on_save(). +## Called when the game is loaded. [param data] will have the same structure you defined for the +## returned [Dictionary] by [method _on_save]. func on_load(data: Dictionary) -> void: _on_load(data) diff --git a/addons/popochiu/engine/objects/popochiu_settings.gd b/addons/popochiu/engine/objects/popochiu_settings.gd index 826840db7..05ae3da54 100644 --- a/addons/popochiu/engine/objects/popochiu_settings.gd +++ b/addons/popochiu/engine/objects/popochiu_settings.gd @@ -1,26 +1,70 @@ @tool -extends Resource class_name PopochiuSettings +extends Resource +## Defines properties as settings for the game. -const ImporterDefaults :=\ -preload('res://addons/popochiu/engine/others/importer_defaults.gd') +## @deprecated +const ImporterDefaults := preload('res://addons/popochiu/engine/others/importer_defaults.gd') +# TODO: Deprecate this property. There is no need for this anymore since we have to GUI templates, +# and a tab dedicated to the GUI. +## A reference to the scene used as the GUI for the game. +## This will be [color=bf5a50]deprecated[/color]. @export var graphic_interface: PackedScene = null +# TODO: Deprecate this property. The TransitionLayer could be also part of the GUI tab. And we need +# a cleaner way to give devs tools to customize this. Maybe we can take a look to the +# SceneManager (https://github.com/glass-brick/Scene-Manager) plugin to see how it handles +# transitions. +## A reference to the scene used as to handle transition animations between rooms and other game +## events. +## This will be [color=bf5a50]deprecated[/color]. @export var transition_layer: PackedScene = null +## The time, in seconds, that will take the game to skip a cutscene. @export var skip_cutscene_time := 0.2 +## The text speed options that will be available in the game. In the ContextSensitive GUI you can +## loop between them usin the text speed button in the SettingsBar. @export var text_speeds := [0.1, 0.01, 0.0] +## The index of the default text speed value in [member text_speeds]. @export var default_text_speed := 0 +## If [code]true[/code], then dialog lines should auto continue once the animation that shows them +## finishes. Otherwise, players will have to click the screen in order to continue. @export var auto_continue_text := false -#@export var languages := ['en', 'es', 'es_CO'] -#@export var default_language := 0 # (int, 'en', 'es', 'co') +## When [code]true[/code] the game will call [method Object.tr] when getting the texts to show in +## the game. @export var use_translations := false +## An array with the [code]script_name[/code] of the inventory items that will be added to the +## inventory when the game starts. You can use the context menu in front of each inventory item in +## Popochiu's Main tab to add or remove items from start with the +## [img]res://addons/popochiu/icons/inventory_item_start.png[/img] [b]Start with it[/b] option. @export var items_on_start := [] +## The max number of items players will be able to put in the inventory. @export var inventory_limit := 0 +## Whether the inventory will be always visible, or players will have to do something to make it +## appear. [b]This is specific to the ContextSensitive GUI[/b]. @export var inventory_always_visible := false +## Whether the toolbar (SettingsBar) will be always visible, or players will have to do something to +## make it appear. [b]This is specific to the ContextSensitive GUI[/b]. @export var toolbar_always_visible := false +## The color the screen changes to it plays a transition (e.g. move between rooms, skip a cutscene). @export var fade_color: Color = Color.BLACK +## Whether the GUI should scale to match the native game resolution. The default GUI has a 320x180 +## resolution. @export var scale_gui := true +## The number of dialog options to show before showing a scroll bar to render those that exceed this +## limit. @export var max_dialog_options := 3 +## If [code]true[/code], the [member CanvasItem.texture_filter] of [PopochiuClickable] +## and [PopochiuInventoryItem] will be set to +## [enum CanvasItem.TextureFilter].TEXTURE_FILTER_NEAREST when those objects are created. @export var is_pixel_art_game := false +## Whether the cursor should move in whole pixels or not. @export var is_pixel_perfect := false +## The style to use in dialog lines:[br][br] +## - [b]Above Character[/b]. Makes the text appear in top of each character. You can define +## the position of if using the [b]DialoPos[/b] node in the character's scene.[br] +## - [b]Portrait[/b]. Texts will appear in a panel located in the center of the game window +## accompanied by the avatar of the character who is speaking. You can define an avatar for each +## emotion with the [member PopochiuCharacter.avatars] property.[br] +## - [b]Caption[/b]. The texts will appear at the bottom of the game window (as if they were +## subtitles). @export_enum("Above Character", "Portrait", "Caption") var dialog_style := 0 diff --git a/addons/popochiu/engine/objects/prop/popochiu_prop.gd b/addons/popochiu/engine/objects/prop/popochiu_prop.gd index 6758af86a..c3ef91009 100644 --- a/addons/popochiu/engine/objects/prop/popochiu_prop.gd +++ b/addons/popochiu/engine/objects/prop/popochiu_prop.gd @@ -2,16 +2,38 @@ @icon('res://addons/popochiu/icons/prop.png') class_name PopochiuProp extends PopochiuClickable -## Visual elements in the Room. Can have interaction. -## E.g. Background, foreground, a table, a cup, etc. - -signal linked_item_removed(node) -signal linked_item_discarded(node) - +## Visual elements in the Room that can have interaction (i.e. the background, the foreground, a +## table, a cup). +## +## When selecting a Prop in the scene tree (Scene dock), Popochiu will enable three buttons in +## the Canvas Editor Menu: Baseline, Walk to, and Interaction. This can be used to select the child +## nodes that allow to modify the position of the [member PopochiuClickable.baseline], +## the position of the [member PopochiuClickable.walk_to_point], and the position and the polygon +## points of the [b]$InteractionPolygon[/b] child. + +## Emitted when the [param item] linked to this object (by [member link_to_item]) is removed from +## the inventory. This may happen when the inventory item dissapears forever from the game. +signal linked_item_removed(item: PopochiuInventoryItem) +## Emitted when the [param item] linked to this object (by [member link_to_item]) is discarded from +## the inventory. This may happen when the inventory item dissapears forever from the game. +signal linked_item_discarded(item: PopochiuInventoryItem) + +## The image to use as the [member Sprite2D.texture] of the [b]$Sprite2D[/b] child. @export var texture: Texture2D : set = set_texture +## The number of horizontal frames this node's texture image has. Modifying this will change the +## value of the [member Sprite2D.hframes] property in the [b]$Sprite2D[/b] child. @export var frames := 1 : set = set_frames +## The number of vertical frames this node's texture image has. Modifying this will change the +## value of the [member Sprite2D.vframes] property in the [b]$Sprite2D[/b] child. @export var v_frames := 1 : set = set_v_frames -@export var current_frame := 0: set = set_current_frame # (int, 0, 99) +## The current frame to use as the texture of this node. Modifying this will change the value of the +## [member Sprite2D.frame] property in the [b]$Sprite2D[/b] child. Trying to assign a value lesser +## than 0 will make this property to be 0, and trying to assign a value higher than the number of +## total frames will make this property to be [code](frames + v_frames) - 1[/code]. +@export var current_frame := 0: set = set_current_frame +## Links the prop to a [PopochiuInventoryItem] by its [member PopochiuInventoryItem.script_name]. +## This will make the prop disappear from the room, depending on whether or not said inventory item +## is inside the inventory. @export var link_to_item := '' @onready var _sprite: Sprite2D = $Sprite2D @@ -48,10 +70,14 @@ func _ready() -> void: #endregion #region Virtual #################################################################################### +## Called when the [PopochiuInventoryItem] linked to this prop is removed from the inventory. +## [i]Virtual[/i]. func _on_linked_item_removed() -> void: pass +## Called when the [PopochiuInventoryItem] linked to this prop is discarded from the inventory. +## [i]Virtual[/i]. func _on_linked_item_discarded() -> void: pass @@ -59,10 +85,14 @@ func _on_linked_item_discarded() -> void: #endregion #region Public ##################################################################################### +## Changes the value of the [member Sprite2D.frame] property to [param new_frame] in the +## [b]$Sprite2D[/b] child. +## [br][i]This method is intended to be used inside a [method Popochiu.queue] of instructions.[/i] func queue_change_frame(new_frame: int) -> Callable: return func (): await change_frame(new_frame) - +## Changes the value of the [member Sprite2D.frame] property to [param new_frame] in the +## [b]$Sprite2D[/b] child. func change_frame(new_frame: int) -> void: self.current_frame = new_frame await get_tree().process_frame diff --git a/addons/popochiu/engine/objects/region/popochiu_region.gd b/addons/popochiu/engine/objects/region/popochiu_region.gd index 4d97c68df..9757c8e07 100644 --- a/addons/popochiu/engine/objects/region/popochiu_region.gd +++ b/addons/popochiu/engine/objects/region/popochiu_region.gd @@ -2,21 +2,30 @@ @icon('res://addons/popochiu/icons/region.png') class_name PopochiuRegion extends Area2D -# Can trigger events when the player walks checked them. Can tint the PC. -# ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ +## Used to handle events when a character walks inside or outside of it. Can also be used to scale +## characters while they walk through the region's polygon. +## +## By default, can be used to apply a tint to characters when they enter or leave the region. +## The identifier of the object used in scripts. @export var script_name := '' +## Can be used to show the name of the area to players. @export var description := '' +## Whether the region is or not enabled. @export var enabled := true : set = _set_enabled -# TODO: If walkable is false, characters should not be able to walk through this. -#export var walkable := true +## The [Color] to apply to the character that enters this region. @export var tint := Color.WHITE +## Whether the region will scale the character while it moves through it. @export var scaling :bool = false +## The scale to apply to the character inside the region when it moves to the top ([code]y[/code]) +## of it. @export var scale_top :float = 1.0 +## The scale to apply to the character inside the region when it moves to the bottom +## ([code]y[/code]) of it. @export var scale_bottom :float = 1.0 -# ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ GODOT ░░░░ +#region Godot ###################################################################################### func _ready() -> void: add_to_group('regions') @@ -26,14 +35,58 @@ func _ready() -> void: area_shape_exited.connect(_check_scaling.bind(false)) -# ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ VIRTUAL ░░░░ +#endregion + +#region Virtual #################################################################################### +## Called when a [param chr] enters this region. +## [i]Virtual[/i]. func _on_character_entered(chr: PopochiuCharacter) -> void: pass +## Called when a [param chr] leaves this region. +## [i]Virtual[/i]. func _on_character_exited(chr: PopochiuCharacter) -> void: pass + +#endregion + +#region SetGet ##################################################################################### +func _set_enabled(value: bool) -> void: + enabled = value + monitoring = value + + notify_property_list_changed() + + +#endregion + +#region Private #################################################################################### +func _check_area(area: PopochiuCharacter, entered: bool) -> void: + if area is PopochiuCharacter: + if entered: + _on_character_entered(area) + else: + _on_character_exited(area) + + +func _check_scaling( + area_rid: RID, area: Area2D, area_shape_index: int, local_shape_index: int, entered: bool +): + if ( + area is PopochiuCharacter + and area.get_node_or_null("ScalingPolygon") + and area_shape_index == area.get_node("ScalingPolygon").get_index() + ): + if entered: + if scaling: + _update_scaling_region(area) + E.current_room.update_character_scale(area) + else: + _clear_scaling_region(area) + + func _update_scaling_region(chr: PopochiuCharacter) -> void: var polygon_y_array = [] for x in get_node("InteractionPolygon").get_polygon(): @@ -62,34 +115,5 @@ func _clear_scaling_region(chr: PopochiuCharacter) -> void: if chr.on_scaling_region and chr.on_scaling_region['region_description'] == self.description: chr.on_scaling_region = {} -# ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ PRIVATE ░░░░ -func _check_scaling( - area_rid: RID, area: Area2D, area_shape_index: int, local_shape_index: int, entered: bool - ): - if ( - area is PopochiuCharacter - and area.get_node_or_null("ScalingPolygon") - and area_shape_index == area.get_node("ScalingPolygon").get_index() - ): - if entered: - if scaling: - _update_scaling_region(area) - E.current_room.update_character_scale(area) - else: - _clear_scaling_region(area) - - -func _check_area(area: PopochiuCharacter, entered: bool) -> void: - - if area is PopochiuCharacter: - if entered: - _on_character_entered(area) - else: - _on_character_exited(area) - -func _set_enabled(value: bool) -> void: - enabled = value - monitoring = value - - notify_property_list_changed() +#endregion diff --git a/addons/popochiu/engine/objects/room/popochiu_room.gd b/addons/popochiu/engine/objects/room/popochiu_room.gd index a00dcb49b..21247aa93 100644 --- a/addons/popochiu/engine/objects/room/popochiu_room.gd +++ b/addons/popochiu/engine/objects/room/popochiu_room.gd @@ -1,36 +1,63 @@ @tool -@icon('res://addons/popochiu/icons/room.png') +@icon("res://addons/popochiu/icons/room.png") class_name PopochiuRoom extends Node2D -## The scenes used by Popochiu. +## Each scene of the game. Is composed by Props, Hotspots, Regions, Markers, Walkable areas, and +## Characters. ## -## Can have: Props, Hotspots, Regions, Markers and -## Walkable areas. Characters can move through this and interact with its Props -## and Hotspots. Regions can be used to trigger methods when a character enters -## or leaves. +## Characters can move through it in the spaces defined by walkable areas, interact with its props +## and hotspots, react to its regions, and move to its markers. -@export var script_name := '' +## The identifier of the object used in scripts. +@export var script_name := "" +## Whether this room should add the Player-controlled Character (PC) to its [b]$Characters[/b] node +## when the room is loaded. @export var has_player := true +## If [code]true[/code] the whole GUI will be hidden when the room is loaded. Useful for cutscenes, +## splash screens and when showing game menus or popups. @export var hide_gi := false @export_category("Camera limits") +## If this different from [constant INF], the value will define the left limit of the camera +## relative to the native game resolution. I.e. if your native game resolution is 320x180, and the +## background (size) of the room is 448x180, the left limit of the camera should be -64 (this is the +## difference between 320 and 448). +## [br][br][i]Set this on rooms that are bigger than the native game resolution so the camera will +## follow the character.[/i] @export var limit_left := INF +## If this different from [constant INF], the value will define the right limit of the camera +## relative to the native game resolution. I.e. if your native game resolution is 320x180, and the +## background (size) of the room is 448x180, the right limit of the camera should be 384 (320 + 64 +## (this is the difference between 320 and 448)). +## [br][br][i]Set this on rooms that are bigger than the native game resolution so the camera will +## follow the character.[/i] @export var limit_right := INF +## If this different from [constant INF], the value will define the top limit of the camera +## relative to the native game resolution. +## [br][br][i]Set this on rooms that are bigger than the native game resolution so the camera will +## follow the character.[/i] @export var limit_top := INF +## If this different from [constant INF], the value will define the bottom limit of the camera +## relative to the native game resolution. +## [br][br][i]Set this on rooms that are bigger than the native game resolution so the camera will +## follow the character.[/i] @export var limit_bottom := INF +# This category is used by the Aseprite Importer in order to allow the creation of a section in the +# Inspector for it. @export_category("Aseprite") +## Whether this is the room in which players are. When [code]true[/code], the room starts processing +## unhandled inputs. var is_current := false : set = set_is_current var _nav_path: PopochiuWalkableArea = null -## It contains the information of the characters moving around the room.[br] -## Each entry has the form: -## [codeblock] -## PopochiuCharacter.ID: int = { -## character: PopochiuCharacter, -## path: PackedVector2Array -## } -## [/codeblock] +# It contains the information of the characters moving around the room. Each entry has the form: +# PopochiuCharacter.ID: int = { +# character: PopochiuCharacter, +# path: PackedVector2Array +# } var _moving_characters := {} +# Stores the childrens defined in the Editor"s Scene tree for each character inside $Characters to +# add them to the corresponding PopochiuCharacter instance when the room is loaded in runtime. var _characters_childs := {} @@ -51,8 +78,8 @@ func _enter_tree() -> void: func _ready(): if Engine.is_editor_hint(): return - if not get_tree().get_nodes_in_group('walkable_areas').is_empty(): - _nav_path = get_tree().get_nodes_in_group('walkable_areas')[0] + if not get_tree().get_nodes_in_group("walkable_areas").is_empty(): + _nav_path = get_tree().get_nodes_in_group("walkable_areas")[0] NavigationServer2D.map_set_active(_nav_path.map_rid, true) set_process_unhandled_input(false) @@ -90,12 +117,12 @@ func _unhandled_input(event): if not has_player: return if I.active: - if event.is_action_released('popochiu-look')\ - or event.is_action_pressed('popochiu-interact'): + if event.is_action_released("popochiu-look")\ + or event.is_action_pressed("popochiu-interact"): I.set_active_item() return - if not event.is_action_pressed('popochiu-interact'): + if not event.is_action_pressed("popochiu-interact"): return if is_instance_valid(C.player) and C.player.can_move: @@ -105,33 +132,27 @@ func _unhandled_input(event): #endregion #region Virtual #################################################################################### -## What happens when Popochiu loads the room. At this point the room is in the tree but it is not -## visible. +## Called when Popochiu loads the room. At this point the room is in the tree but it is not visible. func _on_room_entered() -> void: pass -## What happens when the room changing transition finishes. At this point the room is visible. +## Called when the room-changing transition finishes. At this point the room is visible. func _on_room_transition_finished() -> void: pass -## What happens before Popochiu unloads the room. At this point the room is in the tree but it is -## not visible, it is not processing and has no childs in the $Characters node. +## Called before Popochiu unloads the room. At this point the room is in the tree but it is not +## visible, it is not processing inputs, and has no childrens in the [b]$Characters[/b] node. func _on_room_exited() -> void: pass -# TODO: Make this to work and then add it to RoomTemplate.gd -func _on_entered_from_editor() -> void: - pass - - #endregion #region Public ##################################################################################### -## This function is called by Popochiu before moving the PC to another room. By default, characters -## are removed only to keep their instances in the array of characters in ICharacter.gd. +## Called by Popochiu before moving the Player-controlled Character (PC) to another room. +## By default, characters are only removed (not deleted) to keep their instances in memory. func exit_room() -> void: set_physics_process(false) @@ -147,6 +168,10 @@ func exit_room() -> void: _on_room_exited() +## Adds the instance (in memory) of [param chr] to the [b]$Characters[/b] node and connects to its +## [signal PopochiuCharacter.started_walk_to] and [signal PopochiuCharacter.stoped_walk] signals. +## It also adds to it any children of the character in the Editor"s Scene tree. The [b]idle[/b] +## animation is triggered. func add_character(chr: PopochiuCharacter) -> void: $Characters.add_child(chr) @@ -162,19 +187,23 @@ func add_character(chr: PopochiuCharacter) -> void: if chr.follow_player: C.player.started_walk_to.connect(_follow_player.bind(chr)) - + chr.idle() +## Removes [param chr] the [b]$Characters[/b] node without destroying it. func remove_character(chr: PopochiuCharacter) -> void: $Characters.remove_child(chr) +## Hides all its [PopochiuProp]s. func hide_props() -> void: - for p in $Props.get_children(): - p.hide() + for prop: PopochiuProp in get_props(): + prop.hide() +## Checks if the [PopochiuCharacter], whose property [member PopochiuCharacter.script_name] matches +## [param character_name], is inside the [b]$Characters[/b] node. func has_character(character_name: String) -> bool: var result := false @@ -186,6 +215,7 @@ func has_character(character_name: String) -> bool: return result +## Called by Popochiu when loading the room to assign its camera limits to the player camera. func setup_camera() -> void: if limit_left != INF: E.main_camera.limit_left = limit_left @@ -197,6 +227,8 @@ func setup_camera() -> void: E.main_camera.limit_bottom = limit_bottom +## Remove all children from the [b]$Characters[/b] node, storing the children of each node to later +## assign them to the corresponding [PopochiuCharacter] when the room is loaded. func clean_characters() -> void: for c in $Characters.get_children(): if not c is PopochiuCharacter: continue @@ -212,31 +244,33 @@ func clean_characters() -> void: c.queue_free() -func update_character_scale(chr): +## Updates the scale of [param chr] depending on the properties of the scaling region where it is +## located. +func update_character_scale(chr: PopochiuCharacter): if chr.on_scaling_region: var polygon_range = ( - chr.on_scaling_region['polygon_bottom_y'] - chr.on_scaling_region['polygon_top_y'] + chr.on_scaling_region["polygon_bottom_y"] - chr.on_scaling_region["polygon_top_y"] ) var scale_range = ( - chr.on_scaling_region['scale_bottom'] - chr.on_scaling_region['scale_top'] + chr.on_scaling_region["scale_bottom"] - chr.on_scaling_region["scale_top"] ) var position_from_the_top_of_region = ( - chr.position.y-chr.on_scaling_region['polygon_top_y'] + chr.position.y-chr.on_scaling_region["polygon_top_y"] ) var scale_for_position = ( - chr.on_scaling_region['scale_top']+( + chr.on_scaling_region["scale_top"]+( scale_range/polygon_range*position_from_the_top_of_region ) ) chr.scale.x = [ - [scale_for_position, chr.on_scaling_region['scale_min']].max(), - chr.on_scaling_region['scale_max'] + [scale_for_position, chr.on_scaling_region["scale_min"]].max(), + chr.on_scaling_region["scale_max"] ].min() chr.scale.y = [ - [scale_for_position, chr.on_scaling_region['scale_min']].max(), - chr.on_scaling_region['scale_max'] + [scale_for_position, chr.on_scaling_region["scale_min"]].max(), + chr.on_scaling_region["scale_max"] ].min() chr.walk_speed = chr.default_walk_speed/chr.default_scale.x*scale_for_position else: @@ -244,7 +278,8 @@ func update_character_scale(chr): chr.walk_speed = chr.default_walk_speed -func update_characters_position(character): +## Updates the position of [param character] in the room, and then updates its scale. +func update_characters_position(character: PopochiuCharacter): character.position = ( character.position_stored if character.position_stored @@ -253,82 +288,98 @@ func update_characters_position(character): update_character_scale(character) -#endregion - -#region SetGet ##################################################################################### +## Returns the [Marker2D] which [member Node.name] matches [param marker_name]. func get_marker(marker_name: String) -> Marker2D: - var marker: Marker2D = get_node_or_null('Markers/' + marker_name) + var marker: Marker2D = get_node_or_null("Markers/" + marker_name) if marker: return marker - printerr('[Popochiu] Marker %s not found' % marker_name) + PopochiuUtils.print_error("Marker %s not found" % marker_name) return null +## Returns the [b]global position[/b] of the [Marker2D] which [member Node.name] matches +## [param marker_name]. func get_marker_position(marker_name: String) -> Vector2: var marker := get_marker(marker_name) return marker.global_position if marker != null else Vector2.ZERO +## Returns the [PopochiuProp] which [member PopochiuClickable.script_name] matches +## [param prop_name]. func get_prop(prop_name: String) -> PopochiuProp: - for p in get_tree().get_nodes_in_group('props'): + for p in get_tree().get_nodes_in_group("props"): if p.script_name == prop_name or p.name == prop_name: return p as PopochiuProp - printerr('[Popochiu] Prop %s not found' % prop_name) + PopochiuUtils.print_error("Prop %s not found" % prop_name) return null +## Returns the [PopochiuHotspot] which [member PopochiuClickable.script_name] matches +## [param hotspot_name]. func get_hotspot(hotspot_name: String) -> PopochiuHotspot: - for h in get_tree().get_nodes_in_group('hotspots'): + for h in get_tree().get_nodes_in_group("hotspots"): if h.script_name == hotspot_name or h.name == hotspot_name: return h - printerr('[Popochiu] Hotspot %s not found' % hotspot_name) + PopochiuUtils.print_error("Hotspot %s not found" % hotspot_name) return null +## Returns the [PopochiuRegion] which [member PopochiuRegion.script_name] matches +## [param region_name]. func get_region(region_name: String) -> PopochiuRegion: - for r in get_tree().get_nodes_in_group('regions'): + for r in get_tree().get_nodes_in_group("regions"): if r.script_name == region_name or r.name == region_name: return r - printerr('[Popochiu] Region %s not found' % region_name) + PopochiuUtils.print_error("Region %s not found" % region_name) return null +## Returns the [PopochiuWalkableArea] which [member PopochiuWalkableArea.script_name] matches +## [param walkable_area_name]. func get_walkable_area(walkable_area_name: String) -> PopochiuWalkableArea: - for wa in get_tree().get_nodes_in_group('walkable_areas'): + for wa in get_tree().get_nodes_in_group("walkable_areas"): if wa.name == walkable_area_name: return wa - printerr('[Popochiu] Walkable area %s not found' % walkable_area_name) + PopochiuUtils.print_error("Walkable area %s not found" % walkable_area_name) return null +## Returns all the [PopochiuProp]s in the room. func get_props() -> Array: - return get_tree().get_nodes_in_group('props') + return get_tree().get_nodes_in_group("props") +## Returns all the [PopochiuHotspot]s in the room. func get_hotspots() -> Array: - return get_tree().get_nodes_in_group('hotspots') + return get_tree().get_nodes_in_group("hotspots") +## Returns all the [PopochiuRegion]s in the room. func get_regions() -> Array: - return get_tree().get_nodes_in_group('regions') + return get_tree().get_nodes_in_group("regions") +## Returns all the [Marker2D]s in the room. func get_markers() -> Array: return $Markers.get_children() +## Returns all the [PopochiuWalkableArea]s in the room. func get_walkable_areas() -> Array: - return get_tree().get_nodes_in_group('walkable_areas') + return get_tree().get_nodes_in_group("walkable_areas") +## Returns the current active [PopochiuWalkableArea]. func get_active_walkable_area() -> PopochiuWalkableArea: return _nav_path +## Returns the [member PopochiuWalkableArea.script_name] of current active [PopochiuWalkableArea]. func get_active_walkable_area_name() -> String: return _nav_path.script_name +## Returns all the [PopochiuCharacter]s in the room. func get_characters() -> Array: var characters := [] @@ -339,23 +390,27 @@ func get_characters() -> Array: return characters +## Returns the number of characters in the room. func get_characters_count() -> int: return $Characters.get_child_count() -func set_is_current(value: bool) -> void: - is_current = value - set_process_unhandled_input(is_current) - - +## Sets as active the [PopochiuWalkableArea] which [member Node.name] matches +## [param walkable_area_name]. func set_active_walkable_area(walkable_area_name: String) -> void: var active_walkable_area = $WalkableAreas.get_node(walkable_area_name) if active_walkable_area != null: _nav_path = active_walkable_area else: - printerr( - "[Popochiu] Can't set %s as active walkable area" % walkable_area_name - ) + PopochiuUtils.print_error("Can't set %s as active walkable area" % walkable_area_name) + + +#endregion + +#region SetGet ##################################################################################### +func set_is_current(value: bool) -> void: + is_current = value + set_process_unhandled_input(is_current) #endregion @@ -406,7 +461,7 @@ func _update_navigation_path( character: PopochiuCharacter, start_position: Vector2, end_position: Vector2 ): if not _nav_path: - printerr('[Popochiu] No walkable areas in this room') + PopochiuUtils.print_error("No walkable areas in this room") return _moving_characters[character.get_instance_id()] = {} @@ -444,7 +499,7 @@ func _update_navigation_path( func _clear_navigation_path(character: PopochiuCharacter) -> void: - # INFO: fixes 'function signature missmatch in Web export' error thrown when + # INFO: fixes "function signature missmatch in Web export" error thrown when # clearing an empty Array. if not _moving_characters.has(character.get_instance_id()): return diff --git a/addons/popochiu/engine/objects/room/popochiu_room.tscn b/addons/popochiu/engine/objects/room/popochiu_room.tscn index cb0109f75..74b643deb 100644 --- a/addons/popochiu/engine/objects/room/popochiu_room.tscn +++ b/addons/popochiu/engine/objects/room/popochiu_room.tscn @@ -4,6 +4,7 @@ [node name="Room" type="Node2D"] script = ExtResource("1") +popochiu_placeholder = null [node name="WalkableAreas" type="Node2D" parent="."] diff --git a/addons/popochiu/engine/objects/room/popochiu_room_data.gd b/addons/popochiu/engine/objects/room/popochiu_room_data.gd index 2eda93ea4..b4ad712b1 100644 --- a/addons/popochiu/engine/objects/room/popochiu_room_data.gd +++ b/addons/popochiu/engine/objects/room/popochiu_room_data.gd @@ -1,25 +1,46 @@ @icon('res://addons/popochiu/icons/room.png') class_name PopochiuRoomData extends Resource +## This class is used to store information when saving and loading the game. It also ensures that +## the data remains throughout the game's execution. +## +## It also has data of the [PopochiuProp]s, [PopochiuHotspot]s, [PopochiuWalkableArea]s, +## [PopochiuRegion]s, and [PopochiuCharacter]s in a [PopochiuRoom]. +## The identifier of the object used in scripts. @export var script_name := '' +## The path to the scene file to be used when adding the character to the game during runtime. @export_file("*.tscn") var scene := '' +## Whether the room was already visited by the player. @export var visited := false +## Whether this is the first time the player visits the room. @export var visited_first_time := false +## The number of times the player has visited this room. @export var visited_times := 0 +## Stores data about the [PopochiuProp]s in the room. var props := {} +## Stores data about the [PopochiuHotspot]s in the room. var hotspots := {} +## Stores data about the [PopochiuWalkableArea]s in the room. var walkable_areas := {} +## Stores data about the [PopochiuRegion]s in the room. var regions := {} +## Stores data about the [PopochiuCharacter]s in the room. To see the stored data by default, check +## [method save_characters]. var characters := {} #region Virtual #################################################################################### +## Called when the game is saved. +## [i]Virtual[/i]. func _on_save() -> Dictionary: return {} +## Called when the game is loaded. The structure of [param data] is the same returned by +## [method _on_save]. +## [i]Virtual[/i]. func _on_load(_data: Dictionary) -> void: pass @@ -27,19 +48,20 @@ func _on_load(_data: Dictionary) -> void: #endregion #region Public ##################################################################################### -# Use this to save custom data for this PopochiuRoom when saving the game. -# The Dictionary must contain only JSON supported types: bool, int, float, String. +## Use this to store custom data when saving the game. The returned [Dictionary] must contain only +## JSON supported types: [bool], [int], [float], [String]. func on_save() -> Dictionary: return _on_save() -# Called when the game is loaded. -# This Dictionary should has the same structure you defined for the returned -# one in on_save(). +## Called when the game is loaded. [param data] will have the same structure you defined for the +## returned [Dictionary] by [method _on_save]. func on_load(data: Dictionary) -> void: _on_load(data) +## Stores the data of each of the childrens inside [b]$WalkableAreas[/b], [b]$Props[/b], +## [b]$Hotspots[/b], [b]$Regions[/b], and [b]$Characters[/b]. func save_childs_states() -> void: if E.current_room and E.current_room.state == self: for t in PopochiuResources.ROOM_CHILDS: @@ -103,6 +125,16 @@ func save_childs_states() -> void: folder_name = dir.get_next() +## Save room data related to the characters in the room. The stored data contains: +## [codeblock]{ +## x = PopochiuCharacter.position.x +## y = PopochiuCharacter.position.y +## facing = PopochiuCharacter._looking_dir +## visible = PopochiuCharacter.visible +## modulate = PopochiuCharacter.modulate +## self_modulate = PopochiuCharacter.self_modulate +## light_mask = PopochiuCharacter.light_mask +## }[/codeblock] func save_characters() -> void: for c in E.current_room.get_characters(): var pc: PopochiuCharacter = c diff --git a/addons/popochiu/engine/objects/transition_layer/transition_layer.gd b/addons/popochiu/engine/objects/transition_layer/transition_layer.gd index 4405f34a5..bdf551a41 100644 --- a/addons/popochiu/engine/objects/transition_layer/transition_layer.gd +++ b/addons/popochiu/engine/objects/transition_layer/transition_layer.gd @@ -1,5 +1,8 @@ -extends Node2D class_name PopochiuTransitionLayer +extends Node2D +## Used to play different transition animations when moving between rooms, skipping a cutscene, +## and so on. + # warning-ignore-all:return_value_discarded signal transition_finished(transition_name) diff --git a/addons/popochiu/engine/objects/walkable_area/popochiu_walkable_area.gd b/addons/popochiu/engine/objects/walkable_area/popochiu_walkable_area.gd index 39345a11d..d781f844f 100644 --- a/addons/popochiu/engine/objects/walkable_area/popochiu_walkable_area.gd +++ b/addons/popochiu/engine/objects/walkable_area/popochiu_walkable_area.gd @@ -2,26 +2,34 @@ @icon('res://addons/popochiu/icons/walkable_area.png') class_name PopochiuWalkableArea extends Node2D -# Areas players can walk upon. -# No specific behavior at the moment, the area is defined by a polygon. -# ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ +## The areas where characters can move. +## +## The area is defined by a [NavigationRegion2D]. +## The identifier of the object used in scripts. @export var script_name := '' +## Can be used to show the name of the area to players. @export var description := '' +## Whether the area is or not enabled. @export var enabled := true : set = _set_enabled # TODO: If walkable is false, characters should not be able to walk through this. -#export var walkable := true -@export var tint := Color.WHITE +#@export var walkable := true +# TODO: Make the value of the tint property to modify the modulate color of the polygon (or the +# modulate of the node itself). +#@export var tint := Color.WHITE # TODO: Make the scale of the character change depending checked where it is placed in -# this walkable area. -#export var scale_top := 1.0 -#export var scale_bottom := 1.0 +# this walkable area. +#@export var scale_top := 1.0 +#@export var scale_bottom := 1.0 +## Property used by [PopochiuRoom]s to activate the map of this area in the [NavigationServer2D]. var map_rid: RID +## Used to assign a map in the [NavigationServer2D] to the region RID of the [b]$Perimeter[/b] +## child. var rid: RID -# ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ GODOT ░░░░ +#region Godot ###################################################################################### func _ready() -> void: add_to_group('walkable_areas') @@ -38,7 +46,12 @@ func _exit_tree(): NavigationServer2D.map_set_active(map_rid, false) -# ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ PUBLIC ░░░░ +#endregion + +#region SetGet ##################################################################################### func _set_enabled(value: bool) -> void: enabled = value notify_property_list_changed() + + +#endregion diff --git a/addons/popochiu/engine/others/popochiu_save_load.gd b/addons/popochiu/engine/others/popochiu_save_load.gd index 2ccd06711..ee7bb3454 100644 --- a/addons/popochiu/engine/others/popochiu_save_load.gd +++ b/addons/popochiu/engine/others/popochiu_save_load.gd @@ -1,8 +1,9 @@ -# Class for saving and loading game data. -# -# Thanks GDQuest for this! ↴↴↴ -# https://github.com/GDQuest/godot-demos-2022/tree/main/save-game +class_name PopochiuSaveLoad extends Resource +## Class that allows to save and load game data. +## +## Thanks GDQuest for this! ↴↴↴ +## https://github.com/GDQuest/godot-demos-2022/tree/main/save-game # TODO: This could be in PopochiuSettings for devs to change the path const SAVE_GAME_PATH := 'user://save_%d.json' diff --git a/addons/popochiu/engine/popochiu.gd b/addons/popochiu/engine/popochiu.gd index 1b04f7aac..4e72de42a 100644 --- a/addons/popochiu/engine/popochiu.gd +++ b/addons/popochiu/engine/popochiu.gd @@ -1,59 +1,123 @@ +class_name Popochiu extends Node -## (E) Popochiu's core -## It is the system main class, and is in charge of a making the game to work. - +## This is Popochiu's main class, and is in charge of making the game to work. +## +## Is the shortcut for [b]Popochiu.gd[/b], and can be used (from any script) with [b]E[/b] (E.g. +## [code]E.goto_room("House")[/code]). +## +## Some things you can do with it: +## - Change to another room. +## - Access the main camera and some game settings. +## - Run commands sequentialy (even in a form that makes the skippable). +## - Use some utility methods (such as making a function of yours able to be in a run queue). +## +## Examples +## [codeblock] +## # Makes the player-controlled character say "Hi", wait a second, and then say another thing +## E.queue([ +## "Player: Hi", +## "...", +## "Player: I'm the character you can control!!!", +## ]) +## # Make the camera shake with a strength of 2.0 during 3.0 seconds +## E.camera_shake(2.0, 3.0) +## [/codeblock] + +## Emitted when the text speed changes in [PopochiuSettings]. signal text_speed_changed +## Emitted when the language changes in [PopochiuSettings]. signal language_changed +## Emitted after [method save_game] saves a file with the current game data. signal game_saved -signal game_loaded(data) +## Emitted by [method room_readied] when stored game [param data] is loaded for the current room. +signal game_loaded(data: Dictionary) +## Emitted when [member current_command] changes. Can be used to know the active command for the +## current GUI template. signal command_selected +## Emitted when the dialog style changes in [PopochiuSettings]. signal dialog_style_changed +## Path to the script with the class used to save and load game data. const SAVELOAD_PATH := 'res://addons/popochiu/engine/others/popochiu_save_load.gd' -## Used to prevent going to another room when there is one being loaded +## Used to prevent going to another room when there is one being loaded. var in_room := false : set = _set_in_room +## Stores a reference to the current [PopochiuRoom]. var current_room: PopochiuRoom -## Stores the las PopochiuClickable node clicked to ease access to it from -## any other class +## Stores the last clicked [PopochiuClickable] node to ease access to it from any other class. var clicked: PopochiuClickable = null +## Stores the last hovered [PopochiuClickable] node to ease access to it from any other class. var hovered: PopochiuClickable = null : get = get_hovered, set = set_hovered +## Used to know if a cutscene was skipped. +## A reference to [PopochiuSettings]. Can be used to quickly access its members. +var settings := PopochiuResources.get_settings() +## Reference to the [PopochiuAudioManager]. +var am: PopochiuAudioManager = null +# NOTE: This might not just be a boolean, but there could be an array that puts +# the calls to queue in an Array and executes them in order. Or perhaps it could +# be something that allows for more dynamism, such as putting one queue to execute +# during the execution of another one. +## Indicates if the game is playing a queue of instructions. +var playing_queue := false +## Reference to the [PopochiuGraphicInterface]. +var gi: PopochiuGraphicInterface = null +## Reference to the [PopochiuTransitionLayer]. +var tl: Node2D = null +## The current class used as the game commands var cutscene_skipped := false +## Stores the state of each [PopochiuRoom] in the game. The key of each room is its +## [member PopochiuRoom.script_name], and each value is a [Dictionary] with its properties and the +## data of all its [PopochiuProp]s, [PopochiuHotspot]s, [PopochiuWalkableArea]s, [PopochiuRegion]s, +## and some data related with the [PopochiuCharacter]s in it. For more info about the data stored, +## check the documentation for [PopochiuRoomData]. var rooms_states := {} +## Stores the state of each [PopochiuDialog] in the game. The key of each dialog is its +## [member PopochiuDialog.script_name]. For more info about the stored data, check [PopochiuDialog]. var dialog_states := {} +## Stores a list of game events (triggered actions and dialog lines). Each event is defined by a +## [Dictionary]. var history := [] +## The width, in pixels, of the game native resolution +## (that is [code]get_viewport().get_visible_rect().end.x[/code]). var width := 0.0 : get = get_width +## The height, in pixels, of the game native resolution +## (that is [code]get_viewport().get_visible_rect().end.y[/code]). var height := 0.0 : get = get_height +## [member width] divided by 2. var half_width := 0.0 : get = get_half_width +## [member height] divided by 2. var half_height := 0.0 : get = get_half_height -var settings := PopochiuResources.get_settings() +## Used to access the value of the current text speed. The possible text speed values are stored +## in the [member PopochiuSettings.text_speeds] [Array], so this property has the index of the +## speed being used by the game. var current_text_speed_idx := settings.default_text_speed +## The text speed being used by the game. When this property changes, the +## [signal text_speed_changed] signal is emitted. var current_text_speed: float = settings.text_speeds[current_text_speed_idx] : set = set_current_text_speed -var current_language := 0 +## The number of seconds to wait before moving to the next dialog line (when playing dialog lines +## triggered inside a [method queue]. var auto_continue_after := -1.0 +## The current dialog style used by the game. When this property changes, the +## [signal dialog_style_changed] signal is emitted. var current_dialog_style := settings.dialog_style : set = set_dialog_style +## The scale value of the game. Defined by the native game resolution compared with (320, 180), +## which is the default game resolution defined by Popochiu. var scale := Vector2.ONE -var am: PopochiuAudioManager = null -# TODO: This might not just be a boolean, but there could be an array that puts -# the calls to queue in an Array and executes them in order. Or perhaps it could -# be something that allows for more dynamism, such as putting one queue to execute -# during the execution of another queue -var playing_queue := false -var gi: PopochiuGraphicInterface = null -var tl: Node2D = null -## The current class used as the game commands -## (i.e. NineVerbsCommands, SierraCommands, and so on) +## A reference to the current commands script. +## (i.e. [NineVerbCommands], [SierraCommands] or [SimpleClickCommands]) var commands: PopochiuCommands = null +## Serves as a map to access the fallback methods of the current GUI. var commands_map := { -1: { "name" = "fallback", fallback = _command_fallback } } +## The ID of the current active command in the GUI. When this property changes, the +## [signal command_selected] signal is emitted. var current_command := -1 : set = set_current_command -# TODO: This could be in the camera's own script var _is_camera_shaking := false var _camera_shake_amount := 15.0 var _shake_timer := 0.0 @@ -61,10 +125,13 @@ var _use_transition_on_room_change := true var _config: ConfigFile = null var _loaded_game := {} var _hovered_queue := [] +# Will have the instance of the PopochiuSaveLoad class in order to call the methods that save and +# load the game. var _saveload: Resource = null -@onready var _tween: Tween = null +## A reference to the game [Camera2D]. @onready var main_camera: Camera2D = find_child('MainCamera') +@onready var _tween: Tween = null @onready var _defaults := { camera_limits = { left = main_camera.limit_left, @@ -178,14 +245,14 @@ func _process(delta: float) -> void: if _shake_timer <= 0.0: stop_camera_shake() elif ( - not Engine.is_editor_hint() - and is_instance_valid(C.camera_owner) - and C.camera_owner.is_inside_tree() + not Engine.is_editor_hint() + and is_instance_valid(C.camera_owner) + and C.camera_owner.is_inside_tree() ): main_camera.position = ( - C.camera_owner.position_stored - if C.camera_owner.position_stored - else C.camera_owner.position + C.camera_owner.position_stored + if C.camera_owner.position_stored + else C.camera_owner.position ) @@ -198,23 +265,23 @@ func _input(event: InputEvent) -> void: ) await tl.transition_finished - - #G.continue_clicked.emit() func _unhandled_key_input(event: InputEvent) -> void: - # TODO: Capture keys for debugging or for triggering game signals that can - # ease tests + # TODO: Capture keys for debugging or for triggering game signals that can ease tests pass #endregion #region Public ##################################################################################### +## Creates a delay timer that will last [param time] seconds. This method is intended to be used +## inside a [method queue] of instructions. func queue_wait(time := 1.0) -> Callable: return func (): await wait(time) +## Creates a delay timer that will last [param time] seconds. func wait(time := 1.0) -> void: if cutscene_skipped: await get_tree().process_frame @@ -228,7 +295,7 @@ func wait(time := 1.0) -> void: # pass -## Executes a series of instructions one by one. show_gi determines if the +## Executes an array of [param instructions] one by one. [param show_gi] determines if the ## Graphic Interface will appear once all instructions have ran. func queue(instructions: Array, show_gi := true) -> void: if instructions.is_empty(): @@ -264,7 +331,9 @@ func queue(instructions: Array, show_gi := true) -> void: playing_queue = false -## Like queue, but can be skipped with the input action: popochiu-skip. +## Like [method queue], but [param instructions] can be skipped with the input action: +## [code]popochiu-skip[/code] (see [b]Project Settings... > Input Map[/b]). By default you can skip +## a cutscene with the [kbd]ESC[/kbd] key. func cutscene(instructions: Array) -> void: set_process_input(true) await queue(instructions) @@ -280,8 +349,11 @@ func cutscene(instructions: Array) -> void: cutscene_skipped = false -## Loads the room with script_name. use_transition can be used to trigger a fade -## out animation before loading the room, and a fade in animation once it is ready +## Loads the room with [param script_name]. [param use_transition] can be used to trigger a [i]fade +## out[/i] animation before loading the room, and a [i]fade in[/i] animation once it is ready. +## If [param store_state] is [code]true[/code] the state of the room will be stored in memory. +## [param ignore_change] is used internally by Popochiu to know if it's the first time the room is +## loaded when starting the game. func goto_room( script_name := '', use_transition := true, @@ -333,7 +405,7 @@ func goto_room( get_tree().change_scene_to_file(load(rp).scene) -## Called once the loaded room is _ready +## Called once the loaded [param room] is "ready" ([method Node._ready]). func room_readied(room: PopochiuRoom) -> void: current_room = room @@ -346,9 +418,9 @@ func room_readied(room: PopochiuRoom) -> void: self.in_room = true - # Calling this will make the camera be set to its default values and - # will store the state of the main room (the last parameter will prevent - # Popochiu from changing the scene to the same that is already loaded + # Calling this will make the camera be set to its default values and will store the state of + # the main room (the last parameter will prevent Popochiu from changing the scene to the + # same that is already loaded) goto_room(room.script_name, false, true, true) # Make the camera be ready for the room @@ -386,8 +458,8 @@ func room_readied(room: PopochiuRoom) -> void: current_room.add_character(chr) - # If the room must have the player character but it is not part of its - # $Characters node, add it to the room + # If the room must have the player character but it is not part of its $Characters node, then + # add the PopochiuCharacter to the room if current_room.has_player and is_instance_valid(C.player): if not current_room.has_character(C.player.script_name): current_room.add_character(C.player) @@ -444,22 +516,26 @@ func room_readied(room: PopochiuRoom) -> void: current_room._on_room_transition_finished() +## Changes the main camera's offset by [param offset] pixels. This method is intended to be used +## inside a [method queue] of instructions. func queue_camera_offset(offset := Vector2.ZERO) -> Callable: return func (): await camera_offset(offset) -## Changes the main camera's offset (useful when zooming the camera) +## Changes the main camera's offset by [param offset] pixels. Useful when zooming the camera. func camera_offset(offset := Vector2.ZERO) -> void: main_camera.offset = offset await get_tree().process_frame +## Makes the camera shake with [param strength] during [param duration] seconds. This method is +## intended to be used inside a [method queue] of instructions. func queue_camera_shake(strength := 1.0, duration := 1.0) -> Callable: return func (): await camera_shake(strength, duration) -## Makes the camera shake with `strength` for `duration` seconds +## Makes the camera shake with [param strength] during [param duration] seconds. func camera_shake(strength := 1.0, duration := 1.0) -> void: _camera_shake_amount = strength _shake_timer = duration @@ -468,12 +544,15 @@ func camera_shake(strength := 1.0, duration := 1.0) -> void: await get_tree().create_timer(duration).timeout +## Makes the camera shake with [param strength] during [param duration] seconds without blocking +## excecution (that means it runs in the background). This method is intended to be used inside a +## [method queue] of instructions. func queue_camera_shake_bg(strength := 1.0, duration := 1.0) -> Callable: return func (): await camera_shake_bg(strength, duration) -## Makes the camera shake with `strength` for `duration` seconds without blocking -## excecution (a.k.a. in the background) +## Makes the camera shake with [param strength] during [param duration] seconds without blocking +## excecution (that means it runs in the background). func camera_shake_bg(strength := 1.0, duration := 1.0) -> void: _camera_shake_amount = strength _shake_timer = duration @@ -482,13 +561,17 @@ func camera_shake_bg(strength := 1.0, duration := 1.0) -> void: await get_tree().process_frame +## Changes the camera zoom. If [param target] is greater than [code]Vector2(1, 1)[/code] the camera +## will [b]zoom out[/b], smaller values will make it [b]zoom in[/b]. The effect will last +## [param duration] seconds. This method is intended to be used inside a [method queue] of +## instructions. func queue_camera_zoom(target := Vector2.ONE, duration := 1.0) -> Callable: return func (): await camera_zoom(target, duration) -## Changes the camera zoom. If `target` is larger than Vector2(1, 1) the camera -## will zoom out, smaller values make it zoom in. The effect will last `duration` -## seconds +## Changes the camera zoom. If [param target] is greater than [code]Vector2(1, 1)[/code] the camera +## will [b]zoom out[/b], smaller values will make it [b]zoom in[/b]. The effect will last +## [param duration] seconds. func camera_zoom(target := Vector2.ONE, duration := 1.0) -> void: if is_instance_valid(_tween) and _tween.is_running(): _tween.kill() @@ -500,12 +583,14 @@ func camera_zoom(target := Vector2.ONE, duration := 1.0) -> void: await _tween.finished -## Returns a String of a text that could be a position key +## Returns [param msg] translated to the current language if the game is using translations +## [member PopochiuSettings.use_translations]. Otherwise, the returned [String] will be the same +## as the one received as a parameter. func get_text(msg: String) -> String: return tr(msg) if settings.use_translations else msg -## Gets the PopochiuCharacter with script_name +## Gets the instance of the [PopochiuCharacter] identified with [param script_name]. func get_character_instance(script_name: String) -> PopochiuCharacter: for rp in PopochiuResources.get_section('characters'): var popochiu_character: PopochiuCharacterData = load(rp) @@ -516,7 +601,7 @@ func get_character_instance(script_name: String) -> PopochiuCharacter: return null -## Gets the PopochiuInventoryItem with script_name +## Gets the instance of the [PopochiuInventoryItem] identified with [param script_name]. func get_inventory_item_instance(script_name: String) -> PopochiuInventoryItem: for rp in PopochiuResources.get_section('inventory_items'): var popochiu_inventory_item: PopochiuInventoryItemData = load(rp) @@ -527,7 +612,7 @@ func get_inventory_item_instance(script_name: String) -> PopochiuInventoryItem: return null -## Gets the PopochiuDialog with script_name +## Gets the instance of the [PopochiuDialog] identified with [param script_name]. func get_dialog(script_name: String) -> PopochiuDialog: for rp in PopochiuResources.get_section('dialogs'): var tree: PopochiuDialog = load(rp) @@ -538,26 +623,88 @@ func get_dialog(script_name: String) -> PopochiuDialog: return null -## Adds an action to the history of actions. -## Look PopochiuClickable._unhandled_input or GraphicInterface._show_dialog_text -## for examples. +## Adds an action, represented by [param data], to the [member history] of actions. +## The structure that [param data] can have may be in the form: +## [codeblock]# To store the Look At interaction with the prop ToyCar: +## { +## action = "look_at", +## target = "ToyCar" +## }[/codeblock] +## or +## [codeblock]# To store a dialog line said by the Popsy character +## { +## character = "Popsy", +## text = "Hi. I said this and now it is recorded in the game's log!" +## }[/codeblock] +## [method PopochiuClickable.handle_command] and [method PopochiuInventoryItem.handle_command] store +## interactions with clickables and inventory items. +## [method PopochiuGraphicInterface.on_dialog_line_started] stores dialog lines said by characters. func add_history(data: Dictionary) -> void: history.push_front(data) -## Makes a method in node to be able to be used in a `queue()` call. -## Method parameters can be passed with params, and yield_signal is the signal -## that will notify the function has been completed (so `queue()` can continue -## with the next command in the queue) +## Makes a [param method] in [param node] to be able to be used inside an array of instructions for +## [method queue]. Parameters for [param method] can be passed as an array in [param params]. +## By default the queued method will wait for [code]"completed"[/code], but in can wait for a +## specific signal given the [param signal_name]. +## Examples: +## [codeblock] +## # queue() will wait until $AnimationPlayer.animation_finished signal is emitted +## E.queue([ +## "Player: Ok. This is a queueable example", +## E.queueable($AnimationPlayer, "play", ["glottis_appears"], "animation_finished"), +## 'Popsy: Hi Goddiu!', +## "Player: You're finally here!!!" +## ]) +## [/codeblock] +## An example with a custom method: +## [codeblock] +## # queue pauses until _make_glottis_appear.completed signal is emitted +## func _ready() -> void: +## E.queue([ +## "Player: Ok. This is another queueable example", +## E.queueable(self, '_make_glottis_appear', [], 'completed'), +## "Popsy: Hi Goddiu!", +## "Player: So... you're finally here!!!", +## ]) +## +## func _make_glottis_appear() -> void: +## $AnimationPlayer.play("make_glottis_appear") +## await $AnimationPlayer.animation_finished +## Globals.glottis_appeared = true +## await E.wait(1.0) +## [/codeblock] +## An example with a custom signal +## [codeblock] +## # queue pauses until the "clicked" signal is emitted in the %PopupButton +## # ---- In some prop ---- +## func on_click() -> void: +## E.run([ +## "Player: Ok. This is the last queueable example.", +## "Player: Promise!", +## E.queueable(%PopupButton, "_show_button", [], "clicked"), +## "Popsy: Are we done!?", +## "Player: Yup", +## ]) +## +## # ---- In the PopupButton node ---- +## signal clicked +## +## func _show_button() -> void: +## $BtnPlay.show() +## +## func _on_BtnPlay_pressed() -> void: +## await A.mx_mysterious_place.play() +## clicked.emit() +## [/codeblock] func queueable( node: Object, method: String, params := [], signal_name := '' ) -> Callable: return func (): await _queueable(node, method, params, signal_name) -## Checks if the room with script_name exists in the array of rooms of Popochiu +## Checks if the room with [param script_name] exists in the list of rooms of the game. func room_exists(script_name: String) -> bool: -# for r in rooms: for rp in PopochiuResources.get_section('rooms'): var room: PopochiuRoomData = load(rp) if room.script_name.to_lower() == script_name.to_lower(): @@ -565,18 +712,23 @@ func room_exists(script_name: String) -> bool: return false +## Plays the transition [param type] animation in the [TransitionLayer] with a [param duration] in +## seconds. Available type values can be found in [member TransitionLayer.Types]. This method is +## intended to be used inside a [method queue] of instructions. func queue_play_transition(type: int, duration: float) -> Callable: return func (): await play_transition(type, duration) -## Plays the transition type animation in TransitionLayer.tscn that last duration -## in seconds. Possible type values can be found in TransitionLayer +## Plays the transition [param type] animation in the [TransitionLayer] with a [param duration] in +## seconds. Available type values can be found in [member TransitionLayer.Types]. func play_transition(type: int, duration: float) -> void: tl.play_transition(type, duration) await tl.transition_finished +## Changes the speed of the text in dialog lines looping through the values in +## [member PopochiuSettings.text_speeds]. func change_text_speed() -> void: current_text_speed_idx = wrapi( current_text_speed_idx + 1, @@ -588,18 +740,24 @@ func change_text_speed() -> void: text_speed_changed.emit() +## Checks if there are any saved game sessions in the game's folder. By default Godot's +## [code]user://[/code] (you can open this folder with [b]Project > Open User Data Folder[/b]). func has_save() -> bool: return !_saveload.get_saves_descriptions().is_empty() +## Counts the number of saved game files in the game's folder. By default Godot's +## [code]user://[/code] (you can open this folder with [b]Project > Open User Data Folder[/b]). func saves_count() -> int: return _saveload.count_saves() +## Gets the names of the saved games (the name given to the slot when the game is saved). func get_saves_descriptions() -> Dictionary: return _saveload.get_saves_descriptions() +## Saves the current game state in a given [param slot] with the name in [param description]. func save_game(slot := 1, description := '') -> void: if _saveload.save_game(slot, description): game_saved.emit() @@ -607,6 +765,7 @@ func save_game(slot := 1, description := '') -> void: await G.show_system_text('Game saved') +## Loads the game in the given [param slot]. func load_game(slot := 1) -> void: I.clean_inventory(true) @@ -621,12 +780,15 @@ func load_game(slot := 1) -> void: ) +## Makes the camera stop shaking. func stop_camera_shake() -> void: _is_camera_shaking = false _shake_timer = 0.0 main_camera.offset = Vector2.ZERO +## Adds the [param node] to the array of hovered PopochiuClickable. If [param prepend] is +## [code]true[/code], then the [param node] will be added at the beginning of the array. func add_hovered(node: PopochiuClickable, prepend := false) -> void: if prepend: _hovered_queue.push_front(node) @@ -634,6 +796,8 @@ func add_hovered(node: PopochiuClickable, prepend := false) -> void: _hovered_queue.append(node) +## Removes a [param node] from the array of hovered PopochiuClickable. Returns [code]true[/code] +## if, after deletion, the array becomes empty. func remove_hovered(node: PopochiuClickable) -> bool: _hovered_queue.erase(node) @@ -649,11 +813,15 @@ func remove_hovered(node: PopochiuClickable) -> bool: return true +## Clears the array of hovered PopochiuClickable. func clear_hovered() -> void: _hovered_queue.clear() self.hovered = null +## Registers a GUI command identified by [param id], with name [param command_name] and a +## [param fallback] method to be called when the object receiving the interaction doesn't has an +## implementation for the registered command. func register_command(id: int, command_name: String, fallback: Callable) -> void: commands_map[id] = { "name" = command_name, @@ -661,6 +829,9 @@ func register_command(id: int, command_name: String, fallback: Callable) -> void } +## Registers a GUI command with just its name in [param command_name] and a [param fallback] method +## to be called when the object receiving the interaction doesn't has an implementation for the +## registered command. Returns the [code]id[/code] assigned to the registered command. func register_command_without_id(command_name: String, fallback: Callable) -> int: var id := commands_map.size() register_command(id, command_name, fallback) @@ -668,6 +839,8 @@ func register_command_without_id(command_name: String, fallback: Callable) -> in return id +## Calls the fallback method registered for the current active GUI command. If no fallback method is +## registered, [method _command_fallback] is called. func command_fallback() -> void: var fallback: Callable = commands_map[-1].fallback @@ -677,6 +850,7 @@ func command_fallback() -> void: await fallback.call() +## Returns the name of the GUI command registered with [param command_id]. func get_command_name(command_id: int) -> String: var command_name := "" @@ -686,6 +860,7 @@ func get_command_name(command_id: int) -> String: return command_name +## Returns the name of the current active GUI command. func get_current_command_name() -> String: return get_command_name(current_command) @@ -821,13 +996,11 @@ func _set_in_room(value: bool) -> void: # language_changed.emit() -func _queueable( - node: Object, method: String, params := [], signal_name := '' -) -> void: +func _queueable(node: Object, method: String, params := [], signal_name := '') -> void: if cutscene_skipped: - # TODO: What should happen if the skipped function was an animation that - # triggers calls during execution? What should happen if the skipped - # function has to change the state of the game? + # TODO: What should happen if the skipped function was an animation that triggers calls + # during execution? What should happen if the skipped function has to change the state of + # the game? await get_tree().process_frame return @@ -838,7 +1011,7 @@ func _queueable( if signal_name == 'completed': await c else: - # TODO: How to do this in GDScript 2 + # TODO: Is there a better way to do this in GDScript 2? await node.get(signal_name) else: await get_tree().process_frame