Add addons
This commit is contained in:
parent
2c862b2235
commit
3367bad24f
527 changed files with 36197 additions and 0 deletions
|
|
@ -0,0 +1,15 @@
|
|||
extends DialogicAnimation
|
||||
|
||||
func animate():
|
||||
var tween = (node.create_tween() as Tween)
|
||||
node.scale = Vector2()
|
||||
node.modulate.a = 0
|
||||
|
||||
tween.set_ease(Tween.EASE_IN_OUT)
|
||||
tween.set_trans(Tween.TRANS_LINEAR)
|
||||
tween.set_parallel()
|
||||
|
||||
tween.tween_property(node, 'scale', Vector2(1,1), time).set_trans(Tween.TRANS_ELASTIC).set_ease(Tween.EASE_OUT)
|
||||
tween.tween_property(node, 'modulate:a', 1.0, time)
|
||||
|
||||
tween.finished.connect(emit_signal.bind('finished_once'))
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
extends DialogicAnimation
|
||||
|
||||
func animate():
|
||||
var tween = (node.create_tween() as Tween)
|
||||
node.scale = Vector2(1,1)
|
||||
node.modulate.a = 1
|
||||
|
||||
tween.set_ease(Tween.EASE_IN_OUT)
|
||||
tween.set_trans(Tween.TRANS_LINEAR)
|
||||
tween.set_parallel()
|
||||
|
||||
tween.tween_property(node, 'scale', Vector2(), time).set_trans(Tween.TRANS_ELASTIC).set_ease(Tween.EASE_IN)
|
||||
tween.tween_property(node, 'modulate:a', 0.0, time)
|
||||
|
||||
tween.finished.connect(emit_signal.bind('finished_once'))
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
extends DialogicAnimation
|
||||
|
||||
func animate():
|
||||
var tween = (node.create_tween() as Tween)
|
||||
node.position.y = orig_pos.y + node.get_viewport().size.y/5
|
||||
node.modulate.a = 0
|
||||
tween.set_ease(Tween.EASE_IN_OUT)
|
||||
tween.set_trans(Tween.TRANS_SINE)
|
||||
tween.set_parallel()
|
||||
|
||||
tween.tween_property(node, 'position', orig_pos, time)
|
||||
tween.tween_property(node, 'modulate:a', 1.0, time)
|
||||
|
||||
tween.finished.connect(emit_signal.bind('finished_once'))
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
extends DialogicAnimation
|
||||
|
||||
func animate():
|
||||
var tween = (node.create_tween() as Tween)
|
||||
tween.set_ease(Tween.EASE_IN_OUT)
|
||||
tween.set_trans(Tween.TRANS_SINE)
|
||||
tween.set_parallel()
|
||||
|
||||
tween.tween_property(node, 'position:y', orig_pos.y + node.get_viewport().size.y/5, time)
|
||||
tween.tween_property(node, 'modulate:a', 0.0, time)
|
||||
|
||||
tween.finished.connect(emit_signal.bind('finished_once'))
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
extends DialogicAnimation
|
||||
|
||||
func animate():
|
||||
var tween = (node.create_tween() as Tween)
|
||||
#tween.set_parallel(true)
|
||||
#node.scale = Vector2(1,1)*1.2
|
||||
tween.tween_property(node, 'scale', Vector2(1,1)*1.2, time*0.5).set_trans(Tween.TRANS_ELASTIC).set_ease(Tween.EASE_OUT)
|
||||
#tween.tween_property(node, 'scale', Vector2(1,1)*1.1, time*0.5).set_trans(Tween.TRANS_BACK).set_ease(Tween.EASE_OUT)
|
||||
tween.tween_property(node, 'scale', Vector2(1,1), time*0.5).set_trans(Tween.TRANS_BOUNCE).set_ease(Tween.EASE_OUT)
|
||||
|
||||
tween.finished.connect(emit_signal.bind('finished_once'))
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
extends DialogicAnimation
|
||||
|
||||
func animate():
|
||||
await node.get_tree().process_frame
|
||||
emit_signal('finished')
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
extends DialogicAnimation
|
||||
|
||||
func animate():
|
||||
var tween = (node.create_tween() as Tween)
|
||||
tween.set_parallel(true)
|
||||
tween.set_trans(Tween.TRANS_SINE)
|
||||
tween.set_ease(Tween.EASE_OUT)
|
||||
|
||||
tween.tween_property(node, 'scale', Vector2(1,1)*1.1, time*0.3)
|
||||
tween.tween_property(node, 'rotation', -0.1, time*0.1).set_delay(time*0.2)
|
||||
tween.tween_property(node, 'rotation', 0.1, time*0.1).set_delay(time*0.3)
|
||||
tween.tween_property(node, 'rotation', -0.1, time*0.1).set_delay(time*0.4)
|
||||
tween.tween_property(node, 'rotation', 0.1, time*0.1).set_delay(time*0.5)
|
||||
tween.tween_property(node, 'rotation', -0.1, time*0.1).set_delay(time*0.6)
|
||||
tween.chain().tween_property(node, 'scale', Vector2(1,1), time*0.3)
|
||||
tween.parallel().tween_property(node, 'rotation', 0.0, time*0.3)
|
||||
tween.finished.connect(emit_signal.bind('finished_once'))
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
class_name DialogicAnimation
|
||||
extends Node
|
||||
|
||||
## Class that can be used to animate portraits. Can be extended to create animations.
|
||||
|
||||
signal finished_once
|
||||
signal finished
|
||||
|
||||
## Set at runtime, will be the node to animate.
|
||||
var node :Node
|
||||
## Set at runtime, will be the length of the animation.
|
||||
var time : float
|
||||
## Set at runtime, will be the position at which to end the animation.
|
||||
var end_position : Vector2
|
||||
## Set at runtime. The position the node started at.
|
||||
var orig_pos : Vector2
|
||||
|
||||
## Used to repeate the animation for a number of times.
|
||||
var repeats : int
|
||||
|
||||
|
||||
func _ready():
|
||||
connect('finished_once', finished_one_loop)
|
||||
|
||||
|
||||
## To be overridden. Do the actual animating/tweening in here.
|
||||
## Use the properties [node], [time], [end_position], [orig_pos].
|
||||
func animate():
|
||||
pass
|
||||
|
||||
|
||||
func finished_one_loop():
|
||||
repeats -= 1
|
||||
if repeats > 0:
|
||||
animate()
|
||||
elif repeats == 0:
|
||||
emit_signal("finished")
|
||||
|
||||
|
||||
func pause():
|
||||
if node:
|
||||
node.process_mode = Node.PROCESS_MODE_DISABLED
|
||||
|
||||
|
||||
func resume():
|
||||
if node:
|
||||
node.process_mode = Node.PROCESS_MODE_INHERIT
|
||||
48
Sprout/addons/dialogic/Events/Character/default_portrait.gd
Normal file
48
Sprout/addons/dialogic/Events/Character/default_portrait.gd
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
@tool
|
||||
class_name DialogicDefaultPortrait # TODO: Question should this have a class_name? To be extended or what?
|
||||
extends Node
|
||||
|
||||
## Default portrait scene.
|
||||
|
||||
## Stores the character that this scene displays.
|
||||
var character: DialogicCharacter
|
||||
## Stores the name of the current portrait.
|
||||
var portrait: String
|
||||
|
||||
|
||||
## Function to accept and use the extra data, if the custom portrait wants to accept it
|
||||
func _set_extra_data(data: String) -> void:
|
||||
pass
|
||||
|
||||
|
||||
## This function can be overridden. Defaults to true, if not overridden!
|
||||
func _should_do_portrait_update(character:DialogicCharacter, portrait:String) -> bool:
|
||||
return true
|
||||
|
||||
|
||||
## If the custom portrait accepts a change, then accept it here
|
||||
func _update_portrait(passed_character:DialogicCharacter, passed_portrait:String) -> void:
|
||||
if passed_portrait == "" or not passed_portrait in passed_character.portraits.keys():
|
||||
passed_portrait = passed_character['default_portrait']
|
||||
portrait = passed_portrait
|
||||
if passed_character != null:
|
||||
if character == null or character != passed_character:
|
||||
character = passed_character
|
||||
|
||||
var path :String = character.portraits[portrait].get('image', '')
|
||||
$Portrait.texture = null
|
||||
if !path.is_empty(): $Portrait.texture = load(path)
|
||||
$Portrait.centered = false
|
||||
$Portrait.position = $Portrait.get_rect().size * Vector2(-0.5, -1)
|
||||
|
||||
|
||||
## If implemented, this is called when the mirror changes
|
||||
func _set_mirror(mirror:bool) -> void:
|
||||
$Portrait.flip_h = mirror
|
||||
|
||||
|
||||
## If implemented, this is used by the editor for the "full view" mode
|
||||
func _get_covered_rect() -> Rect2:
|
||||
if $Portrait.texture == null:
|
||||
return Rect2()
|
||||
return Rect2($Portrait.position, $Portrait.get_rect().size)
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
[gd_scene load_steps=3 format=3 uid="uid://c4yp65n7ju1br"]
|
||||
|
||||
[ext_resource type="Script" path="res://addons/dialogic/Events/Character/default_portrait.gd" id="1_wn77n"]
|
||||
|
||||
[sub_resource type="Texture2D" id="Texture2D_sny5f"]
|
||||
resource_local_to_scene = false
|
||||
resource_name = ""
|
||||
|
||||
[node name="DefaultPortrait" type="Node2D"]
|
||||
script = ExtResource("1_wn77n")
|
||||
|
||||
[node name="Portrait" type="Sprite2D" parent="."]
|
||||
texture = SubResource("Texture2D_sny5f")
|
||||
centered = false
|
||||
471
Sprout/addons/dialogic/Events/Character/event_character.gd
Normal file
471
Sprout/addons/dialogic/Events/Character/event_character.gd
Normal file
|
|
@ -0,0 +1,471 @@
|
|||
@tool
|
||||
class_name DialogicCharacterEvent
|
||||
extends DialogicEvent
|
||||
## Event that allows to manipulate character portraits.
|
||||
|
||||
enum PortraitModes {VisualNovel, RPG}
|
||||
enum ActionTypes {Join, Leave, Update}
|
||||
|
||||
|
||||
### Settings
|
||||
|
||||
## The type of action of this event (JOIN/LEAVE/UPDATE). See [ActionTypes].
|
||||
var action_type : int = ActionTypes.Join
|
||||
## The character that will join/leave/update.
|
||||
var character : DialogicCharacter = null
|
||||
## For Join/Update, this will be the portrait of the character that is shown.
|
||||
## Not used on Leave.
|
||||
## If empty, the default portrait will be used.
|
||||
var portrait: String = ""
|
||||
## The index of the position this character should move to
|
||||
var position: int = 1
|
||||
## Path to an animation script (extending DialogicAnimation).
|
||||
## On Join/Leave empty (default) will fallback to the animations set in the settings.
|
||||
## On Update empty will mean no animation.
|
||||
var animation_name: String = ""
|
||||
## Length of the animation.
|
||||
var animation_length: float = 0.5
|
||||
## How often the animation is repeated. Only for Update events.
|
||||
var animation_repeats: int = 1
|
||||
## If true, the events waits for the animation to finish before the next event starts.
|
||||
var animation_wait: bool = false
|
||||
## For Update only. If bigger then 0, the portrait will tween to the
|
||||
## new position (if changed) in this time (in seconds).
|
||||
var position_move_time: float = 0.0
|
||||
## The z_index that the portrait should have.
|
||||
var z_index: int = 0
|
||||
## If true, the portrait will be set to mirrored.
|
||||
var mirrored: bool = false
|
||||
## If set, will be passed to the portrait scene.
|
||||
var extra_data: String = ""
|
||||
|
||||
|
||||
### Helpers
|
||||
|
||||
## Indicates if the z_index should be updated.
|
||||
var _update_zindex: bool = false
|
||||
## Used to set the character resource from the unique name identifier and vice versa
|
||||
var _character_from_directory: String:
|
||||
get:
|
||||
if _character_from_directory == '--All--':
|
||||
return '--All--'
|
||||
for item in _character_directory.keys():
|
||||
if _character_directory[item]['resource'] == character:
|
||||
return item
|
||||
break
|
||||
return ""
|
||||
set(value):
|
||||
_character_from_directory = value
|
||||
if value in _character_directory.keys():
|
||||
character = _character_directory[value]['resource']
|
||||
else:
|
||||
character = null
|
||||
## Used by [_character_from_directory]
|
||||
var _character_directory: Dictionary = {}
|
||||
|
||||
|
||||
################################################################################
|
||||
## EXECUTION
|
||||
################################################################################
|
||||
|
||||
func _execute() -> void:
|
||||
match action_type:
|
||||
ActionTypes.Join:
|
||||
|
||||
if character:
|
||||
if !dialogic.Portraits.is_character_joined(character):
|
||||
var n = dialogic.Portraits.add_portrait(character, portrait, position, mirrored, z_index, extra_data)
|
||||
if n:
|
||||
if animation_name.is_empty():
|
||||
animation_name = DialogicUtil.get_project_setting('dialogic/animations/join_default',
|
||||
get_script().resource_path.get_base_dir().path_join('DefaultAnimations/fade_in_up.gd'))
|
||||
animation_length = DialogicUtil.get_project_setting('dialogic/animations/join_default_length', 0.5)
|
||||
animation_wait = DialogicUtil.get_project_setting('dialogic/animations/join_default_wait', true)
|
||||
if animation_name:
|
||||
var anim:DialogicAnimation = dialogic.Portraits.animate_portrait(character, animation_name, animation_length, animation_repeats)
|
||||
|
||||
if animation_wait:
|
||||
dialogic.current_state = Dialogic.states.ANIMATING
|
||||
await anim.finished
|
||||
dialogic.current_state = Dialogic.states.IDLE
|
||||
else:
|
||||
dialogic.Portraits.change_portrait(character, portrait)
|
||||
if animation_name.is_empty():
|
||||
animation_length = DialogicUtil.get_project_setting('dialogic/animations/join_default_length', 0.5)
|
||||
dialogic.Portraits.move_portrait(character, position, z_index, false, animation_length)
|
||||
ActionTypes.Leave:
|
||||
if _character_from_directory == '--All--':
|
||||
if animation_name.is_empty():
|
||||
animation_name = DialogicUtil.get_project_setting('dialogic/animations/leave_default',
|
||||
get_script().resource_path.get_base_dir().path_join('DefaultAnimations/fade_out_down.gd'))
|
||||
animation_length = DialogicUtil.get_project_setting('dialogic/animations/leave_default_length', 0.5)
|
||||
animation_wait = DialogicUtil.get_project_setting('dialogic/animations/leave_default_wait', true)
|
||||
|
||||
if animation_name:
|
||||
for chara in dialogic.Portraits.get_joined_characters():
|
||||
var anim = dialogic.Portraits.animate_portrait(chara, animation_name, animation_length, animation_repeats)
|
||||
|
||||
anim.finished.connect(dialogic.Portraits.remove_portrait.bind(chara))
|
||||
|
||||
if animation_wait:
|
||||
dialogic.current_state = Dialogic.states.ANIMATING
|
||||
await anim.finished
|
||||
dialogic.current_state = Dialogic.states.IDLE
|
||||
|
||||
else:
|
||||
for chara in dialogic.Portraits.get_joined_characters():
|
||||
dialogic.Portraits.remove_portrait(chara)
|
||||
elif character:
|
||||
if dialogic.Portraits.is_character_joined(character):
|
||||
if animation_name.is_empty():
|
||||
animation_name = DialogicUtil.get_project_setting('dialogic/animations/leave_default',
|
||||
get_script().resource_path.get_base_dir().path_join('DefaultAnimations/fade_out_down.gd'))
|
||||
animation_length = DialogicUtil.get_project_setting('dialogic/animations/leave_default_length', 0.5)
|
||||
animation_wait = DialogicUtil.get_project_setting('dialogic/animations/leave_default_wait', true)
|
||||
|
||||
if animation_name:
|
||||
var anim = dialogic.Portraits.animate_portrait(character, animation_name, animation_length, animation_repeats)
|
||||
|
||||
anim.finished.connect(dialogic.Portraits.remove_portrait.bind(character))
|
||||
|
||||
if animation_wait:
|
||||
dialogic.current_state = Dialogic.states.ANIMATING
|
||||
await anim.finished
|
||||
dialogic.current_state = Dialogic.states.IDLE
|
||||
|
||||
else:
|
||||
dialogic.Portraits.remove_portrait(character)
|
||||
|
||||
ActionTypes.Update:
|
||||
if character:
|
||||
if dialogic.Portraits.is_character_joined(character):
|
||||
dialogic.Portraits.change_portrait(character, portrait, mirrored, z_index, _update_zindex, extra_data)
|
||||
if position != 0:
|
||||
dialogic.Portraits.move_portrait(character, position, z_index, _update_zindex, position_move_time)
|
||||
|
||||
if animation_name:
|
||||
var anim = dialogic.Portraits.animate_portrait(character, animation_name, animation_length, animation_repeats)
|
||||
|
||||
if animation_wait:
|
||||
dialogic.current_state = Dialogic.states.ANIMATING
|
||||
await anim.finished
|
||||
dialogic.current_state = Dialogic.states.IDLE
|
||||
|
||||
finish()
|
||||
|
||||
|
||||
################################################################################
|
||||
## INITIALIZE
|
||||
################################################################################
|
||||
|
||||
func _init() -> void:
|
||||
event_name = "Character"
|
||||
set_default_color('Color2')
|
||||
event_category = Category.Main
|
||||
event_sorting_index = 2
|
||||
continue_at_end = true
|
||||
expand_by_default = false
|
||||
|
||||
|
||||
func _get_icon() -> Resource:
|
||||
return load(self.get_script().get_path().get_base_dir().path_join('icon_character.png'))
|
||||
|
||||
################################################################################
|
||||
## SAVING/LOADING
|
||||
################################################################################
|
||||
|
||||
func to_text() -> String:
|
||||
var result_string := ""
|
||||
|
||||
match action_type:
|
||||
ActionTypes.Join: result_string += "Join "
|
||||
ActionTypes.Leave: result_string += "Leave "
|
||||
ActionTypes.Update: result_string += "Update "
|
||||
|
||||
print('to_string')
|
||||
|
||||
print('character ', character)
|
||||
print('characterfrom ', _character_from_directory)
|
||||
|
||||
if character or _character_from_directory == '--All--':
|
||||
if action_type == ActionTypes.Leave and _character_from_directory == '--All--':
|
||||
result_string += "--All--"
|
||||
else:
|
||||
var name := ""
|
||||
for path in _character_directory.keys():
|
||||
if _character_directory[path]['resource'] == character:
|
||||
name = path
|
||||
break
|
||||
if name.count(" ") > 0:
|
||||
name = '"' + name + '"'
|
||||
result_string += name
|
||||
if !portrait.is_empty() and action_type != ActionTypes.Leave:
|
||||
result_string+= " ("+portrait+")"
|
||||
|
||||
if position and action_type != ActionTypes.Leave:
|
||||
result_string += " "+str(position)
|
||||
if animation_name != "" or z_index != 0 or mirrored != false or position_move_time != 0.0 or extra_data != "":
|
||||
result_string += " ["
|
||||
if animation_name:
|
||||
result_string += 'animation="'+DialogicUtil.pretty_name(animation_name)+'"'
|
||||
|
||||
if animation_length != 0.5:
|
||||
result_string += ' length="'+str(animation_length)+'"'
|
||||
|
||||
if animation_wait:
|
||||
result_string += ' wait="'+str(animation_wait)+'"'
|
||||
|
||||
if animation_repeats != 1:
|
||||
result_string += ' repeat="'+str(animation_repeats)+'"'
|
||||
if z_index != 0:
|
||||
result_string += ' z-index="' + str(z_index) + '"'
|
||||
|
||||
if mirrored:
|
||||
result_string += ' mirrored="' + str(mirrored) + '"'
|
||||
|
||||
if position_move_time != 0:
|
||||
result_string += ' move_time="' + str(position_move_time) + '"'
|
||||
|
||||
if extra_data != "":
|
||||
result_string += ' extra_data="' + extra_data + '"'
|
||||
|
||||
result_string += "]"
|
||||
return result_string
|
||||
|
||||
|
||||
func from_text(string:String) -> void:
|
||||
if Engine.is_editor_hint() == false:
|
||||
_character_directory = Dialogic.character_directory
|
||||
else:
|
||||
_character_directory = self.get_meta("editor_character_directory")
|
||||
|
||||
var regex := RegEx.new()
|
||||
|
||||
# Reference regex without Godot escapes: (?<type>Join|Update|Leave)\s*(")?(?<name>(?(2)[^"\n]*|[^(: \n]*))(?(2)"|)(\W*\((?<portrait>.*)\))?(\s*(?<position>\d))?(\s*\[(?<shortcode>.*)\])?
|
||||
regex.compile("(?<type>Join|Update|Leave)\\s*(\")?(?<name>(?(2)[^\"\\n]*|[^(: \\n]*))(?(2)\"|)(\\W*\\((?<portrait>.*)\\))?(\\s*(?<position>\\d))?(\\s*\\[(?<shortcode>.*)\\])?")
|
||||
|
||||
var result := regex.search(string)
|
||||
|
||||
match result.get_string('type'):
|
||||
"Join":
|
||||
action_type = ActionTypes.Join
|
||||
"Leave":
|
||||
action_type = ActionTypes.Leave
|
||||
"Update":
|
||||
action_type = ActionTypes.Update
|
||||
|
||||
if result.get_string('name').strip_edges():
|
||||
if action_type == ActionTypes.Leave and result.get_string('name').strip_edges() == "--All--":
|
||||
_character_from_directory = '--All--'
|
||||
else:
|
||||
var name := result.get_string('name').strip_edges()
|
||||
|
||||
|
||||
if _character_directory != null:
|
||||
if _character_directory.size() > 0:
|
||||
character = null
|
||||
if _character_directory.has(name):
|
||||
character = _character_directory[name]['resource']
|
||||
else:
|
||||
name = name.replace('"', "")
|
||||
# First do a full search to see if more of the path is there then necessary:
|
||||
for character in _character_directory:
|
||||
if name in _character_directory[character]['full_path']:
|
||||
character = _character_directory[character]['resource']
|
||||
break
|
||||
|
||||
# If it doesn't exist, we'll consider it a guest and create a temporary character
|
||||
if character == null:
|
||||
if Engine.is_editor_hint() == false:
|
||||
character = DialogicCharacter.new()
|
||||
character.display_name = name
|
||||
var entry:Dictionary = {}
|
||||
entry['resource'] = character
|
||||
entry['full_path'] = "runtime://" + name
|
||||
Dialogic.character_directory[name] = entry
|
||||
|
||||
if result.get_string('portrait').strip_edges():
|
||||
portrait = result.get_string('portrait').strip_edges()
|
||||
|
||||
if result.get_string('position'):
|
||||
position = result.get_string('position').to_int()
|
||||
elif action_type == ActionTypes.Update:
|
||||
# Override the normal default if it's an Update
|
||||
position = 0
|
||||
|
||||
if result.get_string('shortcode'):
|
||||
var shortcode_params = parse_shortcode_parameters(result.get_string('shortcode'))
|
||||
animation_name = shortcode_params.get('animation', '')
|
||||
if animation_name != "":
|
||||
if !animation_name.ends_with('.gd'):
|
||||
animation_name = guess_animation_file(animation_name)
|
||||
if !animation_name.ends_with('.gd'):
|
||||
printerr("[Dialogic] Couldn't identify animation '"+animation_name+"'.")
|
||||
animation_name = ""
|
||||
|
||||
var animLength = shortcode_params.get('length', '0.5').to_float()
|
||||
if typeof(animLength) == TYPE_FLOAT:
|
||||
animation_length = animLength
|
||||
else:
|
||||
animation_length = animLength.to_float()
|
||||
|
||||
animation_wait = DialogicUtil.str_to_bool(shortcode_params.get('wait', 'false'))
|
||||
|
||||
#repeat is supported on Update, the other two should not be checking this
|
||||
if action_type == ActionTypes.Update:
|
||||
animation_repeats = shortcode_params.get('repeat', 1).to_int()
|
||||
position_move_time = shortcode_params.get('move_time', 0.0)
|
||||
#move time is only supported on Update, but it isnt part of the animations so its separate
|
||||
if action_type == ActionTypes.Update:
|
||||
if typeof(shortcode_params.get('move_time', 0)) == TYPE_STRING:
|
||||
position_move_time = shortcode_params.get('move_time', 0.0).to_float()
|
||||
|
||||
if typeof(shortcode_params.get('z-index', 0)) == TYPE_STRING:
|
||||
z_index = shortcode_params.get('z-index', 0).to_int()
|
||||
_update_zindex = true
|
||||
mirrored = DialogicUtil.str_to_bool(shortcode_params.get('mirrored', 'false'))
|
||||
extra_data = shortcode_params.get('extra_data', "")
|
||||
|
||||
|
||||
func is_valid_event(string:String) -> bool:
|
||||
if string.begins_with("Join ") or string.begins_with("Leave ") or string.begins_with("Update "):
|
||||
return true
|
||||
return false
|
||||
|
||||
|
||||
################################################################################
|
||||
## EDITOR REPRESENTATION
|
||||
################################################################################
|
||||
|
||||
func build_event_editor() -> void:
|
||||
add_header_edit('action_type', ValueType.FixedOptionSelector, '', '', {
|
||||
'selector_options': [
|
||||
{
|
||||
'label': 'Join',
|
||||
'value': ActionTypes.Join,
|
||||
'icon': load("res://addons/dialogic/Editor/Images/Dropdown/join.svg")
|
||||
},
|
||||
{
|
||||
'label': 'Leave',
|
||||
'value': ActionTypes.Leave,
|
||||
'icon': load("res://addons/dialogic/Editor/Images/Dropdown/leave.svg")
|
||||
},
|
||||
{
|
||||
'label': 'Update',
|
||||
'value': ActionTypes.Update,
|
||||
'icon': load("res://addons/dialogic/Editor/Images/Dropdown/update.svg")
|
||||
}
|
||||
]
|
||||
})
|
||||
add_header_edit('_character_from_directory', ValueType.ComplexPicker, '', '',
|
||||
{'empty_text' : 'Character',
|
||||
'file_extension' : '.dch',
|
||||
'suggestions_func' : get_character_suggestions,
|
||||
'icon' : load("res://addons/dialogic/Editor/Images/Resources/character.svg")})
|
||||
add_header_button('', _on_character_edit_pressed, 'Edit character', ["Edit", "EditorIcons"], 'character != null and _character_from_directory != "--All--"')
|
||||
|
||||
add_header_edit('portrait', ValueType.ComplexPicker, '', '',
|
||||
{'empty_text' : 'Default',
|
||||
'suggestions_func' : get_portrait_suggestions,
|
||||
'icon' : load("res://addons/dialogic/Editor/Images/Resources/portrait.svg")},
|
||||
'character != null and !has_no_portraits() and action_type != %s' %ActionTypes.Leave)
|
||||
add_header_edit('position', ValueType.Integer, ' at position', '', {},
|
||||
'character != null and !has_no_portraits() and action_type != %s' %ActionTypes.Leave)
|
||||
|
||||
# Body
|
||||
add_body_edit('animation_name', ValueType.ComplexPicker, 'Animation:', '',
|
||||
{'suggestions_func' : get_animation_suggestions,
|
||||
'editor_icon' : ["Animation", "EditorIcons"],
|
||||
'placeholder' : 'Default',
|
||||
'enable_pretty_name' : true},
|
||||
'should_show_animation_options()')
|
||||
add_body_edit('animation_length', ValueType.Float, 'Length:', '', {},
|
||||
'should_show_animation_options() and !animation_name.is_empty()')
|
||||
add_body_edit('animation_wait', ValueType.Bool, 'Wait for animation to finish:', '', {},
|
||||
'should_show_animation_options() and !animation_name.is_empty()')
|
||||
add_body_edit('animation_repeats', ValueType.Integer, 'Repeat:', '', {},
|
||||
'should_show_animation_options() and !animation_name.is_empty() and action_type == %s)' %ActionTypes.Update)
|
||||
add_body_edit('z_index', ValueType.Integer, 'portrait z-index:', "",{},
|
||||
'action_type != %s' %ActionTypes.Leave)
|
||||
add_body_edit('mirrored', ValueType.Bool, 'mirrored:', "",{},
|
||||
'action_type != %s' %ActionTypes.Leave)
|
||||
add_body_edit('position_move_time', ValueType.Float, 'Transiton time to change position:', '', {},
|
||||
'action_type == %s' %ActionTypes.Update)
|
||||
|
||||
|
||||
func should_show_animation_options() -> bool:
|
||||
return (character != null and !character.portraits.is_empty()) or _character_from_directory == '--All--'
|
||||
|
||||
func has_no_portraits() -> bool:
|
||||
return character and character.portraits.is_empty()
|
||||
|
||||
|
||||
func get_character_suggestions(search_text:String) -> Dictionary:
|
||||
var suggestions := {}
|
||||
|
||||
#override the previous _character_directory with the meta, specifically for searching otherwise new nodes wont work
|
||||
_character_directory = Engine.get_meta('dialogic_character_directory')
|
||||
|
||||
var icon = load("res://addons/dialogic/Editor/Images/Resources/character.svg")
|
||||
|
||||
suggestions['(No one)'] = {'value':'', 'editor_icon':["GuiRadioUnchecked", "EditorIcons"]}
|
||||
if action_type == ActionTypes.Leave:
|
||||
suggestions['ALL'] = {'value':'--All--', 'tooltip':'All currently joined characters leave', 'editor_icon':["GuiEllipsis", "EditorIcons"]}
|
||||
for resource in _character_directory.keys():
|
||||
suggestions[resource] = {'value': resource, 'tooltip': _character_directory[resource]['full_path'], 'icon': icon.duplicate()}
|
||||
return suggestions
|
||||
|
||||
|
||||
func get_portrait_suggestions(search_text:String) -> Dictionary:
|
||||
var suggestions := {}
|
||||
var icon = load("res://addons/dialogic/Editor/Images/Resources/portrait.svg")
|
||||
if action_type == ActionTypes.Update:
|
||||
suggestions["Don't Change"] = {'value':'', 'editor_icon':["GuiRadioUnchecked", "EditorIcons"]}
|
||||
if action_type == ActionTypes.Join:
|
||||
suggestions["Default portrait"] = {'value':'', 'editor_icon':["GuiRadioUnchecked", "EditorIcons"]}
|
||||
if character != null:
|
||||
for portrait in character.portraits:
|
||||
suggestions[portrait] = {'value':portrait, 'icon':icon.duplicate()}
|
||||
return suggestions
|
||||
|
||||
|
||||
func get_animation_suggestions(search_text:String) -> Dictionary:
|
||||
var suggestions := {}
|
||||
|
||||
match action_type:
|
||||
ActionTypes.Join, ActionTypes.Leave:
|
||||
suggestions['Default'] = {'value':"", 'editor_icon':["GuiRadioUnchecked", "EditorIcons"]}
|
||||
ActionTypes.Update:
|
||||
suggestions['None'] = {'value':"", 'editor_icon':["GuiRadioUnchecked", "EditorIcons"]}
|
||||
|
||||
for anim in list_animations():
|
||||
match action_type:
|
||||
ActionTypes.Join:
|
||||
if '_in' in anim.get_file():
|
||||
suggestions[DialogicUtil.pretty_name(anim)] = {'value':anim, 'editor_icon':["Animation", "EditorIcons"]}
|
||||
ActionTypes.Leave:
|
||||
if '_out' in anim.get_file():
|
||||
suggestions[DialogicUtil.pretty_name(anim)] = {'value':anim, 'editor_icon':["Animation", "EditorIcons"]}
|
||||
ActionTypes.Update:
|
||||
if not ('_in' in anim.get_file() or '_out' in anim.get_file()):
|
||||
suggestions[DialogicUtil.pretty_name(anim)] = {'value':anim, 'editor_icon':["Animation", "EditorIcons"]}
|
||||
continue
|
||||
return suggestions
|
||||
|
||||
|
||||
func list_animations() -> Array:
|
||||
var list := DialogicUtil.listdir(get_script().resource_path.get_base_dir().path_join('DefaultAnimations'), true, false, true)
|
||||
list.append_array(DialogicUtil.listdir(DialogicUtil.get_project_setting('dialogic/animations/custom_folder', 'res://addons/dialogic_additions/Animations'), true, false, true))
|
||||
return list
|
||||
|
||||
|
||||
func guess_animation_file(animation_name: String) -> String:
|
||||
for file in list_animations():
|
||||
if DialogicUtil.pretty_name(animation_name) == DialogicUtil.pretty_name(file):
|
||||
return file
|
||||
return animation_name
|
||||
|
||||
func _on_character_edit_pressed() -> void:
|
||||
var editor_manager := _editor_node.find_parent('EditorsManager')
|
||||
if editor_manager:
|
||||
editor_manager.edit_resource(character)
|
||||
111
Sprout/addons/dialogic/Events/Character/event_position.gd
Normal file
111
Sprout/addons/dialogic/Events/Character/event_position.gd
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
@tool
|
||||
class_name DialogicPositionEvent
|
||||
extends DialogicEvent
|
||||
|
||||
## Event that allows moving of positions (and characters that are on that position).
|
||||
## Requires the Portraits subsystem to be present!
|
||||
|
||||
enum ActionTypes {SetRelative, SetAbsolute, Reset, ResetAll}
|
||||
|
||||
|
||||
### Settings
|
||||
|
||||
## The type of action: SetRelative, SetAbsolute, Reset, ResetAll
|
||||
var action_type := ActionTypes.SetRelative
|
||||
## The position that should be affected
|
||||
var position: int = 0
|
||||
## A vector representing a relative change or an absolute position (for SetRelative and SetAbsolute)
|
||||
var vector: Vector2 = Vector2()
|
||||
## The time the tweening will take.
|
||||
var movement_time: float = 0
|
||||
|
||||
|
||||
################################################################################
|
||||
## EXECUTE
|
||||
################################################################################
|
||||
func _execute() -> void:
|
||||
# If for some someone sets it to 0, ignore it entirely. 0 position is used for Update to indicate no change.
|
||||
if action_type != ActionTypes.ResetAll and position == 0:
|
||||
finish()
|
||||
return
|
||||
|
||||
match action_type:
|
||||
ActionTypes.SetRelative:
|
||||
dialogic.Portraits.move_portrait_position(position, vector, true, movement_time)
|
||||
ActionTypes.SetAbsolute:
|
||||
dialogic.Portraits.move_portrait_position(position, vector, false, movement_time)
|
||||
ActionTypes.ResetAll:
|
||||
dialogic.Portraits.reset_portrait_positions(movement_time)
|
||||
ActionTypes.Reset:
|
||||
dialogic.Portraits.reset_portrait_position(position, movement_time)
|
||||
|
||||
finish()
|
||||
|
||||
|
||||
##############################################file_path##################################
|
||||
## INITIALIZE
|
||||
################################################################################
|
||||
|
||||
func _init() -> void:
|
||||
event_name = "position"
|
||||
set_default_color('Color2')
|
||||
event_category = Category.Main
|
||||
event_sorting_index = 2
|
||||
continue_at_end = true
|
||||
expand_by_default = false
|
||||
|
||||
|
||||
func _get_icon() -> Resource:
|
||||
return load(self.get_script().get_path().get_base_dir().path_join('icon_position.png'))
|
||||
|
||||
################################################################################
|
||||
## SAVING/LOADING
|
||||
################################################################################
|
||||
|
||||
func get_shortcode() -> String:
|
||||
return "update_position"
|
||||
|
||||
|
||||
func get_shortcode_parameters() -> Dictionary:
|
||||
return {
|
||||
#param_name : property_info
|
||||
"action" : {"sproperty": "action_type", "default": ActionTypes.SetRelative,
|
||||
"suggestions": func(): return {"Set Relative":{'value':'0'}, "Set Absolute":{'value':'1'}, "Reset":{'value':'2'}, "Reset All":{'value':'3'}}},
|
||||
"position" : {"property": "position", "default": 0},
|
||||
"vector" : {"property": "vector", "default": Vector2()},
|
||||
"time" : {"property": "movement_time", "default": 0},
|
||||
}
|
||||
|
||||
|
||||
################################################################################
|
||||
## EDITOR REPRESENTATION
|
||||
################################################################################
|
||||
|
||||
func build_event_editor():
|
||||
add_header_edit('action_type', ValueType.FixedOptionSelector, '', '', {
|
||||
'selector_options': [
|
||||
{
|
||||
'label': 'Change',
|
||||
'value': ActionTypes.SetRelative,
|
||||
},
|
||||
{
|
||||
'label': 'Set',
|
||||
'value': ActionTypes.SetAbsolute,
|
||||
},
|
||||
{
|
||||
'label': 'Reset',
|
||||
'value': ActionTypes.Reset,
|
||||
},
|
||||
{
|
||||
'label': 'Reset All',
|
||||
'value': ActionTypes.ResetAll,
|
||||
}
|
||||
]
|
||||
})
|
||||
add_header_edit("position", ValueType.Integer, "position", '', {},
|
||||
'action_type != ActionTypes.ResetAll')
|
||||
add_header_label('to (absolute)', 'action_type == ActionTypes.SetAbsolute')
|
||||
add_header_label('by (relative)', 'action_type == ActionTypes.SetRelative')
|
||||
add_header_edit("vector", ValueType.Vector2, "", '', {},
|
||||
'action_type != ActionTypes.Reset and action_type != ActionTypes.ResetAll')
|
||||
add_body_edit("movement_time", ValueType.Float, "AnimationTime:", "(0 for instant)")
|
||||
34
Sprout/addons/dialogic/Events/Character/icon.png.import
Normal file
34
Sprout/addons/dialogic/Events/Character/icon.png.import
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://dn5jx2ucynfio"
|
||||
path="res://.godot/imported/icon.png-a6ef7c3eeb0fb100c7d0b0c505ea4b6f.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/dialogic/Events/Character/icon.png"
|
||||
dest_files=["res://.godot/imported/icon.png-a6ef7c3eeb0fb100c7d0b0c505ea4b6f.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/bptc_ldr=0
|
||||
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
|
||||
BIN
Sprout/addons/dialogic/Events/Character/icon_character.png
Normal file
BIN
Sprout/addons/dialogic/Events/Character/icon_character.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 569 B |
|
|
@ -0,0 +1,34 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://b1i3ttk36kghm"
|
||||
path="res://.godot/imported/icon_character.png-93ea754ecc6f43d01c1116ffee9f80e3.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/dialogic/Events/Character/icon_character.png"
|
||||
dest_files=["res://.godot/imported/icon_character.png-93ea754ecc6f43d01c1116ffee9f80e3.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/bptc_ldr=0
|
||||
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
|
||||
BIN
Sprout/addons/dialogic/Events/Character/icon_position.png
Normal file
BIN
Sprout/addons/dialogic/Events/Character/icon_position.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1,017 B |
|
|
@ -0,0 +1,34 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://cu6cj55m6dr78"
|
||||
path="res://.godot/imported/icon_position.png-18fc8e57ed28c84781c862b6ca4492f7.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/dialogic/Events/Character/icon_position.png"
|
||||
dest_files=["res://.godot/imported/icon_position.png-18fc8e57ed28c84781c862b6ca4492f7.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/bptc_ldr=0
|
||||
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
|
||||
14
Sprout/addons/dialogic/Events/Character/index.gd
Normal file
14
Sprout/addons/dialogic/Events/Character/index.gd
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
@tool
|
||||
extends DialogicIndexer
|
||||
|
||||
|
||||
func _get_events() -> Array:
|
||||
return [this_folder.path_join('event_character.gd'), this_folder.path_join('event_position.gd')]
|
||||
|
||||
|
||||
func _get_subsystems() -> Array:
|
||||
return [{'name':'Portraits', 'script':this_folder.path_join('subsystem_portraits.gd')}]
|
||||
|
||||
|
||||
func _get_settings_pages() -> Array:
|
||||
return [this_folder.path_join('settings_portraits.tscn')]
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
class_name DialogicNode_PortraitHolder
|
||||
extends CanvasLayer
|
||||
|
||||
|
||||
func _ready():
|
||||
add_to_group('dialogic_portrait_holder')
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
class_name DialogicNode_PortraitPosition
|
||||
extends Marker2D
|
||||
|
||||
## Used to identify positions in the [DialogicCharacterEvent].
|
||||
@export var position_index = 0
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
add_to_group('dialogic_portrait_position')
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
@tool
|
||||
extends HBoxContainer
|
||||
|
||||
var current_animation_path = ""
|
||||
|
||||
func _ready():
|
||||
%JoinDefault.get_suggestions_func = get_join_animation_suggestions
|
||||
%JoinDefault.enable_pretty_name = true
|
||||
%LeaveDefault.get_suggestions_func = get_leave_animation_suggestions
|
||||
%LeaveDefault.enable_pretty_name = true
|
||||
|
||||
func refresh():
|
||||
%CustomAnimationsFolderOpener.icon = get_theme_icon("Folder", "EditorIcons")
|
||||
%CustomAnimationsFolder.text = DialogicUtil.get_project_setting('dialogic/animations/custom_folder', 'res://addons/dialogic_additions/Animations')
|
||||
%PortraitMode.select(DialogicUtil.get_project_setting('dialogic/portrait_mode', 0))
|
||||
|
||||
%JoinDefault.resource_icon = get_theme_icon("Animation", "EditorIcons")
|
||||
%LeaveDefault.resource_icon = get_theme_icon("Animation", "EditorIcons")
|
||||
%JoinDefault.set_value(DialogicUtil.pretty_name(DialogicUtil.get_project_setting('dialogic/animations/join_default',
|
||||
get_script().resource_path.get_base_dir().path_join('DefaultAnimations/fade_in_up.gd'))))
|
||||
%LeaveDefault.set_value(DialogicUtil.get_project_setting('dialogic/animations/leave_default',
|
||||
get_script().resource_path.get_base_dir().path_join('DefaultAnimations/fade_out_down.gd')))
|
||||
%JoinDefaultLength.set_value(DialogicUtil.get_project_setting('dialogic/animations/join_default_length', 0.5))
|
||||
%LeaveDefaultLength.set_value(DialogicUtil.get_project_setting('dialogic/animations/leave_default_length', 0.5))
|
||||
%LeaveDefaultWait.button_pressed = DialogicUtil.get_project_setting('dialogic/animations/leave_default_wait', true)
|
||||
%JoinDefaultWait.button_pressed = DialogicUtil.get_project_setting('dialogic/animations/join_default_wait', true)
|
||||
|
||||
|
||||
func _on_LeaveDefault_value_changed(property_name, value):
|
||||
ProjectSettings.set_setting('dialogic/animations/leave_default', value)
|
||||
ProjectSettings.save()
|
||||
|
||||
|
||||
func _on_JoinDefault_value_changed(property_name, value):
|
||||
ProjectSettings.set_setting('dialogic/animations/join_default', value)
|
||||
ProjectSettings.save()
|
||||
|
||||
|
||||
func _on_JoinDefaultLength_value_changed(value):
|
||||
ProjectSettings.set_setting('dialogic/animations/join_default_length', value)
|
||||
ProjectSettings.save()
|
||||
|
||||
|
||||
func _on_LeaveDefaultLength_value_changed(value):
|
||||
ProjectSettings.set_setting('dialogic/animations/leave_default_length', value)
|
||||
ProjectSettings.save()
|
||||
|
||||
func _on_JoinDefaultWait_toggled(button_pressed):
|
||||
ProjectSettings.set_setting('dialogic/animations/join_default_wait', button_pressed)
|
||||
ProjectSettings.save()
|
||||
|
||||
func _on_LeaveDefaultWait_toggled(button_pressed):
|
||||
ProjectSettings.set_setting('dialogic/animations/leave_default_wait', button_pressed)
|
||||
ProjectSettings.save()
|
||||
|
||||
|
||||
func get_join_animation_suggestions(search_text:String) -> Dictionary:
|
||||
var suggestions = {}
|
||||
for anim in list_animations():
|
||||
if '_in' in anim.get_file():
|
||||
suggestions[DialogicUtil.pretty_name(anim)] = {'value':anim, 'icon':get_theme_icon('Animation', 'EditorIcons')}
|
||||
return suggestions
|
||||
|
||||
func get_leave_animation_suggestions(search_text:String) -> Dictionary:
|
||||
var suggestions = {}
|
||||
for anim in list_animations():
|
||||
if '_out' in anim.get_file():
|
||||
suggestions[DialogicUtil.pretty_name(anim)] = {'value':anim, 'icon':get_theme_icon('Animation', 'EditorIcons')}
|
||||
return suggestions
|
||||
|
||||
func list_animations() -> Array:
|
||||
var list = DialogicUtil.listdir(get_script().resource_path.get_base_dir().path_join('DefaultAnimations'), true, false, true)
|
||||
list.append_array(DialogicUtil.listdir(DialogicUtil.get_project_setting('dialogic/animations/custom_folder', 'res://addons/dialogic_additions/Animations'), true, false, true))
|
||||
return list
|
||||
|
||||
|
||||
func _on_CustomAnimationsFolderOpener_pressed():
|
||||
find_parent('EditorView').godot_file_dialog(custom_anims_folder_selected, '', EditorFileDialog.FILE_MODE_OPEN_DIR, 'Select custom animation folder')
|
||||
|
||||
func custom_anims_folder_selected(path):
|
||||
%CustomAnimationsFolder.text = path
|
||||
ProjectSettings.set_setting('dialogic/animations/custom_folder', path)
|
||||
ProjectSettings.save()
|
||||
|
||||
|
||||
func _on_PortraitMode_item_selected(index):
|
||||
ProjectSettings.set_setting('dialogic/portrait_mode', index)
|
||||
ProjectSettings.save()
|
||||
232
Sprout/addons/dialogic/Events/Character/settings_portraits.tscn
Normal file
232
Sprout/addons/dialogic/Events/Character/settings_portraits.tscn
Normal file
|
|
@ -0,0 +1,232 @@
|
|||
[gd_scene load_steps=7 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://addons/dialogic/Events/Character/settings_portraits.gd" id="2"]
|
||||
[ext_resource type="StyleBox" uid="uid://dmsjhgv22dns8" path="res://addons/dialogic/Editor/Common/TitleBgStylebox.tres" id="2_i6l15"]
|
||||
[ext_resource type="PackedScene" uid="uid://dpwhshre1n4t6" path="res://addons/dialogic/Editor/Events/Fields/ComplexPicker.tscn" id="3"]
|
||||
[ext_resource type="Script" path="res://addons/dialogic/Editor/Settings/HintLabelStylingScript.gd" id="3_jknrx"]
|
||||
|
||||
[sub_resource type="Image" id="Image_t2ykh"]
|
||||
data = {
|
||||
"data": PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||
"format": "LumAlpha8",
|
||||
"height": 16,
|
||||
"mipmaps": false,
|
||||
"width": 16
|
||||
}
|
||||
|
||||
[sub_resource type="ImageTexture" id="2"]
|
||||
image = SubResource("Image_t2ykh")
|
||||
|
||||
[node name="Portraits" type="HBoxContainer"]
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
script = ExtResource("2")
|
||||
|
||||
[node name="General" type="VBoxContainer" parent="."]
|
||||
layout_mode = 2
|
||||
offset_right = 650.0
|
||||
offset_bottom = 648.0
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="Title" type="Label" parent="General"]
|
||||
layout_mode = 2
|
||||
offset_right = 650.0
|
||||
offset_bottom = 36.0
|
||||
theme_override_styles/normal = ExtResource("2_i6l15")
|
||||
text = "Portrait Settings"
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="General"]
|
||||
layout_mode = 2
|
||||
offset_top = 40.0
|
||||
offset_right = 650.0
|
||||
offset_bottom = 71.0
|
||||
|
||||
[node name="Label" type="Label" parent="General/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
offset_top = 2.0
|
||||
offset_right = 460.0
|
||||
offset_bottom = 28.0
|
||||
size_flags_horizontal = 3
|
||||
text = "Portraits mode"
|
||||
|
||||
[node name="PortraitMode" type="OptionButton" parent="General/HBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
offset_left = 464.0
|
||||
offset_right = 650.0
|
||||
offset_bottom = 31.0
|
||||
item_count = 2
|
||||
selected = 0
|
||||
popup/item_0/text = "Visual Novel Mode"
|
||||
popup/item_0/id = 0
|
||||
popup/item_1/text = "RPG Mode"
|
||||
popup/item_1/id = 1
|
||||
|
||||
[node name="Info" type="Label" parent="General"]
|
||||
layout_mode = 2
|
||||
offset_top = 75.0
|
||||
offset_right = 650.0
|
||||
offset_bottom = 205.0
|
||||
text = "Visual Novel: Multiple characters can show up in different positions at the same time. They have to be joined and leaved manually.
|
||||
|
||||
RPG: Only the character that speaks is visible (always in the same location). Does not have to be joined/left manually. Uses only position_idx 1."
|
||||
autowrap_mode = 3
|
||||
script = ExtResource("3_jknrx")
|
||||
|
||||
[node name="VSeparator" type="VSeparator" parent="."]
|
||||
layout_mode = 2
|
||||
offset_left = 654.0
|
||||
offset_right = 658.0
|
||||
offset_bottom = 648.0
|
||||
|
||||
[node name="Animations" type="VBoxContainer" parent="."]
|
||||
layout_mode = 2
|
||||
offset_left = 662.0
|
||||
offset_right = 1152.0
|
||||
offset_bottom = 648.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_stretch_ratio = 0.5
|
||||
|
||||
[node name="Title" type="Label" parent="Animations"]
|
||||
layout_mode = 2
|
||||
offset_right = 490.0
|
||||
offset_bottom = 36.0
|
||||
theme_override_styles/normal = ExtResource("2_i6l15")
|
||||
text = "Animations
|
||||
"
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="Animations"]
|
||||
layout_mode = 2
|
||||
offset_top = 40.0
|
||||
offset_right = 490.0
|
||||
offset_bottom = 71.0
|
||||
|
||||
[node name="Label2" type="Label" parent="Animations/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
offset_top = 2.0
|
||||
offset_right = 229.0
|
||||
offset_bottom = 28.0
|
||||
size_flags_horizontal = 3
|
||||
text = "Custom anims folder"
|
||||
|
||||
[node name="CustomAnimationsFolder" type="LineEdit" parent="Animations/HBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
offset_left = 233.0
|
||||
offset_right = 462.0
|
||||
offset_bottom = 31.0
|
||||
size_flags_horizontal = 3
|
||||
caret_blink = true
|
||||
|
||||
[node name="CustomAnimationsFolderOpener" type="Button" parent="Animations/HBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
offset_left = 466.0
|
||||
offset_right = 490.0
|
||||
offset_bottom = 31.0
|
||||
icon = SubResource("2")
|
||||
|
||||
[node name="HSeparator" type="HSeparator" parent="Animations"]
|
||||
layout_mode = 2
|
||||
offset_top = 75.0
|
||||
offset_right = 490.0
|
||||
offset_bottom = 79.0
|
||||
|
||||
[node name="Title2" type="Label" parent="Animations"]
|
||||
layout_mode = 2
|
||||
offset_top = 83.0
|
||||
offset_right = 490.0
|
||||
offset_bottom = 119.0
|
||||
theme_override_styles/normal = ExtResource("2_i6l15")
|
||||
text = "Default Animations
|
||||
"
|
||||
|
||||
[node name="DefaultIn" type="HBoxContainer" parent="Animations"]
|
||||
layout_mode = 2
|
||||
offset_top = 123.0
|
||||
offset_right = 490.0
|
||||
offset_bottom = 156.0
|
||||
|
||||
[node name="Label3" type="Label" parent="Animations/DefaultIn"]
|
||||
layout_mode = 2
|
||||
offset_top = 3.0
|
||||
offset_right = 107.0
|
||||
offset_bottom = 29.0
|
||||
size_flags_horizontal = 3
|
||||
text = "Default Join"
|
||||
|
||||
[node name="JoinDefault" parent="Animations/DefaultIn" instance=ExtResource("3")]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
anchors_preset = 0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
offset_left = 111.0
|
||||
offset_right = 311.0
|
||||
offset_bottom = 33.0
|
||||
|
||||
[node name="JoinDefaultLength" type="SpinBox" parent="Animations/DefaultIn"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
offset_left = 315.0
|
||||
offset_right = 398.0
|
||||
offset_bottom = 33.0
|
||||
step = 0.1
|
||||
|
||||
[node name="JoinDefaultWait" type="CheckButton" parent="Animations/DefaultIn"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
offset_left = 402.0
|
||||
offset_right = 490.0
|
||||
offset_bottom = 33.0
|
||||
text = "Wait:"
|
||||
|
||||
[node name="DefaultOut" type="HBoxContainer" parent="Animations"]
|
||||
layout_mode = 2
|
||||
offset_top = 160.0
|
||||
offset_right = 490.0
|
||||
offset_bottom = 193.0
|
||||
|
||||
[node name="Label4" type="Label" parent="Animations/DefaultOut"]
|
||||
layout_mode = 2
|
||||
offset_top = 3.0
|
||||
offset_right = 107.0
|
||||
offset_bottom = 29.0
|
||||
size_flags_horizontal = 3
|
||||
text = "Default Leave"
|
||||
|
||||
[node name="LeaveDefault" parent="Animations/DefaultOut" instance=ExtResource("3")]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
anchors_preset = 0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
offset_left = 111.0
|
||||
offset_right = 311.0
|
||||
offset_bottom = 33.0
|
||||
|
||||
[node name="LeaveDefaultLength" type="SpinBox" parent="Animations/DefaultOut"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
offset_left = 315.0
|
||||
offset_right = 398.0
|
||||
offset_bottom = 33.0
|
||||
step = 0.1
|
||||
|
||||
[node name="LeaveDefaultWait" type="CheckButton" parent="Animations/DefaultOut"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
offset_left = 402.0
|
||||
offset_right = 490.0
|
||||
offset_bottom = 33.0
|
||||
text = "Wait:"
|
||||
|
||||
[connection signal="item_selected" from="General/HBoxContainer/PortraitMode" to="." method="_on_PortraitMode_item_selected"]
|
||||
[connection signal="pressed" from="Animations/HBoxContainer/CustomAnimationsFolderOpener" to="." method="_on_CustomAnimationsFolderOpener_pressed"]
|
||||
[connection signal="value_changed" from="Animations/DefaultIn/JoinDefault" to="." method="_on_JoinDefault_value_changed"]
|
||||
[connection signal="value_changed" from="Animations/DefaultIn/JoinDefaultLength" to="." method="_on_JoinDefaultLength_value_changed"]
|
||||
[connection signal="toggled" from="Animations/DefaultIn/JoinDefaultWait" to="." method="_on_JoinDefaultWait_toggled"]
|
||||
[connection signal="value_changed" from="Animations/DefaultOut/LeaveDefault" to="." method="_on_LeaveDefault_value_changed"]
|
||||
[connection signal="value_changed" from="Animations/DefaultOut/LeaveDefaultLength" to="." method="_on_LeaveDefaultLength_value_changed"]
|
||||
[connection signal="toggled" from="Animations/DefaultOut/LeaveDefaultWait" to="." method="_on_LeaveDefaultWait_toggled"]
|
||||
306
Sprout/addons/dialogic/Events/Character/subsystem_portraits.gd
Normal file
306
Sprout/addons/dialogic/Events/Character/subsystem_portraits.gd
Normal file
|
|
@ -0,0 +1,306 @@
|
|||
extends DialogicSubsystem
|
||||
|
||||
## Subsystem that manages portraits and portrait positions.
|
||||
|
||||
## The default portrait scene.
|
||||
var default_portrait_scene = load(get_script().resource_path.get_base_dir().path_join('default_portrait.tscn'))
|
||||
## Temporarily stores the default positions.
|
||||
var _default_positions: Dictionary = {}
|
||||
## Stores the current positions.
|
||||
var current_positions: Dictionary = {}
|
||||
|
||||
## A reference to the current [DialogicNode_PortraitHolder].
|
||||
var _portrait_holder_reference: Node = null
|
||||
|
||||
####################################################################################################
|
||||
## STATE
|
||||
####################################################################################################
|
||||
|
||||
func clear_game_state():
|
||||
for character in dialogic.current_state_info.get('portraits', {}).keys():
|
||||
remove_portrait(load(character))
|
||||
dialogic.current_state_info['portraits'] = {}
|
||||
|
||||
|
||||
func load_game_state():
|
||||
for character_path in dialogic.current_state_info['portraits']:
|
||||
add_portrait(
|
||||
load(character_path),
|
||||
dialogic.current_state_info['portraits'][character_path].portrait, dialogic.current_state_info['portraits'][character_path].position_index,
|
||||
false)
|
||||
|
||||
|
||||
func pause() -> void:
|
||||
for portrait in dialogic.current_state_info['portraits'].values():
|
||||
if portrait.has('animation_node'):
|
||||
portrait.animation_node.pause()
|
||||
|
||||
|
||||
func resume() -> void:
|
||||
for portrait in dialogic.current_state_info['portraits'].values():
|
||||
if portrait.has('animation_node'):
|
||||
portrait.animation_node.resume()
|
||||
|
||||
|
||||
####################################################################################################
|
||||
## MAIN METHODS
|
||||
####################################################################################################
|
||||
|
||||
## Joins a character and then calls change_portrait().
|
||||
func add_portrait(character:DialogicCharacter, portrait:String, position_idx:int, mirrored: bool = false, z_index: int = 0, extra_data:String = "") -> Node:
|
||||
var character_node = null
|
||||
|
||||
if portrait.is_empty():
|
||||
portrait = character.default_portrait
|
||||
|
||||
if not character:
|
||||
print_debug('[DialogicError] Cannot call add_portrait() with null character.')
|
||||
return null
|
||||
if not portrait in character.portraits:
|
||||
print_debug("[DialogicError] Tried joining ",character.display_name, " wit not-existing portrait '", portrait, "'. Will use default portrait instead.")
|
||||
portrait = character.default_portrait
|
||||
if portrait.is_empty():
|
||||
print_debug("[DialogicError] Character ",character.display_name, " has no default portrait to use.")
|
||||
return null
|
||||
|
||||
check_positions_and_holder()
|
||||
|
||||
character_node = Node2D.new()
|
||||
character_node.name = character.get_character_name()
|
||||
character_node.position = current_positions[position_idx]
|
||||
character_node.z_index = z_index
|
||||
character_node.set_meta("position", position_idx)
|
||||
_portrait_holder_reference.add_child(character_node)
|
||||
|
||||
if character_node:
|
||||
dialogic.current_state_info['portraits'][character.resource_path] = {'portrait':portrait, 'node':character_node, 'position_index':position_idx}
|
||||
if portrait:
|
||||
change_portrait(character, portrait, mirrored, z_index, false, extra_data)
|
||||
|
||||
return character_node
|
||||
|
||||
## Changes the portrait of a character. Only works with characters that joined previously.
|
||||
func change_portrait(character:DialogicCharacter, portrait:String, mirrored:bool = false, z_index: int = 0, update_zindex:bool = false, extra_data:String = "") -> void:
|
||||
if not character or not is_character_joined(character):
|
||||
print_debug('[DialogicError] Cannot change portrait of null/not joined character.')
|
||||
return null
|
||||
|
||||
if portrait.is_empty():
|
||||
portrait = character.default_portrait
|
||||
|
||||
if not portrait in character.portraits.keys():
|
||||
print_debug('[Dialogic] Change to not-existing portrait will be ignored!')
|
||||
return
|
||||
|
||||
var char_node :Node = dialogic.current_state_info.portraits[character.resource_path].node
|
||||
|
||||
if update_zindex:
|
||||
char_node.z_index = z_index
|
||||
|
||||
# path to the scene to use
|
||||
var scene_path :String = character.portraits[portrait].get('scene', '')
|
||||
|
||||
var portrait_node = null
|
||||
|
||||
# check if the scene is the same as the currently loaded scene
|
||||
if (char_node.get_child_count() and
|
||||
character.portraits[dialogic.current_state_info['portraits'][character.resource_path]['portrait']].get('scene', '') == scene_path and
|
||||
# also check if the scene supports changing to the given portrait
|
||||
(!char_node.get_child(0).has_method('_should_do_portrait_update') or char_node.get_child(0)._should_do_portrait_update(character, portrait))):
|
||||
portrait_node = char_node.get_child(0)
|
||||
else:
|
||||
# remove previous portrait
|
||||
if char_node.get_child_count():
|
||||
char_node.get_child(0).queue_free()
|
||||
|
||||
if scene_path.is_empty():
|
||||
portrait_node = default_portrait_scene.instantiate()
|
||||
else:
|
||||
var p = load(scene_path)
|
||||
if p:
|
||||
portrait_node = p.instantiate()
|
||||
else:
|
||||
push_error('Dialogic: Portrait node "' + str(scene_path) + '" for character [' + character.display_name + '] could not be loaded. Your portrait might not show up on the screen.')
|
||||
|
||||
if portrait_node:
|
||||
portrait_node.position = character.offset + character.portraits[portrait].get('offset', Vector2())
|
||||
|
||||
# ignore the character scale on custom portraits that have 'ignore_char_scale' set to true
|
||||
if scene_path.is_empty() or !character.portraits[portrait].get('ignore_char_scale', false):
|
||||
portrait_node.scale = Vector2(1,1)*character.scale * character.portraits[portrait].get('scale', 1)
|
||||
else:
|
||||
portrait_node.scale = Vector2(1,1)*character.portraits[portrait].get('scale', 1)
|
||||
|
||||
for property in character.portraits[portrait].get('export_overrides', {}).keys():
|
||||
portrait_node.set(property, str_to_var(character.portraits[portrait]['export_overrides'][property]))
|
||||
|
||||
if portrait_node.has_method('_update_portrait'):
|
||||
portrait_node._update_portrait(character, portrait)
|
||||
if portrait_node.has_method('_set_mirror'):
|
||||
portrait_node._set_mirror(mirrored)
|
||||
if portrait_node.has_method('_set_extra_data'):
|
||||
portrait_node._set_extra_data(extra_data)
|
||||
|
||||
if !portrait_node.is_inside_tree():
|
||||
char_node.add_child(portrait_node)
|
||||
dialogic.current_state_info['portraits'][character.resource_path]['portrait'] = portrait
|
||||
|
||||
## Animates the portrait of the given character with the given animation.
|
||||
func animate_portrait(character:DialogicCharacter, animation_path:String, length:float, repeats = 1) -> DialogicAnimation:
|
||||
if not character or not is_character_joined(character):
|
||||
print_debug('[DialogicError] Cannot animate portrait of null/not joined character.')
|
||||
return null
|
||||
|
||||
var char_node = dialogic.current_state_info['portraits'][character.resource_path].node
|
||||
|
||||
if dialogic.current_state_info['portraits'][character.resource_path].get('animation_node', null):
|
||||
if is_instance_valid(dialogic.current_state_info['portraits'][character.resource_path].animation_node):
|
||||
dialogic.current_state_info['portraits'][character.resource_path].animation_node.queue_free()
|
||||
var anim_script = load(animation_path)
|
||||
var anim_node = Node.new()
|
||||
anim_node.set_script(anim_script)
|
||||
anim_node = (anim_node as DialogicAnimation)
|
||||
anim_node.node = char_node
|
||||
anim_node.orig_pos = char_node.position
|
||||
anim_node.end_position = char_node.position
|
||||
anim_node.time = length
|
||||
anim_node.repeats = repeats
|
||||
add_child(anim_node)
|
||||
anim_node.animate()
|
||||
dialogic.current_state_info['portraits'][character.resource_path]['animation_node'] = anim_node
|
||||
return anim_node
|
||||
|
||||
|
||||
## Moves the portrait of the given character to the given positions. Also allows updating the z_index.
|
||||
## TODO: Question, why the z_index is set here and in change_portrait and doesn't have it's own method.
|
||||
func move_portrait(character:DialogicCharacter, position_idx:int, z_index:int = 0, update_zindex:bool = false, time:float = 0.0):
|
||||
if not character or not is_character_joined(character):
|
||||
print_debug('[DialogicError] Cannot move portrait of null/not joined character.')
|
||||
return null
|
||||
|
||||
var char_node = dialogic.current_state_info.portraits[character.resource_path].node
|
||||
|
||||
if update_zindex:
|
||||
char_node.z_index = z_index
|
||||
|
||||
char_node.set_meta('position', position_idx)
|
||||
|
||||
if time == 0.0:
|
||||
char_node.position = current_positions[position_idx]
|
||||
else:
|
||||
var tween = char_node.create_tween()
|
||||
tween.tween_property(char_node, "position", current_positions[position_idx], time)
|
||||
|
||||
dialogic.current_state_info.portraits[character.resource_path].position_index = position_idx
|
||||
|
||||
|
||||
func remove_portrait(character:DialogicCharacter) -> void:
|
||||
dialogic.current_state_info['portraits'][character.resource_path].node.queue_free()
|
||||
dialogic.current_state_info['portraits'].erase(character.resource_path)
|
||||
|
||||
|
||||
## Creates additional positions either from timeline or at runtime
|
||||
## If it's an existing position, will move that position to the coordinates instead
|
||||
## There's no need to actually remove them once added, but saves will need to track position updates as well, so the whole current_positions array will need to be saved
|
||||
## This will always be an absolute value for new positions, existing positions will be updated as absolute values by this
|
||||
func add_portrait_position(position_number: int, position:Vector2) -> void:
|
||||
|
||||
check_positions_and_holder()
|
||||
|
||||
if position_number in current_positions:
|
||||
move_portrait_position(position_number, position)
|
||||
else:
|
||||
# Add to both current and default positions
|
||||
_default_positions[position_number] = position
|
||||
current_positions[position_number] = position
|
||||
|
||||
func reset_portrait_positions(time:float = 0.0) -> void:
|
||||
for position in current_positions:
|
||||
move_portrait_position(position, _default_positions[position], false, time)
|
||||
|
||||
func reset_portrait_position(position:int, time:float = 0.0) -> void:
|
||||
move_portrait_position(position, _default_positions[position], false, time)
|
||||
|
||||
|
||||
func move_portrait_position(position_number: int, vector:Vector2, relative:bool = false, time:float = 0.0) -> void:
|
||||
check_positions_and_holder()
|
||||
|
||||
if !position_number in current_positions:
|
||||
if !relative:
|
||||
add_portrait_position(position_number, vector)
|
||||
else:
|
||||
print_debug('[DialogicError] Cannot move non-existent position. (Use SetAbsolute to create a new position)')
|
||||
return null
|
||||
|
||||
if !relative:
|
||||
current_positions[position_number] = vector
|
||||
else:
|
||||
current_positions[position_number] += vector
|
||||
|
||||
for child in _portrait_holder_reference.get_children():
|
||||
if child.get_meta('position') == position_number:
|
||||
if time != 0.0:
|
||||
var tween = child.create_tween()
|
||||
tween.tween_property(child, "position", current_positions[position_number], time)
|
||||
else:
|
||||
child.position = current_positions[position_number]
|
||||
|
||||
|
||||
####################################################################################################
|
||||
## HELPERS
|
||||
####################################################################################################
|
||||
|
||||
func is_character_joined(character:DialogicCharacter) -> bool:
|
||||
return character.resource_path in dialogic.current_state_info['portraits']
|
||||
|
||||
func get_joined_characters() -> Array:
|
||||
var chars = []
|
||||
for char_path in dialogic.current_state_info.get('portraits', {}).keys():
|
||||
chars.append(load(char_path))
|
||||
return chars
|
||||
|
||||
func update_rpg_portrait_mode(character:DialogicCharacter = null, portrait:String = "") -> void:
|
||||
if DialogicUtil.get_project_setting('dialogic/portrait_mode', 0) == DialogicCharacterEvent.PortraitModes.RPG:
|
||||
if !Dialogic.current_state_info.has('rpg_last_portrait'):
|
||||
Dialogic.current_state_info['rpg_last_portraits'] = {}
|
||||
|
||||
if character != null:
|
||||
if portrait == "":
|
||||
if Dialogic.current_state_info['rpg_last_portraits'].has(character.resource_path):
|
||||
portrait = Dialogic.current_state_info['rpg_last_portraits'][character.resource_path]
|
||||
else:
|
||||
portrait = character.default_portrait
|
||||
Dialogic.current_state_info['rpg_last_portraits'][character.resource_path] = portrait
|
||||
var char_joined = false
|
||||
for joined_character in dialogic.current_state_info.portraits:
|
||||
if not character or (joined_character != character.resource_path):
|
||||
var AnimationName = DialogicUtil.get_project_setting('dialogic/animations/leave_default',
|
||||
get_script().resource_path.get_base_dir().path_join('DefaultAnimations/fade_out_down.gd'))
|
||||
var AnimationLength = DialogicUtil.get_project_setting('dialogic/animations/leave_default_length', 0.5)
|
||||
|
||||
var anim = animate_portrait(load(joined_character), AnimationName, AnimationLength)
|
||||
|
||||
anim.finished.connect(remove_portrait.bind(load(joined_character)))
|
||||
else:
|
||||
char_joined = true
|
||||
|
||||
if (not char_joined) and character and portrait in character.portraits:
|
||||
var AnimationName = DialogicUtil.get_project_setting('dialogic/animations/join_default',
|
||||
get_script().resource_path.get_base_dir().path_join('DefaultAnimations/fade_in_up.gd'))
|
||||
var AnimationLength = DialogicUtil.get_project_setting('dialogic/animations/join_default_length', 0.5)
|
||||
add_portrait(character, portrait, 1, false)
|
||||
var anim = animate_portrait(character, AnimationName, AnimationLength)
|
||||
|
||||
# makes sure positions are listed and can be accessed
|
||||
func check_positions_and_holder() -> void:
|
||||
if _portrait_holder_reference == null and len(get_tree().get_nodes_in_group('dialogic_portrait_holder')) == 0:
|
||||
assert(false, '[Dialogic] If you want to display portraits, you need a PortraitHolder scene!')
|
||||
else:
|
||||
if _portrait_holder_reference == null:
|
||||
_portrait_holder_reference = get_tree().get_first_node_in_group('dialogic_portrait_holder')
|
||||
if _default_positions.size() == 0:
|
||||
for node in get_tree().get_nodes_in_group('dialogic_portrait_position'):
|
||||
_default_positions[node['position_index']] = node['position']
|
||||
|
||||
if current_positions.size() == 0:
|
||||
current_positions = _default_positions.duplicate()
|
||||
Loading…
Add table
Add a link
Reference in a new issue