First commit 🎉

This commit is contained in:
Tony Bark 2025-07-17 01:49:18 -04:00
commit 43ea213f9b
728 changed files with 37080 additions and 0 deletions

View file

@ -0,0 +1,979 @@
@tool
@icon('res://addons/popochiu/icons/character.png')
class_name PopochiuCharacter
extends PopochiuClickable
## 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 {
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,
## 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].
}
## Emitted when a [param character] starts moving from [param start] to [param end]. [PopochiuRoom]
## connects 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
## Emitted when the animation to grab things has finished.
signal grab_done
## Empty string constant to perform type checks (String is not nullable in GDScript. See #381, #382).
const EMPTY_STRING = ""
## 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
## 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: set = set_follow_player
## 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)
## 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
## Used by the GUI to calculate where to render the dialogue lines said by the character when it
## speaks.
@export var dialog_pos: Vector2
# 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 previously visited [PopochiuRoom].
var last_room := EMPTY_STRING
## The suffix text to add to animation names.
var anim_suffix := EMPTY_STRING
## Whether the character is or not moving through the room.
var is_moving := false
## The current emotion used by the character.
var emotion := EMPTY_STRING
##
var on_scaling_region: Dictionary = {}
## 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
# Holds the direction the character is looking at.
# Initialized to DOWN.
var _looking_dir: int = Looking.DOWN
# Holds a suffixes fallback list for the animations to play.
# Initialized to the suffixes corresponding to the DOWN direction.
var _animation_suffixes: Array = ['_d', '_dr', '_dl', '_r', '_l', EMPTY_STRING]
# Holds the last PopochiuClickable that the character reached.
var _last_reached_clickable: PopochiuClickable = null
# Holds the animation that's currently selected in the character's AnimationPlayer.
var _current_animation: String = "null"
# Holds the last animation category requested for the character (idle, walk, talk, grab, ...).
var _last_requested_animation_label: String = "null"
# Holds the direction the character was looking at when the current animation was requested.
var _last_requested_animation_dir: int = -1
@onready var animation_player: AnimationPlayer = $AnimationPlayer
# Array of the animation suffixes to search for
# based on the angle the character is facing.
var _valid_animation_suffixes = [
['_r', '_l', '_dr', '_dl', '_d'], # 0 - 22.5 degrees
['_dr', '_dl', '_r' , '_l', '_d'], # 22.5 - 45 degrees
['_dr', '_dl', '_d' , '_r', '_l'], # 45 - 67.5 degrees
['_d', '_dr', '_dl', '_r', '_l'], # 67.5 - 90 degrees
['_d', '_dl', '_dr', '_l', '_r'], # 90 - 112.5 degrees
['_dl', '_dr', '_d', '_l', '_r'], # 112.5 - 135 degrees
['_dl', '_dr', '_l', '_r', '_d'], # 135 - 157.5 degrees
['_l', '_r', '_dl', '_dr', '_d'], # 157.5 - 180 degrees
['_l', '_r', '_ul', '_ur', '_u'], # 180 - 202.5 degrees
['_ul', '_ur', '_l', '_r', '_u'], # 202.5 - 225 degrees
['_ul', '_ur', '_u', '_l', '_r'], # 225 - 247.5 degrees
['_u', '_ul', '_ur', '_l', '_r'], # 247.5 - 270 degrees
['_u', '_ur', '_ul', '_r', '_l'], # 270 - 292.5 degrees
['_ur', '_ul', '_u', '_r', '_l'], # 292.5 - 315 degrees
['_ur', '_ul', '_r', '_l', '_u'], # 315 - 337.5 degrees
['_r', '_l', '_ur', '_ul', '_u']] # 337.5 - 360 degrees
#region Godot ######################################################################################
func _ready():
super()
default_walk_speed = walk_speed
default_scale = Vector2(scale)
if Engine.is_editor_hint():
hide_helpers()
set_process(true)
else:
set_process(follow_player)
for child in get_children():
if not child is Sprite2D:
continue
child.frame_changed.connect(_update_position)
move_ended.connect(_on_move_ended)
func _get_property_list():
return [
{
name = "popochiu_placeholder",
type = TYPE_NIL,
}
]
#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')
func _on_move_ended() -> void:
pass
#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 character has a [b]$Sprite2D[/b] child, it makes it flip based on the [member flips_when]
## value.[br][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 character has a [b]$Sprite2D[/b] child, it makes it flip based on the [member flips_when]
## value.
func idle() -> void:
if PopochiuUtils.e.cutscene_skipped:
await get_tree().process_frame
return
_flip_left_right(
_looking_dir in [Looking.LEFT, Looking.DOWN_LEFT, Looking.UP_LEFT],
_looking_dir in [Looking.RIGHT, Looking.DOWN_RIGHT, Looking.UP_RIGHT]
)
# Call the virtual that plays the idle animation
_play_idle()
await get_tree().create_timer(0.2).timeout
## Makes the character move to [param target_pos] and plays its walk animation.
## If the character has a [b]$Sprite2D[/b] child, it makes it flip based on the [member flips_when]
## value.[br][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 character 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
_last_reached_clickable = null
# The ROOM will take care of moving the character
# and face her in the correct direction from here
_flip_left_right(
target_pos.x < position.x,
target_pos.x > position.x
)
if PopochiuUtils.e.cutscene_skipped:
is_moving = false
await get_tree().process_frame
position = target_pos
PopochiuUtils.e.camera.position = target_pos
await get_tree().process_frame
return
# Call the virtual that plays the walk animation
_play_walk(target_pos)
# Trigger the signal for the room to start moving the character
started_walk_to.emit(self, position, target_pos)
await move_ended
is_moving = false
func turn_towards(target_pos: Vector2) -> void:
_flip_left_right(
target_pos.x < position.x,
target_pos.x > position.x
)
face_direction(target_pos)
_play_walk(target_pos)
## Makes the character stop moving and emits [signal stopped_walk].[br][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
stopped_walk.emit()
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][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:
face_direction(position + Vector2.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][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:
face_direction(position + Vector2.UP + Vector2.RIGHT)
await idle()
## Makes the character to look right by setting [member _looking_dir] to [constant RIGHT] and waits
## until [method idle] finishes.[br][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:
face_direction(position + Vector2.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][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:
face_direction(position + Vector2.DOWN + Vector2.RIGHT)
await idle()
## Makes the character to look down by setting [member _looking_dir] to [constant DOWN] and waits
## until [method idle] finishes.[br][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:
face_direction(position + Vector2.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][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:
face_direction(position + Vector2.DOWN + Vector2.LEFT)
await idle()
## Makes the character to look left by setting [member _looking_dir] to [constant LEFT] and waits
## until [method idle] finishes.[br][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:
face_direction(position + Vector2.LEFT)
await idle()
## Makes the character to look up and left by setting [member _looking_dir] to [constant UP_LEFT]
## and waits until [method idle] finishes.[br][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()
## 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:
face_direction(position + Vector2.UP + Vector2.LEFT)
await idle()
## Makes the character face in the direction of the last clicked [PopochiuClickable], which is
## stored in [member Popochiu.clicked].[br][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:
var global_lap = PopochiuUtils.e.clicked.to_global(PopochiuUtils.e.clicked.look_at_point)
_flip_left_right(
global_lap.x < global_position.x,
global_lap.x > global_position.x
)
await face_direction(global_lap)
## 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][br]
## [i]This method is intended to be used inside a [method Popochiu.queue] of instructions.[/i]
func queue_say(dialog: String, emo := EMPTY_STRING) -> 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 := EMPTY_STRING) -> void:
if PopochiuUtils.e.cutscene_skipped:
await get_tree().process_frame
return
if not emo.is_empty():
emotion = emo
# Call the virtual that plays the talk animation
_play_talk()
var vo_name := _get_vo_cue(emotion)
if not vo_name.is_empty() and PopochiuUtils.a.get(vo_name):
PopochiuUtils.a[vo_name].play(false, global_position)
PopochiuUtils.c.character_spoke.emit(self, dialog)
await PopochiuUtils.g.dialog_line_finished
# Stop the voice if it is still playing (feature #202)
# Fix: Check if the vo_name is valid in order to stop it
if not vo_name.is_empty() and PopochiuUtils.a[vo_name].is_playing():
PopochiuUtils.a[vo_name].stop(0.3)
emotion = EMPTY_STRING
idle()
## Calls [method _play_grab] and waits until the [signal grab_done] is emitted, then goes back to
## [method idle].[br][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 grab_done] is emitted, then goes back to
## [method idle].
func grab() -> void:
if PopochiuUtils.e.cutscene_skipped:
await get_tree().process_frame
return
# Call the virtual that plays the grab animation
_play_grab()
await grab_done
idle()
## Calls [method PopochiuClickable.hide_helpers].
func hide_helpers() -> void:
super()
# TODO: add visibility logic for dialog_pos gizmo
## Calls [method PopochiuClickable.show_helpers].
func show_helpers() -> void:
super()
# TODO: add visibility logic for dialog_pos gizmo
## Makes the character walk to [param pos].[br][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(PopochiuUtils.r.current.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][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 (NON-BLOCKING) 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:
var clicked_id: String = PopochiuUtils.e.clicked.script_name
if PopochiuUtils.e.clicked == _last_reached_clickable:
await get_tree().process_frame
return
await _walk_to_node(PopochiuUtils.e.clicked, offset)
_last_reached_clickable = PopochiuUtils.e.clicked
# Check if the action was cancelled
if not PopochiuUtils.e.clicked or clicked_id != PopochiuUtils.e.clicked.script_name:
await PopochiuUtils.e.await_stopped
## Makes the character walk (BLOCKING the GUI) 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_blocking(offset := Vector2.ZERO) -> void:
PopochiuUtils.g.block()
await _walk_to_node(PopochiuUtils.e.clicked, offset)
PopochiuUtils.g.unblock()
## Makes the character walk (BLOCKING the GUI) to the last clicked [PopochiuClickable], which is
## stored in [member Popochiu.clicked]. You can set an [param offset] relative to the target position.
## [i]This method is intended to be used inside a [method Popochiu.queue] of instructions.[/i]
func queue_walk_to_clicked_blocking(offset := Vector2.ZERO) -> Callable:
return func(): await walk_to_clicked_blocking(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][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(PopochiuUtils.r.current.get_prop(id), offset)
## Makes the character teleport (disappear at one location and instantly appear at another) 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][br]
## [i]This method is intended to be used inside a [method Popochiu.queue] of instructions.[/i]
func queue_teleport_to_prop(id: String, offset := Vector2.ZERO) -> Callable:
return func(): await teleport_to_prop(id, offset)
## Makes the character teleport (disappear at one location and instantly appear at another) 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 teleport_to_prop(id: String, offset := Vector2.ZERO) -> void:
await _teleport_to_node(PopochiuUtils.r.current.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][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(PopochiuUtils.r.current.get_hotspot(id), offset)
## Makes the character teleport (disappear at one location and instantly appear at another) 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][br]
## [i]This method is intended to be used inside a [method Popochiu.queue] of instructions.[/i]
func queue_teleport_to_hotspot(id: String, offset := Vector2.ZERO) -> Callable:
return func(): await teleport_to_hotspot(id, offset)
## Makes the character teleport (disappear at one location and instantly appear at another) 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 teleport_to_hotspot(id: String, offset := Vector2.ZERO) -> void:
await _teleport_to_node(PopochiuUtils.r.current.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][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(PopochiuUtils.r.current.get_marker(id), offset)
## Makes the character teleport (disappear at one location and instantly appear at another) 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][br]
## [i]This method is intended to be used inside a [method Popochiu.queue] of instructions.[/i]
func queue_teleport_to_marker(id: String, offset := Vector2.ZERO) -> Callable:
return func(): await teleport_to_marker(id, offset)
## Makes the character teleport (disappear at one location and instantly appear at another) 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 teleport_to_marker(id: String, offset := Vector2.ZERO) -> void:
await _teleport_to_node(PopochiuUtils.r.current.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][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)
## 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 (animation_label != _last_requested_animation_label) or (_looking_dir != _last_requested_animation_dir):
if not has_node("AnimationPlayer"):
PopochiuUtils.print_error(
"Can't play character animation. Required AnimationPlayer not found in character %s" %
[script_name]
)
return
if animation_player.get_animation_list().is_empty():
return
# Search for a valid animation corresponding to animation_label
_current_animation = _get_valid_oriented_animation(animation_label)
# If is not present, do the same for the the fallback animation.
if _current_animation.is_empty():
_current_animation = _get_valid_oriented_animation(animation_fallback)
# In neither are available, exit and throw an error to check for the presence of the animations.
if _current_animation.is_empty(): # Again!
PopochiuUtils.print_error(
"Neither the requested nor the fallback animation could be found for character %s.\
Requested:%s - Fallback: %s" % [script_name, animation_label, animation_fallback]
)
return
# Cache the the _current_animation context to avoid re-searching for it.
_last_requested_animation_label = animation_label
_last_requested_animation_dir = _looking_dir
# Play the animation in the best available orientation
animation_player.play(_current_animation)
# If the playing is blocking, wait for the animation to finish
await animation_player.animation_finished
# Go back to idle state
_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][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 (
animation_player.get_animation(
animation_player.current_animation
).loop_mode == Animation.LOOP_NONE
or animation_player.current_animation == 'idle'
or animation_player.current_animation.begins_with('idle_')
):
return
# Save the loop mode, wait for the anim to be over as designed, then restore the mode
var animation: Animation = animation_player.get_animation(animation_player.current_animation)
var animation_loop_mode := animation.loop_mode
animation.loop_mode = Animation.LOOP_NONE
await animation_player.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][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][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():
animation_player.pause()
## Resumes the current animation (that was previously paused).[br][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():
animation_player.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):
# Determine the direction the character is facing.
# Remember: Y coordinates have opposite sign in Godot.
# This means that negative angles are up movements.
# Set the direction using the _looking property.
# We cannot use the face_* functions because they
# set the state as IDLE.
# Based on the character facing direction, define a set of
# animation suffixes in reference order.
# Notice how we seek for opposite directions for left and
# right. Flipping is done in other functions. We just define
# a preference order for animations when available.
# Get the vector from the origin to the destination.
var angle = wrapf(rad_to_deg((destination - position).angle()) , 0, 360)
# The angle calculation uses 16 angles rather than 8 for greater accuracy
# in choosing the facing direction fallback animations.
var _looking_angle := int(angle / 22.5) % 16
# Selecting the animation suffixes for the current facing direction.
# Note that we add a fallback empty string to the list, in case the only
# available animation is the base one ('walk', 'talk', etc).
_animation_suffixes = _valid_animation_suffixes[_looking_angle] + [EMPTY_STRING]
# The 16 directions used for animation suffixes are simplified to 8 general directions
_looking_dir = int(angle / 45) % 8
## 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 := EMPTY_STRING) -> Texture:
var texture: Texture = null
while not texture and not avatars.is_empty():
for dic in avatars:
if dic.emotion.is_empty():
texture = dic.avatar
elif dic.emotion == emo:
texture = dic.avatar
break
return texture
## Returns the [code]y[/code] value of the dialog_pos [Vector2] that defines the
## position of the dialog lines said by the character when it talks.
func get_dialog_pos() -> float:
return dialog_pos.y
func update_position() -> void:
position = (
position_stored
if position_stored
else position
)
## Updates the scale depending on the properties of the scaling region where it is located.
func update_scale():
if on_scaling_region:
var polygon_range = (
on_scaling_region["polygon_bottom_y"] - on_scaling_region["polygon_top_y"]
)
var scale_range = (
on_scaling_region["scale_bottom"] - on_scaling_region["scale_top"]
)
var position_from_the_top_of_region = (
position.y - on_scaling_region["polygon_top_y"]
)
var scale_for_position = (
on_scaling_region["scale_top"] + (
scale_range / polygon_range * position_from_the_top_of_region
)
)
scale.x = [
[scale_for_position, on_scaling_region["scale_min"]].max(),
on_scaling_region["scale_max"]
].min()
scale.y = [
[scale_for_position, on_scaling_region["scale_min"]].max(),
on_scaling_region["scale_max"]
].min()
walk_speed = default_walk_speed / default_scale.x * scale_for_position
else:
scale = default_scale
walk_speed = default_walk_speed
#endregion
#region SetGet #####################################################################################
func set_voices(value: Array) -> void:
voices = value
for idx in value.size():
if not value[idx]:
var arr: Array[AudioCueSound] = []
voices[idx] = {
emotion = EMPTY_STRING,
variations = arr
}
elif not value[idx].variations.is_empty():
if value[idx].variations[-1] == null:
value[idx].variations[-1] = AudioCueSound.new()
func set_follow_player(value: bool) -> void:
follow_player = value
if not Engine.is_editor_hint():
set_process(follow_player)
func set_avatars(value: Array) -> void:
avatars = value
for idx in value.size():
if not value[idx]:
avatars[idx] = {
emotion = EMPTY_STRING,
avatar = Texture.new(),
}
#endregion
#region Private ####################################################################################
func _translate() -> void:
if Engine.is_editor_hint() or not is_inside_tree(): return
description = PopochiuUtils.e.get_text(_description_code)
func _get_vo_cue(emotion := EMPTY_STRING) -> String:
for v in voices:
if v.emotion.to_lower() == emotion.to_lower():
var cue_name := EMPTY_STRING
if not v.variations.is_empty():
if not v.has('not_played') or v.not_played.is_empty():
v['not_played'] = range(v.variations.size())
var idx: int = (v['not_played'] as Array).pop_at(
PopochiuUtils.get_random_array_idx(v['not_played'])
)
cue_name = v.variations[idx].resource_name
return cue_name
return EMPTY_STRING
func _get_valid_oriented_animation(animation_label):
# The list of prefixes is in order of preference
# Eg. walk_dl, walk_l, walk
# Scan the AnimationPlayer and return the first that matches.
for suffix in _animation_suffixes:
var animation = "%s%s" % [animation_label, suffix]
if animation_player.has_animation(animation):
return animation
return EMPTY_STRING
func _walk_to_node(node: Node2D, offset: Vector2) -> void:
if not is_instance_valid(node):
await get_tree().process_frame
return
await walk(
node.to_global(node.walk_to_point if node is PopochiuClickable else Vector2.ZERO) + offset
)
# Instantly move to the node position
func _teleport_to_node(node: Node2D, offset: Vector2) -> void:
if not is_instance_valid(node):
await get_tree().process_frame
return
position = node.to_global(
node.walk_to_point if node is PopochiuClickable else Vector2.ZERO
) + offset
func _update_position():
PopochiuUtils.r.current.update_characters_position(self)
# Flips sprites depending on user preferences: requires two boolean conditions
# as arguments for flipping left [param left_cond] or right [param right_cond]
func _flip_left_right(left_cond: bool, right_cond: bool) -> void:
if has_node('Sprite2D'):
$Sprite2D.flip_h = false
match flips_when:
FlipsWhen.LOOKING_LEFT:
$Sprite2D.flip_h = left_cond
FlipsWhen.LOOKING_RIGHT:
$Sprite2D.flip_h = right_cond
#endregion

View file

@ -0,0 +1 @@
uid://vq4ev5brs6us

View file

@ -0,0 +1,18 @@
[gd_scene load_steps=2 format=3 uid="uid://cwtpncpx24dm7"]
[ext_resource type="Script" path="res://addons/popochiu/engine/objects/character/popochiu_character.gd" id="1_2xmr4"]
[node name="Character" type="Area2D"]
script = ExtResource("1_2xmr4")
popochiu_placeholder = null
interaction_polygon = PackedVector2Array(-10, -10, 10, -10, 10, 10, -10, 10)
[node name="InteractionPolygon" type="CollisionPolygon2D" parent="."]
polygon = PackedVector2Array(-10, -10, 10, -10, 10, 10, -10, 10)
[node name="ScalingPolygon" type="CollisionPolygon2D" parent="."]
polygon = PackedVector2Array(0, 0, 0, 0, 0, 0, 0, 0)
[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
[node name="Sprite2D" type="Sprite2D" parent="."]

View file

@ -0,0 +1,42 @@
@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
#endregion
#region Public #####################################################################################
## 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. [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)
#endregion

View file

@ -0,0 +1 @@
uid://id2ek58lklcx

View file

@ -0,0 +1,419 @@
@tool
class_name PopochiuClickable
extends Area2D
## Handles an Area2D that reacts to mouse events.
##
## Is the base class 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: set = set_clickable
## The [code]y[/code] position of the baseline relative to the center of the object.
@export var baseline := 0
## The [Vector2] position where characters will move when approaching the object.
@export var walk_to_point := Vector2.ZERO
## The [Vector2] position where characters will turn looking at the object.
@export var look_at_point := Vector2.ZERO
## 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
## 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 double-clicked.
var times_double_clicked := 0
## The number of times this object has been right-clicked.
var times_right_clicked := 0
## 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 this object should emit a signal about the click
# (command execution).
## Stores the last [enum MouseButton] pressed on this object.
var last_click_button := -1
# Used for setting the double click delay. Windows default is 500 milliseconds.
var _double_click_delay: float = 0.2
# Used for tracking if a double click has occurred.
var _has_double_click: bool = false
@onready var _description_code := description
#region Godot ######################################################################################
func _ready():
add_to_group("PopochiuClickable")
if Engine.is_editor_hint():
hide_helpers()
# Add interaction polygon to the proper group
if (get_node_or_null("InteractionPolygon") != null):
get_node("InteractionPolygon").add_to_group(
PopochiuEditorHelper.POPOCHIU_OBJECT_POLYGON_GROUP
)
# Ignore assigning the polygon when:
if (
get_node_or_null("InteractionPolygon") == null # there is no InteractionPolygon node
or not get_parent() is Node2D # editing it in the .tscn file of the object directly
or self is PopochiuCharacter # avoid resetting the polygon for characters (see issue #158))
):
return
if interaction_polygon.is_empty():
interaction_polygon = get_node("InteractionPolygon").polygon
interaction_polygon_position = get_node("InteractionPolygon").position
else:
get_node("InteractionPolygon").polygon = interaction_polygon
get_node("InteractionPolygon").position = interaction_polygon_position
# If we are in the editor, we're done
return
# When the game is running...
# Update the node's polygon when:
if (
get_node_or_null("InteractionPolygon") # there is an InteractionPolygon node
and not self is PopochiuCharacter # avoids resetting the polygon (see issue #158)
):
get_node("InteractionPolygon").polygon = interaction_polygon
get_node("InteractionPolygon").position = interaction_polygon_position
visibility_changed.connect(_toggle_input)
# Ignore this object if it is a temporary one (its name has *)
if clickable and not "*" in name:
# Connect to own signals
mouse_entered.connect(_on_mouse_entered)
mouse_exited.connect(_on_mouse_exited)
# Fix #183 by listening only to inputs in this CollisionObject2D
input_event.connect(_on_input_event)
# Connect to singleton signals
PopochiuUtils.e.language_changed.connect(_translate)
_translate()
func _notification(event: int) -> void:
if event == NOTIFICATION_EDITOR_PRE_SAVE:
interaction_polygon = get_node("InteractionPolygon").polygon
interaction_polygon_position = get_node("InteractionPolygon").position
#endregion
#region Virtual ####################################################################################
## Called when the room this node belongs to has been added to the tree.
## [i]Virtual[/i].
func _on_room_set() -> void:
pass
## Called when the node is clicked.
## [i]Virtual[/i].
func _on_click() -> void:
pass
## Called when the node is double clicked.
## [i]Virtual[/i].
func _on_double_click() -> void:
pass
## Called when the node is right clicked.
## [i]Virtual[/i].
func _on_right_click() -> void:
pass
## Called when the node is middle clicked.
## [i]Virtual[/i].
func _on_middle_click() -> void:
pass
## Called when the node is clicked and there is an inventory item selected.
## [i]Virtual[/i].
func _on_item_used(item: PopochiuInventoryItem) -> void:
pass
#endregion
#region Public #####################################################################################
## Used by the plugin to hide the visual helpers that show the interaction polygon
## in the 2D Canvas Editor when this node is unselected in the Scene panel.
func hide_helpers() -> void:
if get_node_or_null("InteractionPolygon"):
$InteractionPolygon.hide()
## Used by the plugin to make visible the visual helpers that show the interaction polygon
## in the 2D Canvas Editor when this node is unselected in the Scene panel.
func show_helpers() -> void:
if get_node_or_null("InteractionPolygon"):
$InteractionPolygon.show()
## Hides this Node.[br][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 this Node.
func disable() -> void:
self.visible = false
await get_tree().process_frame
## Shows this Node.[br][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()
## 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():
description = name
return description
return PopochiuUtils.e.get_text(description)
## Called when the object is left clicked.
func on_click() -> void:
await _on_click()
## Called when the object is double clicked.
func on_double_click() -> void:
_reset_double_click()
await _on_double_click()
## Called when the object is right clicked.
func on_right_click() -> void:
await _on_right_click()
## Called when the object is middle clicked.
func on_middle_click() -> void:
await _on_middle_click()
## Called when an [param item] is used on this object.
func on_item_used(item: PopochiuInventoryItem) -> void:
await _on_item_used(item)
# after item has been used return to normal state
PopochiuUtils.i.active = null
## 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 = PopochiuUtils.e.get_current_command_name().to_snake_case()
var prefix := "on_%s"
var suffix := "click"
match button_idx:
MOUSE_BUTTON_RIGHT:
suffix = "right_" + suffix
MOUSE_BUTTON_MIDDLE:
suffix = "middle_" + suffix
if not command.is_empty():
var command_method := suffix.replace("click", command)
if has_method(prefix % command_method):
suffix = command_method
PopochiuUtils.e.add_history({
action = suffix if command.is_empty() else command,
target = description
})
await call(prefix % suffix)
#endregion
#region SetGet #####################################################################################
func set_clickable(value: bool) -> void:
clickable = value
input_pickable = clickable
func set_room(value: Node2D) -> void:
room = value
_on_room_set()
#endregion
#region Private ####################################################################################
func _on_mouse_entered() -> void:
if PopochiuUtils.e.hovered and is_instance_valid(PopochiuUtils.e.hovered) and (
PopochiuUtils.e.hovered.get_parent() == self
or get_index() < PopochiuUtils.e.hovered.get_index()
):
PopochiuUtils.e.add_hovered(self, true)
return
PopochiuUtils.e.add_hovered(self)
PopochiuUtils.g.mouse_entered_clickable.emit(self)
func _on_mouse_exited() -> void:
last_click_button = -1
if PopochiuUtils.e.remove_hovered(self):
PopochiuUtils.g.mouse_exited_clickable.emit(self)
func _on_input_event(_viewport: Node, event: InputEvent, _shape_idx: int):
if PopochiuUtils.g.is_blocked or not PopochiuUtils.e.hovered or PopochiuUtils.e.hovered != self:
return
if _is_double_click_or_tap(event):
times_double_clicked += 1
PopochiuUtils.e.clicked = self
on_double_click()
return
if not await _is_click_or_touch_pressed(event): return
var event_index := PopochiuUtils.get_click_or_touch_index(event)
PopochiuUtils.e.clicked = self
last_click_button = event_index
get_viewport().set_input_as_handled()
match event_index:
MOUSE_BUTTON_LEFT:
if PopochiuUtils.i.active:
await on_item_used(PopochiuUtils.i.active)
else:
await handle_command(event_index)
times_clicked += 1
MOUSE_BUTTON_RIGHT, MOUSE_BUTTON_MIDDLE:
if PopochiuUtils.i.active: return
await handle_command(event_index)
if event_index == MOUSE_BUTTON_RIGHT:
times_right_clicked += 1
elif event_index == MOUSE_BUTTON_MIDDLE:
times_middle_clicked += 1
PopochiuUtils.e.clicked = null
func _toggle_input() -> void:
if clickable:
input_pickable = visible
func _translate() -> void:
if (
Engine.is_editor_hint()
or not is_inside_tree()
or not PopochiuUtils.e.settings.use_translations
):
return
description = PopochiuUtils.e.get_text("%s-%s" % [get_tree().current_scene.name, _description_code])
# ---- @anthonyirwin82 -----------------------------------------------------------------------------
# NOTE: Temporarily duplicating PopochiuUtils functions here with an added delay for double click.
# Having delay in the PopochiuUtils class that other gui code calls introduced unwanted issues.
# This is a temporary work around until a more permanent solution is found.
# Checks if [param event] is an [InputEventMouseButton] or [InputEventScreenTouch] event.
func _is_click_or_touch(event: InputEvent) -> bool:
if (
(event is InputEventMouseButton and not event.double_click)
or (event is InputEventScreenTouch and not event.double_tap)
):
# This delay is need to prevent a single click being detected before double click
await PopochiuUtils.e.wait(_double_click_delay)
if not _has_double_click:
return (event is InputEventMouseButton or event is InputEventScreenTouch)
return false
# Checks if [param event] is an [InputEventMouseButton] or [InputEventScreenTouch] event and if it
# is pressed.
func _is_click_or_touch_pressed(event: InputEvent) -> bool:
# Fix #183 by including `event is InputEventScreenTouch` validation
if not _has_double_click:
return await _is_click_or_touch(event) and event.pressed
else:
return false
# Checks if [param event] is a double click or double tap event.
func _is_double_click_or_tap(event: InputEvent) -> bool:
if (
(event is InputEventMouseButton and event.double_click)
or (event is InputEventScreenTouch and event.double_tap)
):
_has_double_click = true
if event is InputEventMouseButton:
return event.double_click
elif event is InputEventScreenTouch:
return event.double_tap
return false
# Resets the double click status to false by default
func _reset_double_click(double_click: bool = false) -> void:
# this delay is needed to prevent single click being detected after double click event
await PopochiuUtils.e.wait(_double_click_delay)
_has_double_click = double_click
# ----------------------------------------------------------------------------- @anthonyirwin82 ----
#endregion

View file

@ -0,0 +1 @@
uid://df27veamriamt

View file

@ -0,0 +1,165 @@
@tool
@icon('res://addons/popochiu/icons/dialog.png')
class_name PopochiuDialog
extends Resource
## A class for branching dialogs. The dialog options can be used to trigger events.
## 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
#endregion
#region Public #####################################################################################
## Starts this dialog, then [method _on_start] is called.[br][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:
if PopochiuUtils.d.current_dialog == self:
return
# Start this dialog
PopochiuUtils.d.current_dialog = self
await _start()
## Stops the dialog (which makes the menu with the options to disappear).[br][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:
PopochiuUtils.d.finish_dialog()
## 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 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. [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[PopochiuDialogOption]) -> void:
options = value
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[idx] = new_opt
#endregion
#region Private ####################################################################################
func _start() -> void:
PopochiuUtils.g.block()
PopochiuUtils.d.dialog_started.emit(self)
await _on_start()
_show_options()
await PopochiuUtils.d.dialog_finished
PopochiuUtils.g.unblock()
PopochiuUtils.d.option_selected.disconnect(_on_option_selected)
func _show_options() -> void:
if not PopochiuUtils.d.active: return
PopochiuUtils.d.dialog_options_requested.emit(options)
if not PopochiuUtils.d.option_selected.is_connected(_on_option_selected):
PopochiuUtils.d.option_selected.connect(_on_option_selected)
func _on_option_selected(opt: PopochiuDialogOption) -> void:
opt.used = true
opt.used_times += 1
PopochiuUtils.d.selected_option = opt
_option_selected(opt)
#endregion

View file

@ -0,0 +1 @@
uid://osh8vbx7f1ah

View file

@ -0,0 +1,67 @@
@tool
class_name PopochiuDialogOption
extends Resource
## Each of the options in a [PopochiuDialog].
## 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
## 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
#region Virtual ####################################################################################
## Called when the option is selected.
## [i]Virtual[/i].
func _on_selected() -> void:
pass
#endregion
#region Public #####################################################################################
## Makes the option visible. Won´t work if the option is [member disabled].
func turn_on() -> void:
if disabled: return
visible = true
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
#endregion
#region SetGet #####################################################################################
func set_id(value: String) -> void:
id = value
script_name = id
resource_name = id
#endregion

View file

@ -0,0 +1 @@
uid://cclk5bj1l4p4p

View file

@ -0,0 +1,144 @@
class_name PopochiuDialogMenu
extends Control
@warning_ignore("return_value_discarded")
@warning_ignore("unused_signal")
signal shown
@export var option_scene: PackedScene
## Max height of the menu in pixels. If visible options make the menu to exceed this value, it will
## enable a vertical scroll bar.
@export var max_height := 49
@export_category("Option buttons")
@export var normal_font_color: Color = Color("706deb")
@export var normal_used_font_color: Color = Color("2e2c9b")
@export var hover_font_color: Color = Color("ffffff")
@export var hover_used_font_color: Color = Color("b2b2b2")
@export var pressed_font_color: Color = Color("a9ff9f")
@export var pressed_used_font_color: Color = Color("56ac4d")
var current_options := []
@onready var panel_container: PanelContainer = $PanelContainer
@onready var dialog_options_container: VBoxContainer = %DialogOptionsContainer
#region Godot ######################################################################################
func _ready() -> void:
for child in dialog_options_container.get_children():
child.queue_free()
panel_container.custom_minimum_size = Vector2.ZERO
# Connect to own signals
gui_input.connect(_clicked)
# Connect to autoloads signals
PopochiuUtils.d.dialog_options_requested.connect(_create_options.bind(true))
PopochiuUtils.d.inline_dialog_requested.connect(_create_inline_options)
PopochiuUtils.d.dialog_finished.connect(remove_options)
hide()
#endregion
#region Private ####################################################################################
func _clicked(event: InputEvent) -> void:
if PopochiuUtils.get_click_or_touch_index(event) == MOUSE_BUTTON_LEFT:
accept_event()
# Creates an Array of PopochiuDialogOption to show dialog tree options created
# during execution, (those that are created after calling D.show_inline_dialog)
func _create_inline_options(opts: Array) -> void:
var tmp_opts := []
for idx in opts.size():
var new_opt: PopochiuDialogOption = PopochiuDialogOption.new()
new_opt.id = str(idx)
new_opt.text = opts[idx]
tmp_opts.append(new_opt)
_create_options(tmp_opts, true)
func _create_options(options := [], autoshow := false) -> void:
remove_options()
if options.is_empty():
if not current_options.is_empty():
show_options()
return
current_options = options.duplicate(true)
for dialog_option: PopochiuDialogOption in options:
var dialog_menu_option := option_scene.instantiate()
dialog_menu_option.normal_color = normal_font_color
dialog_menu_option.normal_used_color = normal_used_font_color
dialog_menu_option.hover_color = hover_font_color
dialog_menu_option.hover_used_color = hover_used_font_color
dialog_menu_option.pressed_color = pressed_font_color
dialog_menu_option.pressed_used_color = pressed_used_font_color
dialog_options_container.add_child(dialog_menu_option)
dialog_menu_option.option = dialog_option
dialog_menu_option.pressed.connect(_on_option_clicked)
if dialog_option.disabled or not dialog_option.visible:
dialog_menu_option.hide()
else:
dialog_menu_option.show()
if autoshow: show_options()
await get_tree().create_timer(0.1).timeout
# Fix: Height and position of the dialog menu was wrong when changing the amount of options to
# show.
var options_height := 0
var visible_options := 0
for opt in dialog_options_container.get_children():
if not opt.visible: continue
options_height += opt.size.y
visible_options += 1
options_height += (
dialog_options_container.get_theme_constant("separation") * (visible_options - 1)
)
panel_container.size.y = min(options_height, max_height)
panel_container.position.y = PopochiuUtils.e.height - panel_container.size.y
func remove_options(_dialog: PopochiuDialog = null) -> void:
if not current_options.is_empty():
current_options.clear()
for btn in dialog_options_container.get_children():
btn.queue_free()
await get_tree().process_frame
size.y = 0
dialog_options_container.size.y = 0
func show_options() -> void:
PopochiuUtils.g.block()
PopochiuUtils.g.dialog_options_shown.emit()
show()
shown.emit()
func _on_option_clicked(opt: PopochiuDialogOption) -> void:
PopochiuUtils.g.unblock()
hide()
PopochiuUtils.d.option_selected.emit(opt)
#endregion

View file

@ -0,0 +1 @@
uid://c6el34etfenet

View file

@ -0,0 +1,39 @@
[gd_scene load_steps=4 format=3 uid="uid://dhsfl8ot4j5fj"]
[ext_resource type="Script" path="res://addons/popochiu/engine/objects/gui/components/dialog_menu/dialog_menu.gd" id="1_3dp72"]
[ext_resource type="Theme" uid="uid://dpequqav4rjaf" path="res://addons/popochiu/engine/objects/gui/resources/base_gui_theme.tres" id="1_cvsnu"]
[ext_resource type="PackedScene" uid="uid://dcta4urojglil" path="res://addons/popochiu/engine/objects/gui/components/dialog_menu/dialog_menu_option/dialog_menu_option.tscn" id="3_0jfsm"]
[node name="DialogMenu" type="Control" groups=["popochiu_gui_component"]]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 2
theme = ExtResource("1_cvsnu")
script = ExtResource("1_3dp72")
option_scene = ExtResource("3_0jfsm")
[node name="PanelContainer" type="PanelContainer" parent="."]
custom_minimum_size = Vector2(0, 53)
layout_mode = 1
anchors_preset = 12
anchor_top = 1.0
anchor_right = 1.0
anchor_bottom = 1.0
offset_top = -53.0
grow_horizontal = 2
grow_vertical = 0
[node name="ScrollContainer" type="ScrollContainer" parent="PanelContainer"]
layout_mode = 2
horizontal_scroll_mode = 0
[node name="DialogOptionsContainer" type="VBoxContainer" parent="PanelContainer/ScrollContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 8
theme_override_constants/separation = 1

View file

@ -0,0 +1,92 @@
class_name PopochiuDialogMenuOption
extends PanelContainer
signal pressed(node: PopochiuDialogOption)
var option: PopochiuDialogOption : set = set_dialog_option
var text := "" : set = set_text
var used := false : set = set_used
var normal_color := Color.WHITE
var normal_used_color := normal_color
var hover_color := Color.WHITE
var hover_used_color := hover_color
var pressed_color := Color.WHITE
var pressed_used_color := pressed_color
var _state := "normal" : set = set_state
@onready var rich_text_label: RichTextLabel = %RichTextLabel
@onready var handler: Button = %Handler
#region Godot ######################################################################################
func _ready() -> void:
handler.pressed.connect(_on_pressed)
handler.mouse_entered.connect(_on_mouse_entered)
handler.mouse_exited.connect(_on_mouse_exited)
handler.button_down.connect(_on_button_down)
handler.button_up.connect(_on_button_up)
_update_font_color()
#endregion
#region SetGet #####################################################################################
func set_dialog_option(value: PopochiuDialogOption) -> void:
option = value
if PopochiuConfig.should_dialog_options_be_gibberish():
text = PopochiuUtils.d.create_gibberish(option.text)
else:
text = option.text
used = option.used and not option.always_on
func set_text(value: String) -> void:
text = value
rich_text_label.text = value
func set_used(value: bool) -> void:
used = value
_update_font_color()
func set_state(value: String) -> void:
_state = value
_update_font_color()
#endregion
#region Private ####################################################################################
func _on_pressed() -> void:
_state = "pressed"
pressed.emit(option)
func _on_mouse_entered() -> void:
_state = "hover"
func _on_mouse_exited() -> void:
_state = "normal"
func _on_button_down() -> void:
_state = "pressed"
func _on_button_up() -> void:
_state = "hover" if handler.is_hovered() else "normal"
func _update_font_color() -> void:
rich_text_label.add_theme_color_override(
"default_color",
get("%s_color" % (_state + ("_used" if used else "")))
)
#endregion

View file

@ -0,0 +1,40 @@
[gd_scene load_steps=6 format=3 uid="uid://dcta4urojglil"]
[ext_resource type="Theme" uid="uid://dpequqav4rjaf" path="res://addons/popochiu/engine/objects/gui/resources/base_gui_theme.tres" id="1_y0k4l"]
[ext_resource type="FontFile" uid="uid://dixh1egf7k2fb" path="res://addons/popochiu/engine/objects/gui/fonts/monkeyisland_1991.ttf" id="2_5iw2f"]
[ext_resource type="Script" path="res://addons/popochiu/engine/objects/gui/components/dialog_menu/dialog_menu_option/dialog_menu_option.gd" id="2_nywcv"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_un1pr"]
content_margin_left = 2.0
content_margin_right = 2.0
content_margin_bottom = 2.0
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_we03b"]
[node name="DialogMenuOption" type="PanelContainer"]
anchors_preset = 10
anchor_right = 1.0
offset_bottom = 24.0
grow_horizontal = 2
mouse_filter = 2
theme = ExtResource("1_y0k4l")
theme_override_styles/panel = SubResource("StyleBoxEmpty_un1pr")
script = ExtResource("2_nywcv")
[node name="RichTextLabel" type="RichTextLabel" parent="."]
unique_name_in_owner = true
layout_mode = 2
bbcode_enabled = true
text = "A [wave]veeeeeeeeeeeeeery[/wave] long line option that should wrap so devs can have long options......"
fit_content = true
scroll_active = false
[node name="Handler" type="Button" parent="."]
unique_name_in_owner = true
layout_mode = 2
theme_override_fonts/font = ExtResource("2_5iw2f")
theme_override_font_sizes/font_size = 12
theme_override_styles/focus = SubResource("StyleBoxEmpty_we03b")
flat = true
alignment = 0
text_overrun_behavior = 4

View file

@ -0,0 +1,17 @@
extends PopochiuDialogText
#region Private ####################################################################################
func _modify_size(msg: String, _target_position: Vector2) -> void:
var _size := await _calculate_size(msg)
# Define size and position (before calculating overflow)
rich_text_label.size.y = _size.y
rich_text_label.position.y = get_meta(DFLT_POSITION).y - (_size.y - get_meta(DFLT_SIZE).y)
func _append_text(msg: String, props: Dictionary) -> void:
rich_text_label.text = "[center][color=%s]%s[/color][/center]" % [props.color.to_html(), msg]
#endregion

View file

@ -0,0 +1,58 @@
[gd_scene load_steps=4 format=3 uid="uid://bpl3qjbxonfpb"]
[ext_resource type="Script" path="res://addons/popochiu/engine/objects/gui/components/dialog_text/dialog_caption/dialog_caption.gd" id="1_17s2p"]
[ext_resource type="Theme" uid="uid://dpequqav4rjaf" path="res://addons/popochiu/engine/objects/gui/resources/base_gui_theme.tres" id="1_xoamn"]
[ext_resource type="Texture2D" uid="uid://h156lkhxk5tl" path="res://addons/popochiu/engine/objects/gui/components/dialog_text/images/ico_continue.png" id="3_etbl2"]
[node name="DialogCaption" type="Control" groups=["popochiu_gui_component"]]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 2
theme = ExtResource("1_xoamn")
script = ExtResource("1_17s2p")
[node name="RichTextLabel" type="RichTextLabel" parent="."]
unique_name_in_owner = true
clip_contents = false
custom_minimum_size = Vector2(16, 16)
layout_mode = 1
anchors_preset = 12
anchor_top = 1.0
anchor_right = 1.0
anchor_bottom = 1.0
offset_left = 20.0
offset_top = -20.0
offset_right = -20.0
offset_bottom = -4.0
grow_horizontal = 2
grow_vertical = 0
size_flags_horizontal = 0
mouse_filter = 2
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/outline_size = 4
bbcode_enabled = true
text = "[center]A [shake]caption[/shake] dialog text[/center]"
fit_content = true
scroll_active = false
meta_underlined = false
[node name="ContinueIcon" type="TextureProgressBar" parent="RichTextLabel"]
unique_name_in_owner = true
texture_filter = 1
layout_mode = 1
anchors_preset = 3
anchor_left = 1.0
anchor_top = 1.0
anchor_right = 1.0
anchor_bottom = 1.0
offset_top = -16.0
offset_right = 16.0
grow_horizontal = 0
grow_vertical = 0
value = 100.0
fill_mode = 2
texture_progress = ExtResource("3_etbl2")

View file

@ -0,0 +1,47 @@
extends PopochiuDialogText
#region Private ####################################################################################
func _modify_size(msg: String, target_position: Vector2) -> void:
var _size := await _calculate_size(msg)
# Define size and position (before calculating overflow)
rich_text_label.size = _size
rich_text_label.position = target_position - rich_text_label.size / 2.0
rich_text_label.position.y -= rich_text_label.size.y / 2.0
# Calculate overflow and reposition
if rich_text_label.position.x < 0.0:
rich_text_label.position.x = limit_margin
elif rich_text_label.position.x + rich_text_label.size.x + continue_icon_size.x > _x_limit:
rich_text_label.position.x = (
_x_limit - limit_margin - rich_text_label.size.x - continue_icon_size.x
)
if rich_text_label.position.y < 0.0:
rich_text_label.position.y = limit_margin
elif rich_text_label.position.y + rich_text_label.size.y > _y_limit:
rich_text_label.position.y = _y_limit - limit_margin - rich_text_label.size.y
func _set_default_label_size(lbl: Label) -> void:
lbl.size.y = get_meta(DFLT_SIZE).y
func _append_text(msg: String, props: Dictionary) -> void:
var center: float = floor(rich_text_label.position.x + (rich_text_label.size.x / 2))
if center == props.position.x:
rich_text_label.text = "[center]%s[/center]" % msg
elif center < props.position.x:
rich_text_label.text = "[right]%s[/right]" % msg
else:
rich_text_label.text = msg
func _get_icon_from_position() -> float:
return rich_text_label.size.y / 2.0 - 1.0
func _get_icon_to_position() -> float:
return rich_text_label.size.y / 2.0 + 3.0
#endregion

View file

@ -0,0 +1,47 @@
[gd_scene load_steps=4 format=3 uid="uid://bn7o13nv11ka1"]
[ext_resource type="Script" path="res://addons/popochiu/engine/objects/gui/components/dialog_text/dialog_overhead/dialog_overhead.gd" id="1_a5mdx"]
[ext_resource type="Theme" uid="uid://dpequqav4rjaf" path="res://addons/popochiu/engine/objects/gui/resources/base_gui_theme.tres" id="2_t336a"]
[ext_resource type="Texture2D" uid="uid://h156lkhxk5tl" path="res://addons/popochiu/engine/objects/gui/components/dialog_text/images/ico_continue.png" id="3_67j10"]
[node name="DialogOverhead" type="Control" groups=["popochiu_gui_component"]]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 2
theme = ExtResource("2_t336a")
script = ExtResource("1_a5mdx")
[node name="RichTextLabel" type="RichTextLabel" parent="."]
unique_name_in_owner = true
clip_contents = false
custom_minimum_size = Vector2(16, 16)
layout_mode = 0
offset_right = 153.0
offset_bottom = 16.0
size_flags_horizontal = 0
mouse_filter = 2
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/outline_size = 4
bbcode_enabled = true
text = "An [shake]overhead[/shake] dialog text"
fit_content = true
scroll_active = false
meta_underlined = false
[node name="ContinueIcon" type="TextureProgressBar" parent="RichTextLabel"]
unique_name_in_owner = true
texture_filter = 1
layout_mode = 1
anchors_preset = 1
anchor_left = 1.0
anchor_right = 1.0
offset_right = 16.0
offset_bottom = 16.0
grow_horizontal = 0
value = 100.0
fill_mode = 2
texture_progress = ExtResource("3_67j10")

View file

@ -0,0 +1,45 @@
extends PopochiuDialogText
@onready var left_avatar_container: PanelContainer = %LeftAvatarContainer
@onready var left_avatar: TextureRect = %LeftAvatar
@onready var right_avatar_container: PanelContainer = %RightAvatarContainer
@onready var right_avatar: TextureRect = %RightAvatar
#region Godot ######################################################################################
func _ready() -> void:
super()
# Connect to singletons signals
PopochiuUtils.c.character_spoke.connect(_update_avatar)
#endregion
#region Private ####################################################################################
func _update_avatar(chr: PopochiuCharacter, _msg := '') -> void:
if not rich_text_label.visible:
return
left_avatar_container.modulate.a = 0.0
left_avatar.texture = null
right_avatar_container.modulate.a = 0.0
right_avatar.texture = null
var char_pos: Vector2 = PopochiuUtils.get_screen_coords_for(chr).floor() / (
PopochiuUtils.e.scale if PopochiuUtils.e.settings.scale_gui else Vector2.ONE
)
if char_pos.x <= PopochiuUtils.e.half_width:
left_avatar_container.modulate.a = 1.0
left_avatar.texture = chr.get_avatar_for_emotion(chr.emotion)
else:
right_avatar_container.modulate.a = 1.0
right_avatar.texture = chr.get_avatar_for_emotion(chr.emotion)
func _set_default_size() -> void:
pass
#endregion

View file

@ -0,0 +1,106 @@
[gd_scene load_steps=6 format=3 uid="uid://33wmak2jumqm"]
[ext_resource type="Script" path="res://addons/popochiu/engine/objects/gui/components/dialog_text/dialog_portrait/dialog_portrait.gd" id="1_ejue5"]
[ext_resource type="Theme" uid="uid://dpequqav4rjaf" path="res://addons/popochiu/engine/objects/gui/resources/base_gui_theme.tres" id="1_x1xka"]
[ext_resource type="Texture2D" uid="uid://h156lkhxk5tl" path="res://addons/popochiu/engine/objects/gui/components/dialog_text/images/ico_continue.png" id="4_lqu2o"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_8fbbc"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_mjjs7"]
content_margin_left = 4.0
content_margin_top = 2.0
content_margin_right = 4.0
content_margin_bottom = 2.0
bg_color = Color(0, 0, 0, 0.705882)
[node name="DialogPortrait" type="Control" groups=["popochiu_gui_component"]]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 2
theme = ExtResource("1_x1xka")
script = ExtResource("1_ejue5")
[node name="PanelContainer" type="PanelContainer" parent="."]
layout_mode = 1
anchors_preset = 12
anchor_top = 1.0
anchor_right = 1.0
anchor_bottom = 1.0
offset_top = -48.0
grow_horizontal = 2
grow_vertical = 0
mouse_filter = 2
theme_override_styles/panel = SubResource("StyleBoxEmpty_8fbbc")
[node name="HBoxContainer" type="HBoxContainer" parent="PanelContainer"]
layout_mode = 2
mouse_filter = 2
theme_override_constants/separation = 2
[node name="LeftAvatarContainer" type="PanelContainer" parent="PanelContainer/HBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
mouse_filter = 2
[node name="LeftAvatar" type="TextureRect" parent="PanelContainer/HBoxContainer/LeftAvatarContainer"]
unique_name_in_owner = true
texture_filter = 1
custom_minimum_size = Vector2(48, 48)
layout_mode = 2
size_flags_vertical = 4
mouse_filter = 2
stretch_mode = 3
[node name="TextContainer" type="PanelContainer" parent="PanelContainer/HBoxContainer"]
layout_mode = 2
size_flags_horizontal = 3
mouse_filter = 2
theme_override_styles/panel = SubResource("StyleBoxFlat_mjjs7")
[node name="RichTextLabel" type="RichTextLabel" parent="PanelContainer/HBoxContainer/TextContainer"]
unique_name_in_owner = true
clip_contents = false
custom_minimum_size = Vector2(16, 16)
layout_mode = 2
size_flags_horizontal = 3
mouse_filter = 2
bbcode_enabled = true
text = "A [shake]portrait[/shake] dialog text."
scroll_active = false
meta_underlined = false
[node name="ContinueIcon" type="TextureProgressBar" parent="PanelContainer/HBoxContainer/TextContainer/RichTextLabel"]
unique_name_in_owner = true
texture_filter = 1
layout_mode = 1
anchors_preset = 3
anchor_left = 1.0
anchor_top = 1.0
anchor_right = 1.0
anchor_bottom = 1.0
offset_left = -16.0
offset_top = -16.0
grow_horizontal = 0
grow_vertical = 0
mouse_filter = 2
value = 100.0
fill_mode = 2
texture_progress = ExtResource("4_lqu2o")
[node name="RightAvatarContainer" type="PanelContainer" parent="PanelContainer/HBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
mouse_filter = 2
[node name="RightAvatar" type="TextureRect" parent="PanelContainer/HBoxContainer/RightAvatarContainer"]
unique_name_in_owner = true
texture_filter = 1
custom_minimum_size = Vector2(48, 48)
layout_mode = 2
size_flags_vertical = 4
mouse_filter = 2
stretch_mode = 3

View file

@ -0,0 +1,301 @@
class_name PopochiuDialogText
extends Control
## Show dialogue texts char by char using a [RichTextLabel].
##
## An invisible [Label] is used to calculate the width of the [RichTextLabel] node.
signal animation_finished
signal text_show_started
signal text_show_finished
const DFLT_SIZE := "dflt_size"
const DFLT_POSITION := "dflt_position"
@export var wrap_width := 200.0
@export var limit_margin := 4.0
var tween: Tween = null
var continue_icon_tween: Tween = null
var _secs_per_character := 1.0
var _is_waiting_input := false
var _auto_continue := false
var _dialog_pos := Vector2.ZERO
var _x_limit := 0.0
var _y_limit := 0.0
@onready var rich_text_label: RichTextLabel = %RichTextLabel
@onready var continue_icon: TextureProgressBar = %ContinueIcon
@onready var continue_icon_size := continue_icon.texture_progress.get_size()
#region Godot ######################################################################################
func _ready() -> void:
# Set the default values
rich_text_label.text = ""
set_meta(DFLT_SIZE, rich_text_label.size)
set_meta(DFLT_POSITION, rich_text_label.position)
modulate.a = 0.0
_secs_per_character = PopochiuUtils.e.text_speed
_x_limit = PopochiuUtils.e.width / (
PopochiuUtils.e.scale.x if PopochiuUtils.e.settings.scale_gui else 1.0
)
_y_limit = PopochiuUtils.e.height / (
PopochiuUtils.e.scale.y if PopochiuUtils.e.settings.scale_gui else 1.0
)
# Connect to singletons events
PopochiuUtils.e.text_speed_changed.connect(change_speed)
PopochiuUtils.c.character_spoke.connect(_show_dialogue)
continue_icon.hide()
func _input(event: InputEvent) -> void:
if (
not PopochiuUtils.get_click_or_touch_index(event) in [MOUSE_BUTTON_LEFT, MOUSE_BUTTON_RIGHT]
or modulate.a == 0.0
):
return
accept_event()
if rich_text_label.visible_ratio == 1.0:
disappear()
else:
stop()
#endregion
#region Public #####################################################################################
func play_text(props: Dictionary) -> void:
var msg: String = PopochiuUtils.e.get_text(props.text)
_is_waiting_input = false
_dialog_pos = props.position
if PopochiuConfig.should_talk_gibberish():
msg = PopochiuUtils.d.create_gibberish(msg)
# Call the virtual method that modifies the size of the RichTextLabel in case the dialog style
# requires it.
await _modify_size(msg, props.position)
# Assign the text and align mode
msg = "[color=%s]%s[/color]" % [props.color.to_html(), msg]
_append_text(msg, props)
if _secs_per_character > 0.0:
# The text will appear with an animation
if is_instance_valid(tween) and tween.is_running():
tween.kill()
tween = create_tween()
tween.tween_property(
rich_text_label, "visible_ratio",
1,
_secs_per_character * rich_text_label.get_total_character_count()
).from(0.0)
tween.finished.connect(_wait_input)
else:
_wait_input()
modulate.a = 1.0
func stop() ->void:
if modulate.a == 0.0:
return
if _is_waiting_input:
_notify_completion()
else:
# Skip tweens
if is_instance_valid(tween) and tween.is_running():
tween.kill()
rich_text_label.visible_ratio = 1.0
_wait_input()
func disappear() -> void:
if modulate.a == 0.0: return
_auto_continue = false
modulate.a = 0.0
_is_waiting_input = false
if is_instance_valid(tween) and tween.is_running():
tween.kill()
rich_text_label.clear()
rich_text_label.text = ""
_set_default_size()
continue_icon.hide()
continue_icon.modulate.a = 1.0
if is_instance_valid(continue_icon_tween) and continue_icon_tween.is_running():
continue_icon_tween.kill()
set_process_input(false)
text_show_finished.emit()
PopochiuUtils.g.dialog_line_finished.emit()
func change_speed() -> void:
_secs_per_character = PopochiuUtils.e.text_speed
#endregion
#region Private ####################################################################################
func _show_dialogue(chr: PopochiuCharacter, msg := "") -> void:
if not visible: return
play_text({
text = msg,
color = chr.text_color,
position = PopochiuUtils.get_screen_coords_for(chr, chr.dialog_pos).floor() / (
PopochiuUtils.e.scale if PopochiuUtils.e.settings.scale_gui else Vector2.ONE
),
})
PopochiuUtils.g.dialog_line_started.emit()
set_process_input(true)
text_show_started.emit()
func _modify_size(_msg: String, _target_position: Vector2) -> void:
await get_tree().process_frame
## Creates a RichTextLabel to calculate the resulting size of this node once the whole text is shown.
func _calculate_size(msg: String) -> Vector2:
var rt := RichTextLabel.new()
rt.add_theme_font_override("normal_font", get_theme_font("normal_font"))
rt.bbcode_enabled = true
rt.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
rt.text = msg
rt.size = get_meta(DFLT_SIZE)
rich_text_label.add_child(rt)
# Create a Label to check if the text exceeds the wrap_width
var lbl := Label.new()
lbl.add_theme_font_override("normal_font", get_theme_font("normal_font"))
_set_default_label_size(lbl)
lbl.text = rt.get_parsed_text()
rich_text_label.add_child(lbl)
rt.clear()
rt.text = ""
await get_tree().process_frame
var _size := lbl.size
if _size.x > wrap_width:
# This node will have the width of the wrap_width
_size.x = wrap_width
rt.fit_content = true
rt.size.x = _size.x
rt.text = msg
await get_tree().process_frame
_size = rt.size
else:
# This node will have the width of the text
_size.y = get_meta(DFLT_SIZE).y
var characters_count := lbl.get_total_character_count()
lbl.free()
rt.free()
return _size
func _set_default_label_size(lbl: Label) -> void:
lbl.size = get_meta(DFLT_SIZE)
func _append_text(msg: String, _props: Dictionary) -> void:
rich_text_label.append_text(msg)
func _wait_input() -> void:
_is_waiting_input = true
if is_instance_valid(tween) and tween.finished.is_connected(_wait_input):
tween.finished.disconnect(_wait_input)
if PopochiuUtils.e.auto_continue_after >= 0.0:
_auto_continue = true
await get_tree().create_timer(PopochiuUtils.e.auto_continue_after + 0.2).timeout
if _auto_continue:
_continue(true)
else:
_show_icon()
func _show_icon() -> void:
if is_instance_valid(continue_icon_tween) and continue_icon_tween.is_running():
continue_icon_tween.kill()
continue_icon_tween = create_tween()
if not PopochiuUtils.e.settings.auto_continue_text:
# For manual continuation: make the icon jump
continue_icon.value = 100.0
continue_icon_tween.tween_property(
continue_icon, "position:y", _get_icon_to_position(), 0.8
).from(_get_icon_from_position()).set_trans(Tween.TRANS_BOUNCE).set_ease(Tween.EASE_OUT)
continue_icon_tween.set_loops()
else:
# For automatic continuation: Make the icon appear as a progress bar indicating the time
# players have to read before auto-continuing.
continue_icon.value = 0.0
continue_icon.position.y = size.y / 2.0
continue_icon_tween.tween_property(
continue_icon, "value",
100.0, 3.0,
).from_current().set_ease(Tween.EASE_OUT)
continue_icon_tween.finished.connect(_continue)
continue_icon_tween.pause()
await get_tree().create_timer(0.2).timeout
continue_icon_tween.play()
continue_icon.show()
func _get_icon_from_position() -> float:
return rich_text_label.size.y - continue_icon.size.y + 2.0
func _get_icon_to_position() -> float:
return rich_text_label.size.y - continue_icon.size.y - 1.0
func _notify_completion() -> void:
disappear()
animation_finished.emit()
func _continue(forced_continue := false) -> void:
if PopochiuUtils.e.settings.auto_continue_text or forced_continue:
disappear()
func _set_default_size() -> void:
rich_text_label.size = get_meta(DFLT_SIZE)
#endregion

View file

@ -0,0 +1 @@
uid://1kyr8r56atd8

View file

@ -0,0 +1,38 @@
[gd_scene load_steps=4 format=3 uid="uid://cymfte4xe3tnw"]
[ext_resource type="Theme" uid="uid://dpequqav4rjaf" path="res://addons/popochiu/engine/objects/gui/resources/base_gui_theme.tres" id="1_mrmwc"]
[ext_resource type="Script" path="res://addons/popochiu/engine/objects/gui/components/dialog_text/dialog_text.gd" id="2_adpg7"]
[ext_resource type="Texture2D" uid="uid://h156lkhxk5tl" path="res://addons/popochiu/engine/objects/gui/components/dialog_text/images/ico_continue.png" id="3_fqlmr"]
[node name="DialogText" type="Control" groups=["popochiu_gui_component"]]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 2
theme = ExtResource("1_mrmwc")
script = ExtResource("2_adpg7")
[node name="RichTextLabel" type="RichTextLabel" parent="."]
unique_name_in_owner = true
layout_mode = 0
offset_right = 74.0
offset_bottom = 12.0
text = "Dialog text"
fit_content = true
[node name="ContinueIcon" type="TextureProgressBar" parent="RichTextLabel"]
unique_name_in_owner = true
texture_filter = 1
layout_mode = 1
anchors_preset = 1
anchor_left = 1.0
anchor_right = 1.0
offset_right = 16.0
offset_bottom = 16.0
grow_horizontal = 0
value = 100.0
fill_mode = 2
texture_progress = ExtResource("3_fqlmr")

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 B

View file

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://h156lkhxk5tl"
path="res://.godot/imported/ico_continue.png-1c56d7b39fdf03dafd5aacca996d24e0.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/popochiu/engine/objects/gui/components/dialog_text/images/ico_continue.png"
dest_files=["res://.godot/imported/ico_continue.png-1c56d7b39fdf03dafd5aacca996d24e0.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

View file

@ -0,0 +1,39 @@
extends Control
class_name PopochiuHoverText
@export var hide_during_dialogs := false
@onready var label: RichTextLabel = $RichTextLabel
#region Godot ######################################################################################
func _ready() -> void:
label.text = ""
# Connect to autoloads' signals
PopochiuUtils.g.hover_text_shown.connect(_show_text)
PopochiuUtils.g.dialog_line_started.connect(_on_dialog_line_started)
PopochiuUtils.g.dialog_line_finished.connect(_on_dialog_line_finished)
#endregion
#region Virtual ####################################################################################
func _show_text(txt := "") -> void:
label.text = "[center]%s[/center]" % txt
#endregion
#region Private ####################################################################################
func _on_dialog_line_started() -> void:
if hide_during_dialogs:
hide()
func _on_dialog_line_finished() -> void:
if hide_during_dialogs:
show()
#endregion

View file

@ -0,0 +1 @@
uid://cb8ngs7ei1rao

View file

@ -0,0 +1,29 @@
[gd_scene load_steps=3 format=3 uid="uid://esorelppu4hw"]
[ext_resource type="Theme" uid="uid://dpequqav4rjaf" path="res://addons/popochiu/engine/objects/gui/resources/base_gui_theme.tres" id="1_s7kd8"]
[ext_resource type="Script" path="res://addons/popochiu/engine/objects/gui/components/hover_text/hover_text.gd" id="2_r2ckj"]
[node name="HoverText" type="Control" groups=["popochiu_gui_component"]]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 2
theme = ExtResource("1_s7kd8")
script = ExtResource("2_r2ckj")
[node name="RichTextLabel" type="RichTextLabel" parent="."]
layout_mode = 1
anchors_preset = 10
anchor_right = 1.0
offset_bottom = 12.0
grow_horizontal = 2
mouse_filter = 2
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/outline_size = 4
bbcode_enabled = true
text = "[center]text for hovered objects[/center]"
fit_content = true
scroll_active = false

View file

@ -0,0 +1,183 @@
extends Control
@export var always_visible := false
@export var hide_when_gui_is_blocked := false
## Defines the height in pixels of the zone where moving the mouse in the top of the screen will
## make the bar to show. Note: This value will be affected by the Experimental Scale GUI checkbox
## in Project Settings > Popochiu > GUI.
@export var input_zone_height := 4
var is_disabled := false
var tween: Tween = null
var _is_hidden := true
@onready var panel_container: PanelContainer = %PanelContainer
@onready var box: Container = %Box
@onready var hidden_y := panel_container.position.y - panel_container.size.y
#region Godot ######################################################################################
func _ready():
if not always_visible:
panel_container.position.y = hidden_y
# Connect to singletons signals
PopochiuUtils.g.blocked.connect(_on_gui_blocked)
PopochiuUtils.g.unblocked.connect(_on_gui_unblocked)
PopochiuUtils.i.item_added.connect(_add_item)
PopochiuUtils.i.item_removed.connect(_remove_item)
PopochiuUtils.i.item_replaced.connect(_replace_item)
PopochiuUtils.i.inventory_show_requested.connect(_show_and_hide)
PopochiuUtils.i.inventory_hide_requested.connect(_close)
# Check if there are already items in the inventory (set manually in the scene)
for ii in box.get_children():
if ii is PopochiuInventoryItem:
ii.in_inventory = true
ii.selected.connect(_change_cursor)
set_process_input(not always_visible)
func _input(event: InputEvent) -> void:
if not event is InputEventMouseMotion: return
var rect := panel_container.get_rect()
rect.size += Vector2(0.0, input_zone_height)
if PopochiuUtils.e.settings.scale_gui:
rect = Rect2(
panel_container.get_rect().position * PopochiuUtils.e.scale,
panel_container.get_rect().size * PopochiuUtils.e.scale
)
if _is_hidden and rect.has_point(get_global_mouse_position()):
_open()
elif not _is_hidden and not rect.has_point(get_global_mouse_position()):
_close()
#endregion
#region Private ####################################################################################
func _open() -> void:
if always_visible: return
if not is_disabled and panel_container.position.y != hidden_y: return
if is_instance_valid(tween) and tween.is_running():
tween.kill()
tween = create_tween().set_trans(Tween.TRANS_EXPO).set_ease(Tween.EASE_OUT)
tween.tween_property(
panel_container, "position:y", 0.0, 0.5
).from(hidden_y if not is_disabled else panel_container.position.y)
_is_hidden = false
func _close() -> void:
if always_visible: return
await get_tree().process_frame
if is_instance_valid(tween) and tween.is_running():
tween.kill()
tween = create_tween()
tween.tween_property(
panel_container, "position:y",
hidden_y if not is_disabled else hidden_y - 3.5,
0.2
).from(0.0).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN)
_is_hidden = true
func _on_tween_finished() -> void:
_is_hidden = panel_container.position.y == hidden_y
func _change_cursor(item: PopochiuInventoryItem) -> void:
PopochiuUtils.i.set_active_item(item)
func _on_gui_blocked() -> void:
set_process_input(false)
if hide_when_gui_is_blocked:
hide()
func _on_gui_unblocked() -> void:
set_process_input(true)
if hide_when_gui_is_blocked:
show()
func _add_item(item: PopochiuInventoryItem, animate := true) -> void:
box.add_child(item)
item.expand_mode = TextureRect.EXPAND_FIT_WIDTH
item.custom_minimum_size.y = box.size.y
item.selected.connect(_change_cursor)
if not always_visible and animate:
# Show the inventory for a while and hide after a couple of seconds so players can see the
# item being added to the inventory
set_process_input(false)
_open()
await get_tree().create_timer(2.0).timeout
# The mouse not being on the inventory can close the inventory prior to the 2 seconds
# expiring. This check fixes this. Bug 350.
if not _is_hidden:
_close()
await get_tree().create_timer(0.5).timeout
set_process_input(true)
else:
await get_tree().process_frame
PopochiuUtils.i.item_add_done.emit(item)
func _remove_item(item: PopochiuInventoryItem, animate := true) -> void:
item.selected.disconnect(_change_cursor)
box.remove_child(item)
if not always_visible:
PopochiuUtils.cursor.show_cursor()
PopochiuUtils.g.show_hover_text()
if animate:
_close()
await get_tree().create_timer(1.0).timeout
await get_tree().process_frame
PopochiuUtils.i.item_remove_done.emit(item)
func _replace_item(item: PopochiuInventoryItem, new_item: PopochiuInventoryItem) -> void:
item.replace_by(new_item)
await get_tree().process_frame
PopochiuUtils.i.item_replace_done.emit()
func _show_and_hide(time := 1.0) -> void:
set_process_input(false)
_open()
await tween.finished
await PopochiuUtils.e.wait(time)
_close()
await tween.finished
set_process_input(true)
PopochiuUtils.i.inventory_shown.emit()
#endregion

View file

@ -0,0 +1 @@
uid://cnso60yytp7ot

View file

@ -0,0 +1,27 @@
[gd_scene load_steps=3 format=3 uid="uid://ciar5j7qm85bc"]
[ext_resource type="Script" path="res://addons/popochiu/engine/objects/gui/components/inventory_bar/inventory_bar.gd" id="1"]
[ext_resource type="Theme" uid="uid://dpequqav4rjaf" path="res://addons/popochiu/engine/objects/gui/resources/base_gui_theme.tres" id="1_aynoo"]
[node name="InventoryBar" type="Control" groups=["popochiu_gui_component"]]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 2
theme = ExtResource("1_aynoo")
script = ExtResource("1")
[node name="PanelContainer" type="PanelContainer" parent="."]
unique_name_in_owner = true
texture_filter = 1
layout_mode = 0
offset_right = 36.0
offset_bottom = 24.0
[node name="Box" type="HBoxContainer" parent="PanelContainer"]
unique_name_in_owner = true
layout_mode = 2
mouse_filter = 2

Binary file not shown.

After

Width:  |  Height:  |  Size: 249 B

View file

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://s4phlorab5ds"
path="res://.godot/imported/inventory_grid_down_button.png-ffac1afa54860747ab14c6a1f8220bae.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/popochiu/engine/objects/gui/components/inventory_grid/images/inventory_grid_down_button.png"
dest_files=["res://.godot/imported/inventory_grid_down_button.png-ffac1afa54860747ab14c6a1f8220bae.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 B

View file

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dfa511cxg31g5"
path="res://.godot/imported/inventory_grid_up_button.png-dd40c7fcb22a7dfc4741c7c1c2d05d54.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/popochiu/engine/objects/gui/components/inventory_grid/images/inventory_grid_up_button.png"
dest_files=["res://.godot/imported/inventory_grid_up_button.png-dd40c7fcb22a7dfc4741c7c1c2d05d54.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

View file

@ -0,0 +1,226 @@
@tool
class_name PopochiuInventoryGrid
extends HBoxContainer
const EMPTY_SLOT := "[Empty Slot]00"
@export var slot_scene: PackedScene = null : set = set_slot_scene
@export var columns := 4 : set = set_columns
@export var visible_rows := 2 : set = set_visible_rows
@export var number_of_slots := 16 : set = set_number_of_slots
@export var h_separation := 0 : set = set_h_separation
@export var v_separation := 0 : set = set_v_separation
@export var show_arrows := true : set = set_show_arrows
@export var scroll_with_mouse_wheel := true
var rows := 0
var max_scroll := 0.0
var slot_size: float = 0.0
@onready var scroll_container: ScrollContainer = $ScrollContainer
@onready var box: GridContainer = %Box
@onready var scroll_buttons: VBoxContainer = $ScrollButtons
@onready var up: TextureButton = %Up
@onready var down: TextureButton = %Down
@onready var gap_size: int = box.get_theme_constant("v_separation")
#region Godot ######################################################################################
func _ready():
if Engine.is_editor_hint():
_update_box()
return
scroll_container.mouse_filter = (
Control.MOUSE_FILTER_PASS if scroll_with_mouse_wheel else Control.MOUSE_FILTER_IGNORE
)
_update_box()
_calculate_rows_and_scroll()
# _check_starting_items()
# Connect to child signals
up.pressed.connect(_on_up_pressed)
down.pressed.connect(_on_down_pressed)
scroll_container.get_v_scroll_bar().value_changed.connect(_on_scroll)
# Connect to singletons signals
PopochiuUtils.i.item_added.connect(_add_item)
PopochiuUtils.i.item_removed.connect(_remove_item)
PopochiuUtils.i.item_replaced.connect(_replace_item)
_check_scroll_buttons()
#endregion
#region SetGet #####################################################################################
func set_visible_rows(value: int) -> void:
visible_rows = value
_update_box()
func set_columns(value: int) -> void:
columns = value
_update_box()
func set_slot_scene(value: PackedScene) -> void:
slot_scene = value
_update_box()
func set_number_of_slots(value: int) -> void:
number_of_slots = value
_update_box()
func set_h_separation(value: int) -> void:
h_separation = value
_update_box()
func set_v_separation(value: int) -> void:
v_separation = value
_update_box()
func set_show_arrows(value: bool) -> void:
show_arrows = value
if is_instance_valid(scroll_buttons):
scroll_buttons.visible = value
#endregion
#region Private ####################################################################################
func _update_box() -> void:
if not is_instance_valid(box): return
box.columns = columns
box.add_theme_constant_override("h_separation", h_separation)
box.add_theme_constant_override("v_separation", v_separation)
# Fix: remove the child immediately (instead of calling queue_free()), and do not await for
# a process frame cause it can cause an issue when adding items marked as "Start with it".
for child in box.get_children():
child.free()
for idx in number_of_slots:
var slot := slot_scene.instantiate()
box.add_child(slot)
slot.name = EMPTY_SLOT
slot_size = slot.size.y
scroll_container.custom_minimum_size = Vector2(
(columns * (slot_size + h_separation)) - h_separation,
(visible_rows * (slot_size + v_separation)) - v_separation
)
## Calculate the number of rows in the box and the max scroll
func _calculate_rows_and_scroll() -> void:
var visible_slots := 0
for slot in box.get_children():
if slot.visible:
visible_slots += 1
@warning_ignore("integer_division")
rows = visible_slots / box.columns
max_scroll = ((slot_size + gap_size) * int(rows / 2))
## Check if there are inventory items in the scene tree and add them to the
## Inventory interface class (I).
func _check_starting_items() -> void:
for slot in box.get_children():
if (slot.get_child_count() > 0
and slot.get_child(0) is PopochiuInventoryItem
):
PopochiuUtils.i.items.append(slot.get_child(0).script_name)
slot.name = slot.get_child(0).script_name
else:
slot.name = EMPTY_SLOT
func _on_up_pressed() -> void:
scroll_container.scroll_vertical -= (slot_size + gap_size) + 1
_check_scroll_buttons()
func _on_down_pressed() -> void:
scroll_container.scroll_vertical += (slot_size + gap_size) + 1
_check_scroll_buttons()
func _add_item(item: PopochiuInventoryItem, _animate := true) -> void:
var slot := box.get_child(PopochiuUtils.i.items.size() - 1)
slot.name = "[%s]" % item.script_name
slot.add_child(item)
item.expand_mode = TextureRect.EXPAND_FIT_WIDTH
if slot.has_method("get_content_height"):
item.custom_minimum_size.y = slot.get_content_height()
else:
item.custom_minimum_size.y = slot.size.y
box.set_meta(item.script_name, slot)
item.selected.connect(_change_cursor)
_check_scroll_buttons()
# Common call to all inventories. Should be in the class from where inventory panels will
# inherit from
await get_tree().process_frame
PopochiuUtils.i.item_add_done.emit(item)
func _remove_item(item: PopochiuInventoryItem, _animate := true) -> void:
item.selected.disconnect(_change_cursor)
box.get_meta(item.script_name).remove_child(item)
box.get_meta(item.script_name).name = EMPTY_SLOT
_check_scroll_buttons()
await get_tree().process_frame
PopochiuUtils.i.item_remove_done.emit(item)
func _replace_item(
item: PopochiuInventoryItem, new_item: PopochiuInventoryItem
) -> void:
item.replace_by(new_item)
box.remove_meta(item.script_name)
box.set_meta(new_item.script_name, new_item.get_parent())
_check_scroll_buttons()
await get_tree().process_frame
PopochiuUtils.i.item_replace_done.emit()
func _change_cursor(item: PopochiuInventoryItem) -> void:
PopochiuUtils.i.set_active_item(item)
## Checks if the UP and DOWN buttons should be enabled
func _check_scroll_buttons() -> void:
up.disabled = scroll_container.scroll_vertical == 0
down.disabled = (
scroll_container.scroll_vertical >= max_scroll
or not (PopochiuUtils.i.items.size() > box.columns * visible_rows)
)
func _on_scroll(_value: float) -> void:
_check_scroll_buttons()
#endregion

View file

@ -0,0 +1 @@
uid://5iimjg0vmeqf

View file

@ -0,0 +1,91 @@
[gd_scene load_steps=14 format=3 uid="uid://cn2b5v8k1lseo"]
[ext_resource type="Script" path="res://addons/popochiu/engine/objects/gui/components/inventory_grid/inventory_grid.gd" id="1_0y5i1"]
[ext_resource type="Theme" uid="uid://dpequqav4rjaf" path="res://addons/popochiu/engine/objects/gui/resources/base_gui_theme.tres" id="1_kaq1v"]
[ext_resource type="Texture2D" uid="uid://dfa511cxg31g5" path="res://addons/popochiu/engine/objects/gui/components/inventory_grid/images/inventory_grid_up_button.png" id="2_6y3so"]
[ext_resource type="PackedScene" uid="uid://db6csk6i4f3un" path="res://addons/popochiu/engine/objects/gui/components/inventory_grid/inventory_grid_slot.tscn" id="3_ma7vn"]
[ext_resource type="Texture2D" uid="uid://s4phlorab5ds" path="res://addons/popochiu/engine/objects/gui/components/inventory_grid/images/inventory_grid_down_button.png" id="3_yoinj"]
[sub_resource type="AtlasTexture" id="AtlasTexture_7tbkh"]
atlas = ExtResource("2_6y3so")
region = Rect2(0, 0, 16, 16)
[sub_resource type="AtlasTexture" id="AtlasTexture_yafup"]
atlas = ExtResource("2_6y3so")
region = Rect2(32, 0, 16, 16)
[sub_resource type="AtlasTexture" id="AtlasTexture_8r5xk"]
atlas = ExtResource("2_6y3so")
region = Rect2(16, 0, 16, 16)
[sub_resource type="AtlasTexture" id="AtlasTexture_73nr4"]
atlas = ExtResource("2_6y3so")
region = Rect2(48, 0, 16, 16)
[sub_resource type="AtlasTexture" id="AtlasTexture_mcgs4"]
atlas = ExtResource("3_yoinj")
region = Rect2(0, 0, 16, 16)
[sub_resource type="AtlasTexture" id="AtlasTexture_kw4h2"]
atlas = ExtResource("3_yoinj")
region = Rect2(32, 0, 16, 16)
[sub_resource type="AtlasTexture" id="AtlasTexture_pi25e"]
atlas = ExtResource("3_yoinj")
region = Rect2(16, 0, 16, 16)
[sub_resource type="AtlasTexture" id="AtlasTexture_pejpn"]
atlas = ExtResource("3_yoinj")
region = Rect2(48, 0, 16, 16)
[node name="InventoryGrid" type="HBoxContainer" groups=["popochiu_gui_component"]]
offset_right = 152.0
offset_bottom = 50.0
size_flags_horizontal = 3
size_flags_vertical = 3
mouse_filter = 0
theme = ExtResource("1_kaq1v")
script = ExtResource("1_0y5i1")
slot_scene = ExtResource("3_ma7vn")
[node name="ScrollButtons" type="VBoxContainer" parent="."]
custom_minimum_size = Vector2(24, 0)
layout_mode = 2
theme_override_constants/separation = 0
[node name="Up" type="TextureButton" parent="ScrollButtons"]
texture_filter = 1
layout_mode = 2
size_flags_vertical = 3
texture_normal = SubResource("AtlasTexture_7tbkh")
texture_pressed = SubResource("AtlasTexture_yafup")
texture_hover = SubResource("AtlasTexture_8r5xk")
texture_disabled = SubResource("AtlasTexture_73nr4")
stretch_mode = 3
[node name="Down" type="TextureButton" parent="ScrollButtons"]
texture_filter = 1
layout_mode = 2
size_flags_vertical = 3
texture_normal = SubResource("AtlasTexture_mcgs4")
texture_pressed = SubResource("AtlasTexture_kw4h2")
texture_hover = SubResource("AtlasTexture_pi25e")
texture_disabled = SubResource("AtlasTexture_pejpn")
stretch_mode = 3
[node name="ScrollContainer" type="ScrollContainer" parent="."]
custom_minimum_size = Vector2(100, 50)
layout_mode = 2
size_flags_horizontal = 3
scroll_vertical_custom_step = 27.0
horizontal_scroll_mode = 3
vertical_scroll_mode = 3
[node name="Box" type="GridContainer" parent="ScrollContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
theme_override_constants/h_separation = 0
theme_override_constants/v_separation = 0
columns = 4

View file

@ -0,0 +1,17 @@
[gd_scene load_steps=2 format=3 uid="uid://db6csk6i4f3un"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_fjc4l"]
content_margin_left = 2.0
content_margin_top = 2.0
content_margin_right = 2.0
content_margin_bottom = 2.0
bg_color = Color(0.180392, 0.172549, 0.607843, 1)
border_width_left = 1
border_width_top = 1
border_width_right = 1
border_width_bottom = 1
border_color = Color(1, 1, 1, 1)
[node name="Slot" type="PanelContainer"]
custom_minimum_size = Vector2(31, 25)
theme_override_styles/panel = SubResource("StyleBoxFlat_fjc4l")

View file

@ -0,0 +1,25 @@
extends "../popochiu_popup.gd"
#region Virtual ####################################################################################
## Called when the popup is opened. At this point it is not visible yet.
func _open() -> void:
pass
## Called when the popup is closed. The node hides after calling this method.
func _close() -> void:
pass
## Called when OK is pressed.
func _on_ok() -> void:
pass
## Called when CANCEL or X (top-right corner) are pressed.
func _on_cancel() -> void:
pass
#endregion

View file

@ -0,0 +1,82 @@
[gd_scene load_steps=7 format=3 uid="uid://d06okn5i6id2g"]
[ext_resource type="Theme" uid="uid://dpequqav4rjaf" path="res://addons/popochiu/engine/objects/gui/resources/base_gui_theme.tres" id="1_ck2qk"]
[ext_resource type="Script" path="res://addons/popochiu/engine/objects/gui/components/popups/confirmation_popup/confirmation_popup.gd" id="2_2ngwd"]
[ext_resource type="StyleBox" uid="uid://dbajakvkltfaj" path="res://addons/popochiu/engine/objects/gui/components/popups/popochiu_popup_panel_container.tres" id="3_jqrxu"]
[ext_resource type="Texture2D" uid="uid://cmxrewai8t2lm" path="res://addons/popochiu/engine/objects/gui/resources/images/close.png" id="3_n4smw"]
[ext_resource type="Texture2D" uid="uid://p32i25numi5e" path="res://addons/popochiu/engine/objects/gui/resources/images/close_highlight.png" id="4_4phlw"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_x73gy"]
[node name="ConfirmationPopup" type="Control" groups=["popochiu_gui_popup"]]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme = ExtResource("1_ck2qk")
script = ExtResource("2_2ngwd")
script_name = &"ConfirmationPopup"
title = "Confirmation"
[node name="Overlay" type="PanelContainer" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme_override_styles/panel = SubResource("StyleBoxEmpty_x73gy")
[node name="PanelContainer" type="PanelContainer" parent="Overlay"]
layout_mode = 2
size_flags_horizontal = 4
size_flags_vertical = 4
theme_override_styles/panel = ExtResource("3_jqrxu")
[node name="VBoxContainer" type="VBoxContainer" parent="Overlay/PanelContainer"]
layout_mode = 2
[node name="HeaderContainer" type="HBoxContainer" parent="Overlay/PanelContainer/VBoxContainer"]
layout_mode = 2
[node name="Title" type="Label" parent="Overlay/PanelContainer/VBoxContainer/HeaderContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
text = "Confirmation"
horizontal_alignment = 1
vertical_alignment = 1
[node name="Close" type="TextureButton" parent="Overlay/PanelContainer/VBoxContainer/HeaderContainer"]
unique_name_in_owner = true
texture_filter = 1
layout_mode = 2
size_flags_vertical = 4
texture_normal = ExtResource("3_n4smw")
texture_pressed = ExtResource("4_4phlw")
texture_hover = ExtResource("4_4phlw")
[node name="Question" type="Label" parent="Overlay/PanelContainer/VBoxContainer"]
layout_mode = 2
size_flags_horizontal = 3
text = "Yes or No?"
horizontal_alignment = 1
vertical_alignment = 1
autowrap_mode = 3
[node name="FooterContainer" type="HBoxContainer" parent="Overlay/PanelContainer/VBoxContainer"]
layout_mode = 2
size_flags_vertical = 10
alignment = 1
[node name="Ok" type="Button" parent="Overlay/PanelContainer/VBoxContainer/FooterContainer"]
unique_name_in_owner = true
layout_mode = 2
text = "ok"
[node name="Cancel" type="Button" parent="Overlay/PanelContainer/VBoxContainer/FooterContainer"]
unique_name_in_owner = true
layout_mode = 2
text = "cancel"

View file

@ -0,0 +1,13 @@
[gd_scene load_steps=2 format=3 uid="uid://b6dm3xvvr7dvi"]
[ext_resource type="FontFile" uid="uid://dixh1egf7k2fb" path="res://addons/popochiu/engine/objects/gui/fonts/monkeyisland_1991.ttf" id="1_o6vvl"]
[node name="DialogLine" type="RichTextLabel"]
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
size_flags_horizontal = 3
theme_override_fonts/normal_font = ExtResource("1_o6vvl")
bbcode_enabled = true
text = "Popochiu: Hi!"
fit_content = true

View file

@ -0,0 +1,13 @@
[gd_scene load_steps=2 format=3 uid="uid://2mnjw3qsi8hc"]
[ext_resource type="FontFile" uid="uid://dixh1egf7k2fb" path="res://addons/popochiu/engine/objects/gui/fonts/monkeyisland_1991.ttf" id="1_i1qxr"]
[node name="InteractionLine" type="RichTextLabel"]
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
size_flags_horizontal = 3
theme_override_fonts/normal_font = ExtResource("1_i1qxr")
bbcode_enabled = true
text = "Player [color=edf171]click[/color] Toy car"
fit_content = true

View file

@ -0,0 +1,57 @@
@tool
extends PopochiuPopup
@export var dialog_line: PackedScene = null
@export var interaction_line: PackedScene = null
@onready var lines_list: VBoxContainer = find_child("LinesList")
@onready var empty: Label = %Empty
@onready var lines_scroll: ScrollContainer = %LinesScroll
#region Godot ######################################################################################
func _ready() -> void:
super()
if Engine.is_editor_hint(): return
for c in lines_list.get_children():
(c as Control).queue_free()
#endregion
#region Virtual ####################################################################################
func _open() -> void:
if PopochiuUtils.e.history.is_empty():
empty.show()
lines_scroll.hide()
else:
empty.hide()
lines_scroll.show()
for data in PopochiuUtils.e.history:
var lbl: RichTextLabel
if data.has("character"):
lbl = dialog_line.instantiate()
lbl.text = "[color=%s]%s:[/color] %s" % [
(data.character as PopochiuCharacter).text_color.to_html(false),
(data.character as PopochiuCharacter).description,
data.text
]
else:
lbl = interaction_line.instantiate()
lbl.text = "[color=edf171]%s[/color] [color=a9ff9f]%s[/color]" % [
data.action, data.target
]
lines_list.add_child(lbl)
func _close() -> void:
for c in lines_list.get_children():
(c as Control).queue_free()
#endregion

View file

@ -0,0 +1 @@
uid://beng6nsf3gmgy

View file

@ -0,0 +1,115 @@
[gd_scene load_steps=12 format=3 uid="uid://dfrsiyyqncspo"]
[ext_resource type="Theme" uid="uid://dpequqav4rjaf" path="res://addons/popochiu/engine/objects/gui/resources/base_gui_theme.tres" id="1_ktant"]
[ext_resource type="Script" path="res://addons/popochiu/engine/objects/gui/components/popups/history_popup/history_popup.gd" id="2_bdgcw"]
[ext_resource type="Texture2D" uid="uid://cmxrewai8t2lm" path="res://addons/popochiu/engine/objects/gui/resources/images/close.png" id="3_6f0nr"]
[ext_resource type="PackedScene" uid="uid://b6dm3xvvr7dvi" path="res://addons/popochiu/engine/objects/gui/components/popups/history_popup/components/dialog_line.tscn" id="3_8deqt"]
[ext_resource type="Texture2D" uid="uid://p32i25numi5e" path="res://addons/popochiu/engine/objects/gui/resources/images/close_highlight.png" id="4_e8jii"]
[ext_resource type="PackedScene" uid="uid://2mnjw3qsi8hc" path="res://addons/popochiu/engine/objects/gui/components/popups/history_popup/components/interaction_line.tscn" id="4_ndekf"]
[ext_resource type="StyleBox" uid="uid://dbajakvkltfaj" path="res://addons/popochiu/engine/objects/gui/components/popups/popochiu_popup_panel_container.tres" id="5_odsj4"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_xipc1"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_pm06l"]
bg_color = Color(1, 1, 1, 1)
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_gr6a3"]
bg_color = Color(0.768627, 0.423529, 0.443137, 1)
border_width_left = 8
border_color = Color(0.388235, 0.607843, 1, 1)
[sub_resource type="Theme" id="Theme_cqgnt"]
VScrollBar/styles/grabber = SubResource("StyleBoxFlat_pm06l")
VScrollBar/styles/grabber_highlight = SubResource("StyleBoxFlat_pm06l")
VScrollBar/styles/grabber_pressed = SubResource("StyleBoxFlat_pm06l")
VScrollBar/styles/scroll = SubResource("StyleBoxFlat_gr6a3")
VScrollBar/styles/scroll_focus = SubResource("StyleBoxFlat_gr6a3")
[node name="HistoryPopup" type="Control" groups=["popochiu_gui_popup"]]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme = ExtResource("1_ktant")
script = ExtResource("2_bdgcw")
dialog_line = ExtResource("3_8deqt")
interaction_line = ExtResource("4_ndekf")
script_name = &"HistoryPopup"
title = "History"
[node name="Overlay" type="PanelContainer" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme_override_styles/panel = SubResource("StyleBoxEmpty_xipc1")
[node name="PanelContainer" type="PanelContainer" parent="Overlay"]
custom_minimum_size = Vector2(256, 144)
layout_mode = 2
size_flags_horizontal = 4
size_flags_vertical = 4
theme_override_styles/panel = ExtResource("5_odsj4")
[node name="VBoxContainer" type="VBoxContainer" parent="Overlay/PanelContainer"]
layout_mode = 2
[node name="HeaderContainer" type="HBoxContainer" parent="Overlay/PanelContainer/VBoxContainer"]
layout_mode = 2
[node name="Title" type="Label" parent="Overlay/PanelContainer/VBoxContainer/HeaderContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
text = "History"
horizontal_alignment = 1
vertical_alignment = 1
[node name="Close" type="TextureButton" parent="Overlay/PanelContainer/VBoxContainer/HeaderContainer"]
unique_name_in_owner = true
texture_filter = 1
layout_mode = 2
size_flags_vertical = 4
texture_normal = ExtResource("3_6f0nr")
texture_pressed = ExtResource("4_e8jii")
texture_hover = ExtResource("4_e8jii")
[node name="Empty" type="Label" parent="Overlay/PanelContainer/VBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_vertical = 3
text = "Nothing to show yet"
horizontal_alignment = 1
vertical_alignment = 1
[node name="LinesScroll" type="ScrollContainer" parent="Overlay/PanelContainer/VBoxContainer"]
unique_name_in_owner = true
visible = false
layout_mode = 2
size_flags_vertical = 3
theme = SubResource("Theme_cqgnt")
[node name="LinesList" type="VBoxContainer" parent="Overlay/PanelContainer/VBoxContainer/LinesScroll"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="FooterContainer" type="HBoxContainer" parent="Overlay/PanelContainer/VBoxContainer"]
visible = false
layout_mode = 2
size_flags_vertical = 10
alignment = 1
[node name="Ok" type="Button" parent="Overlay/PanelContainer/VBoxContainer/FooterContainer"]
unique_name_in_owner = true
layout_mode = 2
text = "ok"
[node name="Cancel" type="Button" parent="Overlay/PanelContainer/VBoxContainer/FooterContainer"]
unique_name_in_owner = true
layout_mode = 2
text = "cancel"

View file

@ -0,0 +1,139 @@
@tool
class_name PopochiuPopup
extends Control
## The base popup node used by Popochiu GUIs.
@export var closes_by_clicking_out := true
@export var script_name: StringName = ""
@export var title := "" : set = set_title
@onready var lbl_title: Label = %Title
@onready var btn_ok: Button = %Ok
@onready var btn_cancel: Button = %Cancel
@onready var btn_close: TextureButton = %Close
#region Godot ######################################################################################
func _ready() -> void:
if not title.is_empty():
lbl_title.text = title
if Engine.is_editor_hint(): return
# Connect to own signals
$Overlay.gui_input.connect(_check_click)
# Connect to child signals
btn_ok.pressed.connect(on_ok_pressed)
btn_cancel.pressed.connect(on_cancel_pressed)
btn_close.pressed.connect(on_cancel_pressed)
# Connect to singleton signals
PopochiuUtils.g.popup_requested.connect(_on_popup_requested)
close()
#endregion
#region Virtual ####################################################################################
## Called when the popup is opened. At this point it is not visible yet.
func _open() -> void:
pass
## Called when the popup is closed. The node hides after calling this method.
func _close() -> void:
pass
## Called when OK is pressed.
func _on_ok() -> void:
pass
## Called when CANCEL or X (top-right corner) are pressed.
func _on_cancel() -> void:
pass
#endregion
#region Public #####################################################################################
## Shows the popup scaling it and blocking interactions with the graphic interface.
func open() -> void:
_open()
PopochiuUtils.g.block()
PopochiuUtils.cursor.show_cursor("gui", true)
# Never open a popup on top of another
if not PopochiuUtils.e.gui.popups_stack.is_empty():
PopochiuUtils.e.gui.popups_stack.back().hide()
PopochiuUtils.e.gui.popups_stack.append(self)
show()
## Closes the popup unlocking interactions with the graphic interface.
func close() -> void:
PopochiuUtils.e.gui.popups_stack.erase(self)
hide()
if PopochiuUtils.e.gui.popups_stack.is_empty():
PopochiuUtils.g.unblock()
PopochiuUtils.cursor.unblock()
else:
# Idempotent call, no need to check the mode
PopochiuUtils.e.gui.popups_stack.back().show()
_close()
## Called when the OK button is pressed. It closes the popup afterwards.
func on_ok_pressed() -> void:
_on_ok()
close()
## Called when the CANCEL button is pressed. It closes the popup afterwards.
func on_cancel_pressed() -> void:
_on_cancel()
close()
## Called when the X (top-right corner) button is pressed. It closes the popup
## afterwards.
func on_close_pressed() -> void:
_on_cancel()
close()
#endregion
#region SetGet #####################################################################################
func set_title(value: String) -> void:
title = value
if is_instance_valid(lbl_title):
lbl_title.text = title
#endregion
#region Private ####################################################################################
## Checks if the overlay area of the popup was clicked in order to close it.
func _check_click(event: InputEvent) -> void:
if (
PopochiuUtils.get_click_or_touch_index(event) == MOUSE_BUTTON_LEFT
and closes_by_clicking_out
):
_on_cancel()
close()
func _on_popup_requested(popup_script_name: StringName) -> void:
if popup_script_name == script_name:
open()
#endregion

View file

@ -0,0 +1 @@
uid://bmlrdxcv748wb

View file

@ -0,0 +1,69 @@
[gd_scene load_steps=6 format=3 uid="uid://c51xplyeuk787"]
[ext_resource type="Theme" uid="uid://dpequqav4rjaf" path="res://addons/popochiu/engine/objects/gui/resources/base_gui_theme.tres" id="1_4hfpy"]
[ext_resource type="Script" path="res://addons/popochiu/engine/objects/gui/components/popups/popochiu_popup.gd" id="2_yuv82"]
[ext_resource type="Texture2D" uid="uid://cmxrewai8t2lm" path="res://addons/popochiu/engine/objects/gui/resources/images/close.png" id="3_5rk5h"]
[ext_resource type="StyleBox" uid="uid://dbajakvkltfaj" path="res://addons/popochiu/engine/objects/gui/components/popups/popochiu_popup_panel_container.tres" id="3_co4j2"]
[ext_resource type="Texture2D" uid="uid://p32i25numi5e" path="res://addons/popochiu/engine/objects/gui/resources/images/close_highlight.png" id="4_4odj8"]
[node name="PopochiuPopup" type="Control" groups=["popochiu_gui_popup"]]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme = ExtResource("1_4hfpy")
script = ExtResource("2_yuv82")
[node name="Overlay" type="PanelContainer" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="PanelContainer" type="PanelContainer" parent="Overlay"]
layout_mode = 2
size_flags_horizontal = 4
size_flags_vertical = 4
theme_override_styles/panel = ExtResource("3_co4j2")
[node name="VBoxContainer" type="VBoxContainer" parent="Overlay/PanelContainer"]
layout_mode = 2
[node name="HeaderContainer" type="HBoxContainer" parent="Overlay/PanelContainer/VBoxContainer"]
layout_mode = 2
[node name="Title" type="Label" parent="Overlay/PanelContainer/VBoxContainer/HeaderContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
text = "Title"
horizontal_alignment = 1
vertical_alignment = 1
[node name="Close" type="TextureButton" parent="Overlay/PanelContainer/VBoxContainer/HeaderContainer"]
unique_name_in_owner = true
texture_filter = 1
layout_mode = 2
size_flags_vertical = 4
texture_normal = ExtResource("3_5rk5h")
texture_pressed = ExtResource("4_4odj8")
texture_hover = ExtResource("4_4odj8")
[node name="FooterContainer" type="HBoxContainer" parent="Overlay/PanelContainer/VBoxContainer"]
layout_mode = 2
size_flags_vertical = 10
alignment = 1
[node name="Ok" type="Button" parent="Overlay/PanelContainer/VBoxContainer/FooterContainer"]
unique_name_in_owner = true
layout_mode = 2
text = "ok"
[node name="Cancel" type="Button" parent="Overlay/PanelContainer/VBoxContainer/FooterContainer"]
unique_name_in_owner = true
layout_mode = 2
text = "cancel"

View file

@ -0,0 +1,12 @@
[gd_resource type="StyleBoxFlat" format=3 uid="uid://dbajakvkltfaj"]
[resource]
content_margin_left = 4.0
content_margin_top = 2.0
content_margin_right = 4.0
content_margin_bottom = 2.0
bg_color = Color(0, 0, 0, 0.705882)
expand_margin_left = 2.0
expand_margin_top = 2.0
expand_margin_right = 2.0
expand_margin_bottom = 2.0

View file

@ -0,0 +1,26 @@
@tool
extends PopochiuPopup
#region Virtual ####################################################################################
## Called when the popup is opened. At this point it is not visible yet.
func _open() -> void:
pass
## Called when the popup is closed. The node hides after calling this method.
func _close() -> void:
pass
## Called when OK is pressed.
func _on_ok() -> void:
get_tree().quit()
## Called when CANCEL or X (top-right corner) are pressed.
func _on_cancel() -> void:
pass
#endregion

View file

@ -0,0 +1 @@
uid://bqvdywnh28ces

View file

@ -0,0 +1,84 @@
[gd_scene load_steps=7 format=3 uid="uid://bnjo044fkdcq7"]
[ext_resource type="Theme" uid="uid://dpequqav4rjaf" path="res://addons/popochiu/engine/objects/gui/resources/base_gui_theme.tres" id="1_3nwvu"]
[ext_resource type="Script" path="res://addons/popochiu/engine/objects/gui/components/popups/quit_popup/quit_popup.gd" id="2_nkwwk"]
[ext_resource type="StyleBox" uid="uid://dbajakvkltfaj" path="res://addons/popochiu/engine/objects/gui/components/popups/popochiu_popup_panel_container.tres" id="3_828u5"]
[ext_resource type="Texture2D" uid="uid://cmxrewai8t2lm" path="res://addons/popochiu/engine/objects/gui/resources/images/close.png" id="3_r2fp8"]
[ext_resource type="Texture2D" uid="uid://p32i25numi5e" path="res://addons/popochiu/engine/objects/gui/resources/images/close_highlight.png" id="4_mra7q"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_il3mr"]
[node name="QuitPopup" type="Control" groups=["popochiu_gui_popup"]]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme = ExtResource("1_3nwvu")
script = ExtResource("2_nkwwk")
script_name = &"QuitPopup"
title = "Quit game"
[node name="Overlay" type="PanelContainer" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme_override_styles/panel = SubResource("StyleBoxEmpty_il3mr")
[node name="PanelContainer" type="PanelContainer" parent="Overlay"]
custom_minimum_size = Vector2(256, 0)
layout_mode = 2
size_flags_horizontal = 4
size_flags_vertical = 4
theme_override_styles/panel = ExtResource("3_828u5")
[node name="VBoxContainer" type="VBoxContainer" parent="Overlay/PanelContainer"]
layout_mode = 2
[node name="HeaderContainer" type="HBoxContainer" parent="Overlay/PanelContainer/VBoxContainer"]
layout_mode = 2
[node name="Title" type="Label" parent="Overlay/PanelContainer/VBoxContainer/HeaderContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
text = "Quit game"
horizontal_alignment = 1
vertical_alignment = 1
[node name="Close" type="TextureButton" parent="Overlay/PanelContainer/VBoxContainer/HeaderContainer"]
unique_name_in_owner = true
texture_filter = 1
layout_mode = 2
size_flags_vertical = 4
texture_normal = ExtResource("3_r2fp8")
texture_pressed = ExtResource("4_mra7q")
texture_hover = ExtResource("4_mra7q")
[node name="Question" type="Label" parent="Overlay/PanelContainer/VBoxContainer"]
layout_mode = 2
size_flags_horizontal = 3
text = "Are you sure you want to quit?"
horizontal_alignment = 1
vertical_alignment = 1
autowrap_mode = 3
[node name="FooterContainer" type="HBoxContainer" parent="Overlay/PanelContainer/VBoxContainer"]
layout_mode = 2
size_flags_vertical = 10
alignment = 1
[node name="Ok" type="Button" parent="Overlay/PanelContainer/VBoxContainer/FooterContainer"]
unique_name_in_owner = true
layout_mode = 2
text = "OK"
[node name="Cancel" type="Button" parent="Overlay/PanelContainer/VBoxContainer/FooterContainer"]
unique_name_in_owner = true
layout_mode = 2
text = "Cancel
"

View file

@ -0,0 +1,134 @@
@tool
extends PopochiuPopup
signal slot_selected
const SELECTION_COLOR := Color("edf171")
const OVERWRITE_COLOR := Color("c46c71")
var _current_slot: Button = null
var _slot_name := ""
var _prev_text := ""
var _slot := 0
@onready var slots: VBoxContainer = %Slots
#region Godot ######################################################################################
func _ready() -> void:
super()
if Engine.is_editor_hint(): return
btn_ok.disabled = true
var saves: Dictionary = PopochiuUtils.e.get_saves_descriptions()
for btn: Button in slots.get_children():
btn.set_meta("has_save", false)
if saves.has(btn.get_index() + 1):
btn.text = saves[btn.get_index() + 1]
btn.set_meta("has_save", true)
else:
btn.disabled = true
btn.pressed.connect(_select_slot.bind(btn))
#endregion
#region Virtual ####################################################################################
func _open() -> void:
btn_ok.disabled = true
_slot = 0
if _current_slot:
_current_slot.text = _prev_text
_current_slot.button_pressed = false
_current_slot = null
_prev_text = ""
func _close() -> void:
if not _slot: return
slot_selected.emit()
if _slot_name:
PopochiuUtils.e.save_game(_slot, _slot_name)
else:
PopochiuUtils.e.load_game(_slot)
func _on_ok() -> void:
_slot = _current_slot.get_index() + 1
if _slot_name:
_prev_text = _current_slot.text
_current_slot.set_meta("has_save", true)
#endregion
#region Public #####################################################################################
func open_save() -> void:
_show_save()
func open_load() -> void:
_show_load()
#endregion
#region Private ####################################################################################
func _show_save(slot_text := "") -> void:
lbl_title.text = "Choose a slot to save the game"
_slot_name = slot_text
if _slot_name.is_empty():
_slot_name = _format_date(Time.get_datetime_dict_from_system())
for btn in slots.get_children():
btn.disabled = false
open()
func _show_load() -> void:
lbl_title.text = "Choose the slot to load"
_slot_name = ""
for btn in slots.get_children():
btn.disabled = !(btn as Button).get_meta("has_save")
open()
func _select_slot(btn: Button) -> void:
if _slot_name:
if _current_slot:
_current_slot.text = _prev_text
_current_slot.button_pressed = false
_current_slot = btn
_prev_text = _current_slot.text
_current_slot.text = _slot_name
else:
if _current_slot:
_current_slot.button_pressed = false
_current_slot = btn
_prev_text = _current_slot.text
btn_ok.disabled = false
func _format_date(date: Dictionary) -> String:
return "%d/%02d/%02d %02d:%02d:%02d" % [
date.year, date.month, date.day, date.hour, date.minute, date.second
]
#endregion

View file

@ -0,0 +1,100 @@
[gd_scene load_steps=7 format=3 uid="uid://cndputybyj57n"]
[ext_resource type="Theme" uid="uid://dpequqav4rjaf" path="res://addons/popochiu/engine/objects/gui/resources/base_gui_theme.tres" id="1_llqb8"]
[ext_resource type="Script" path="res://addons/popochiu/engine/objects/gui/components/popups/save_and_load_popup/save_and_load_popup.gd" id="2_m1ot6"]
[ext_resource type="StyleBox" uid="uid://dbajakvkltfaj" path="res://addons/popochiu/engine/objects/gui/components/popups/popochiu_popup_panel_container.tres" id="3_inruf"]
[ext_resource type="Texture2D" uid="uid://cmxrewai8t2lm" path="res://addons/popochiu/engine/objects/gui/resources/images/close.png" id="3_n4oyj"]
[ext_resource type="Texture2D" uid="uid://p32i25numi5e" path="res://addons/popochiu/engine/objects/gui/resources/images/close_highlight.png" id="4_jqolx"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_yg86r"]
[node name="SaveAndLoadPopup" type="Control" groups=["popochiu_gui_popup"]]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme = ExtResource("1_llqb8")
script = ExtResource("2_m1ot6")
script_name = &"SaveAndLoadPopup"
[node name="Overlay" type="PanelContainer" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme_override_styles/panel = SubResource("StyleBoxEmpty_yg86r")
[node name="PanelContainer" type="PanelContainer" parent="Overlay"]
custom_minimum_size = Vector2(192, 0)
layout_mode = 2
size_flags_horizontal = 4
size_flags_vertical = 4
theme_override_styles/panel = ExtResource("3_inruf")
[node name="VBoxContainer" type="VBoxContainer" parent="Overlay/PanelContainer"]
layout_mode = 2
[node name="HeaderContainer" type="HBoxContainer" parent="Overlay/PanelContainer/VBoxContainer"]
layout_mode = 2
[node name="Title" type="Label" parent="Overlay/PanelContainer/VBoxContainer/HeaderContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
text = "Choose a slot to..."
horizontal_alignment = 1
vertical_alignment = 1
[node name="Close" type="TextureButton" parent="Overlay/PanelContainer/VBoxContainer/HeaderContainer"]
unique_name_in_owner = true
texture_filter = 1
layout_mode = 2
size_flags_vertical = 4
texture_normal = ExtResource("3_n4oyj")
texture_pressed = ExtResource("4_jqolx")
texture_hover = ExtResource("4_jqolx")
[node name="Slots" type="VBoxContainer" parent="Overlay/PanelContainer/VBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_vertical = 3
alignment = 1
[node name="BtnSlot1" type="Button" parent="Overlay/PanelContainer/VBoxContainer/Slots"]
layout_mode = 2
toggle_mode = true
text = "slot 1"
[node name="BtnSlot2" type="Button" parent="Overlay/PanelContainer/VBoxContainer/Slots"]
layout_mode = 2
toggle_mode = true
text = "slot 2"
[node name="BtnSlot3" type="Button" parent="Overlay/PanelContainer/VBoxContainer/Slots"]
layout_mode = 2
toggle_mode = true
text = "slot 3"
[node name="BtnSlot4" type="Button" parent="Overlay/PanelContainer/VBoxContainer/Slots"]
layout_mode = 2
toggle_mode = true
text = "slot 4"
[node name="FooterContainer" type="HBoxContainer" parent="Overlay/PanelContainer/VBoxContainer"]
layout_mode = 2
size_flags_vertical = 10
alignment = 1
[node name="Ok" type="Button" parent="Overlay/PanelContainer/VBoxContainer/FooterContainer"]
unique_name_in_owner = true
layout_mode = 2
text = "OK"
[node name="Cancel" type="Button" parent="Overlay/PanelContainer/VBoxContainer/FooterContainer"]
unique_name_in_owner = true
layout_mode = 2
text = "Cancel"

View file

@ -0,0 +1,16 @@
@tool
extends PopochiuPopup
@onready var sound_volumes: GridContainer = %SoundVolumes
#region Virtual ####################################################################################
func _open() -> void:
sound_volumes.update_sliders()
func _on_cancel() -> void:
sound_volumes.restore_last_volumes()
#endregion

View file

@ -0,0 +1,80 @@
[gd_scene load_steps=8 format=3 uid="uid://dwxm2p1iyhpx6"]
[ext_resource type="Theme" uid="uid://dpequqav4rjaf" path="res://addons/popochiu/engine/objects/gui/resources/base_gui_theme.tres" id="1_rwmoe"]
[ext_resource type="Script" path="res://addons/popochiu/engine/objects/gui/components/popups/sound_settings_popup/sound_settings_popup.gd" id="2_qt85i"]
[ext_resource type="Texture2D" uid="uid://cmxrewai8t2lm" path="res://addons/popochiu/engine/objects/gui/resources/images/close.png" id="3_knqsp"]
[ext_resource type="StyleBox" uid="uid://dbajakvkltfaj" path="res://addons/popochiu/engine/objects/gui/components/popups/popochiu_popup_panel_container.tres" id="3_nqnfj"]
[ext_resource type="Texture2D" uid="uid://p32i25numi5e" path="res://addons/popochiu/engine/objects/gui/resources/images/close_highlight.png" id="4_v7y6x"]
[ext_resource type="PackedScene" uid="uid://drx0r8w00ivck" path="res://addons/popochiu/engine/objects/gui/components/sound_volumes/sound_volumes.tscn" id="5_lh576"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_6mo8y"]
[node name="SoundSettingsPopup" type="Control" groups=["popochiu_gui_popup"]]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme = ExtResource("1_rwmoe")
script = ExtResource("2_qt85i")
script_name = &"SoundSettingsPopup"
title = "Sound Settings"
[node name="Overlay" type="PanelContainer" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme_override_styles/panel = SubResource("StyleBoxEmpty_6mo8y")
[node name="PanelContainer" type="PanelContainer" parent="Overlay"]
layout_mode = 2
size_flags_horizontal = 4
size_flags_vertical = 4
theme_override_styles/panel = ExtResource("3_nqnfj")
[node name="VBoxContainer" type="VBoxContainer" parent="Overlay/PanelContainer"]
layout_mode = 2
[node name="HeaderContainer" type="HBoxContainer" parent="Overlay/PanelContainer/VBoxContainer"]
layout_mode = 2
[node name="Title" type="Label" parent="Overlay/PanelContainer/VBoxContainer/HeaderContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
text = "Sound Settings"
horizontal_alignment = 1
vertical_alignment = 1
[node name="Close" type="TextureButton" parent="Overlay/PanelContainer/VBoxContainer/HeaderContainer"]
unique_name_in_owner = true
visible = false
texture_filter = 1
layout_mode = 2
size_flags_vertical = 4
texture_normal = ExtResource("3_knqsp")
texture_pressed = ExtResource("4_v7y6x")
texture_hover = ExtResource("4_v7y6x")
[node name="SoundVolumes" parent="Overlay/PanelContainer/VBoxContainer" instance=ExtResource("5_lh576")]
unique_name_in_owner = true
layout_mode = 2
[node name="FooterContainer" type="HBoxContainer" parent="Overlay/PanelContainer/VBoxContainer"]
layout_mode = 2
size_flags_vertical = 10
alignment = 1
[node name="Ok" type="Button" parent="Overlay/PanelContainer/VBoxContainer/FooterContainer"]
unique_name_in_owner = true
layout_mode = 2
text = "ok"
[node name="Cancel" type="Button" parent="Overlay/PanelContainer/VBoxContainer/FooterContainer"]
unique_name_in_owner = true
layout_mode = 2
text = "cancel"

View file

@ -0,0 +1,40 @@
@tool
extends PopochiuPopup
@onready var text_speed: HSlider = %TextSpeed
@onready var dialog_style: OptionButton = %DialogStyle
@onready var continue_mode: CheckButton = %ContinueMode
#region Godot ######################################################################################
func _ready() -> void:
super()
if Engine.is_editor_hint(): return
text_speed.value = 0.1 - PopochiuUtils.e.text_speed
dialog_style.selected = PopochiuUtils.e.settings.dialog_style
continue_mode.button_pressed = PopochiuUtils.e.settings.auto_continue_text
# Connect to child signals
text_speed.value_changed.connect(_on_text_speed_changed)
dialog_style.item_selected.connect(_on_dialog_style_selected)
continue_mode.toggled.connect(_on_continue_mode_toggled)
#endregion
#region Private ####################################################################################
func _on_text_speed_changed(value: float) -> void:
PopochiuUtils.e.text_speed = 0.1 - value
func _on_dialog_style_selected(idx: int) -> void:
PopochiuUtils.e.current_dialog_style = dialog_style.get_item_id(idx)
func _on_continue_mode_toggled(toggled_on: bool) -> void:
PopochiuUtils.e.settings.auto_continue_text = toggled_on
#endregion

View file

@ -0,0 +1,151 @@
[gd_scene load_steps=13 format=3 uid="uid://de68lx1xqv7fb"]
[ext_resource type="Theme" uid="uid://dpequqav4rjaf" path="res://addons/popochiu/engine/objects/gui/resources/base_gui_theme.tres" id="1_7sq5d"]
[ext_resource type="Script" path="res://addons/popochiu/engine/objects/gui/components/popups/text_settings_popup/text_settings_popup.gd" id="2_nmcxa"]
[ext_resource type="StyleBox" uid="uid://dbajakvkltfaj" path="res://addons/popochiu/engine/objects/gui/components/popups/popochiu_popup_panel_container.tres" id="3_coq7y"]
[ext_resource type="Texture2D" uid="uid://cmxrewai8t2lm" path="res://addons/popochiu/engine/objects/gui/resources/images/close.png" id="3_rckox"]
[ext_resource type="Texture2D" uid="uid://p32i25numi5e" path="res://addons/popochiu/engine/objects/gui/resources/images/close_highlight.png" id="4_gfs8i"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_bh5os"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_b5jxw"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_rinqp"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_vprmd"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_372y7"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_t5skw"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_5015x"]
[node name="TextSettingsPopup" type="Control" groups=["popochiu_gui_popup"]]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme = ExtResource("1_7sq5d")
script = ExtResource("2_nmcxa")
script_name = &"SierraTextPopup"
title = "Text options"
[node name="Overlay" type="PanelContainer" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme_override_styles/panel = SubResource("StyleBoxEmpty_bh5os")
[node name="PanelContainer" type="PanelContainer" parent="Overlay"]
custom_minimum_size = Vector2(160, 140)
layout_mode = 2
size_flags_horizontal = 4
size_flags_vertical = 4
theme_override_styles/panel = ExtResource("3_coq7y")
[node name="VBoxContainer" type="VBoxContainer" parent="Overlay/PanelContainer"]
layout_mode = 2
[node name="HeaderContainer" type="HBoxContainer" parent="Overlay/PanelContainer/VBoxContainer"]
layout_mode = 2
[node name="Title" type="Label" parent="Overlay/PanelContainer/VBoxContainer/HeaderContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
text = "Text options"
horizontal_alignment = 1
vertical_alignment = 1
[node name="Close" type="TextureButton" parent="Overlay/PanelContainer/VBoxContainer/HeaderContainer"]
unique_name_in_owner = true
visible = false
texture_filter = 1
layout_mode = 2
size_flags_vertical = 4
texture_normal = ExtResource("3_rckox")
texture_pressed = ExtResource("4_gfs8i")
texture_hover = ExtResource("4_gfs8i")
[node name="BodyContainer" type="VBoxContainer" parent="Overlay/PanelContainer/VBoxContainer"]
layout_mode = 2
[node name="TextSpeedContainer" type="HBoxContainer" parent="Overlay/PanelContainer/VBoxContainer/BodyContainer"]
layout_mode = 2
[node name="Label" type="Label" parent="Overlay/PanelContainer/VBoxContainer/BodyContainer/TextSpeedContainer"]
layout_mode = 2
text = "Typing speed"
[node name="TextSpeed" type="HSlider" parent="Overlay/PanelContainer/VBoxContainer/BodyContainer/TextSpeedContainer"]
unique_name_in_owner = true
texture_filter = 1
layout_mode = 2
size_flags_horizontal = 3
max_value = 0.1
step = 0.01
[node name="DialogStyleContainer" type="HBoxContainer" parent="Overlay/PanelContainer/VBoxContainer/BodyContainer"]
visible = false
layout_mode = 2
[node name="Label" type="Label" parent="Overlay/PanelContainer/VBoxContainer/BodyContainer/DialogStyleContainer"]
layout_mode = 2
text = "Style"
horizontal_alignment = 1
[node name="DialogStyle" type="OptionButton" parent="Overlay/PanelContainer/VBoxContainer/BodyContainer/DialogStyleContainer"]
unique_name_in_owner = true
texture_filter = 1
layout_mode = 2
size_flags_horizontal = 3
selected = 0
item_count = 3
popup/item_0/text = "Above character"
popup/item_1/text = "Portrait"
popup/item_1/id = 1
popup/item_2/text = "Caption"
popup/item_2/id = 2
[node name="ContinueModeContainer" type="HBoxContainer" parent="Overlay/PanelContainer/VBoxContainer/BodyContainer"]
layout_mode = 2
[node name="Label" type="Label" parent="Overlay/PanelContainer/VBoxContainer/BodyContainer/ContinueModeContainer"]
layout_mode = 2
text = "Autoadvance"
horizontal_alignment = 1
[node name="ContinueMode" type="CheckButton" parent="Overlay/PanelContainer/VBoxContainer/BodyContainer/ContinueModeContainer"]
unique_name_in_owner = true
texture_filter = 1
layout_mode = 2
size_flags_horizontal = 10
size_flags_vertical = 0
theme_override_styles/focus = SubResource("StyleBoxEmpty_b5jxw")
theme_override_styles/disabled = SubResource("StyleBoxEmpty_rinqp")
theme_override_styles/hover_pressed = SubResource("StyleBoxEmpty_vprmd")
theme_override_styles/hover = SubResource("StyleBoxEmpty_372y7")
theme_override_styles/pressed = SubResource("StyleBoxEmpty_t5skw")
theme_override_styles/normal = SubResource("StyleBoxEmpty_5015x")
icon_alignment = 2
[node name="FooterContainer" type="HBoxContainer" parent="Overlay/PanelContainer/VBoxContainer"]
layout_mode = 2
size_flags_vertical = 10
alignment = 1
[node name="Ok" type="Button" parent="Overlay/PanelContainer/VBoxContainer/FooterContainer"]
unique_name_in_owner = true
visible = false
layout_mode = 2
text = "OK"
[node name="Cancel" type="Button" parent="Overlay/PanelContainer/VBoxContainer/FooterContainer"]
unique_name_in_owner = true
layout_mode = 2
text = "Back"

View file

@ -0,0 +1,15 @@
extends PopochiuSettingsBarButton
#region Godot ######################################################################################
func _ready() -> void:
super()
PopochiuUtils.e.game_saved.connect(show)
if PopochiuUtils.e.has_save():
show()
else:
hide()
#endregion

View file

@ -0,0 +1 @@
uid://p0vkry54t2lc

View file

@ -0,0 +1,11 @@
extends PopochiuSettingsBarButton
#region Godot ######################################################################################
func _ready() -> void:
super()
if OS.has_feature("web"):
hide()
#endregion

View file

@ -0,0 +1 @@
uid://7tvb4u0a2cgs

View file

@ -0,0 +1,32 @@
class_name PopochiuSettingsBarButton
extends TextureButton
@export var description := "" : get = get_description
@export var script_name := ""
#region Godot ######################################################################################
func _ready() -> void:
mouse_entered.connect(_on_mouse_entered)
mouse_exited.connect(_on_mouse_exited)
#endregion
#region SetGet #####################################################################################
func get_description() -> String:
return description
#endregion
#region Private ####################################################################################
func _on_mouse_entered() -> void:
PopochiuUtils.g.show_hover_text(self.description)
func _on_mouse_exited() -> void:
PopochiuUtils.g.show_hover_text()
#endregion

Binary file not shown.

After

Width:  |  Height:  |  Size: 259 B

View file

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cyvd8h2ouw8rg"
path="res://.godot/imported/btn_audio.png-0e4052f1dae1f1f9c4ac0c708f040b4f.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/popochiu/engine/objects/gui/components/settings_bar/images/btn_audio.png"
dest_files=["res://.godot/imported/btn_audio.png-0e4052f1dae1f1f9c4ac0c708f040b4f.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 247 B

View file

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bg1txcy1ofatq"
path="res://.godot/imported/btn_dialog_history.png-5e6b81c2188724ad496fcf8877a9452a.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/popochiu/engine/objects/gui/components/settings_bar/images/btn_dialog_history.png"
dest_files=["res://.godot/imported/btn_dialog_history.png-5e6b81c2188724ad496fcf8877a9452a.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 250 B

View file

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bns33w6nl2qkb"
path="res://.godot/imported/btn_load.png-ecbfe8ff6b76c734e44ba7e7e6bdcc9b.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/popochiu/engine/objects/gui/components/settings_bar/images/btn_load.png"
dest_files=["res://.godot/imported/btn_load.png-ecbfe8ff6b76c734e44ba7e7e6bdcc9b.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 B

View file

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cxpcw7xvcjcfy"
path="res://.godot/imported/btn_quit.png-38ab2b1afef2a5dae796f87d983b4a23.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/popochiu/engine/objects/gui/components/settings_bar/images/btn_quit.png"
dest_files=["res://.godot/imported/btn_quit.png-38ab2b1afef2a5dae796f87d983b4a23.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 B

View file

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bexxkrmqdiemq"
path="res://.godot/imported/btn_save.png-885612922cd34c7a3774c5fde51c9c48.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/popochiu/engine/objects/gui/components/settings_bar/images/btn_save.png"
dest_files=["res://.godot/imported/btn_save.png-885612922cd34c7a3774c5fde51c9c48.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 406 B

View file

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://hjol4hvanbt5"
path="res://.godot/imported/btn_text.png-55ab59a0b65de9503101bf16f8b64b3f.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/popochiu/engine/objects/gui/components/settings_bar/images/btn_text.png"
dest_files=["res://.godot/imported/btn_text.png-55ab59a0b65de9503101bf16f8b64b3f.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

View file

@ -0,0 +1,5 @@
extends Resource
@export var icon: Texture2D = null
@export var description := ""
@export var speed := 0.0

View file

@ -0,0 +1,143 @@
class_name PopochiuSettingsBar
extends Control
signal option_selected(option_name: String)
@export var used_in_game := true
@export var always_visible := false
@export var hide_when_gui_is_blocked := false
## Defines the height in pixels of the zone where moving the mouse in the top of the screen will
## make the bar to show. Note: This value will be affected by the Experimental Scale GUI checkbox
## in Project Settings > Popochiu > GUI.
@export var input_zone_height := 4
var is_disabled := false
var tween: Tween = null
var _can_hide := true
var _is_hidden := true
var _is_mouse_hover := false
@onready var panel_container: PanelContainer = $PanelContainer
@onready var box: BoxContainer = %Box
@onready var hidden_y := panel_container.position.y - panel_container.size.y
#region Godot ######################################################################################
func _ready() -> void:
if not always_visible:
panel_container.position.y = hidden_y
# Connect to child signals
for button: TextureButton in box.get_children():
button.mouse_entered.connect(_disable_hide)
button.mouse_exited.connect(_enable_hide)
button.pressed.connect(_on_button_clicked.bind(button))
# Connect to singletons signals
if hide_when_gui_is_blocked:
PopochiuUtils.g.blocked.connect(_on_gui_blocked)
PopochiuUtils.g.unblocked.connect(_on_gui_unblocked)
if not used_in_game:
hide()
set_process_input(not always_visible)
panel_container.size.x = box.size.x
func _input(event: InputEvent) -> void:
if not event is InputEventMouseMotion: return
var rect := panel_container.get_rect()
rect.size += Vector2(0.0, input_zone_height)
if PopochiuUtils.e.settings.scale_gui:
rect = Rect2(
panel_container.get_rect().position * PopochiuUtils.e.scale,
panel_container.get_rect().size * PopochiuUtils.e.scale
)
if rect.has_point(get_global_mouse_position()):
_is_mouse_hover = true
PopochiuUtils.cursor.show_cursor("gui")
elif _is_mouse_hover:
_is_mouse_hover = false
if PopochiuUtils.d.current_dialog:
PopochiuUtils.cursor.show_cursor("gui")
elif PopochiuUtils.g.gui.is_showing_dialog_line:
PopochiuUtils.cursor.show_cursor("wait")
else:
PopochiuUtils.cursor.show_cursor("normal")
if _is_hidden and rect.has_point(get_global_mouse_position()):
_open()
elif not _is_hidden and not rect.has_point(get_global_mouse_position()):
_close()
#endregion
#region Public #####################################################################################
func is_open() -> bool:
return _is_hidden == false
#endregion
#region Private ####################################################################################
func _open() -> void:
if always_visible: return
if not is_disabled and panel_container.position.y != hidden_y: return
if is_instance_valid(tween) and tween.is_running():
tween.kill()
tween = create_tween().set_trans(Tween.TRANS_EXPO).set_ease(Tween.EASE_OUT)
tween.tween_property(panel_container, "position:y", 0.0, 0.5).from(
hidden_y if not is_disabled else panel_container.position.y
)
_is_hidden = false
func _close() -> void:
if always_visible: return
await get_tree().process_frame
if not _can_hide: return
if is_instance_valid(tween) and tween.is_running():
tween.kill()
tween = create_tween().set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN)
tween.tween_property(
panel_container, "position:y", hidden_y if not is_disabled else hidden_y - 3.5, 0.2
).from(0.0)
_is_hidden = true
func _disable_hide() -> void:
_can_hide = false
func _enable_hide() -> void:
_can_hide = true
func _on_gui_blocked() -> void:
set_process_input(false)
hide()
func _on_gui_unblocked() -> void:
set_process_input(true)
show()
func _on_button_clicked(button: TextureButton) -> void:
option_selected.emit(button.script_name)
#endregion

View file

@ -0,0 +1 @@
uid://b677h1crcx6gm

View file

@ -0,0 +1,168 @@
[gd_scene load_steps=30 format=3 uid="uid://0cqerawlxb3o"]
[ext_resource type="Theme" uid="uid://dpequqav4rjaf" path="res://addons/popochiu/engine/objects/gui/resources/base_gui_theme.tres" id="1_457q0"]
[ext_resource type="Script" path="res://addons/popochiu/engine/objects/gui/components/settings_bar/settings_bar.gd" id="2_hk0vm"]
[ext_resource type="Texture2D" uid="uid://bexxkrmqdiemq" path="res://addons/popochiu/engine/objects/gui/components/settings_bar/images/btn_save.png" id="3_b0ddg"]
[ext_resource type="Script" path="res://addons/popochiu/engine/objects/gui/components/settings_bar/buttons/settings_bar_button.gd" id="4_lqi16"]
[ext_resource type="Texture2D" uid="uid://bns33w6nl2qkb" path="res://addons/popochiu/engine/objects/gui/components/settings_bar/images/btn_load.png" id="5_8xdf1"]
[ext_resource type="Script" path="res://addons/popochiu/engine/objects/gui/components/settings_bar/buttons/btn_load.gd" id="6_dfxoh"]
[ext_resource type="Texture2D" uid="uid://cyvd8h2ouw8rg" path="res://addons/popochiu/engine/objects/gui/components/settings_bar/images/btn_audio.png" id="11_id5s2"]
[ext_resource type="Texture2D" uid="uid://hjol4hvanbt5" path="res://addons/popochiu/engine/objects/gui/components/settings_bar/images/btn_text.png" id="12_y7pwl"]
[ext_resource type="Texture2D" uid="uid://bg1txcy1ofatq" path="res://addons/popochiu/engine/objects/gui/components/settings_bar/images/btn_dialog_history.png" id="16_7j34k"]
[ext_resource type="Texture2D" uid="uid://cxpcw7xvcjcfy" path="res://addons/popochiu/engine/objects/gui/components/settings_bar/images/btn_quit.png" id="18_64yvb"]
[ext_resource type="Script" path="res://addons/popochiu/engine/objects/gui/components/settings_bar/buttons/btn_quit.gd" id="19_5u3hw"]
[sub_resource type="AtlasTexture" id="AtlasTexture_mnuax"]
atlas = ExtResource("3_b0ddg")
region = Rect2(0, 0, 0, 16)
[sub_resource type="AtlasTexture" id="AtlasTexture_gcwc6"]
atlas = ExtResource("3_b0ddg")
region = Rect2(0, 16, 0, 16)
[sub_resource type="AtlasTexture" id="AtlasTexture_yci17"]
atlas = ExtResource("3_b0ddg")
region = Rect2(0, 32, 0, 16)
[sub_resource type="AtlasTexture" id="AtlasTexture_8ii6v"]
atlas = ExtResource("5_8xdf1")
region = Rect2(0, 0, 0, 16)
[sub_resource type="AtlasTexture" id="AtlasTexture_c5e8t"]
atlas = ExtResource("5_8xdf1")
region = Rect2(0, 16, 0, 16)
[sub_resource type="AtlasTexture" id="AtlasTexture_dtnbp"]
atlas = ExtResource("5_8xdf1")
region = Rect2(0, 32, 0, 16)
[sub_resource type="AtlasTexture" id="AtlasTexture_2vddc"]
atlas = ExtResource("12_y7pwl")
region = Rect2(0, 0, 0, 16)
[sub_resource type="AtlasTexture" id="AtlasTexture_38kcs"]
atlas = ExtResource("12_y7pwl")
region = Rect2(0, 16, 0, 16)
[sub_resource type="AtlasTexture" id="AtlasTexture_ckg43"]
atlas = ExtResource("12_y7pwl")
region = Rect2(0, 32, 0, 16)
[sub_resource type="AtlasTexture" id="AtlasTexture_unaqu"]
atlas = ExtResource("11_id5s2")
region = Rect2(0, 0, 0, 16)
[sub_resource type="AtlasTexture" id="AtlasTexture_i8n60"]
atlas = ExtResource("11_id5s2")
region = Rect2(0, 16, 0, 16)
[sub_resource type="AtlasTexture" id="AtlasTexture_kl1ek"]
atlas = ExtResource("11_id5s2")
region = Rect2(0, 32, 0, 16)
[sub_resource type="AtlasTexture" id="AtlasTexture_vqe4x"]
atlas = ExtResource("16_7j34k")
region = Rect2(0, 0, 0, 16)
[sub_resource type="AtlasTexture" id="AtlasTexture_h0y2i"]
atlas = ExtResource("16_7j34k")
region = Rect2(0, 16, 0, 16)
[sub_resource type="AtlasTexture" id="AtlasTexture_myrqy"]
atlas = ExtResource("16_7j34k")
region = Rect2(0, 32, 0, 16)
[sub_resource type="AtlasTexture" id="AtlasTexture_1sqfr"]
atlas = ExtResource("18_64yvb")
region = Rect2(0, 0, 0, 16)
[sub_resource type="AtlasTexture" id="AtlasTexture_blkpg"]
atlas = ExtResource("18_64yvb")
region = Rect2(0, 16, 0, 16)
[sub_resource type="AtlasTexture" id="AtlasTexture_834us"]
atlas = ExtResource("18_64yvb")
region = Rect2(0, 32, 0, 16)
[node name="SettingsBar" type="Control" groups=["popochiu_gui_component"]]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 2
theme = ExtResource("1_457q0")
script = ExtResource("2_hk0vm")
[node name="PanelContainer" type="PanelContainer" parent="."]
texture_filter = 1
layout_mode = 1
anchors_preset = 1
anchor_left = 1.0
anchor_right = 1.0
offset_left = -96.0
offset_bottom = 24.0
grow_horizontal = 0
[node name="Box" type="HBoxContainer" parent="PanelContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_vertical = 4
mouse_filter = 2
alignment = 2
[node name="BtnSave" type="TextureButton" parent="PanelContainer/Box"]
layout_mode = 2
texture_normal = SubResource("AtlasTexture_mnuax")
texture_pressed = SubResource("AtlasTexture_gcwc6")
texture_hover = SubResource("AtlasTexture_yci17")
script = ExtResource("4_lqi16")
description = "Save game"
script_name = "save"
[node name="BtnLoad" type="TextureButton" parent="PanelContainer/Box"]
visible = false
layout_mode = 2
texture_normal = SubResource("AtlasTexture_8ii6v")
texture_pressed = SubResource("AtlasTexture_c5e8t")
texture_hover = SubResource("AtlasTexture_dtnbp")
script = ExtResource("6_dfxoh")
description = "Load game"
script_name = "load"
[node name="BtnTextSettings" type="TextureButton" parent="PanelContainer/Box"]
layout_mode = 2
texture_normal = SubResource("AtlasTexture_2vddc")
texture_pressed = SubResource("AtlasTexture_38kcs")
texture_hover = SubResource("AtlasTexture_ckg43")
script = ExtResource("4_lqi16")
description = "Text settings"
script_name = "text_settings"
[node name="BtnSoundSettings" type="TextureButton" parent="PanelContainer/Box"]
layout_mode = 2
texture_normal = SubResource("AtlasTexture_unaqu")
texture_pressed = SubResource("AtlasTexture_i8n60")
texture_hover = SubResource("AtlasTexture_kl1ek")
script = ExtResource("4_lqi16")
description = "Sound settings"
script_name = "sound_settings"
[node name="BtnHistory" type="TextureButton" parent="PanelContainer/Box"]
layout_mode = 2
texture_normal = SubResource("AtlasTexture_vqe4x")
texture_pressed = SubResource("AtlasTexture_h0y2i")
texture_hover = SubResource("AtlasTexture_myrqy")
script = ExtResource("4_lqi16")
description = "History"
script_name = "history"
[node name="BtnQuit" type="TextureButton" parent="PanelContainer/Box"]
layout_mode = 2
texture_normal = SubResource("AtlasTexture_1sqfr")
texture_pressed = SubResource("AtlasTexture_blkpg")
texture_hover = SubResource("AtlasTexture_834us")
script = ExtResource("19_5u3hw")
description = "Quit"
script_name = "quit"

View file

@ -0,0 +1,73 @@
extends GridContainer
const MIN_VOLUME := -30
const MUTE_VOLUME := -70
var dflt_volumes := {}
#region Godot ######################################################################################
func _ready() -> void:
# Connect to AudioManager ready signal
PopochiuUtils.e.am.ready.connect(_on_audio_manager_ready)
#endregion
#region Public #####################################################################################
func update_sliders() -> void:
for slider in $SlidersContainer.get_children():
if not slider.has_meta("bus_name"): continue
var bus_name: String = slider.get_meta("bus_name")
slider.value = PopochiuUtils.e.am.volume_settings[bus_name]
dflt_volumes[bus_name] = slider.value
func restore_last_volumes() -> void:
for slider in $SlidersContainer.get_children():
if not slider.has_meta("bus_name"): continue
var bus_name: String = slider.get_meta("bus_name")
PopochiuUtils.e.am.set_bus_volume_db(bus_name, dflt_volumes[bus_name])
#endregion
#region Private ####################################################################################
func _on_audio_manager_ready() -> void:
PopochiuUtils.e.am.load_sound_settings()
# Build sound settings UI
for bus_idx in range(AudioServer.get_bus_count()):
var bus_name := AudioServer.get_bus_name(bus_idx)
# Create the label for the slider
var label := Label.new()
label.text = bus_name
$ChannelsContainer.add_child(label)
# Create the node that will allow players to modify buses volumes
var slider = HSlider.new()
slider.min_value = MIN_VOLUME
slider.max_value = 0
slider.value = PopochiuUtils.e.am.volume_settings[bus_name]
slider.texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST
slider.size_flags_horizontal = Control.SIZE_EXPAND_FILL
slider.size_flags_vertical = Control.SIZE_EXPAND_FILL
slider.custom_minimum_size.x = 120.0
slider.set_meta("bus_name", bus_name)
slider.value_changed.connect(_on_volume_slider_changed.bind(bus_name))
$SlidersContainer.add_child(slider)
# Called when a volume slider changes. It will update the volume of the [param bus_name_param] bus
# to [param value]. If the volume is set below or equal to the minimum volume, it will mute the bus.
func _on_volume_slider_changed(value: float, bus_name_param: String) -> void:
if value > MIN_VOLUME:
PopochiuUtils.e.am.set_bus_volume_db(bus_name_param, value)
else:
PopochiuUtils.e.am.set_bus_volume_db(bus_name_param, MUTE_VOLUME)
#endregion

View file

@ -0,0 +1 @@
uid://blyjwnmbu8c7u

View file

@ -0,0 +1,19 @@
[gd_scene load_steps=3 format=3 uid="uid://drx0r8w00ivck"]
[ext_resource type="Theme" uid="uid://dpequqav4rjaf" path="res://addons/popochiu/engine/objects/gui/resources/base_gui_theme.tres" id="1_37u4o"]
[ext_resource type="Script" path="res://addons/popochiu/engine/objects/gui/components/sound_volumes/sound_volumes.gd" id="1_360xl"]
[node name="SoundVolumes" type="GridContainer" groups=["popochiu_gui_component"]]
size_flags_horizontal = 3
size_flags_vertical = 3
theme = ExtResource("1_37u4o")
columns = 2
script = ExtResource("1_360xl")
[node name="ChannelsContainer" type="VBoxContainer" parent="."]
layout_mode = 2
alignment = 1
[node name="SlidersContainer" type="VBoxContainer" parent="."]
custom_minimum_size = Vector2(120, 0)
layout_mode = 2

View file

@ -0,0 +1,81 @@
extends Control
## Show a text in the form of GUI. Can be used to show game (or narrator)
## messages.
const DFLT_SIZE := "dflt_size"
# Used to fix a warning shown by Godot related to the anchors of the node and changing its size
# during a _ready() execution
var _can_change_size := false
@onready var rich_text_label: RichTextLabel = %RichTextLabel
#region Godot ######################################################################################
func _ready() -> void:
set_meta(DFLT_SIZE, rich_text_label.size)
# Connect to singletons signals
PopochiuUtils.g.system_text_shown.connect(_show_text)
PopochiuUtils.e.ready.connect(set.bind("_can_change_size", true))
close()
func _draw() -> void:
rich_text_label.position = get_parent().size / 2.0 - (rich_text_label.size / 2.0)
func _input(event: InputEvent) -> void:
if event.is_action_released("popochiu-skip"):
close.call_deferred()
if not PopochiuUtils.is_click_or_touch_pressed(event) or not visible:
return
accept_event()
if PopochiuUtils.get_click_or_touch_index(event) == MOUSE_BUTTON_LEFT:
close()
#endregion
#region Public #####################################################################################
func appear() -> void:
show()
set_process_input(true)
func close() -> void:
set_process_input(false)
rich_text_label.clear()
rich_text_label.text = ""
if _can_change_size:
rich_text_label.size = get_meta(DFLT_SIZE)
hide()
PopochiuUtils.g.system_text_hidden.emit()
#endregion
#region Private ####################################################################################
func _show_text(msg := "") -> void:
if PopochiuUtils.e.cutscene_skipped:
close.call_deferred()
return
rich_text_label.clear()
rich_text_label.text = ""
rich_text_label.size = get_meta(DFLT_SIZE)
rich_text_label.append_text("[center]%s[/center]" % msg)
if msg:
appear()
else:
close()
#endregion

View file

@ -0,0 +1 @@
uid://cu5huf6n0l2tf

View file

@ -0,0 +1,43 @@
[gd_scene load_steps=4 format=3 uid="uid://bdgs3xsbq3gdd"]
[ext_resource type="Theme" uid="uid://dpequqav4rjaf" path="res://addons/popochiu/engine/objects/gui/resources/base_gui_theme.tres" id="1_7ydn8"]
[ext_resource type="Script" path="res://addons/popochiu/engine/objects/gui/components/system_text/system_text.gd" id="2"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_4eue6"]
content_margin_left = 8.0
content_margin_top = 6.0
content_margin_right = 8.0
content_margin_bottom = 6.0
bg_color = Color(0, 0, 0, 0.705882)
corner_detail = 4
anti_aliasing = false
[node name="SystemText" type="Control" groups=["popochiu_gui_component"]]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 2
theme = ExtResource("1_7ydn8")
script = ExtResource("2")
[node name="RichTextLabel" type="RichTextLabel" parent="."]
unique_name_in_owner = true
layout_mode = 1
anchors_preset = 14
anchor_top = 0.5
anchor_right = 1.0
anchor_bottom = 0.5
offset_left = 33.0
offset_top = -9.0
offset_right = -33.0
offset_bottom = 9.0
grow_horizontal = 2
grow_vertical = 2
theme_override_styles/normal = SubResource("StyleBoxFlat_4eue6")
bbcode_enabled = true
text = "[center]Text from the game itself[/center]"
fit_content = true
scroll_active = false

View file

@ -0,0 +1,34 @@
[remap]
importer="font_data_dynamic"
type="FontFile"
uid="uid://dm6h44ck2nm2b"
path="res://.godot/imported/minecraftia-regular.ttf-aa9f24486e1e8f742a673dd5ce961da5.fontdata"
[deps]
source_file="res://addons/popochiu/engine/objects/gui/fonts/minecraftia-regular.ttf"
dest_files=["res://.godot/imported/minecraftia-regular.ttf-aa9f24486e1e8f742a673dd5ce961da5.fontdata"]
[params]
Rendering=null
antialiasing=1
generate_mipmaps=false
disable_embedded_bitmaps=true
multichannel_signed_distance_field=false
msdf_pixel_range=8
msdf_size=48
allow_system_fallback=true
force_autohinter=false
hinting=1
subpixel_positioning=1
oversampling=0.0
Fallbacks=null
fallbacks=[]
Compress=null
compress=true
preload=[]
language_support={}
script_support={}
opentype_features={}

Some files were not shown because too many files have changed in this diff Show more