maxgame/addons/popochiu/engine/interfaces/i_character.gd
2025-07-17 01:49:18 -04:00

176 lines
6.5 KiB
GDScript

class_name PopochiuICharacter
extends Node
## Provides access to the [PopochiuCharacter]s in the game. Access with [b]C[/b] (e.g.
## [code]C.player.say("What a wonderful plugin")[/code]).
##
## Use it to manipulate Characters. Its script is [b]i_character.gd[/b].[br][br]
##
## Some things you can do with it:[br][br]
## [b]•[/b] Access the Player-controlled Character (PC) directly [code]C.player[/code].[br]
## [b]•[/b] Access any character (with autocompletion based on its name).[br]
## [b]•[/b] Make characters move or say something.[br][br]
##
## Example:
## [codeblock]
## func on_click() -> void:
## await C.walk_to_clicked() # Make the PC move to the clicked object
## await C.face_clicked() # Make the PC look at the clicked object
## await C.player.say("It's a three-headed monkey!!!") # The PC says something
## await C.Popsy.say("Don't tell me...") # Another character says something
## [/codeblock]
## Emitted when [param character] says [param message].
signal character_spoke(character: PopochiuCharacter, message: String)
## Access to the [PopochiuCharacter] that is the current Player-controlled Character (PC).
var player: PopochiuCharacter : set = set_player
## Access to the [PopochiuCharacter] that is owning the camera.
var camera_owner: PopochiuCharacter
## Stores data about the state of each [PopochiuCharacter] in the game. The key of each entry is the
## [member PopochiuCharacter.script_name] of the character.
var characters_states := {}
var _characters := {}
#region Godot ######################################################################################
func _init() -> void:
Engine.register_singleton(&"C", self)
#endregion
#region Public #####################################################################################
## Makes the Player-controlled Character (PC) move (NON-BLOCKING) to the
## [member PopochiuClickable.walk_to_point] position of the last clicked [PopochiuClickable] (i.e. a
## [PopochiuProp], a [PopochiuHotspot], or another [PopochiuCharacter]) in the room. You can set an
## [param offset] relative to the target position.
func walk_to_clicked(offset := Vector2.ZERO) -> void:
await player.walk_to_clicked(offset)
## Makes the Player-controlled Character (PC) move (NON-BLOCKING) to the
## [member PopochiuClickable.walk_to_point] position of the last clicked [PopochiuClickable] (i.e. a
## [PopochiuProp], a [PopochiuHotspot], or another [PopochiuCharacter]) in the room. 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(offset := Vector2.ZERO) -> Callable:
return func (): await walk_to_clicked(offset)
## Similar to [method walk_to_clicked] but BLOCKING the GUI to prevent players from clicking other
## objects or any point in the room.
func walk_to_clicked_blocking(offset := Vector2.ZERO) -> void:
await player.walk_to_clicked_blocking(offset)
## Similar to [method walk_to_clicked] but BLOCKING the GUI to prevent players from clicking other
## objects or any point in the room.
func queue_walk_to_clicked_blocking(offset := Vector2.ZERO) -> Callable:
return func (): await walk_to_clicked_blocking(offset)
## Makes the Player-controlled Character (PC) look at the last clicked [PopochiuClickable].
func face_clicked() -> void:
await player.face_clicked()
## Makes the Player-controlled Character (PC) look at the last clicked [PopochiuClickable].[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 camera follow [param c].
func change_camera_owner(c: PopochiuCharacter) -> void:
if PopochiuUtils.e.cutscene_skipped:
camera_owner = c
await PopochiuUtils.e.get_tree().process_frame
return
camera_owner = c
await PopochiuUtils.e.get_tree().process_frame
## Makes the camera follow [param c].[br][br]
## [i]This method is intended to be used inside a [method Popochiu.queue] of instructions.[/i]
func queue_change_camera_owner(c: PopochiuCharacter) -> Callable:
return func (): await change_camera_owner(c)
## Returns the instance of the [PopochiuCharacter] identified with [param script_name]. If the
## character doesn't exists, then [code]null[/code] is returned.[br][br]
## This method is used by [b]res://game/autoloads/c.gd[/b] to load the instance of each character
## (present in that script as a variable for code autocompletion) in runtime.
func get_runtime_character(script_name: String) -> PopochiuCharacter:
var character: PopochiuCharacter = null
if _characters.has(script_name):
character = _characters[script_name]
else:
PopochiuUtils.print_error("Character %s is not in the room" % script_name)
return character
## Returns [code]true[/code] if [param script_name] is equal to [code]player[/code] or exist in
## [member characters].
func is_valid_character(script_name: String) -> bool:
var is_valid := false
if script_name.to_lower() == "player":
is_valid = true
else:
is_valid = _characters.has(script_name)
return is_valid
## Gets a [PopochiuCharacter] identified with [param script_name]. If the instance doesn't exist in
## [member characters], then one is created, added to the array, and returned.
func get_character(script_name: String) -> PopochiuCharacter:
var character: PopochiuCharacter = null
if script_name.is_empty():
return character
if (
script_name.to_lower() == "player"
or (is_instance_valid(player) and player.script_name.to_lower() == script_name)
):
character = player
elif _characters.has(script_name):
character = _characters[script_name]
else:
# If the character doesn't exist, try to instantiate it from the list of characters (Resource)
# in popochiu_data.cfg
character = get_instance(script_name)
if character:
_characters[character.script_name] = character
set(character.script_name, character)
return character
## Gets the instance of the [PopochiuCharacter] identified with [param script_name].
func get_instance(script_name: String) -> PopochiuCharacter:
var tres_path: String = PopochiuResources.get_data_value("characters", script_name, "")
if not tres_path:
PopochiuUtils.print_error("Character [b]%s[/b] doesn't exist in the project" % script_name)
return null
return load(load(tres_path).scene).instantiate()
#endregion
#region SetGet #####################################################################################
func set_player(value: PopochiuCharacter) -> void:
player = value
camera_owner = value
#endregion