First work on dialogic, resized guild, and started implementing portraits.
@@ -0,0 +1,16 @@
|
||||
extends DialogicAnimation
|
||||
|
||||
func animate() -> void:
|
||||
var tween := (node.create_tween() as Tween)
|
||||
tween.set_ease(Tween.EASE_OUT)
|
||||
tween.tween_property(node, 'position:y', base_position.y-node.get_viewport().size.y/10, time*0.4).set_trans(Tween.TRANS_EXPO)
|
||||
tween.parallel().tween_property(node, 'scale:y', base_scale.y*1.05, time*0.4).set_trans(Tween.TRANS_EXPO)
|
||||
tween.tween_property(node, 'position:y', base_position.y, time*0.6).set_trans(Tween.TRANS_BOUNCE)
|
||||
tween.parallel().tween_property(node, 'scale:y', base_scale.y, time*0.6).set_trans(Tween.TRANS_BOUNCE)
|
||||
tween.finished.connect(emit_signal.bind('finished_once'))
|
||||
|
||||
|
||||
func _get_named_variations() -> Dictionary:
|
||||
return {
|
||||
"bounce": {"type": AnimationType.ACTION},
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://cxjbflqo8ydvj
|
||||
@@ -0,0 +1,39 @@
|
||||
extends DialogicAnimation
|
||||
|
||||
|
||||
func animate() -> void:
|
||||
var tween := (node.create_tween() as Tween)
|
||||
|
||||
var end_scale: Vector2 = node.scale
|
||||
var end_modulate_alpha := 1.0
|
||||
var modulation_property := get_modulation_property()
|
||||
|
||||
if is_reversed:
|
||||
end_scale = Vector2(0, 0)
|
||||
end_modulate_alpha = 0.0
|
||||
|
||||
else:
|
||||
node.scale = Vector2(0, 0)
|
||||
var original_modulation: Color = node.get(modulation_property)
|
||||
original_modulation.a = 0.0
|
||||
node.set(modulation_property, original_modulation)
|
||||
|
||||
|
||||
tween.set_ease(Tween.EASE_IN_OUT)
|
||||
tween.set_trans(Tween.TRANS_SINE)
|
||||
tween.set_parallel()
|
||||
|
||||
(tween.tween_property(node, "scale", end_scale, time)
|
||||
.set_trans(Tween.TRANS_SPRING)
|
||||
.set_ease(Tween.EASE_OUT))
|
||||
tween.tween_property(node, modulation_property + ":a", end_modulate_alpha, time)
|
||||
|
||||
await tween.finished
|
||||
finished_once.emit()
|
||||
|
||||
|
||||
func _get_named_variations() -> Dictionary:
|
||||
return {
|
||||
"bounce in": {"reversed": false, "type": AnimationType.IN},
|
||||
"bounce out": {"reversed": true, "type": AnimationType.OUT},
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://ycvv3pukkwcq
|
||||
@@ -0,0 +1,44 @@
|
||||
extends DialogicAnimation
|
||||
|
||||
func animate() -> void:
|
||||
var tween := (node.create_tween() as Tween)
|
||||
|
||||
var start_height: float = base_position.y - node.get_viewport().size.y / 5
|
||||
var end_height := base_position.y
|
||||
|
||||
var start_modulation := 0.0
|
||||
var end_modulation := 1.0
|
||||
|
||||
if is_reversed:
|
||||
end_height = start_height
|
||||
start_height = base_position.y
|
||||
end_modulation = 0.0
|
||||
start_modulation = 1.0
|
||||
|
||||
node.position.y = start_height
|
||||
|
||||
tween.set_ease(Tween.EASE_OUT)
|
||||
tween.set_trans(Tween.TRANS_SINE)
|
||||
tween.set_parallel()
|
||||
|
||||
var end_postion := Vector2(base_position.x, end_height)
|
||||
tween.tween_property(node, "position", end_postion, time)
|
||||
|
||||
var property := get_modulation_property()
|
||||
|
||||
var original_modulation: Color = node.get(property)
|
||||
original_modulation.a = start_modulation
|
||||
node.set(property, original_modulation)
|
||||
var modulation_alpha := property + ":a"
|
||||
|
||||
tween.tween_property(node, modulation_alpha, end_modulation, time)
|
||||
|
||||
await tween.finished
|
||||
finished_once.emit()
|
||||
|
||||
|
||||
func _get_named_variations() -> Dictionary:
|
||||
return {
|
||||
"fade in down": {"reversed": false, "type": AnimationType.IN},
|
||||
"fade out up": {"reversed": true, "type": AnimationType.OUT},
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://dk47pnk3okpls
|
||||
@@ -0,0 +1,34 @@
|
||||
extends DialogicAnimation
|
||||
|
||||
func animate() -> void:
|
||||
|
||||
var modulation_property := get_modulation_property()
|
||||
var end_modulation_alpha := 1.0
|
||||
|
||||
if is_reversed:
|
||||
end_modulation_alpha = 0.0
|
||||
|
||||
else:
|
||||
var original_modulation: Color = node.get(modulation_property)
|
||||
original_modulation.a = 0.0
|
||||
node.set(modulation_property, original_modulation)
|
||||
|
||||
var tween := (node.create_tween() as Tween)
|
||||
if is_reversed:
|
||||
tween.set_ease(Tween.EASE_IN)
|
||||
else:
|
||||
tween.set_ease(Tween.EASE_OUT)
|
||||
tween.set_trans(Tween.TRANS_SINE)
|
||||
tween.tween_property(node, modulation_property + ":a", end_modulation_alpha, time)
|
||||
|
||||
await tween.finished
|
||||
finished_once.emit()
|
||||
|
||||
|
||||
func _get_named_variations() -> Dictionary:
|
||||
return {
|
||||
"fade in": {"reversed": false, "type": AnimationType.IN},
|
||||
"fade out": {"reversed": true, "type": AnimationType.OUT},
|
||||
"fade cross": {"type": AnimationType.CROSSFADE},
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://cw4f0q7bbh3be
|
||||
@@ -0,0 +1,44 @@
|
||||
extends DialogicAnimation
|
||||
|
||||
func animate() -> void:
|
||||
var tween := (node.create_tween() as Tween)
|
||||
|
||||
var start_height: float = base_position.y + node.get_viewport().size.y / 5
|
||||
var end_height := base_position.y
|
||||
|
||||
var start_modulation := 0.0
|
||||
var end_modulation := 1.0
|
||||
|
||||
if is_reversed:
|
||||
end_height = start_height
|
||||
start_height = base_position.y
|
||||
end_modulation = 0.0
|
||||
start_modulation = 1.0
|
||||
|
||||
node.position.y = start_height
|
||||
|
||||
tween.set_ease(Tween.EASE_OUT)
|
||||
tween.set_trans(Tween.TRANS_SINE)
|
||||
tween.set_parallel()
|
||||
|
||||
var end_postion := Vector2(base_position.x, end_height)
|
||||
tween.tween_property(node, "position", end_postion, time)
|
||||
|
||||
var property := get_modulation_property()
|
||||
|
||||
var original_modulation: Color = node.get(property)
|
||||
original_modulation.a = start_modulation
|
||||
node.set(property, original_modulation)
|
||||
var modulation_alpha := property + ":a"
|
||||
|
||||
tween.tween_property(node, modulation_alpha, end_modulation, time)
|
||||
|
||||
await tween.finished
|
||||
finished_once.emit()
|
||||
|
||||
|
||||
func _get_named_variations() -> Dictionary:
|
||||
return {
|
||||
"fade in up": {"reversed": false, "type": AnimationType.IN},
|
||||
"fade out down": {"reversed": true, "type": AnimationType.OUT},
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://dxc52wjbrwfww
|
||||
@@ -0,0 +1,13 @@
|
||||
extends DialogicAnimation
|
||||
|
||||
func animate() -> void:
|
||||
var tween := (node.create_tween() as Tween)
|
||||
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), time*0.5).set_trans(Tween.TRANS_BOUNCE).set_ease(Tween.EASE_OUT)
|
||||
tween.finished.connect(emit_signal.bind('finished_once'))
|
||||
|
||||
|
||||
func _get_named_variations() -> Dictionary:
|
||||
return {
|
||||
"heartbeat": {"type": AnimationType.ACTION},
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://w5n6c761qi70
|
||||
@@ -0,0 +1,12 @@
|
||||
extends DialogicAnimation
|
||||
|
||||
func animate() -> void:
|
||||
await node.get_tree().process_frame
|
||||
finished.emit()
|
||||
|
||||
|
||||
func _get_named_variations() -> Dictionary:
|
||||
return {
|
||||
"instant in": {"reversed": false, "type": AnimationType.IN},
|
||||
"instant out": {"reversed": true, "type": AnimationType.OUT},
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://dq6qd77wqtuak
|
||||
@@ -0,0 +1,20 @@
|
||||
extends DialogicAnimation
|
||||
|
||||
func animate() -> void:
|
||||
var tween := (node.create_tween() as Tween)
|
||||
tween.set_ease(Tween.EASE_IN_OUT).set_trans(Tween.TRANS_SINE)
|
||||
var strength: float = node.get_viewport().size.x/60
|
||||
var bound_multitween := DialogicUtil.multitween.bind(node, "position", "animation_shake_x")
|
||||
tween.tween_method(bound_multitween, Vector2(), Vector2(1, 0)*strength, time*0.2)
|
||||
tween.tween_method(bound_multitween, Vector2(), Vector2(-1,0)*strength, time*0.1)
|
||||
tween.tween_method(bound_multitween, Vector2(), Vector2(1, 0)*strength, time*0.1)
|
||||
tween.tween_method(bound_multitween, Vector2(), Vector2(-1,0)*strength, time*0.1)
|
||||
tween.tween_method(bound_multitween, Vector2(), Vector2(1, 0)*strength, time*0.1)
|
||||
tween.tween_method(bound_multitween, Vector2(), Vector2(-1,0)*strength, time*0.1)
|
||||
tween.tween_method(bound_multitween, Vector2(), Vector2(1, 0)*strength, time*0.2)
|
||||
tween.finished.connect(emit_signal.bind('finished_once'))
|
||||
|
||||
func _get_named_variations() -> Dictionary:
|
||||
return {
|
||||
"shake x": {"type": AnimationType.ACTION},
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://d2m8ruax5nid5
|
||||
@@ -0,0 +1,23 @@
|
||||
extends DialogicAnimation
|
||||
|
||||
func animate() -> void:
|
||||
var tween := (node.create_tween() as Tween)
|
||||
tween.set_ease(Tween.EASE_IN_OUT).set_trans(Tween.TRANS_SINE)
|
||||
|
||||
var strength: float = node.get_viewport().size.y/40
|
||||
tween.tween_property(node, 'position:y', base_position.y + strength, time * 0.2)
|
||||
tween.tween_property(node, 'position:y', base_position.y - strength, time * 0.1)
|
||||
tween.tween_property(node, 'position:y', base_position.y + strength, time * 0.1)
|
||||
tween.tween_property(node, 'position:y', base_position.y - strength, time * 0.1)
|
||||
tween.tween_property(node, 'position:y', base_position.y + strength, time * 0.1)
|
||||
tween.tween_property(node, 'position:y', base_position.y - strength, time * 0.1)
|
||||
tween.tween_property(node, 'position:y', base_position.y + strength, time * 0.1)
|
||||
tween.tween_property(node, 'position:y', base_position.y, time * 0.2)
|
||||
|
||||
tween.finished.connect(emit_signal.bind('finished_once'))
|
||||
|
||||
|
||||
func _get_named_variations() -> Dictionary:
|
||||
return {
|
||||
"shake y": {"type": AnimationType.ACTION},
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://bjc3ljt064o5c
|
||||
@@ -0,0 +1,26 @@
|
||||
extends DialogicAnimation
|
||||
|
||||
func animate() -> void:
|
||||
var tween := (node.create_tween() as Tween)
|
||||
tween.set_ease(Tween.EASE_OUT).set_trans(Tween.TRANS_BACK)
|
||||
|
||||
var target_position := base_position.y
|
||||
var start_position: float = -node.get_viewport().size.y
|
||||
|
||||
if is_reversed:
|
||||
target_position = -node.get_viewport().size.y
|
||||
start_position = base_position.y
|
||||
|
||||
node.position.y = start_position
|
||||
|
||||
tween.tween_property(node, 'position:y', target_position, time)
|
||||
|
||||
await tween.finished
|
||||
finished_once.emit()
|
||||
|
||||
|
||||
func _get_named_variations() -> Dictionary:
|
||||
return {
|
||||
"slide in down": {"reversed": false, "type": AnimationType.IN},
|
||||
"slide out up": {"reversed": true, "type": AnimationType.OUT},
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://dg0cged7g0gby
|
||||
@@ -0,0 +1,26 @@
|
||||
extends DialogicAnimation
|
||||
|
||||
|
||||
func animate() -> void:
|
||||
var tween := (node.create_tween() as Tween)
|
||||
tween.set_ease(Tween.EASE_OUT).set_trans(Tween.TRANS_BACK)
|
||||
|
||||
var end_position_x: float = base_position.x
|
||||
|
||||
if is_reversed:
|
||||
end_position_x = -node.get_viewport().size.x / 2
|
||||
|
||||
else:
|
||||
node.position.x = -node.get_viewport().size.x / 5
|
||||
|
||||
tween.tween_property(node, 'position:x', end_position_x, time)
|
||||
|
||||
await tween.finished
|
||||
finished_once.emit()
|
||||
|
||||
|
||||
func _get_named_variations() -> Dictionary:
|
||||
return {
|
||||
"slide in left": {"reversed": false, "type": AnimationType.IN},
|
||||
"slide out right": {"reversed": true, "type": AnimationType.OUT},
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://b0nuamcfgq6pr
|
||||
@@ -0,0 +1,27 @@
|
||||
extends DialogicAnimation
|
||||
|
||||
func animate() -> void:
|
||||
var tween := (node.create_tween() as Tween)
|
||||
tween.set_ease(Tween.EASE_OUT).set_trans(Tween.TRANS_BACK)
|
||||
|
||||
var viewport_x: float = node.get_viewport().size.x
|
||||
|
||||
var start_position_x: float = viewport_x + viewport_x / 5
|
||||
var end_position_x := base_position.x
|
||||
|
||||
if is_reversed:
|
||||
start_position_x = base_position.x
|
||||
end_position_x = viewport_x + node.get_viewport().size.x / 5
|
||||
|
||||
|
||||
node.position.x = start_position_x
|
||||
tween.tween_property(node, 'position:x', end_position_x, time)
|
||||
|
||||
tween.finished.connect(emit_signal.bind('finished_once'))
|
||||
|
||||
|
||||
func _get_named_variations() -> Dictionary:
|
||||
return {
|
||||
"slide in right": {"reversed": false, "type": AnimationType.IN},
|
||||
"slide out left": {"reversed": true, "type": AnimationType.OUT},
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://cp530lw7pc54s
|
||||
@@ -0,0 +1,25 @@
|
||||
extends DialogicAnimation
|
||||
|
||||
func animate() -> void:
|
||||
var tween := (node.create_tween() as Tween)
|
||||
tween.set_ease(Tween.EASE_OUT).set_trans(Tween.TRANS_BACK)
|
||||
|
||||
var start_position_y: float = node.get_viewport().size.y * 2
|
||||
var end_position_y := base_position.y
|
||||
|
||||
if is_reversed:
|
||||
start_position_y = base_position.y
|
||||
end_position_y = node.get_viewport().size.y * 2
|
||||
|
||||
node.position.y = start_position_y
|
||||
tween.tween_property(node, 'position:y', end_position_y, time)
|
||||
|
||||
await tween.finished
|
||||
finished_once.emit()
|
||||
|
||||
|
||||
func _get_named_variations() -> Dictionary:
|
||||
return {
|
||||
"slide in up": {"reversed": false, "type": AnimationType.IN},
|
||||
"slide out down": {"reversed": true, "type": AnimationType.OUT},
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://l77151y81bnk
|
||||
25
addons/dialogic/Modules/Character/DefaultAnimations/tada.gd
Normal file
@@ -0,0 +1,25 @@
|
||||
extends DialogicAnimation
|
||||
|
||||
func animate() -> void:
|
||||
var tween := (node.create_tween() as Tween)
|
||||
tween.set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_OUT)
|
||||
|
||||
var strength: float = 0.01
|
||||
|
||||
tween.set_parallel(true)
|
||||
tween.tween_property(node, 'scale', Vector2(1,1)*(1+strength), time*0.3)
|
||||
tween.tween_property(node, 'rotation', -strength, time*0.1).set_delay(time*0.2)
|
||||
tween.tween_property(node, 'rotation', strength, time*0.1).set_delay(time*0.3)
|
||||
tween.tween_property(node, 'rotation', -strength, time*0.1).set_delay(time*0.4)
|
||||
tween.tween_property(node, 'rotation', strength, time*0.1).set_delay(time*0.5)
|
||||
tween.tween_property(node, 'rotation', -strength, 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'))
|
||||
|
||||
|
||||
func _get_named_variations() -> Dictionary:
|
||||
return {
|
||||
"tada": {"type": AnimationType.ACTION},
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://crvqdyahfjgw2
|
||||
@@ -0,0 +1,36 @@
|
||||
extends DialogicAnimation
|
||||
|
||||
func animate() -> void:
|
||||
var modulate_property := get_modulation_property()
|
||||
var modulate_alpha_property := modulate_property + ":a"
|
||||
|
||||
var end_scale: Vector2 = node.scale
|
||||
var end_modulation_alpha := 1.0
|
||||
|
||||
if is_reversed:
|
||||
end_modulation_alpha = 0.0
|
||||
|
||||
else:
|
||||
node.scale = Vector2(0, 0)
|
||||
node.position.y = base_position.y - node.get_viewport().size.y * 0.5
|
||||
|
||||
var original_modulation: Color = node.get(modulate_property)
|
||||
original_modulation.a = 0.0
|
||||
node.set(modulate_property, original_modulation)
|
||||
|
||||
var tween := (node.create_tween() as Tween)
|
||||
tween.set_ease(Tween.EASE_IN_OUT).set_trans(Tween.TRANS_EXPO)
|
||||
tween.set_parallel(true)
|
||||
tween.tween_property(node, "scale", end_scale, time)
|
||||
tween.tween_property(node, "position", base_position, time)
|
||||
tween.tween_property(node, modulate_alpha_property, end_modulation_alpha, time)
|
||||
|
||||
await tween.finished
|
||||
finished_once.emit()
|
||||
|
||||
|
||||
func _get_named_variations() -> Dictionary:
|
||||
return {
|
||||
"zoom center in": {"reversed": false, "type": AnimationType.IN},
|
||||
"zoom center out": {"reversed": true, "type": AnimationType.OUT},
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://b6etvhp8jjomy
|
||||
@@ -0,0 +1,35 @@
|
||||
extends DialogicAnimation
|
||||
|
||||
func animate() -> void:
|
||||
var modulate_property := get_modulation_property()
|
||||
var modulate_alpha_property := modulate_property + ":a"
|
||||
|
||||
var end_scale: Vector2 = node.scale
|
||||
var end_modulation_alpha := 1.0
|
||||
|
||||
if is_reversed:
|
||||
end_scale = Vector2(0, 0)
|
||||
end_modulation_alpha = 0.0
|
||||
|
||||
else:
|
||||
node.scale = Vector2(0,0)
|
||||
|
||||
var original_modulation: Color = node.get(modulate_property)
|
||||
original_modulation.a = 0.0
|
||||
node.set(modulate_property, original_modulation)
|
||||
|
||||
var tween := (node.create_tween() as Tween)
|
||||
tween.set_ease(Tween.EASE_OUT).set_trans(Tween.TRANS_EXPO)
|
||||
tween.set_parallel(true)
|
||||
tween.tween_property(node, "scale", end_scale, time)
|
||||
tween.tween_property(node, modulate_alpha_property, end_modulation_alpha, time)
|
||||
|
||||
await tween.finished
|
||||
finished_once.emit()
|
||||
|
||||
|
||||
func _get_named_variations() -> Dictionary:
|
||||
return {
|
||||
"zoom in": {"reversed": false, "type": AnimationType.IN},
|
||||
"zoom out": {"reversed": true, "type": AnimationType.OUT},
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://jbpknfsqxd1o
|
||||
@@ -0,0 +1,47 @@
|
||||
@tool
|
||||
class_name DialogicPortraitAnimationUtil
|
||||
|
||||
enum AnimationType {ALL=-1, IN=1, OUT=2, ACTION=3, CROSSFADE=4}
|
||||
|
||||
|
||||
static func guess_animation(string:String, type := AnimationType.ALL) -> String:
|
||||
var default := {}
|
||||
var filter := {}
|
||||
var ignores := []
|
||||
match type:
|
||||
AnimationType.ALL:
|
||||
pass
|
||||
AnimationType.IN:
|
||||
filter = {"type":AnimationType.IN}
|
||||
ignores = ["in"]
|
||||
AnimationType.OUT:
|
||||
filter = {"type":AnimationType.OUT}
|
||||
ignores = ["out"]
|
||||
AnimationType.ACTION:
|
||||
filter = {"type":AnimationType.ACTION}
|
||||
AnimationType.CROSSFADE:
|
||||
filter = {"type":AnimationType.CROSSFADE}
|
||||
ignores = ["cross"]
|
||||
return DialogicResourceUtil.guess_special_resource(&"PortraitAnimation", string, default, filter, ignores).get("path", "")
|
||||
|
||||
|
||||
static func get_portrait_animations_filtered(type := AnimationType.ALL) -> Dictionary:
|
||||
var filter := {"type":type}
|
||||
if type == AnimationType.ALL:
|
||||
filter["type"] = [AnimationType.IN, AnimationType.OUT, AnimationType.ACTION]
|
||||
return DialogicResourceUtil.list_special_resources("PortraitAnimation", filter)
|
||||
|
||||
|
||||
static func get_suggestions(_search_text := "", current_value:= "", empty_text := "Default", action := AnimationType.ALL) -> Dictionary:
|
||||
var suggestions := {}
|
||||
|
||||
if empty_text and current_value:
|
||||
suggestions[empty_text] = {'value':"", 'editor_icon':["GuiRadioUnchecked", "EditorIcons"]}
|
||||
|
||||
for anim_name in get_portrait_animations_filtered(action):
|
||||
suggestions[DialogicUtil.pretty_name(anim_name)] = {
|
||||
'value' : DialogicUtil.pretty_name(anim_name),
|
||||
'editor_icon' : ["Animation", "EditorIcons"]
|
||||
}
|
||||
|
||||
return suggestions
|
||||
@@ -0,0 +1 @@
|
||||
uid://ctnhk0vfhcq5q
|
||||
@@ -0,0 +1,77 @@
|
||||
class_name DialogicAnimation
|
||||
extends Node
|
||||
|
||||
## Class that can be used to animate portraits. Can be extended to create animations.
|
||||
|
||||
enum AnimationType {IN=1, OUT=2, ACTION=3, CROSSFADE=4}
|
||||
|
||||
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 base position of the node.
|
||||
## Depending on the animation, this might be the start, end or both.
|
||||
var base_position: Vector2
|
||||
## Set at runtime, will be the base scale of the node.
|
||||
var base_scale: Vector2
|
||||
|
||||
## Used to repeate the animation for a number of times.
|
||||
var repeats: int
|
||||
|
||||
## If `true`, the animation will be reversed.
|
||||
## This must be implemented by each animation or it will have no effect.
|
||||
var is_reversed: bool = false
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
finished_once.connect(finished_one_loop)
|
||||
|
||||
|
||||
## To be overridden. Do the actual animating/tweening in here.
|
||||
## Use the properties [member node], [member time], [member base_position], etc.
|
||||
func animate() -> void:
|
||||
pass
|
||||
|
||||
|
||||
## This method controls whether to repeat the animation or not.
|
||||
## Animations must call this once they finished an animation.
|
||||
func finished_one_loop() -> void:
|
||||
repeats -= 1
|
||||
|
||||
if repeats > 0:
|
||||
animate()
|
||||
|
||||
else:
|
||||
finished.emit()
|
||||
|
||||
|
||||
func pause() -> void:
|
||||
if node:
|
||||
node.process_mode = Node.PROCESS_MODE_DISABLED
|
||||
|
||||
|
||||
func resume() -> void:
|
||||
if node:
|
||||
node.process_mode = Node.PROCESS_MODE_INHERIT
|
||||
|
||||
|
||||
func _get_named_variations() -> Dictionary:
|
||||
return {}
|
||||
|
||||
|
||||
## If the animation wants to change the modulation, this method
|
||||
## will return the property to change.
|
||||
##
|
||||
## The [class CanvasGroup] can use `self_modulate` instead of `modulate`
|
||||
## to uniformly change the modulation of all children without additively
|
||||
## overlaying the modulations.
|
||||
func get_modulation_property() -> String:
|
||||
if node is CanvasGroup:
|
||||
return "self_modulate"
|
||||
else:
|
||||
return "modulate"
|
||||
@@ -0,0 +1 @@
|
||||
uid://ccyk44gg2r0w2
|
||||
BIN
addons/dialogic/Modules/Character/custom_portrait_thumbnail.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
@@ -0,0 +1,40 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://c5tu88x32sjkf"
|
||||
path="res://.godot/imported/custom_portrait_thumbnail.png-0513583853d87342a634d56bc0bec965.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/dialogic/Modules/Character/custom_portrait_thumbnail.png"
|
||||
dest_files=["res://.godot/imported/custom_portrait_thumbnail.png-0513583853d87342a634d56bc0bec965.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
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/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
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
|
||||
15
addons/dialogic/Modules/Character/default_portrait.gd
Normal file
@@ -0,0 +1,15 @@
|
||||
@tool
|
||||
extends DialogicPortrait
|
||||
|
||||
## Default portrait scene.
|
||||
## The parent class has a character and portrait variable.
|
||||
|
||||
@export_group('Main')
|
||||
@export_file var image := ""
|
||||
|
||||
|
||||
## Load anything related to the given character and portrait
|
||||
func _update_portrait(passed_character:DialogicCharacter, passed_portrait:String) -> void:
|
||||
apply_character_and_portrait(passed_character, passed_portrait)
|
||||
|
||||
apply_texture($Portrait, image)
|
||||
@@ -0,0 +1 @@
|
||||
uid://br7r46x628pxp
|
||||
9
addons/dialogic/Modules/Character/default_portrait.tscn
Normal file
@@ -0,0 +1,9 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://b32paf0ll6um8"]
|
||||
|
||||
[ext_resource type="Script" path="res://addons/dialogic/Modules/Character/default_portrait.gd" id="1_wn77n"]
|
||||
|
||||
[node name="DefaultPortrait" type="Node2D"]
|
||||
script = ExtResource("1_wn77n")
|
||||
|
||||
[node name="Portrait" type="Sprite2D" parent="."]
|
||||
centered = false
|
||||
BIN
addons/dialogic/Modules/Character/default_portrait_thumbnail.png
Normal file
|
After Width: | Height: | Size: 5.5 KiB |
@@ -0,0 +1,40 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://b0eisk30btlx2"
|
||||
path="res://.godot/imported/default_portrait_thumbnail.png-f9f92adb946f409def18655d6ab5c5df.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/dialogic/Modules/Character/default_portrait_thumbnail.png"
|
||||
dest_files=["res://.godot/imported/default_portrait_thumbnail.png-f9f92adb946f409def18655d6ab5c5df.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
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/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
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
|
||||
121
addons/dialogic/Modules/Character/dialogic_portrait.gd
Normal file
@@ -0,0 +1,121 @@
|
||||
class_name DialogicPortrait
|
||||
extends Node
|
||||
|
||||
## Default portrait class. Should be extended by custom portraits.
|
||||
|
||||
## Stores the character that this scene displays.
|
||||
var character: DialogicCharacter
|
||||
## Stores the name of the current portrait.
|
||||
var portrait: String
|
||||
|
||||
#region MAIN OVERRIDES
|
||||
################################################################################
|
||||
|
||||
## This function can be overridden.
|
||||
## If this returns true, it won't instance a new scene, but call
|
||||
## [method _update_portrait] on this one.
|
||||
## This is only relevant if the next portrait uses the same scene.
|
||||
## This allows implementing transitions between portraits that use the same scene.
|
||||
func _should_do_portrait_update(_character: DialogicCharacter, _portrait: String) -> bool:
|
||||
return false
|
||||
|
||||
|
||||
## If the custom portrait accepts a change, then accept it here
|
||||
## You should position your portrait so that the root node is at the pivot point*.
|
||||
## For example for a simple sprite this code would work:
|
||||
## >>> $Sprite.position = $Sprite.get_rect().size * Vector2(-0.5, -1)
|
||||
##
|
||||
## * this depends on the portrait containers, but it will most likely be the bottom center (99% of cases)
|
||||
func _update_portrait(_passed_character: DialogicCharacter, _passed_portrait: String) -> void:
|
||||
pass
|
||||
|
||||
|
||||
## This should be implemented. It is used for sizing in the
|
||||
## character editor preview and in portrait containers.
|
||||
## Scale and offset will be applied by Dialogic.
|
||||
## For example, a simple sprite:
|
||||
## >>> return Rect2($Sprite.position, $Sprite.get_rect().size)
|
||||
##
|
||||
## This will only work as expected if the portrait is positioned so that the
|
||||
## root is at the pivot point.
|
||||
##
|
||||
## If you've used apply_texture this should work automatically.
|
||||
func _get_covered_rect() -> Rect2:
|
||||
if has_meta('texture_holder_node') and get_meta('texture_holder_node', null) != null and is_instance_valid(get_meta('texture_holder_node')):
|
||||
var node: Node = get_meta('texture_holder_node')
|
||||
if node is Sprite2D or node is TextureRect:
|
||||
return Rect2(node.position, node.get_rect().size)
|
||||
return Rect2()
|
||||
|
||||
|
||||
## If implemented, this is called when the mirror changes
|
||||
func _set_mirror(mirror:bool) -> void:
|
||||
if has_meta('texture_holder_node') and get_meta('texture_holder_node', null) != null and is_instance_valid(get_meta('texture_holder_node')):
|
||||
var node: Node = get_meta('texture_holder_node')
|
||||
if node is Sprite2D or node is TextureRect:
|
||||
node.flip_h = mirror
|
||||
|
||||
|
||||
## Function to accept and use the extra data, if the custom portrait wants to accept it
|
||||
func _set_extra_data(_data: String) -> void:
|
||||
pass
|
||||
|
||||
#endregion
|
||||
|
||||
#region HIGHLIGHT OVERRIDES
|
||||
################################################################################
|
||||
|
||||
## Called when this becomes the active speaker
|
||||
func _highlight() -> void:
|
||||
pass
|
||||
|
||||
|
||||
## Called when this stops being the active speaker
|
||||
func _unhighlight() -> void:
|
||||
pass
|
||||
#endregion
|
||||
|
||||
|
||||
#region HELPERS
|
||||
################################################################################
|
||||
|
||||
## Helper that quickly setups and checks the character and portrait.
|
||||
func apply_character_and_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
|
||||
character = passed_character
|
||||
|
||||
|
||||
func apply_texture(node:Node, texture_path:String) -> void:
|
||||
if not character or not character.portraits.has(portrait):
|
||||
return
|
||||
|
||||
if not "texture" in node:
|
||||
return
|
||||
|
||||
node.texture = null
|
||||
|
||||
if not ResourceLoader.exists(texture_path):
|
||||
# This is a leftover from alpha.
|
||||
# Removing this will break any portraits made before alpha-10
|
||||
if ResourceLoader.exists(character.portraits[portrait].get('image', '')):
|
||||
texture_path = character.portraits[portrait].get('image', '')
|
||||
else:
|
||||
return
|
||||
|
||||
node.texture = load(texture_path)
|
||||
|
||||
if node is Sprite2D or node is TextureRect:
|
||||
if node is Sprite2D:
|
||||
node.centered = false
|
||||
node.scale = Vector2.ONE
|
||||
if node is TextureRect:
|
||||
if !is_inside_tree():
|
||||
await ready
|
||||
node.position = node.get_rect().size * Vector2(-0.5, -1)
|
||||
|
||||
set_meta('texture_holder_node', node)
|
||||
|
||||
#endregion
|
||||
@@ -0,0 +1 @@
|
||||
uid://ddpj5fsa86ksb
|
||||
578
addons/dialogic/Modules/Character/event_character.gd
Normal file
@@ -0,0 +1,578 @@
|
||||
@tool
|
||||
class_name DialogicCharacterEvent
|
||||
extends DialogicEvent
|
||||
## Event that allows to manipulate character portraits.
|
||||
|
||||
enum Actions {JOIN, LEAVE, UPDATE}
|
||||
|
||||
### Settings
|
||||
|
||||
## The type of action of this event (JOIN/LEAVE/UPDATE). See [Actions].
|
||||
var action := Actions.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 := ""
|
||||
## The index of the position this character should move to
|
||||
var transform := "center"
|
||||
|
||||
## Name of the 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 := ""
|
||||
## 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 := false
|
||||
|
||||
## The fade animation to use. If left empty, the default cross-fade animation AND time will be used.
|
||||
var fade_animation := ""
|
||||
var fade_length := 0.5
|
||||
|
||||
## For Update only. If bigger then 0, the portrait will tween to the
|
||||
## new position (if changed) in this time (in seconds).
|
||||
var transform_time: float = 0.0
|
||||
var transform_ease := Tween.EaseType.EASE_IN_OUT
|
||||
var transform_trans := Tween.TransitionType.TRANS_SINE
|
||||
|
||||
var ease_options := [
|
||||
{'label': 'In', 'value': Tween.EASE_IN},
|
||||
{'label': 'Out', 'value': Tween.EASE_OUT},
|
||||
{'label': 'In_Out', 'value': Tween.EASE_IN_OUT},
|
||||
{'label': 'Out_In', 'value': Tween.EASE_OUT_IN},
|
||||
]
|
||||
|
||||
var trans_options := [
|
||||
{'label': 'Linear', 'value': Tween.TRANS_LINEAR},
|
||||
{'label': 'Sine', 'value': Tween.TRANS_SINE},
|
||||
{'label': 'Quint', 'value': Tween.TRANS_QUINT},
|
||||
{'label': 'Quart', 'value': Tween.TRANS_QUART},
|
||||
{'label': 'Quad', 'value': Tween.TRANS_QUAD},
|
||||
{'label': 'Expo', 'value': Tween.TRANS_EXPO},
|
||||
{'label': 'Elastic', 'value': Tween.TRANS_ELASTIC},
|
||||
{'label': 'Cubic', 'value': Tween.TRANS_CUBIC},
|
||||
{'label': 'Circ', 'value': Tween.TRANS_CIRC},
|
||||
{'label': 'Bounce', 'value': Tween.TRANS_BOUNCE},
|
||||
{'label': 'Back', 'value': Tween.TRANS_BACK},
|
||||
{'label': 'Spring', 'value': Tween.TRANS_SPRING}
|
||||
]
|
||||
|
||||
## The z_index that the portrait should have.
|
||||
var z_index: int = 0
|
||||
## If true, the portrait will be set to mirrored.
|
||||
var mirrored := false
|
||||
## If set, will be passed to the portrait scene.
|
||||
var extra_data := ""
|
||||
|
||||
|
||||
### Helpers
|
||||
|
||||
## Indicators for whether something should be updated (UPDATE mode only)
|
||||
var set_portrait := false
|
||||
var set_transform := false
|
||||
var set_z_index := false
|
||||
var set_mirrored := false
|
||||
## Used to set the character resource from the unique name identifier and vice versa
|
||||
var character_identifier: String:
|
||||
get:
|
||||
if character_identifier == '--All--':
|
||||
return '--All--'
|
||||
if character:
|
||||
var identifier := DialogicResourceUtil.get_unique_identifier(character.resource_path)
|
||||
if not identifier.is_empty():
|
||||
return identifier
|
||||
return character_identifier
|
||||
set(value):
|
||||
character_identifier = value
|
||||
character = DialogicResourceUtil.get_character_resource(value)
|
||||
if character and not character.portraits.has(portrait):
|
||||
portrait = ""
|
||||
ui_update_needed.emit()
|
||||
|
||||
var regex := RegEx.create_from_string(r'(?<type>join|update|leave)\s*(")?(?<name>(?(2)[^"\n]*|[^(: \n]*))(?(2)"|)(\W*\((?<portrait>.*)\))?(\s*(?<transform>[^\[]*))?(\s*\[(?<shortcode>.*)\])?')
|
||||
|
||||
################################################################################
|
||||
## EXECUTION
|
||||
################################################################################
|
||||
|
||||
func _execute() -> void:
|
||||
if not character and not character_identifier == "--All--":
|
||||
finish()
|
||||
return
|
||||
|
||||
# Calculate animation time (can be shortened during skipping)
|
||||
var final_animation_length: float = animation_length
|
||||
var final_position_move_time: float = transform_time
|
||||
if dialogic.Inputs.auto_skip.enabled:
|
||||
var max_time: float = dialogic.Inputs.auto_skip.time_per_event
|
||||
final_animation_length = min(max_time, animation_length)
|
||||
final_position_move_time = min(max_time, transform_time)
|
||||
|
||||
|
||||
# JOIN -------------------------------------
|
||||
if action == Actions.JOIN:
|
||||
if dialogic.has_subsystem('History') and !dialogic.Portraits.is_character_joined(character):
|
||||
var character_name_text := dialogic.Text.get_character_name_parsed(character)
|
||||
dialogic.History.store_simple_history_entry(character_name_text + " joined", event_name, {'character': character_name_text, 'mode':'Join'})
|
||||
|
||||
await dialogic.Portraits.join_character(
|
||||
character, portrait, transform,
|
||||
mirrored, z_index, extra_data,
|
||||
animation_name, final_animation_length, animation_wait)
|
||||
|
||||
# LEAVE -------------------------------------
|
||||
elif action == Actions.LEAVE:
|
||||
if character_identifier == '--All--':
|
||||
if dialogic.has_subsystem('History') and len(dialogic.Portraits.get_joined_characters()):
|
||||
dialogic.History.store_simple_history_entry("Everyone left", event_name, {'character': "All", 'mode':'Leave'})
|
||||
|
||||
await dialogic.Portraits.leave_all_characters(
|
||||
animation_name,
|
||||
final_animation_length,
|
||||
animation_wait
|
||||
)
|
||||
|
||||
elif character:
|
||||
if dialogic.has_subsystem('History') and dialogic.Portraits.is_character_joined(character):
|
||||
var character_name_text := dialogic.Text.get_character_name_parsed(character)
|
||||
dialogic.History.store_simple_history_entry(character_name_text+" left", event_name, {'character': character_name_text, 'mode':'Leave'})
|
||||
|
||||
await dialogic.Portraits.leave_character(
|
||||
character,
|
||||
animation_name,
|
||||
final_animation_length,
|
||||
animation_wait
|
||||
)
|
||||
|
||||
# UPDATE -------------------------------------
|
||||
elif action == Actions.UPDATE:
|
||||
if not character or not dialogic.Portraits.is_character_joined(character):
|
||||
finish()
|
||||
return
|
||||
|
||||
dialogic.Portraits.change_character_extradata(character, extra_data)
|
||||
|
||||
if set_portrait:
|
||||
dialogic.Portraits.change_character_portrait(character, portrait, fade_animation, fade_length)
|
||||
|
||||
if set_mirrored:
|
||||
dialogic.Portraits.change_character_mirror(character, mirrored)
|
||||
|
||||
if set_z_index:
|
||||
dialogic.Portraits.change_character_z_index(character, z_index)
|
||||
|
||||
if set_transform:
|
||||
dialogic.Portraits.move_character(character, transform, final_position_move_time, transform_ease, transform_trans)
|
||||
|
||||
if animation_name:
|
||||
var final_animation_repetitions: int = animation_repeats
|
||||
|
||||
if dialogic.Inputs.auto_skip.enabled:
|
||||
var time_per_event: float = dialogic.Inputs.auto_skip.time_per_event
|
||||
var time_for_repetitions: float = time_per_event / animation_repeats
|
||||
final_animation_length = time_for_repetitions
|
||||
|
||||
var animation := dialogic.Portraits.animate_character(
|
||||
character,
|
||||
animation_name,
|
||||
final_animation_length,
|
||||
final_animation_repetitions,
|
||||
)
|
||||
|
||||
if animation_wait:
|
||||
dialogic.current_state = DialogicGameHandler.States.ANIMATING
|
||||
await animation.finished
|
||||
dialogic.current_state = DialogicGameHandler.States.IDLE
|
||||
|
||||
|
||||
finish()
|
||||
|
||||
|
||||
#region INITIALIZE
|
||||
###############################################################################
|
||||
|
||||
func _init() -> void:
|
||||
event_name = "Character"
|
||||
set_default_color('Color2')
|
||||
event_category = "Main"
|
||||
event_sorting_index = 2
|
||||
|
||||
|
||||
func _get_icon() -> Resource:
|
||||
return load(self.get_script().get_path().get_base_dir().path_join('icon.svg'))
|
||||
|
||||
#endregion
|
||||
|
||||
#region SAVING, LOADING, DEFAULTS
|
||||
################################################################################
|
||||
|
||||
func to_text() -> String:
|
||||
var result_string := ""
|
||||
|
||||
# ACTIONS
|
||||
match action:
|
||||
Actions.JOIN: result_string += "join "
|
||||
Actions.LEAVE: result_string += "leave "
|
||||
Actions.UPDATE: result_string += "update "
|
||||
|
||||
var default_values := DialogicUtil.get_custom_event_defaults(event_name)
|
||||
|
||||
# CHARACTER IDENTIFIER
|
||||
if action == Actions.LEAVE and character_identifier == '--All--':
|
||||
result_string += "--All--"
|
||||
elif character:
|
||||
var name := DialogicResourceUtil.get_unique_identifier(character.resource_path)
|
||||
|
||||
if name.count(" ") > 0:
|
||||
name = '"' + name + '"'
|
||||
|
||||
result_string += name
|
||||
|
||||
# PORTRAIT
|
||||
if portrait.strip_edges() != default_values.get('portrait', ''):
|
||||
if action != Actions.LEAVE and (action != Actions.UPDATE or set_portrait):
|
||||
result_string += " (" + portrait + ")"
|
||||
|
||||
# TRANSFORM
|
||||
if action == Actions.JOIN or (action == Actions.UPDATE and set_transform):
|
||||
result_string += " " + str(transform)
|
||||
|
||||
# SETS:
|
||||
if action == Actions.JOIN or action == Actions.LEAVE:
|
||||
set_mirrored = mirrored != default_values.get("mirrored", false)
|
||||
set_z_index = z_index != default_values.get("z_index", 0)
|
||||
|
||||
var shortcode := store_to_shortcode_parameters()
|
||||
|
||||
if shortcode != "":
|
||||
result_string += " [" + shortcode + "]"
|
||||
|
||||
return result_string
|
||||
|
||||
|
||||
func from_text(string:String) -> void:
|
||||
# Load default character
|
||||
character = DialogicResourceUtil.get_character_resource(character_identifier)
|
||||
|
||||
var result := regex.search(string)
|
||||
|
||||
# ACTION
|
||||
match result.get_string('type'):
|
||||
"join": action = Actions.JOIN
|
||||
"leave": action = Actions.LEAVE
|
||||
"update": action = Actions.UPDATE
|
||||
|
||||
# CHARACTER
|
||||
var given_name := result.get_string('name').strip_edges()
|
||||
var given_portrait := result.get_string('portrait').strip_edges()
|
||||
var given_transform := result.get_string('transform').strip_edges()
|
||||
|
||||
if given_name:
|
||||
if action == Actions.LEAVE and given_name == "--All--":
|
||||
character_identifier = '--All--'
|
||||
else:
|
||||
character = DialogicResourceUtil.get_character_resource(given_name)
|
||||
|
||||
# PORTRAIT
|
||||
if given_portrait:
|
||||
portrait = given_portrait.trim_prefix('(').trim_suffix(')')
|
||||
set_portrait = true
|
||||
|
||||
# TRANSFORM
|
||||
if given_transform:
|
||||
transform = given_transform
|
||||
set_transform = true
|
||||
|
||||
# SHORTCODE
|
||||
if not result.get_string('shortcode'):
|
||||
return
|
||||
|
||||
load_from_shortcode_parameters(result.get_string('shortcode'))
|
||||
|
||||
|
||||
func get_shortcode_parameters() -> Dictionary:
|
||||
return {
|
||||
#param_name : property_info
|
||||
"action" : {"property": "action", "default": 0, "custom_stored":true,
|
||||
"suggestions": func(): return {'Join':
|
||||
{'value':Actions.JOIN},
|
||||
'Leave':{'value':Actions.LEAVE},
|
||||
'Update':{'value':Actions.UPDATE}}},
|
||||
"character" : {"property": "character_identifier", "default": "", "custom_stored":true,},
|
||||
"portrait" : {"property": "portrait", "default": "", "custom_stored":true,},
|
||||
"transform" : {"property": "transform", "default": "center", "custom_stored":true,},
|
||||
|
||||
"animation" : {"property": "animation_name", "default": ""},
|
||||
"length" : {"property": "animation_length", "default": 0.5},
|
||||
"wait" : {"property": "animation_wait", "default": false},
|
||||
"repeat" : {"property": "animation_repeats", "default": 1},
|
||||
|
||||
"z_index" : {"property": "z_index", "default": 0},
|
||||
"mirrored" : {"property": "mirrored", "default": false},
|
||||
"fade" : {"property": "fade_animation", "default":""},
|
||||
"fade_length" : {"property": "fade_length", "default":0.5},
|
||||
"move_time" : {"property": "transform_time", "default": 0.0},
|
||||
"move_ease" : {"property": "transform_ease", "default": Tween.EaseType.EASE_IN_OUT,
|
||||
"suggestions": func(): return list_to_suggestions(ease_options)},
|
||||
"move_trans" : {"property": "transform_trans", "default": Tween.TransitionType.TRANS_SINE,
|
||||
"suggestions": func(): return list_to_suggestions(trans_options)},
|
||||
"extra_data" : {"property": "extra_data", "default": ""},
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
|
||||
#endregion
|
||||
|
||||
################################################################################
|
||||
## EDITOR REPRESENTATION
|
||||
################################################################################
|
||||
|
||||
func build_event_editor() -> void:
|
||||
add_header_edit('action', ValueType.FIXED_OPTIONS, {
|
||||
'options': [
|
||||
{
|
||||
'label': 'Join',
|
||||
'value': Actions.JOIN,
|
||||
'icon': load("res://addons/dialogic/Editor/Images/Dropdown/join.svg")
|
||||
},
|
||||
{
|
||||
'label': 'Leave',
|
||||
'value': Actions.LEAVE,
|
||||
'icon': load("res://addons/dialogic/Editor/Images/Dropdown/leave.svg")
|
||||
},
|
||||
{
|
||||
'label': 'Update',
|
||||
'value': Actions.UPDATE,
|
||||
'icon': load("res://addons/dialogic/Editor/Images/Dropdown/update.svg")
|
||||
}
|
||||
]
|
||||
})
|
||||
add_header_edit('character_identifier', ValueType.DYNAMIC_OPTIONS,
|
||||
{'placeholder' : 'Character',
|
||||
'file_extension' : '.dch',
|
||||
'mode' : 2,
|
||||
'suggestions_func' : get_character_suggestions,
|
||||
'icon' : load("res://addons/dialogic/Editor/Images/Resources/character.svg"),
|
||||
'autofocus' : true})
|
||||
|
||||
add_header_edit('set_portrait', ValueType.BOOL_BUTTON,
|
||||
{'icon':load("res://addons/dialogic/Modules/Character/update_portrait.svg"),
|
||||
'tooltip':'Change Portrait'}, "should_show_portrait_selector() and action == Actions.UPDATE")
|
||||
add_header_edit('portrait', ValueType.DYNAMIC_OPTIONS,
|
||||
{'placeholder' : 'Default',
|
||||
'collapse_when_empty':true,
|
||||
'suggestions_func' : get_portrait_suggestions,
|
||||
'icon' : load("res://addons/dialogic/Editor/Images/Resources/portrait.svg")},
|
||||
'should_show_portrait_selector() and (action != Actions.UPDATE or set_portrait)')
|
||||
add_header_edit('set_transform', ValueType.BOOL_BUTTON,
|
||||
{'icon': load("res://addons/dialogic/Modules/Character/update_position.svg"), 'tooltip':'Change Position'}, "character != null and !has_no_portraits() and action == Actions.UPDATE")
|
||||
add_header_label('at position', 'character != null and !has_no_portraits() and action == Actions.JOIN')
|
||||
add_header_label('to position', 'character != null and !has_no_portraits() and action == Actions.UPDATE and set_transform')
|
||||
add_header_edit('transform', ValueType.DYNAMIC_OPTIONS,
|
||||
{'placeholder' : 'center',
|
||||
'mode' : 0,
|
||||
'suggestions_func' : get_position_suggestions,
|
||||
'tooltip' : "You can use a predefined position or a custom transform like 'pos=x0.5y1 size=x0.5y1 rot=10'.\nLearn more about this in the documentation."},
|
||||
'character != null and !has_no_portraits() and action != %s and (action != Actions.UPDATE or set_transform)' %Actions.LEAVE)
|
||||
|
||||
# Body
|
||||
add_body_edit('fade_animation', ValueType.DYNAMIC_OPTIONS,
|
||||
{'left_text' : 'Fade:',
|
||||
'suggestions_func' : get_fade_suggestions,
|
||||
'editor_icon' : ["Animation", "EditorIcons"],
|
||||
'placeholder' : 'Default',
|
||||
'enable_pretty_name' : true},
|
||||
'should_show_fade_options()')
|
||||
add_body_edit('fade_length', ValueType.NUMBER, {'left_text':'Length:', 'suffix':'s', "min":0},
|
||||
'should_show_fade_options() and !fade_animation.is_empty()')
|
||||
add_body_line_break("should_show_fade_options()")
|
||||
add_body_edit('animation_name', ValueType.DYNAMIC_OPTIONS,
|
||||
{'left_text' : '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.NUMBER, {'left_text':'Length:', 'suffix':'s', "min":0},
|
||||
'should_show_animation_options() and !animation_name.is_empty()')
|
||||
add_body_edit('animation_wait', ValueType.BOOL, {'left_text':'Await end:'},
|
||||
'should_show_animation_options() and !animation_name.is_empty()')
|
||||
add_body_edit('animation_repeats', ValueType.NUMBER, {'left_text':'Repeat:', 'mode':1, "min":1},
|
||||
'should_show_animation_options() and !animation_name.is_empty() and action == %s)' %Actions.UPDATE)
|
||||
add_body_line_break()
|
||||
add_body_edit('transform_time', ValueType.NUMBER, {'left_text':'Movement duration:', "min":0},
|
||||
"should_show_transform_options()")
|
||||
add_body_edit("transform_trans", ValueType.FIXED_OPTIONS, {'options':trans_options, 'left_text':"Trans:"}, 'should_show_transform_options() and transform_time > 0')
|
||||
add_body_edit("transform_ease", ValueType.FIXED_OPTIONS, {'options':ease_options, 'left_text':"Ease:"}, 'should_show_transform_options() and transform_time > 0')
|
||||
|
||||
add_body_edit('set_z_index', ValueType.BOOL_BUTTON, {'icon':load("res://addons/dialogic/Modules/Character/update_z_index.svg"), 'tooltip':'Change Z-Index'}, "character != null and action == Actions.UPDATE")
|
||||
add_body_edit('z_index', ValueType.NUMBER, {'left_text':'Z-index:', 'mode':1},
|
||||
'action != %s and (action != Actions.UPDATE or set_z_index)' %Actions.LEAVE)
|
||||
add_body_edit('set_mirrored', ValueType.BOOL_BUTTON, {'icon':load("res://addons/dialogic/Modules/Character/update_mirror.svg"), 'tooltip':'Change Mirroring'}, "character != null and action == Actions.UPDATE")
|
||||
add_body_edit('mirrored', ValueType.BOOL, {'left_text':'Mirrored:'},
|
||||
'action != %s and (action != Actions.UPDATE or set_mirrored)' %Actions.LEAVE)
|
||||
add_body_edit('extra_data', ValueType.SINGLELINE_TEXT, {'left_text':'Extra Data:'}, 'action != Actions.LEAVE')
|
||||
|
||||
|
||||
func should_show_transform_options() -> bool:
|
||||
return action == Actions.UPDATE and set_transform
|
||||
|
||||
|
||||
func should_show_animation_options() -> bool:
|
||||
return (character and !character.portraits.is_empty()) or character_identifier == '--All--'
|
||||
|
||||
|
||||
func should_show_fade_options() -> bool:
|
||||
return action == Actions.UPDATE and set_portrait and character and not character.portraits.is_empty()
|
||||
|
||||
|
||||
func should_show_portrait_selector() -> bool:
|
||||
return character and len(character.portraits) > 1 and action != Actions.LEAVE
|
||||
|
||||
|
||||
func has_no_portraits() -> bool:
|
||||
return character and character.portraits.is_empty()
|
||||
|
||||
|
||||
func get_character_suggestions(search_text:String) -> Dictionary:
|
||||
return DialogicUtil.get_character_suggestions(search_text, character, false, action == Actions.LEAVE, editor_node)
|
||||
|
||||
|
||||
func get_portrait_suggestions(search_text:String) -> Dictionary:
|
||||
var empty_text := "Don't Change"
|
||||
if action == Actions.JOIN:
|
||||
empty_text = "Default portrait"
|
||||
return DialogicUtil.get_portrait_suggestions(search_text, character, true, empty_text)
|
||||
|
||||
|
||||
func get_position_suggestions(search_text:String='') -> Dictionary:
|
||||
return DialogicUtil.get_portrait_position_suggestions(search_text)
|
||||
|
||||
|
||||
func get_animation_suggestions(search_text:String='') -> Dictionary:
|
||||
var DPAU := DialogicPortraitAnimationUtil
|
||||
match action:
|
||||
Actions.JOIN:
|
||||
return DPAU.get_suggestions(search_text, animation_name, "Default", DPAU.AnimationType.IN)
|
||||
Actions.LEAVE:
|
||||
return DPAU.get_suggestions(search_text, animation_name, "Default", DPAU.AnimationType.OUT)
|
||||
Actions.UPDATE:
|
||||
return DPAU.get_suggestions(search_text, animation_name, "None", DPAU.AnimationType.ACTION)
|
||||
return {}
|
||||
|
||||
|
||||
func get_fade_suggestions(search_text:String='') -> Dictionary:
|
||||
return DialogicPortraitAnimationUtil.get_suggestions(search_text, fade_animation, "Default", DialogicPortraitAnimationUtil.AnimationType.CROSSFADE)
|
||||
|
||||
|
||||
####################### CODE COMPLETION ########################################
|
||||
################################################################################
|
||||
|
||||
func _get_code_completion(CodeCompletionHelper:Node, TextNode:TextEdit, line:String, _word:String, symbol:String) -> void:
|
||||
var line_until_caret: String = CodeCompletionHelper.get_line_untill_caret(line)
|
||||
if symbol == ' ' and line_until_caret.count(' ') == 1:
|
||||
CodeCompletionHelper.suggest_characters(TextNode, CodeEdit.KIND_MEMBER)
|
||||
if line.begins_with('leave'):
|
||||
TextNode.add_code_completion_option(CodeEdit.KIND_MEMBER, 'All', '--All-- ', event_color, TextNode.get_theme_icon("GuiEllipsis", "EditorIcons"))
|
||||
|
||||
if symbol == '(':
|
||||
var completion_character := regex.search(line).get_string('name')
|
||||
CodeCompletionHelper.suggest_portraits(TextNode, completion_character)
|
||||
|
||||
elif not '[' in line_until_caret and symbol == ' ':
|
||||
if not line.begins_with("leave"):
|
||||
for position in get_position_suggestions():
|
||||
TextNode.add_code_completion_option(CodeEdit.KIND_MEMBER, position, position+' ', TextNode.syntax_highlighter.normal_color)
|
||||
|
||||
# Shortcode Part
|
||||
if '[' in line_until_caret:
|
||||
# Suggest Parameters
|
||||
if symbol == '[' or symbol == ' ' and line_until_caret.count('"')%2 == 0:# and (symbol == "[" or (symbol == " " and line_until_caret.rfind('="') < line_until_caret.rfind('"')-1)):
|
||||
suggest_parameter("animation", line, TextNode)
|
||||
|
||||
if "animation=" in line:
|
||||
for param in ["length", "wait"]:
|
||||
suggest_parameter(param, line, TextNode)
|
||||
if line.begins_with('update'):
|
||||
suggest_parameter("repeat", line, TextNode)
|
||||
if line.begins_with("update"):
|
||||
for param in ["move_time", "move_trans", "move_ease"]:
|
||||
suggest_parameter(param, line, TextNode)
|
||||
if not line.begins_with('leave'):
|
||||
for param in ["mirrored", "z_index", "extra_data"]:
|
||||
suggest_parameter(param, line, TextNode)
|
||||
|
||||
# Suggest Values
|
||||
else:
|
||||
var current_param: RegExMatch = CodeCompletionHelper.completion_shortcode_param_getter_regex.search(line)
|
||||
if not current_param:
|
||||
return
|
||||
|
||||
match current_param.get_string("param"):
|
||||
"animation":
|
||||
var animations := {}
|
||||
if line.begins_with('join'):
|
||||
animations = DialogicPortraitAnimationUtil.get_portrait_animations_filtered(DialogicPortraitAnimationUtil.AnimationType.IN)
|
||||
elif line.begins_with('update'):
|
||||
animations = DialogicPortraitAnimationUtil.get_portrait_animations_filtered(DialogicPortraitAnimationUtil.AnimationType.ACTION)
|
||||
elif line.begins_with('leave'):
|
||||
animations = DialogicPortraitAnimationUtil.get_portrait_animations_filtered(DialogicPortraitAnimationUtil.AnimationType.OUT)
|
||||
|
||||
for script: String in animations:
|
||||
TextNode.add_code_completion_option(CodeEdit.KIND_VARIABLE, DialogicUtil.pretty_name(script), DialogicUtil.pretty_name(script), TextNode.syntax_highlighter.normal_color, null, '" ')
|
||||
|
||||
"wait", "mirrored":
|
||||
CodeCompletionHelper.suggest_bool(TextNode, TextNode.syntax_highlighter.normal_color)
|
||||
"move_trans":
|
||||
CodeCompletionHelper.suggest_custom_suggestions(list_to_suggestions(trans_options), TextNode, TextNode.syntax_highlighter.normal_color)
|
||||
"move_ease":
|
||||
CodeCompletionHelper.suggest_custom_suggestions(list_to_suggestions(ease_options), TextNode, TextNode.syntax_highlighter.normal_color)
|
||||
|
||||
|
||||
func suggest_parameter(parameter:String, line:String, TextNode:TextEdit) -> void:
|
||||
if not parameter + "=" in line:
|
||||
TextNode.add_code_completion_option(CodeEdit.KIND_MEMBER, parameter, parameter + '="', TextNode.syntax_highlighter.normal_color)
|
||||
|
||||
|
||||
func _get_start_code_completion(_CodeCompletionHelper:Node, TextNode:TextEdit) -> void:
|
||||
TextNode.add_code_completion_option(CodeEdit.KIND_PLAIN_TEXT, 'join', 'join ', event_color, load('res://addons/dialogic/Editor/Images/Dropdown/join.svg'))
|
||||
TextNode.add_code_completion_option(CodeEdit.KIND_PLAIN_TEXT, 'leave', 'leave ', event_color, load('res://addons/dialogic/Editor/Images/Dropdown/leave.svg'))
|
||||
TextNode.add_code_completion_option(CodeEdit.KIND_PLAIN_TEXT, 'update', 'update ', event_color, load('res://addons/dialogic/Editor/Images/Dropdown/update.svg'))
|
||||
|
||||
|
||||
#################### SYNTAX HIGHLIGHTING #######################################
|
||||
################################################################################
|
||||
|
||||
func _get_syntax_highlighting(Highlighter:SyntaxHighlighter, dict:Dictionary, line:String) -> Dictionary:
|
||||
var word := line.get_slice(' ', 0)
|
||||
|
||||
dict[line.find(word)] = {"color":event_color}
|
||||
dict[line.find(word)+len(word)] = {"color":Highlighter.normal_color}
|
||||
var result := regex.search(line)
|
||||
if result.get_string('name'):
|
||||
dict[result.get_start('name')] = {"color":event_color.lerp(Highlighter.normal_color, 0.5)}
|
||||
dict[result.get_end('name')] = {"color":Highlighter.normal_color}
|
||||
if result.get_string('portrait'):
|
||||
dict[result.get_start('portrait')] = {"color":event_color.lerp(Highlighter.normal_color, 0.6)}
|
||||
dict[result.get_end('portrait')] = {"color":Highlighter.normal_color}
|
||||
if result.get_string('shortcode'):
|
||||
dict = Highlighter.color_shortcode_content(dict, line, result.get_start('shortcode'), result.get_end('shortcode'), event_color)
|
||||
return dict
|
||||
|
||||
|
||||
## HELPER
|
||||
func list_to_suggestions(list:Array) -> Dictionary:
|
||||
return list.reduce(
|
||||
func(accum, value):
|
||||
accum[value.label] = value
|
||||
accum[value.label]["text_alt"] = [value.label.to_lower()]
|
||||
return accum,
|
||||
{})
|
||||
1
addons/dialogic/Modules/Character/event_character.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://xxqa000yatnt
|
||||
34
addons/dialogic/Modules/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
|
||||
4
addons/dialogic/Modules/Character/icon.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M21.0625 10.483C21.0625 13.5111 18.6077 15.9659 15.5795 15.9659C12.5514 15.9659 10.0966 13.5111 10.0966 10.483C10.0966 7.4548 12.5514 5 15.5795 5C18.6077 5 21.0625 7.4548 21.0625 10.483Z" fill="white"/>
|
||||
<path d="M22.3158 24.1393C22.3158 27 19.3349 27 15.6579 27C11.9808 27 9 27 9 24.1393C9 19.0046 11.9808 14.8421 15.6579 14.8421C19.3349 14.8421 22.3158 19.0046 22.3158 24.1393Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 507 B |
44
addons/dialogic/Modules/Character/icon.svg.import
Normal file
@@ -0,0 +1,44 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://q6lanmf18ii6"
|
||||
path="res://.godot/imported/icon.svg-4f340f6efbb83004dbd5c761dd1dc448.ctex"
|
||||
metadata={
|
||||
"has_editor_variant": true,
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/dialogic/Modules/Character/icon.svg"
|
||||
dest_files=["res://.godot/imported/icon.svg-4f340f6efbb83004dbd5c761dd1dc448.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
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/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
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
|
||||
svg/scale=1.0
|
||||
editor/scale_with_editor_scale=true
|
||||
editor/convert_colors_with_editor_theme=true
|
||||
BIN
addons/dialogic/Modules/Character/icon_position.png
Normal file
|
After Width: | Height: | Size: 1017 B |
40
addons/dialogic/Modules/Character/icon_position.png.import
Normal file
@@ -0,0 +1,40 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://cu6cj55m6dr78"
|
||||
path="res://.godot/imported/icon_position.png-221b7c348ec45b22fd4df49fdb92a7aa.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/dialogic/Modules/Character/icon_position.png"
|
||||
dest_files=["res://.godot/imported/icon_position.png-221b7c348ec45b22fd4df49fdb92a7aa.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
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/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
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
|
||||
58
addons/dialogic/Modules/Character/index.gd
Normal file
@@ -0,0 +1,58 @@
|
||||
@tool
|
||||
extends DialogicIndexer
|
||||
|
||||
|
||||
func _get_events() -> Array:
|
||||
return [this_folder.path_join('event_character.gd')]
|
||||
|
||||
|
||||
func _get_subsystems() -> Array:
|
||||
return [{'name':'Portraits', 'script':this_folder.path_join('subsystem_portraits.gd')}, {'name':'PortraitContainers', 'script':this_folder.path_join('subsystem_containers.gd')}]
|
||||
|
||||
func _get_settings_pages() -> Array:
|
||||
return [this_folder.path_join('settings_portraits.tscn')]
|
||||
|
||||
func _get_text_effects() -> Array[Dictionary]:
|
||||
return [
|
||||
{'command':'portrait', 'subsystem':'Portraits', 'method':'text_effect_portrait', 'arg':true},
|
||||
{'command':'extra_data', 'subsystem':'Portraits', 'method':'text_effect_extradata', 'arg':true},
|
||||
]
|
||||
|
||||
|
||||
func _get_special_resources() -> Dictionary:
|
||||
return {&'PortraitAnimation': list_animations("DefaultAnimations")}
|
||||
|
||||
|
||||
func _get_portrait_scene_presets() -> Array[Dictionary]:
|
||||
return [
|
||||
{
|
||||
"path": "",
|
||||
"name": "Default Scene",
|
||||
"description": "The default scene defined in Settings>Portraits.",
|
||||
"author":"Dialogic",
|
||||
"type": "Default",
|
||||
"icon":"",
|
||||
"preview_image":[this_folder.path_join("default_portrait_thumbnail.png")],
|
||||
"documentation":"",
|
||||
},
|
||||
{
|
||||
"path": "CUSTOM",
|
||||
"name": "Custom Scene",
|
||||
"description": "A custom scene. Should extend DialogicPortrait and be in @tool mode.",
|
||||
"author":"Dialogic",
|
||||
"type": "Custom",
|
||||
"icon":"",
|
||||
"preview_image":[this_folder.path_join("custom_portrait_thumbnail.png")],
|
||||
"documentation":"https://docs.dialogic.pro/custom-portraits.html",
|
||||
},
|
||||
{
|
||||
"path": this_folder.path_join("default_portrait.tscn"),
|
||||
"name": "Simple Image Portrait",
|
||||
"description": "Can display images as portraits. Does nothing else.",
|
||||
"author":"Dialogic",
|
||||
"type": "General",
|
||||
"icon":"",
|
||||
"preview_image":[this_folder.path_join("simple_image_portrait_thumbnail.png")],
|
||||
"documentation":"",
|
||||
}
|
||||
]
|
||||
1
addons/dialogic/Modules/Character/index.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://drr427b3tvasg
|
||||
258
addons/dialogic/Modules/Character/node_portrait_container.gd
Normal file
@@ -0,0 +1,258 @@
|
||||
@tool
|
||||
class_name DialogicNode_PortraitContainer
|
||||
extends Control
|
||||
|
||||
## Node that defines a position for dialogic portraits and how to display portraits at that position.
|
||||
|
||||
enum PositionModes {
|
||||
POSITION, ## This container can be joined/moved to with the Character Event
|
||||
SPEAKER, ## This container is joined/left automatically based on the speaker.
|
||||
}
|
||||
|
||||
@export var mode := PositionModes.POSITION
|
||||
|
||||
@export_subgroup('Mode: Position')
|
||||
## The position this node corresponds to.
|
||||
@export var container_ids: PackedStringArray = ["1"]
|
||||
|
||||
|
||||
@export_subgroup('Mode: Speaker')
|
||||
## Can be used to use a different portrait.
|
||||
## E.g. "Faces/" would mean instead of "happy" it will use portrait "Faces/happy"
|
||||
@export var portrait_prefix := ''
|
||||
|
||||
@export_subgroup('Portrait Placement')
|
||||
enum SizeModes {
|
||||
KEEP, ## The height and width of the container have no effect, only the origin.
|
||||
FIT_STRETCH, ## The portrait will be fitted into the container, ignoring it's aspect ratio and the character/portrait scale.
|
||||
FIT_IGNORE_SCALE, ## The portrait will be fitted into the container, ignoring the character/portrait scale, but preserving the aspect ratio.
|
||||
FIT_SCALE_HEIGHT ## Recommended. The portrait will be scaled to fit the container height. A character/portrait scale of 100% means 100% container height. Aspect ratio will be preserved.
|
||||
}
|
||||
## Defines how to affect the scale of the portrait
|
||||
@export var size_mode: SizeModes = SizeModes.FIT_SCALE_HEIGHT :
|
||||
set(mode):
|
||||
size_mode = mode
|
||||
_update_debug_portrait_transform()
|
||||
|
||||
## If true, portraits will be mirrored in this position.
|
||||
@export var mirrored := false :
|
||||
set(mirror):
|
||||
mirrored = mirror
|
||||
_update_debug_portrait_scene()
|
||||
|
||||
|
||||
@export_group('Origin', 'origin')
|
||||
enum OriginAnchors {TOP_LEFT, TOP_CENTER, TOP_RIGHT, LEFT_MIDDLE, CENTER, RIGHT_MIDDLE, BOTTOM_LEFT, BOTTOM_CENTER, BOTTOM_RIGHT}
|
||||
## The portrait will be placed relative to this point in the container.
|
||||
@export var origin_anchor: OriginAnchors = OriginAnchors.BOTTOM_CENTER :
|
||||
set(anchor):
|
||||
origin_anchor = anchor
|
||||
_update_debug_origin()
|
||||
|
||||
## An offset to apply to the origin. Rarely useful.
|
||||
@export var origin_offset := Vector2() :
|
||||
set(offset):
|
||||
origin_offset = offset
|
||||
_update_debug_origin()
|
||||
|
||||
enum PivotModes {AT_ORIGIN, PERCENTAGE, PIXELS}
|
||||
## Usually you want to rotate or scale around the portrait origin.
|
||||
## For the moments where that is not the case, set the mode to PERCENTAGE or PIXELS and use [member pivot_value].
|
||||
@export var pivot_mode: PivotModes = PivotModes.AT_ORIGIN
|
||||
## Only has an effect when [member pivot_mode] is not AT_ORIGIN. Meaning depends on whether [member pivot_mode] is PERCENTAGE or PIXELS.
|
||||
@export var pivot_value := Vector2()
|
||||
|
||||
@export_group('Debug', 'debug')
|
||||
## A character that will be displayed in the editor, useful for getting the right size.
|
||||
@export var debug_character: DialogicCharacter = null:
|
||||
set(character):
|
||||
debug_character = character
|
||||
_update_debug_portrait_scene()
|
||||
@export var debug_character_portrait := "":
|
||||
set(portrait):
|
||||
debug_character_portrait = portrait
|
||||
_update_debug_portrait_scene()
|
||||
|
||||
var debug_character_holder_node: Node2D = null
|
||||
var debug_character_scene_node: Node = null
|
||||
var debug_origin: Sprite2D = null
|
||||
var default_portrait_scene: String = DialogicUtil.get_module_path('Character').path_join("default_portrait.tscn")
|
||||
# Used if no debug character is specified
|
||||
var default_debug_character := load(DialogicUtil.get_module_path('Character').path_join("preview_character.tres"))
|
||||
|
||||
var ignore_resize := false
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
match mode:
|
||||
PositionModes.POSITION:
|
||||
add_to_group('dialogic_portrait_con_position')
|
||||
PositionModes.SPEAKER:
|
||||
add_to_group('dialogic_portrait_con_speaker')
|
||||
|
||||
if Engine.is_editor_hint():
|
||||
resized.connect(_update_debug_origin)
|
||||
|
||||
if !ProjectSettings.get_setting('dialogic/portraits/default_portrait', '').is_empty():
|
||||
default_portrait_scene = ProjectSettings.get_setting('dialogic/portraits/default_portrait', '')
|
||||
|
||||
debug_origin = Sprite2D.new()
|
||||
add_child(debug_origin)
|
||||
debug_origin.texture = load("res://addons/dialogic/Editor/Images/Dropdown/default.svg")
|
||||
|
||||
_update_debug_origin()
|
||||
_update_debug_portrait_scene()
|
||||
else:
|
||||
resized.connect(update_portrait_transforms)
|
||||
|
||||
|
||||
################################################################################
|
||||
## MAIN METHODS
|
||||
################################################################################
|
||||
|
||||
func update_portrait_transforms() -> void:
|
||||
if ignore_resize:
|
||||
return
|
||||
|
||||
match pivot_mode:
|
||||
PivotModes.AT_ORIGIN:
|
||||
pivot_offset = _get_origin_position()
|
||||
PivotModes.PERCENTAGE:
|
||||
pivot_offset = size*pivot_value
|
||||
PivotModes.PIXELS:
|
||||
pivot_offset = pivot_value
|
||||
|
||||
for child in get_children():
|
||||
DialogicUtil.autoload().Portraits._update_character_transform(child)
|
||||
|
||||
|
||||
## Returns a Rect2 with the position as the position and the scale as the size.
|
||||
func get_local_portrait_transform(portrait_rect:Rect2, character_scale:=1.0) -> Rect2:
|
||||
var transform := Rect2()
|
||||
transform.position = _get_origin_position()
|
||||
|
||||
# Mode that ignores the containers size
|
||||
if size_mode == SizeModes.KEEP:
|
||||
transform.size = Vector2(1,1) * character_scale
|
||||
|
||||
# Mode that makes sure neither height nor width go out of container
|
||||
elif size_mode == SizeModes.FIT_IGNORE_SCALE:
|
||||
if size.x/size.y < portrait_rect.size.x/portrait_rect.size.y:
|
||||
transform.size = Vector2(1,1) * size.x/portrait_rect.size.x
|
||||
else:
|
||||
transform.size = Vector2(1,1) * size.y/portrait_rect.size.y
|
||||
|
||||
# Mode that stretches the portrait to fill the whole container
|
||||
elif size_mode == SizeModes.FIT_STRETCH:
|
||||
transform.size = size/portrait_rect.size
|
||||
|
||||
# Mode that size the character so 100% size fills the height
|
||||
elif size_mode == SizeModes.FIT_SCALE_HEIGHT:
|
||||
transform.size = Vector2(1,1) * size.y / portrait_rect.size.y*character_scale
|
||||
|
||||
return transform
|
||||
|
||||
|
||||
## Returns the current origin position
|
||||
func _get_origin_position(rect_size = null) -> Vector2:
|
||||
if rect_size == null:
|
||||
rect_size = size
|
||||
return rect_size * Vector2(origin_anchor%3 / 2.0, floor(origin_anchor/3.0) / 2.0) + origin_offset
|
||||
|
||||
|
||||
func is_container(id:Variant) -> bool:
|
||||
return str(id) in container_ids
|
||||
|
||||
#region DEBUG METHODS
|
||||
################################################################################
|
||||
### USE THIS TO DEBUG THE POSITIONS
|
||||
#func _draw():
|
||||
#draw_rect(Rect2(Vector2(), size), Color(1, 0.3098039329052, 1), false, 2)
|
||||
#draw_string(get_theme_default_font(),get_theme_default_font().get_string_size(container_ids[0], HORIZONTAL_ALIGNMENT_LEFT, 1, get_theme_default_font_size()) , container_ids[0], HORIZONTAL_ALIGNMENT_CENTER)
|
||||
#
|
||||
#func _process(delta:float) -> void:
|
||||
#queue_redraw()
|
||||
|
||||
|
||||
## Loads the debug_character with the debug_character_portrait
|
||||
## Creates a holder node and applies mirror
|
||||
func _update_debug_portrait_scene() -> void:
|
||||
if !Engine.is_editor_hint():
|
||||
return
|
||||
if is_instance_valid(debug_character_holder_node):
|
||||
for child in get_children():
|
||||
if child != debug_origin:
|
||||
child.free()
|
||||
|
||||
# Get character
|
||||
var character := _get_debug_character()
|
||||
if not character is DialogicCharacter or character.portraits.is_empty():
|
||||
return
|
||||
|
||||
# Determine portrait
|
||||
var debug_portrait := debug_character_portrait
|
||||
if debug_portrait.is_empty():
|
||||
debug_portrait = character.default_portrait
|
||||
if mode == PositionModes.SPEAKER and !portrait_prefix.is_empty():
|
||||
if portrait_prefix+debug_portrait in character.portraits:
|
||||
debug_portrait = portrait_prefix+debug_portrait
|
||||
if not debug_portrait in character.portraits:
|
||||
debug_portrait = character.default_portrait
|
||||
|
||||
var portrait_info: Dictionary = character.get_portrait_info(debug_portrait)
|
||||
|
||||
# Determine scene
|
||||
var portrait_scene_path: String = portrait_info.get('scene', default_portrait_scene)
|
||||
if portrait_scene_path.is_empty():
|
||||
portrait_scene_path = default_portrait_scene
|
||||
|
||||
debug_character_scene_node = load(portrait_scene_path).instantiate()
|
||||
|
||||
if !is_instance_valid(debug_character_scene_node):
|
||||
return
|
||||
|
||||
# Load portrait
|
||||
DialogicUtil.apply_scene_export_overrides(debug_character_scene_node, character.portraits[debug_portrait].get('export_overrides', {}))
|
||||
debug_character_scene_node._update_portrait(character, debug_portrait)
|
||||
|
||||
# Add character node
|
||||
if !is_instance_valid(debug_character_holder_node):
|
||||
debug_character_holder_node = Node2D.new()
|
||||
add_child(debug_character_holder_node)
|
||||
|
||||
# Add portrait node
|
||||
debug_character_holder_node.add_child(debug_character_scene_node)
|
||||
move_child(debug_character_holder_node, 0)
|
||||
debug_character_scene_node._set_mirror(character.mirror != mirrored != portrait_info.get('mirror', false))
|
||||
|
||||
_update_debug_portrait_transform()
|
||||
|
||||
|
||||
## Set's the size and position of the holder and scene node
|
||||
## according to the size_mode
|
||||
func _update_debug_portrait_transform() -> void:
|
||||
if !Engine.is_editor_hint() or !is_instance_valid(debug_character_scene_node) or !is_instance_valid(debug_origin):
|
||||
return
|
||||
var character := _get_debug_character()
|
||||
var portrait_info := character.get_portrait_info(debug_character_portrait)
|
||||
var transform := get_local_portrait_transform(debug_character_scene_node._get_covered_rect(), character.scale*portrait_info.get('scale', 1))
|
||||
debug_character_holder_node.position = transform.position
|
||||
debug_character_scene_node.position = portrait_info.get('offset', Vector2())+character.offset
|
||||
|
||||
debug_character_holder_node.scale = transform.size
|
||||
|
||||
|
||||
## Updates the debug origins position. Also calls _update_debug_portrait_transform()
|
||||
func _update_debug_origin() -> void:
|
||||
if !Engine.is_editor_hint() or !is_instance_valid(debug_origin):
|
||||
return
|
||||
debug_origin.position = _get_origin_position()
|
||||
_update_debug_portrait_transform()
|
||||
|
||||
|
||||
|
||||
## Returns the debug character or the default debug character
|
||||
func _get_debug_character() -> DialogicCharacter:
|
||||
return debug_character if debug_character != null else default_debug_character
|
||||
|
||||
#endregion
|
||||
@@ -0,0 +1 @@
|
||||
uid://ci5bin54hnssd
|
||||
8
addons/dialogic/Modules/Character/portrait_position.svg
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="64" height="64" viewBox="0 0 64 64" fill="none" version="1.1" id="svg13818" sodipodi:docname="event_portrait_position.svg" inkscape:version="1.2.2 (732a01da63, 2022-12-09)" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs id="defs13822" />
|
||||
<sodipodi:namedview id="namedview13820" pagecolor="#505050" bordercolor="#eeeeee" borderopacity="1" inkscape:showpageshadow="0" inkscape:pageopacity="0" inkscape:pagecheckerboard="0" inkscape:deskcolor="#505050" showgrid="false" inkscape:zoom="6.5390625" inkscape:cx="-20.109916" inkscape:cy="11.622461" inkscape:window-width="1920" inkscape:window-height="1017" inkscape:window-x="-8" inkscape:window-y="-8" inkscape:window-maximized="1" inkscape:current-layer="svg13818" />
|
||||
<path d="m 41.97648,22.585683 c 0,5.509774 -4.466676,9.976311 -9.976424,9.976311 -5.509775,0 -9.976338,-4.466537 -9.976338,-9.976311 0,-5.509775 4.466563,-9.976328 9.976338,-9.976328 5.509748,0 9.976424,4.466553 9.976424,9.976328 z" fill="#ffffff" id="path13814" style="stroke-width:2.74349" />
|
||||
<path d="m 43.971538,47.35052 c 0,5.164069 -5.359673,5.164069 -11.971482,5.164069 -6.611724,0 -11.971595,0 -11.971595,-5.164069 0,-9.269422 5.359871,-16.783783 11.971595,-16.783783 6.611808,0 11.971482,7.514361 11.971482,16.783783 z" fill="#ffffff" id="path13816" style="stroke-width:2.74349" />
|
||||
<rect style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:4.081;stroke-linecap:round;stroke-miterlimit:3.2;stroke-dasharray:4.081,8.162;stroke-dashoffset:0" id="rect14304" width="35.873577" height="49.97176" x="14.06331" y="6.9472136" ry="0.19193064" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
@@ -0,0 +1,44 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://bn3nq7gw67kye"
|
||||
path="res://.godot/imported/portrait_position.svg-f025767e40032b9ebdeab1f9e882467a.ctex"
|
||||
metadata={
|
||||
"has_editor_variant": true,
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/dialogic/Modules/Character/portrait_position.svg"
|
||||
dest_files=["res://.godot/imported/portrait_position.svg-f025767e40032b9ebdeab1f9e882467a.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
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/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
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
|
||||
svg/scale=1.0
|
||||
editor/scale_with_editor_scale=true
|
||||
editor/convert_colors_with_editor_theme=true
|
||||
32
addons/dialogic/Modules/Character/preview_character.tres
Normal file
@@ -0,0 +1,32 @@
|
||||
[gd_resource type="Resource" script_class="DialogicCharacter" load_steps=2 format=3 uid="uid://dykf1j17ct5mo"]
|
||||
|
||||
[ext_resource type="Script" path="res://addons/dialogic/Resources/character.gd" id="1_qsljv"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_qsljv")
|
||||
display_name = "Preview"
|
||||
nicknames = [""]
|
||||
color = Color(1, 1, 1, 1)
|
||||
description = ""
|
||||
scale = 1.0
|
||||
offset = Vector2(0, 0)
|
||||
mirror = false
|
||||
default_portrait = "character"
|
||||
portraits = {
|
||||
"character": {
|
||||
"image": "res://addons/dialogic/Editor/Images/preview_character.png",
|
||||
"offset": Vector2(0, 0),
|
||||
"scene": "res://addons/dialogic/Modules/Character/default_portrait.tscn"
|
||||
},
|
||||
"speaker": {
|
||||
"image": "res://addons/dialogic/Editor/Images/preview_character_speaker.png",
|
||||
"offset": Vector2(0, 0),
|
||||
"scene": "res://addons/dialogic/Modules/Character/default_portrait.tscn"
|
||||
}
|
||||
}
|
||||
custom_info = {
|
||||
"sound_mood_default": "",
|
||||
"sound_moods": {},
|
||||
"style": ""
|
||||
}
|
||||
metadata/timeline_not_saved = true
|
||||
92
addons/dialogic/Modules/Character/settings_portraits.gd
Normal file
@@ -0,0 +1,92 @@
|
||||
@tool
|
||||
extends DialogicSettingsPage
|
||||
|
||||
|
||||
const POSITION_SUGGESTION_KEY := 'dialogic/portraits/position_suggestion_names'
|
||||
|
||||
const DEFAULT_PORTRAIT_SCENE_KEY := 'dialogic/portraits/default_portrait'
|
||||
|
||||
const ANIMATION_JOIN_DEFAULT_KEY := 'dialogic/animations/join_default'
|
||||
const ANIMATION_JOIN_DEFAULT_LENGTH_KEY := 'dialogic/animations/join_default_length'
|
||||
const ANIMATION_JOIN_DEFAULT_WAIT_KEY := 'dialogic/animations/join_default_wait'
|
||||
const ANIMATION_LEAVE_DEFAULT_KEY := 'dialogic/animations/leave_default'
|
||||
const ANIMATION_LEAVE_DEFAULT_LENGTH_KEY := 'dialogic/animations/leave_default_length'
|
||||
const ANIMATION_LEAVE_DEFAULT_WAIT_KEY := 'dialogic/animations/leave_default_wait'
|
||||
const ANIMATION_CROSSFADE_DEFAULT_KEY := 'dialogic/animations/cross_fade_default'
|
||||
const ANIMATION_CROSSFADE_DEFAULT_LENGTH_KEY:= 'dialogic/animations/cross_fade_default_length'
|
||||
|
||||
|
||||
func _ready():
|
||||
%JoinDefault.get_suggestions_func = get_join_animation_suggestions
|
||||
%JoinDefault.mode = 1
|
||||
%LeaveDefault.get_suggestions_func = get_leave_animation_suggestions
|
||||
%LeaveDefault.mode = 1
|
||||
%CrossFadeDefault.get_suggestions_func = get_crossfade_animation_suggestions
|
||||
%CrossFadeDefault.mode = 1
|
||||
|
||||
%PositionSuggestions.text_submitted.connect(save_setting.bind(POSITION_SUGGESTION_KEY))
|
||||
%CustomPortraitScene.value_changed.connect(save_setting_with_name.bind(DEFAULT_PORTRAIT_SCENE_KEY))
|
||||
|
||||
%JoinDefault.value_changed.connect(
|
||||
save_setting_with_name.bind(ANIMATION_JOIN_DEFAULT_KEY))
|
||||
%JoinDefaultLength.value_changed.connect(
|
||||
save_setting.bind(ANIMATION_JOIN_DEFAULT_LENGTH_KEY))
|
||||
%JoinDefaultWait.toggled.connect(
|
||||
save_setting.bind(ANIMATION_JOIN_DEFAULT_WAIT_KEY))
|
||||
|
||||
%LeaveDefault.value_changed.connect(
|
||||
save_setting_with_name.bind(ANIMATION_LEAVE_DEFAULT_KEY))
|
||||
%LeaveDefaultLength.value_changed.connect(
|
||||
save_setting.bind(ANIMATION_LEAVE_DEFAULT_LENGTH_KEY))
|
||||
%LeaveDefaultWait.toggled.connect(
|
||||
save_setting.bind(ANIMATION_LEAVE_DEFAULT_WAIT_KEY))
|
||||
|
||||
%CrossFadeDefault.value_changed.connect(
|
||||
save_setting_with_name.bind(ANIMATION_CROSSFADE_DEFAULT_KEY))
|
||||
%CrossFadeDefaultLength.value_changed.connect(
|
||||
save_setting.bind(ANIMATION_CROSSFADE_DEFAULT_LENGTH_KEY))
|
||||
|
||||
|
||||
func _refresh():
|
||||
%PositionSuggestions.text = ProjectSettings.get_setting(POSITION_SUGGESTION_KEY, 'leftmost, left, center, right, rightmost')
|
||||
|
||||
%CustomPortraitScene.resource_icon = get_theme_icon(&"PackedScene", &"EditorIcons")
|
||||
%CustomPortraitScene.set_value(ProjectSettings.get_setting(DEFAULT_PORTRAIT_SCENE_KEY, ''))
|
||||
|
||||
# JOIN
|
||||
%JoinDefault.resource_icon = get_theme_icon(&"Animation", &"EditorIcons")
|
||||
%JoinDefault.set_value(ProjectSettings.get_setting(ANIMATION_JOIN_DEFAULT_KEY, "Fade In Up"))
|
||||
%JoinDefaultLength.set_value(ProjectSettings.get_setting(ANIMATION_JOIN_DEFAULT_LENGTH_KEY, 0.5))
|
||||
%JoinDefaultWait.button_pressed = ProjectSettings.get_setting(ANIMATION_JOIN_DEFAULT_WAIT_KEY, true)
|
||||
|
||||
# LEAVE
|
||||
%LeaveDefault.resource_icon = get_theme_icon(&"Animation", &"EditorIcons")
|
||||
%LeaveDefault.set_value(ProjectSettings.get_setting(ANIMATION_LEAVE_DEFAULT_KEY, "Fade Out Down"))
|
||||
%LeaveDefaultLength.set_value(ProjectSettings.get_setting(ANIMATION_LEAVE_DEFAULT_LENGTH_KEY, 0.5))
|
||||
%LeaveDefaultWait.button_pressed = ProjectSettings.get_setting(ANIMATION_LEAVE_DEFAULT_WAIT_KEY, true)
|
||||
|
||||
# CROSS FADE
|
||||
%CrossFadeDefault.resource_icon = get_theme_icon(&"Animation", &"EditorIcons")
|
||||
%CrossFadeDefault.set_value(ProjectSettings.get_setting(ANIMATION_CROSSFADE_DEFAULT_KEY, "Fade Cross"))
|
||||
%CrossFadeDefaultLength.set_value(ProjectSettings.get_setting(ANIMATION_CROSSFADE_DEFAULT_LENGTH_KEY, 0.5))
|
||||
|
||||
|
||||
func save_setting_with_name(property_name:String, value:Variant, settings_key:String) -> void:
|
||||
save_setting(value, settings_key)
|
||||
|
||||
|
||||
func save_setting(value:Variant, settings_key:String) -> void:
|
||||
ProjectSettings.set_setting(settings_key, value)
|
||||
ProjectSettings.save()
|
||||
|
||||
|
||||
func get_join_animation_suggestions(search_text:String) -> Dictionary:
|
||||
return DialogicPortraitAnimationUtil.get_suggestions(search_text, %JoinDefault.current_value, "", DialogicPortraitAnimationUtil.AnimationType.IN)
|
||||
|
||||
|
||||
func get_leave_animation_suggestions(search_text:String) -> Dictionary:
|
||||
return DialogicPortraitAnimationUtil.get_suggestions(search_text, %LeaveDefault.current_value, "", DialogicPortraitAnimationUtil.AnimationType.OUT)
|
||||
|
||||
|
||||
func get_crossfade_animation_suggestions(search_text:String) -> Dictionary:
|
||||
return DialogicPortraitAnimationUtil.get_suggestions(search_text, %CrossFadeDefault.current_value, "", DialogicPortraitAnimationUtil.AnimationType.CROSSFADE)
|
||||
@@ -0,0 +1 @@
|
||||
uid://d0gwrct1glpjy
|
||||
160
addons/dialogic/Modules/Character/settings_portraits.tscn
Normal file
@@ -0,0 +1,160 @@
|
||||
[gd_scene load_steps=5 format=3 uid="uid://cp463rpri5j8a"]
|
||||
|
||||
[ext_resource type="Script" path="res://addons/dialogic/Modules/Character/settings_portraits.gd" id="2"]
|
||||
[ext_resource type="PackedScene" uid="uid://dbpkta2tjsqim" path="res://addons/dialogic/Editor/Common/hint_tooltip_icon.tscn" id="2_dce78"]
|
||||
[ext_resource type="PackedScene" uid="uid://dpwhshre1n4t6" path="res://addons/dialogic/Editor/Events/Fields/field_options_dynamic.tscn" id="3"]
|
||||
[ext_resource type="PackedScene" uid="uid://7mvxuaulctcq" path="res://addons/dialogic/Editor/Events/Fields/field_file.tscn" id="3_m06d8"]
|
||||
|
||||
[node name="Portraits" type="VBoxContainer"]
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
script = ExtResource("2")
|
||||
|
||||
[node name="PositionsTitle" type="HBoxContainer" parent="."]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_stretch_ratio = 0.5
|
||||
|
||||
[node name="Title2" type="Label" parent="PositionsTitle"]
|
||||
layout_mode = 2
|
||||
theme_type_variation = &"DialogicSettingsSection"
|
||||
text = "Position Suggestions
|
||||
"
|
||||
|
||||
[node name="HintTooltip" parent="PositionsTitle" instance=ExtResource("2_dce78")]
|
||||
layout_mode = 2
|
||||
tooltip_text = "You can change the position names that will be suggested in the timeline editor here."
|
||||
texture = null
|
||||
hint_text = "You can change the position names that will be suggested in the timeline editor here."
|
||||
|
||||
[node name="PositionSuggestions" type="LineEdit" parent="."]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
|
||||
[node name="DefaultSceneTitle" type="HBoxContainer" parent="."]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_stretch_ratio = 0.5
|
||||
|
||||
[node name="Title2" type="Label" parent="DefaultSceneTitle"]
|
||||
layout_mode = 2
|
||||
theme_type_variation = &"DialogicSettingsSection"
|
||||
text = "Default Portrait Scene
|
||||
"
|
||||
|
||||
[node name="HintTooltip" parent="DefaultSceneTitle" instance=ExtResource("2_dce78")]
|
||||
layout_mode = 2
|
||||
tooltip_text = "If this is set, this scene will be what is used by default for any portrait that has no scene specified"
|
||||
texture = null
|
||||
hint_text = "If this is set, this scene will be what is used by default for any portrait that has no scene specified"
|
||||
|
||||
[node name="DefaultScene" type="HBoxContainer" parent="."]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label" type="Label" parent="DefaultScene"]
|
||||
layout_mode = 2
|
||||
text = "Scene"
|
||||
|
||||
[node name="CustomPortraitScene" parent="DefaultScene" instance=ExtResource("3_m06d8")]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
file_filter = "*.tscn, *.scn; PortraitScene"
|
||||
placeholder = "Default Scene"
|
||||
|
||||
[node name="Animations2" type="HBoxContainer" parent="."]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_stretch_ratio = 0.5
|
||||
|
||||
[node name="Title2" type="Label" parent="Animations2"]
|
||||
layout_mode = 2
|
||||
theme_type_variation = &"DialogicSettingsSection"
|
||||
text = "Default Animations
|
||||
"
|
||||
|
||||
[node name="HintTooltip" parent="Animations2" instance=ExtResource("2_dce78")]
|
||||
layout_mode = 2
|
||||
tooltip_text = "These settings are used for Leave and Join events if no animation is selected.
|
||||
|
||||
The Cross-Fade will play if the portrait of a character changes and
|
||||
no animation is set."
|
||||
texture = null
|
||||
hint_text = "These settings are used for Leave and Join events if no animation is selected.
|
||||
|
||||
The Cross-Fade will play if the portrait of a character changes and
|
||||
no animation is set."
|
||||
|
||||
[node name="GridContainer" type="GridContainer" parent="."]
|
||||
layout_mode = 2
|
||||
columns = 2
|
||||
|
||||
[node name="DefaultJoinLabel" type="Label" parent="GridContainer"]
|
||||
layout_mode = 2
|
||||
text = "Join"
|
||||
|
||||
[node name="DefaultIn" type="HBoxContainer" parent="GridContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="JoinDefault" parent="GridContainer/DefaultIn" instance=ExtResource("3")]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
mode = 1
|
||||
|
||||
[node name="JoinDefaultLength" type="SpinBox" parent="GridContainer/DefaultIn"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
step = 0.1
|
||||
|
||||
[node name="JoinDefaultWait" type="CheckButton" parent="GridContainer/DefaultIn"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = "Wait:"
|
||||
|
||||
[node name="DefaultOutLabel" type="Label" parent="GridContainer"]
|
||||
layout_mode = 2
|
||||
text = "Leave"
|
||||
|
||||
[node name="DefaultOut" type="HBoxContainer" parent="GridContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="LeaveDefault" parent="GridContainer/DefaultOut" instance=ExtResource("3")]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
mode = 1
|
||||
|
||||
[node name="LeaveDefaultLength" type="SpinBox" parent="GridContainer/DefaultOut"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
step = 0.1
|
||||
|
||||
[node name="LeaveDefaultWait" type="CheckButton" parent="GridContainer/DefaultOut"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = "Wait:"
|
||||
|
||||
[node name="CrossFadeLabel" type="Label" parent="GridContainer"]
|
||||
layout_mode = 2
|
||||
text = "Cross-Fade"
|
||||
|
||||
[node name="DefaultCrossFade" type="HBoxContainer" parent="GridContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="CrossFadeDefault" parent="GridContainer/DefaultCrossFade" instance=ExtResource("3")]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
mode = 1
|
||||
|
||||
[node name="CrossFadeDefaultLength" type="SpinBox" parent="GridContainer/DefaultCrossFade"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
step = 0.1
|
||||
|
||||
[connection signal="value_changed" from="GridContainer/DefaultIn/JoinDefault" to="." method="_on_JoinDefault_value_changed"]
|
||||
[connection signal="value_changed" from="GridContainer/DefaultIn/JoinDefaultLength" to="." method="_on_JoinDefaultLength_value_changed"]
|
||||
[connection signal="toggled" from="GridContainer/DefaultIn/JoinDefaultWait" to="." method="_on_JoinDefaultWait_toggled"]
|
||||
[connection signal="value_changed" from="GridContainer/DefaultOut/LeaveDefault" to="." method="_on_LeaveDefault_value_changed"]
|
||||
[connection signal="value_changed" from="GridContainer/DefaultOut/LeaveDefaultLength" to="." method="_on_LeaveDefaultLength_value_changed"]
|
||||
[connection signal="toggled" from="GridContainer/DefaultOut/LeaveDefaultWait" to="." method="_on_LeaveDefaultWait_toggled"]
|
||||
[connection signal="value_changed" from="GridContainer/DefaultCrossFade/CrossFadeDefault" to="." method="_on_LeaveDefault_value_changed"]
|
||||
[connection signal="value_changed" from="GridContainer/DefaultCrossFade/CrossFadeDefaultLength" to="." method="_on_LeaveDefaultLength_value_changed"]
|
||||
|
After Width: | Height: | Size: 3.4 KiB |
@@ -0,0 +1,40 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://qihj11n7kx3m"
|
||||
path="res://.godot/imported/simple_image_portrait_thumbnail.png-3d6c6de8187fd7911017e2ef9d3c40a4.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/dialogic/Modules/Character/simple_image_portrait_thumbnail.png"
|
||||
dest_files=["res://.godot/imported/simple_image_portrait_thumbnail.png-3d6c6de8187fd7911017e2ef9d3c40a4.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
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/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
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
|
||||
284
addons/dialogic/Modules/Character/subsystem_containers.gd
Normal file
@@ -0,0 +1,284 @@
|
||||
extends DialogicSubsystem
|
||||
|
||||
## Subsystem that manages portrait positions.
|
||||
|
||||
signal position_changed(info: Dictionary)
|
||||
|
||||
|
||||
var transform_regex := r"(?<part>position|pos|size|siz|rotation|rot)\W*=(?<value>((?!(pos|siz|rot)).)*)"
|
||||
|
||||
#region STATE
|
||||
####################################################################################################
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region MAIN METHODS
|
||||
####################################################################################################
|
||||
|
||||
func get_container(position_id: String) -> DialogicNode_PortraitContainer:
|
||||
for portrait_position:DialogicNode_PortraitContainer in get_tree().get_nodes_in_group(&'dialogic_portrait_con_position'):
|
||||
if portrait_position.is_visible_in_tree() and portrait_position.is_container(position_id):
|
||||
return portrait_position
|
||||
return null
|
||||
|
||||
|
||||
func get_containers(position_id: String) -> Array[DialogicNode_PortraitContainer]:
|
||||
return get_tree().get_nodes_in_group(&'dialogic_portrait_con_position').filter(
|
||||
func(node:DialogicNode_PortraitContainer):
|
||||
return node.is_visible_in_tree() and node.is_container(position_id))
|
||||
|
||||
|
||||
func get_container_container() -> CanvasItem:
|
||||
var any_portrait_container := get_tree().get_first_node_in_group(&'dialogic_portrait_con_position')
|
||||
if any_portrait_container:
|
||||
return any_portrait_container.get_parent()
|
||||
return null
|
||||
|
||||
|
||||
## Creates a new portrait container node.
|
||||
## It will copy it's size and most settings from the first p_container in the tree.
|
||||
## It will be added as a sibling of the first p_container in the tree.
|
||||
func add_container(position_id: String) -> DialogicNode_PortraitContainer:
|
||||
var example_position := get_tree().get_first_node_in_group(&'dialogic_portrait_con_position')
|
||||
if example_position:
|
||||
var new_position := DialogicNode_PortraitContainer.new()
|
||||
example_position.get_parent().add_child(new_position)
|
||||
new_position.name = "Portrait_"+position_id.validate_node_name()
|
||||
copy_container_setup(example_position, new_position)
|
||||
new_position.container_ids = [position_id]
|
||||
position_changed.emit({&'change':'added', &'container_node':new_position, &'position_id':position_id})
|
||||
return new_position
|
||||
return null
|
||||
|
||||
|
||||
## Moves the [container] to the [destionation] (using [tween] and [time]).
|
||||
## The destination can be a position_id (e.g. "center") or translation, roataion and scale.
|
||||
## When moving to a preset container, then some more will be "copied" (e.g. anchors, etc.)
|
||||
func move_container(container:DialogicNode_PortraitContainer, destination:String, tween:Tween = null, time:float=1.0) -> void:
|
||||
var target_position: Vector2 = container.position + container._get_origin_position()
|
||||
var target_rotation: float = container.rotation
|
||||
var target_size: Vector2 = container.size
|
||||
|
||||
var destination_container := get_container(destination)
|
||||
if destination_container:
|
||||
container.set_meta("target_container", destination_container)
|
||||
target_position = destination_container.position + destination_container._get_origin_position()
|
||||
target_rotation = destination_container.rotation_degrees
|
||||
target_size = destination_container.size
|
||||
else:
|
||||
var regex := RegEx.create_from_string(transform_regex)
|
||||
for found in regex.search_all(destination):
|
||||
match found.get_string('part'):
|
||||
'pos', 'position':
|
||||
target_position = str_to_vector(found.get_string("value"), target_position)
|
||||
'rot', 'rotation':
|
||||
target_rotation = float(found.get_string("value"))
|
||||
'siz', 'size':
|
||||
target_size = str_to_vector(found.get_string("value"), target_size)
|
||||
|
||||
translate_container(container, target_position, false, tween, time)
|
||||
rotate_container(container, target_rotation, false, tween, time)
|
||||
resize_container(container, target_size, false, tween, time)
|
||||
|
||||
if destination_container:
|
||||
if time:
|
||||
tween.finished.connect(func():
|
||||
if container.has_meta("target_container"):
|
||||
if container.get_meta("target_container") == destination_container:
|
||||
copy_container_setup(destination_container, container)
|
||||
)
|
||||
else:
|
||||
copy_container_setup(destination_container, container)
|
||||
|
||||
|
||||
func copy_container_setup(from:DialogicNode_PortraitContainer, to:DialogicNode_PortraitContainer) -> void:
|
||||
to.ignore_resize = true
|
||||
to.layout_mode = from.layout_mode
|
||||
to.anchors_preset = from.anchors_preset
|
||||
to.anchor_bottom = from.anchor_bottom
|
||||
to.anchor_left = from.anchor_left
|
||||
to.anchor_right = from.anchor_right
|
||||
to.anchor_top = from.anchor_top
|
||||
to.offset_bottom = from.offset_bottom
|
||||
to.offset_top = from.offset_top
|
||||
to.offset_right = from.offset_right
|
||||
to.offset_left = from.offset_left
|
||||
to.size_mode = from.size_mode
|
||||
to.origin_anchor = from.origin_anchor
|
||||
to.ignore_resize = false
|
||||
to.update_portrait_transforms()
|
||||
|
||||
|
||||
## Translates the given container.
|
||||
## The given translation should be the target position of the ORIGIN point, not the container!
|
||||
func translate_container(container:DialogicNode_PortraitContainer, translation:Variant, relative := false, tween:Tween=null, time:float=1.0) -> void:
|
||||
if !container.has_meta(&'default_translation'):
|
||||
container.set_meta(&'default_translation', container.position + container._get_origin_position())
|
||||
|
||||
var final_translation: Vector2
|
||||
if typeof(translation) == TYPE_STRING:
|
||||
final_translation = str_to_vector(translation, container.position+container._get_origin_position())
|
||||
elif typeof(translation) == TYPE_VECTOR2:
|
||||
final_translation = translation
|
||||
|
||||
if relative:
|
||||
final_translation += container.position
|
||||
else:
|
||||
final_translation -= container._get_origin_position()
|
||||
|
||||
if tween:
|
||||
tween.tween_method(DialogicUtil.multitween.bind(container, "position", "base"), container.position, final_translation, time)
|
||||
if not tween.finished.is_connected(save_position_container):
|
||||
tween.finished.connect(save_position_container.bind(container))
|
||||
else:
|
||||
container.position = final_translation
|
||||
save_position_container(container)
|
||||
position_changed.emit({&'change':'moved', &'container_node':container})
|
||||
|
||||
|
||||
func rotate_container(container:DialogicNode_PortraitContainer, rotation:float, relative := false, tween:Tween=null, time:float=1.0) -> void:
|
||||
if !container.has_meta(&'default_rotation'):
|
||||
container.set_meta(&'default_rotation', container.rotation_degrees)
|
||||
|
||||
var final_rotation := rotation
|
||||
|
||||
if relative:
|
||||
final_rotation += container.rotation_degrees
|
||||
|
||||
container.pivot_offset = container._get_origin_position()
|
||||
|
||||
if tween:
|
||||
tween.tween_property(container, 'rotation_degrees', final_rotation, time)
|
||||
if not tween.finished.is_connected(save_position_container):
|
||||
tween.finished.connect(save_position_container.bind(container))
|
||||
else:
|
||||
container.rotation_degrees = final_rotation
|
||||
save_position_container(container)
|
||||
|
||||
position_changed.emit({&'change':'rotated', &'container_node':container})
|
||||
|
||||
|
||||
func resize_container(container: DialogicNode_PortraitContainer, rect_size: Variant, relative := false, tween:Tween=null, time:float=1.0) -> void:
|
||||
if !container.has_meta(&'default_size'):
|
||||
container.set_meta(&'default_size', container.size)
|
||||
|
||||
var final_rect_resize: Vector2
|
||||
if typeof(rect_size) == TYPE_STRING:
|
||||
final_rect_resize = str_to_vector(rect_size, container.size)
|
||||
elif typeof(rect_size) == TYPE_VECTOR2:
|
||||
final_rect_resize = rect_size
|
||||
|
||||
if relative:
|
||||
final_rect_resize += container.rect_size
|
||||
|
||||
var relative_position_change := container._get_origin_position()-container._get_origin_position(final_rect_resize)
|
||||
|
||||
if tween:
|
||||
tween.tween_method(DialogicUtil.multitween.bind(container, "position", "resize_move"), Vector2(), relative_position_change, time)
|
||||
tween.tween_property(container, 'size', final_rect_resize, time)
|
||||
if not tween.finished.is_connected(save_position_container):
|
||||
tween.finished.connect(save_position_container.bind(container))
|
||||
else:
|
||||
container.position = container.position + relative_position_change
|
||||
container.size = final_rect_resize
|
||||
save_position_container(container)
|
||||
|
||||
position_changed.emit({&'change':'resized', &'container_node':container})
|
||||
|
||||
|
||||
func save_position_container(container: DialogicNode_PortraitContainer) -> void:
|
||||
if not dialogic.current_state_info.has('portrait_containers'):
|
||||
dialogic.current_state_info['portrait_containers'] = {}
|
||||
|
||||
var info := {
|
||||
"container_ids" : container.container_ids,
|
||||
"position" : container.position,
|
||||
"rotation" : container.rotation_degrees,
|
||||
"size" : container.size,
|
||||
"pivot_mode" : container.pivot_mode,
|
||||
"pivot_value" : container.pivot_value,
|
||||
"origin_anchor" : container.origin_anchor,
|
||||
"anchor_left" : container.anchor_left,
|
||||
"anchor_right" : container.anchor_right,
|
||||
"anchor_top" : container.anchor_top,
|
||||
"anchor_bottom" : container.anchor_bottom,
|
||||
"offset_left" : container.offset_left,
|
||||
"offset_right" : container.offset_right,
|
||||
"offset_top" : container.offset_top,
|
||||
"offset_bottom" : container.offset_bottom,
|
||||
}
|
||||
|
||||
dialogic.current_state_info.portrait_containers[container.container_ids[0]] = info
|
||||
|
||||
|
||||
func load_position_container(position_id: String) -> DialogicNode_PortraitContainer:
|
||||
# First check whether the container already exists:
|
||||
var container := get_container(position_id)
|
||||
if container:
|
||||
return container
|
||||
|
||||
if not dialogic.current_state_info.has('portrait_containers') or not dialogic.current_state_info.portrait_containers.has(position_id):
|
||||
return null
|
||||
|
||||
var info: Dictionary = dialogic.current_state_info.portrait_containers[position_id]
|
||||
container = add_container(position_id)
|
||||
|
||||
if not container:
|
||||
return null
|
||||
|
||||
container.container_ids = info.container_ids
|
||||
container.position = info.position
|
||||
container.rotation = info.rotation
|
||||
container.size = info.size
|
||||
container.pivot_mode = info.pivot_mode
|
||||
container.pivot_value = info.pivot_value
|
||||
container.origin_anchor = info.origin_anchor
|
||||
container.anchor_left = info.anchor_left
|
||||
container.anchor_right = info.anchor_right
|
||||
container.anchor_top = info.anchor_top
|
||||
container.anchor_bottom = info.anchor_bottom
|
||||
container.offset_left = info.offset_left
|
||||
container.offset_right = info.offset_right
|
||||
container.offset_top = info.offset_top
|
||||
container.offset_bottom = info.offset_bottom
|
||||
|
||||
return container
|
||||
|
||||
|
||||
func str_to_vector(input: String, base_vector:=Vector2()) -> Vector2:
|
||||
var vector_regex := RegEx.create_from_string(r"(?<part>x|y)\s*(?<number>(-|\+)?(\d|\.|)*)(\s*(?<type>%|px))?")
|
||||
var vec := base_vector
|
||||
for i in vector_regex.search_all(input):
|
||||
var value := float(i.get_string(&'number'))
|
||||
match i.get_string(&'type'):
|
||||
'px':
|
||||
pass # Keep values as they are
|
||||
'%', _:
|
||||
match i.get_string(&'part'):
|
||||
'x': value *= get_viewport().get_visible_rect().size.x
|
||||
'y': value *= get_viewport().get_visible_rect().size.y
|
||||
|
||||
match i.get_string(&'part'):
|
||||
'x': vec.x = value
|
||||
'y': vec.y = value
|
||||
return vec
|
||||
|
||||
|
||||
func vector_to_str(vec:Vector2) -> String:
|
||||
return "x" + str(vec.x) + "px y" + str(vec.y) + "px"
|
||||
|
||||
|
||||
func reset_all_containers(time:= 0.0, tween:Tween = null) -> void:
|
||||
for container in get_tree().get_nodes_in_group(&'dialogic_portrait_con_position'):
|
||||
reset_container(container, time, tween)
|
||||
|
||||
|
||||
func reset_container(container:DialogicNode_PortraitContainer, time := 0.0, tween: Tween = null ) -> void:
|
||||
if container.has_meta(&'default_translation'):
|
||||
translate_container(container, vector_to_str(container.get_meta(&'default_translation')), false, tween, time)
|
||||
if container.has_meta(&'default_rotation'):
|
||||
rotate_container(container, container.get_meta(&'default_rotation'), false, tween, time)
|
||||
if container.has_meta(&'default_size'):
|
||||
resize_container(container, vector_to_str(container.get_meta(&'default_size')), false, tween, time)
|
||||
@@ -0,0 +1 @@
|
||||
uid://j0oftc7hmr6v
|
||||
714
addons/dialogic/Modules/Character/subsystem_portraits.gd
Normal file
@@ -0,0 +1,714 @@
|
||||
extends DialogicSubsystem
|
||||
|
||||
## Subsystem that manages portraits and portrait positions.
|
||||
|
||||
signal character_joined(info:Dictionary)
|
||||
signal character_left(info:Dictionary)
|
||||
signal character_portrait_changed(info:Dictionary)
|
||||
signal character_moved(info:Dictionary)
|
||||
|
||||
## Emitted when a portrait starts animating.
|
||||
#signal portrait_animating(character_node: Node, portrait_node: Node, animation_name: String, animation_length: float)
|
||||
|
||||
|
||||
## The default portrait scene.
|
||||
var default_portrait_scene: PackedScene = load(get_script().resource_path.get_base_dir().path_join('default_portrait.tscn'))
|
||||
|
||||
|
||||
#region STATE
|
||||
####################################################################################################
|
||||
|
||||
func clear_game_state(_clear_flag:=DialogicGameHandler.ClearFlags.FULL_CLEAR) -> void:
|
||||
for character in dialogic.current_state_info.get('portraits', {}).keys():
|
||||
remove_character(load(character))
|
||||
dialogic.current_state_info['portraits'] = {}
|
||||
|
||||
|
||||
func load_game_state(_load_flag:=LoadFlags.FULL_LOAD) -> void:
|
||||
if not "portraits" in dialogic.current_state_info:
|
||||
dialogic.current_state_info["portraits"] = {}
|
||||
|
||||
# Load Position Portraits
|
||||
var portraits_info: Dictionary = dialogic.current_state_info.portraits.duplicate()
|
||||
dialogic.current_state_info.portraits = {}
|
||||
for character_path in portraits_info:
|
||||
var character_info: Dictionary = portraits_info[character_path]
|
||||
var character: DialogicCharacter = load(character_path)
|
||||
var container := dialogic.PortraitContainers.load_position_container(character.get_character_name())
|
||||
add_character(character, container, character_info.portrait, character_info.position_id)
|
||||
change_character_mirror(character, character_info.get('custom_mirror', false))
|
||||
change_character_z_index(character, character_info.get('z_index', 0))
|
||||
change_character_extradata(character, character_info.get('extra_data', ""))
|
||||
|
||||
# Load Speaker Portrait
|
||||
var speaker: Variant = dialogic.current_state_info.get('speaker', "")
|
||||
if speaker:
|
||||
dialogic.current_state_info['speaker'] = ""
|
||||
change_speaker(load(speaker))
|
||||
dialogic.current_state_info['speaker'] = speaker
|
||||
|
||||
|
||||
func pause() -> void:
|
||||
for portrait in dialogic.current_state_info['portraits'].values():
|
||||
if portrait.node.has_meta('animation_node'):
|
||||
portrait.node.get_meta('animation_node').pause()
|
||||
|
||||
|
||||
func resume() -> void:
|
||||
for portrait in dialogic.current_state_info['portraits'].values():
|
||||
if portrait.node.has_meta('animation_node'):
|
||||
portrait.node.get_meta('animation_node').resume()
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
if !ProjectSettings.get_setting('dialogic/portraits/default_portrait', '').is_empty():
|
||||
default_portrait_scene = load(ProjectSettings.get_setting('dialogic/portraits/default_portrait', ''))
|
||||
|
||||
|
||||
#region MAIN METHODS
|
||||
####################################################################################################
|
||||
## The following methods allow manipulating portraits.
|
||||
## A portrait is made up of a character node [Node2D] that instances the portrait scene as it's child.
|
||||
## The character node is then always the child of a portrait container.
|
||||
## - Position (PortraitContainer)
|
||||
## ---- character_node (Node2D)
|
||||
## --------- portrait_node (e.g. default_portrait.tscn, or a custom portrait)
|
||||
##
|
||||
## Using these main methods a character can be present multiple times.
|
||||
## For a VN style, the "character" methods (next section) provide access based on the character.
|
||||
## - (That is what the character event uses)
|
||||
|
||||
|
||||
## Creates a new [character node] for the given [character], and add it to the given [portrait container].
|
||||
func _create_character_node(character:DialogicCharacter, container:DialogicNode_PortraitContainer) -> Node:
|
||||
if container == null:
|
||||
return null
|
||||
var character_node := Node2D.new()
|
||||
character_node.name = character.get_character_name()
|
||||
character_node.set_meta('character', character)
|
||||
container.add_child(character_node)
|
||||
return character_node
|
||||
|
||||
|
||||
## Changes the portrait of a specific [character node].
|
||||
func _change_portrait(character_node: Node2D, portrait: String, fade_animation:="", fade_length := 0.5) -> Dictionary:
|
||||
var character: DialogicCharacter = character_node.get_meta('character')
|
||||
|
||||
if portrait.is_empty():
|
||||
portrait = character.default_portrait
|
||||
|
||||
var info := {'character':character, 'portrait':portrait, 'same_scene':false}
|
||||
|
||||
if not portrait in character.portraits.keys():
|
||||
print_debug('[Dialogic] Change to not-existing portrait will be ignored!')
|
||||
return info
|
||||
|
||||
# Path to the scene to use.
|
||||
var scene_path: String = character.portraits[portrait].get('scene', '')
|
||||
|
||||
var portrait_node: Node = null
|
||||
var previous_portrait: Node = null
|
||||
var portrait_count := character_node.get_child_count()
|
||||
|
||||
if portrait_count > 0:
|
||||
previous_portrait = character_node.get_child(-1)
|
||||
|
||||
# Check if the scene is the same as the currently loaded scene.
|
||||
if (not previous_portrait == null and
|
||||
previous_portrait.get_meta('scene', '') == scene_path and
|
||||
# Also check if the scene supports changing to the given portrait.
|
||||
previous_portrait._should_do_portrait_update(character, portrait)):
|
||||
portrait_node = previous_portrait
|
||||
info['same_scene'] = true
|
||||
|
||||
else:
|
||||
|
||||
if ResourceLoader.exists(scene_path):
|
||||
var packed_scene: PackedScene = load(scene_path)
|
||||
|
||||
if packed_scene:
|
||||
portrait_node = packed_scene.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. Confirm the path is correct.')
|
||||
|
||||
if !portrait_node:
|
||||
portrait_node = default_portrait_scene.instantiate()
|
||||
|
||||
portrait_node.set_meta('scene', scene_path)
|
||||
|
||||
|
||||
if portrait_node:
|
||||
portrait_node.set_meta('portrait', portrait)
|
||||
character_node.set_meta('portrait', portrait)
|
||||
|
||||
DialogicUtil.apply_scene_export_overrides(portrait_node, character.portraits[portrait].get('export_overrides', {}))
|
||||
|
||||
if portrait_node.has_method('_update_portrait'):
|
||||
portrait_node._update_portrait(character, portrait)
|
||||
|
||||
if not portrait_node.is_inside_tree():
|
||||
character_node.add_child(portrait_node)
|
||||
|
||||
_update_portrait_transform(portrait_node)
|
||||
|
||||
## Handle Cross-Animating
|
||||
if previous_portrait and previous_portrait != portrait_node:
|
||||
if not fade_animation.is_empty() and fade_length > 0:
|
||||
var fade_out := _animate_node(previous_portrait, fade_animation, fade_length, 1, true)
|
||||
var _fade_in := _animate_node(portrait_node, fade_animation, fade_length, 1, false)
|
||||
fade_out.finished.connect(previous_portrait.queue_free)
|
||||
else:
|
||||
previous_portrait.queue_free()
|
||||
|
||||
return info
|
||||
|
||||
|
||||
## Changes the mirroring of the given portrait.
|
||||
## Unless @force is false, this will take into consideration the character mirror,
|
||||
## portrait mirror and portrait position mirror settings.
|
||||
func _change_portrait_mirror(character_node: Node2D, mirrored := false, force := false) -> void:
|
||||
var latest_portrait := character_node.get_child(-1)
|
||||
|
||||
if latest_portrait.has_method('_set_mirror'):
|
||||
var character: DialogicCharacter = character_node.get_meta('character')
|
||||
var current_portrait_info := character.get_portrait_info(character_node.get_meta('portrait'))
|
||||
latest_portrait._set_mirror(force or (mirrored != character.mirror != character_node.get_parent().mirrored != current_portrait_info.get('mirror', false)))
|
||||
|
||||
|
||||
func _change_portrait_extradata(character_node: Node2D, extra_data := "") -> void:
|
||||
var latest_portrait := character_node.get_child(-1)
|
||||
|
||||
if latest_portrait.has_method('_set_extra_data'):
|
||||
latest_portrait._set_extra_data(extra_data)
|
||||
|
||||
|
||||
func _update_character_transform(character_node:Node, time := 0.0) -> void:
|
||||
for child in character_node.get_children():
|
||||
_update_portrait_transform(child, time)
|
||||
|
||||
|
||||
func _update_portrait_transform(portrait_node: Node, time:float = 0.0) -> void:
|
||||
var character_node: Node = portrait_node.get_parent()
|
||||
|
||||
var character: DialogicCharacter = character_node.get_meta('character')
|
||||
var portrait_info: Dictionary = character.portraits.get(portrait_node.get_meta('portrait'), {})
|
||||
|
||||
# ignore the character scale on custom portraits that have 'ignore_char_scale' set to true
|
||||
var apply_character_scale: bool = not portrait_info.get('ignore_char_scale', false)
|
||||
|
||||
var transform: Rect2 = character_node.get_parent().get_local_portrait_transform(
|
||||
portrait_node._get_covered_rect(),
|
||||
(character.scale * portrait_info.get('scale', 1))*int(apply_character_scale)+portrait_info.get('scale', 1)*int(!apply_character_scale))
|
||||
|
||||
var tween: Tween
|
||||
|
||||
if character_node.has_meta('move_tween'):
|
||||
if character_node.get_meta('move_tween').is_running():
|
||||
time = character_node.get_meta('move_time')-character_node.get_meta('move_tween').get_total_elapsed_time()
|
||||
tween = character_node.get_meta('move_tween')
|
||||
tween.stop()
|
||||
if time == 0:
|
||||
character_node.position = transform.position
|
||||
portrait_node.position = character.offset + portrait_info.get('offset', Vector2())
|
||||
portrait_node.scale = transform.size
|
||||
else:
|
||||
if not tween:
|
||||
tween = character_node.create_tween().set_parallel().set_ease(Tween.EASE_IN_OUT).set_trans(Tween.TRANS_SINE)
|
||||
character_node.set_meta('move_tween', tween)
|
||||
character_node.set_meta('move_time', time)
|
||||
tween.tween_method(DialogicUtil.multitween.bind(character_node, "position", "base"), character_node.position, transform.position, time)
|
||||
tween.tween_property(portrait_node, 'position',character.offset + portrait_info.get('offset', Vector2()), time)
|
||||
tween.tween_property(portrait_node, 'scale', transform.size, time)
|
||||
|
||||
|
||||
## Animates the node with the given animation.
|
||||
## Is used both on the character node (most animations) and the portrait nodes (cross-fade animations)
|
||||
func _animate_node(node: Node, animation_path: String, length: float, repeats := 1, is_reversed := false) -> DialogicAnimation:
|
||||
if node.has_meta('animation_node') and is_instance_valid(node.get_meta('animation_node')):
|
||||
node.get_meta('animation_node').queue_free()
|
||||
|
||||
var anim_script: Script = load(animation_path)
|
||||
var anim_node := Node.new()
|
||||
anim_node.set_script(anim_script)
|
||||
anim_node = (anim_node as DialogicAnimation)
|
||||
anim_node.node = node
|
||||
anim_node.base_position = node.position
|
||||
anim_node.base_scale = node.scale
|
||||
anim_node.time = length
|
||||
anim_node.repeats = repeats
|
||||
anim_node.is_reversed = is_reversed
|
||||
|
||||
add_child(anim_node)
|
||||
anim_node.animate()
|
||||
|
||||
node.set_meta("animation_path", animation_path)
|
||||
node.set_meta("animation_length", length)
|
||||
node.set_meta("animation_node", anim_node)
|
||||
|
||||
#if not is_silent:
|
||||
#portrait_animating.emit(portrait_node.get_parent(), portrait_node, animation_path, length)
|
||||
|
||||
return anim_node
|
||||
|
||||
|
||||
## Moves the given portrait to the given container.
|
||||
func _move_character(character_node: Node2D, transform:="", time := 0.0, easing:= Tween.EASE_IN_OUT, trans:= Tween.TRANS_SINE) -> void:
|
||||
var tween := character_node.create_tween().set_ease(easing).set_trans(trans).set_parallel()
|
||||
if time == 0:
|
||||
tween.kill()
|
||||
tween = null
|
||||
var container: DialogicNode_PortraitContainer = character_node.get_parent()
|
||||
dialogic.PortraitContainers.move_container(container, transform, tween, time)
|
||||
|
||||
for portrait_node in character_node.get_children():
|
||||
_update_portrait_transform(portrait_node, time)
|
||||
|
||||
|
||||
## Changes the given portraits z_index.
|
||||
func _change_portrait_z_index(character_node: Node, z_index:int, update_zindex:= true) -> void:
|
||||
if update_zindex:
|
||||
character_node.get_parent().set_meta('z_index', z_index)
|
||||
|
||||
var sorted_children := character_node.get_parent().get_parent().get_children()
|
||||
sorted_children.sort_custom(z_sort_portrait_containers)
|
||||
var idx := 0
|
||||
for con in sorted_children:
|
||||
con.get_parent().move_child(con, idx)
|
||||
idx += 1
|
||||
|
||||
|
||||
## Checks if [para, character] has joined the scene, if so, returns its
|
||||
## active [DialogicPortrait] node.
|
||||
##
|
||||
## The difference between an active and inactive nodes is whether the node is
|
||||
## the latest node. [br]
|
||||
## If a portrait is fading/animating from portrait A and B, both will exist
|
||||
## in the scene, but only the new portrait is active, even if it is not
|
||||
## fully visible yet.
|
||||
func get_character_portrait(character: DialogicCharacter) -> DialogicPortrait:
|
||||
if is_character_joined(character):
|
||||
var portrait_node: DialogicPortrait = dialogic.current_state_info['portraits'][character.resource_path].node.get_child(-1)
|
||||
return portrait_node
|
||||
|
||||
return null
|
||||
|
||||
|
||||
func z_sort_portrait_containers(con1: DialogicNode_PortraitContainer, con2: DialogicNode_PortraitContainer) -> bool:
|
||||
if con1.get_meta('z_index', 0) < con2.get_meta('z_index', 0):
|
||||
return true
|
||||
|
||||
return false
|
||||
|
||||
|
||||
## Private method to remove a [param portrait_node].
|
||||
func _remove_portrait(portrait_node: Node) -> void:
|
||||
portrait_node.get_parent().remove_child(portrait_node)
|
||||
portrait_node.queue_free()
|
||||
|
||||
|
||||
## Gets the default animation length for joining characters
|
||||
## If Auto-Skip is enabled, limits the time.
|
||||
func _get_join_default_length() -> float:
|
||||
var default_time: float = ProjectSettings.get_setting('dialogic/animations/join_default_length', 0.5)
|
||||
|
||||
if dialogic.Inputs.auto_skip.enabled:
|
||||
default_time = min(default_time, dialogic.Inputs.auto_skip.time_per_event)
|
||||
|
||||
return default_time
|
||||
|
||||
|
||||
## Gets the default animation length for leaving characters
|
||||
## If Auto-Skip is enabled, limits the time.
|
||||
func _get_leave_default_length() -> float:
|
||||
var default_time: float = ProjectSettings.get_setting('dialogic/animations/leave_default_length', 0.5)
|
||||
|
||||
if dialogic.Inputs.auto_skip.enabled:
|
||||
default_time = min(default_time, dialogic.Inputs.auto_skip.time_per_event)
|
||||
|
||||
return default_time
|
||||
|
||||
|
||||
## Checks multiple cases to return a valid portrait to use.
|
||||
func get_valid_portrait(character:DialogicCharacter, portrait:String) -> String:
|
||||
if character == null:
|
||||
printerr('[Dialogic] Tried to use portrait "', portrait, '" on <null> character.')
|
||||
dialogic.print_debug_moment()
|
||||
return ""
|
||||
|
||||
if "{" in portrait and dialogic.has_subsystem("Expressions"):
|
||||
var test: Variant = dialogic.Expressions.execute_string(portrait)
|
||||
if test:
|
||||
portrait = str(test)
|
||||
|
||||
if not portrait in character.portraits:
|
||||
if not portrait.is_empty():
|
||||
printerr('[Dialogic] Tried to use invalid portrait "', portrait, '" on character "', DialogicResourceUtil.get_unique_identifier(character.resource_path), '". Using default portrait instead.')
|
||||
dialogic.print_debug_moment()
|
||||
portrait = character.default_portrait
|
||||
|
||||
if portrait.is_empty():
|
||||
portrait = character.default_portrait
|
||||
|
||||
return portrait
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Character Methods
|
||||
####################################################################################################
|
||||
## The following methods are used to manage character portraits with the following rules:
|
||||
## - a character can only be present once with these methods.
|
||||
## Most of them will fail silently if the character isn't joined yet.
|
||||
|
||||
|
||||
## Adds a character at a position and sets it's portrait.
|
||||
## If the character is already joined it will only update, portrait, position, etc.
|
||||
func join_character(character:DialogicCharacter, portrait:String, position_id:String, mirrored:= false, z_index:= 0, extra_data:= "", animation_name:= "", animation_length:= 0.0, animation_wait := false) -> Node:
|
||||
if is_character_joined(character):
|
||||
change_character_portrait(character, portrait)
|
||||
|
||||
if animation_name.is_empty():
|
||||
animation_length = _get_join_default_length()
|
||||
|
||||
if animation_wait:
|
||||
dialogic.current_state = DialogicGameHandler.States.ANIMATING
|
||||
await get_tree().create_timer(animation_length).timeout
|
||||
dialogic.current_state = DialogicGameHandler.States.IDLE
|
||||
move_character(character, position_id, animation_length)
|
||||
change_character_mirror(character, mirrored)
|
||||
return
|
||||
|
||||
var container := dialogic.PortraitContainers.add_container(character.get_character_name())
|
||||
var character_node := add_character(character, container, portrait, position_id)
|
||||
if character_node == null:
|
||||
return null
|
||||
|
||||
dialogic.current_state_info['portraits'][character.resource_path] = {'portrait':portrait, 'node':character_node, 'position_id':position_id, 'custom_mirror':mirrored}
|
||||
|
||||
_change_portrait_mirror(character_node, mirrored)
|
||||
_change_portrait_extradata(character_node, extra_data)
|
||||
_change_portrait_z_index(character_node, z_index)
|
||||
|
||||
var info := {'character':character}
|
||||
info.merge(dialogic.current_state_info['portraits'][character.resource_path])
|
||||
character_joined.emit(info)
|
||||
|
||||
if animation_name.is_empty():
|
||||
animation_name = ProjectSettings.get_setting('dialogic/animations/join_default', "Fade In Up")
|
||||
animation_length = _get_join_default_length()
|
||||
animation_wait = ProjectSettings.get_setting('dialogic/animations/join_default_wait', true)
|
||||
|
||||
animation_name = DialogicPortraitAnimationUtil.guess_animation(animation_name, DialogicPortraitAnimationUtil.AnimationType.IN)
|
||||
|
||||
if animation_name and animation_length > 0:
|
||||
var anim: DialogicAnimation = _animate_node(character_node, animation_name, animation_length)
|
||||
if animation_wait:
|
||||
dialogic.current_state = DialogicGameHandler.States.ANIMATING
|
||||
await anim.finished
|
||||
dialogic.current_state = DialogicGameHandler.States.IDLE
|
||||
|
||||
return character_node
|
||||
|
||||
|
||||
func add_character(character:DialogicCharacter, container: DialogicNode_PortraitContainer, portrait:String, position_id:String) -> Node:
|
||||
if is_character_joined(character):
|
||||
printerr('[DialogicError] Cannot add a already joined character. If this is intended call _create_character_node manually.')
|
||||
return null
|
||||
|
||||
portrait = get_valid_portrait(character, portrait)
|
||||
|
||||
if portrait.is_empty():
|
||||
return null
|
||||
|
||||
if not character:
|
||||
printerr('[DialogicError] Cannot call add_portrait() with null character.')
|
||||
return null
|
||||
|
||||
var character_node := _create_character_node(character, container)
|
||||
|
||||
if character_node == null:
|
||||
printerr('[Dialogic] Failed to join character to position ', position_id, ". Could not find position container.")
|
||||
return null
|
||||
|
||||
|
||||
dialogic.current_state_info['portraits'][character.resource_path] = {'portrait':portrait, 'node':character_node, 'position_id':position_id}
|
||||
|
||||
_move_character(character_node, position_id)
|
||||
_change_portrait(character_node, portrait)
|
||||
|
||||
return character_node
|
||||
|
||||
|
||||
## Changes the portrait of a character. Only works with joined characters.
|
||||
func change_character_portrait(character: DialogicCharacter, portrait: String, fade_animation:="DEFAULT", fade_length := -1.0) -> void:
|
||||
if not is_character_joined(character):
|
||||
return
|
||||
|
||||
portrait = get_valid_portrait(character, portrait)
|
||||
|
||||
if dialogic.current_state_info.portraits[character.resource_path].portrait == portrait:
|
||||
return
|
||||
|
||||
if fade_animation == "DEFAULT":
|
||||
fade_animation = ProjectSettings.get_setting('dialogic/animations/cross_fade_default', "Fade Cross")
|
||||
fade_length = ProjectSettings.get_setting('dialogic/animations/cross_fade_default_length', 0.5)
|
||||
|
||||
fade_animation = DialogicPortraitAnimationUtil.guess_animation(fade_animation, DialogicPortraitAnimationUtil.AnimationType.CROSSFADE)
|
||||
|
||||
var info := _change_portrait(dialogic.current_state_info.portraits[character.resource_path].node, portrait, fade_animation, fade_length)
|
||||
dialogic.current_state_info.portraits[character.resource_path].portrait = info.portrait
|
||||
_change_portrait_mirror(
|
||||
dialogic.current_state_info.portraits[character.resource_path].node,
|
||||
dialogic.current_state_info.portraits[character.resource_path].get('custom_mirror', false)
|
||||
)
|
||||
character_portrait_changed.emit(info)
|
||||
|
||||
|
||||
## Changes the mirror of the given character. Only works with joined characters
|
||||
func change_character_mirror(character:DialogicCharacter, mirrored:= false, force:= false) -> void:
|
||||
if !is_character_joined(character):
|
||||
return
|
||||
|
||||
_change_portrait_mirror(dialogic.current_state_info.portraits[character.resource_path].node, mirrored, force)
|
||||
dialogic.current_state_info.portraits[character.resource_path]['custom_mirror'] = mirrored
|
||||
|
||||
|
||||
## Changes the z_index of a character. Only works with joined characters
|
||||
func change_character_z_index(character:DialogicCharacter, z_index:int, update_zindex:= true) -> void:
|
||||
if !is_character_joined(character):
|
||||
return
|
||||
|
||||
_change_portrait_z_index(dialogic.current_state_info.portraits[character.resource_path].node, z_index, update_zindex)
|
||||
if update_zindex:
|
||||
dialogic.current_state_info.portraits[character.resource_path]['z_index'] = z_index
|
||||
|
||||
|
||||
## Changes the extra data on the given character. Only works with joined characters
|
||||
func change_character_extradata(character:DialogicCharacter, extra_data:="") -> void:
|
||||
if !is_character_joined(character):
|
||||
return
|
||||
_change_portrait_extradata(dialogic.current_state_info.portraits[character.resource_path].node, extra_data)
|
||||
dialogic.current_state_info.portraits[character.resource_path]['extra_data'] = extra_data
|
||||
|
||||
|
||||
## Starts the given animation on the given character. Only works with joined characters
|
||||
func animate_character(character: DialogicCharacter, animation_path: String, length: float, repeats := 1, is_reversed := false) -> DialogicAnimation:
|
||||
if not is_character_joined(character):
|
||||
return null
|
||||
|
||||
animation_path = DialogicPortraitAnimationUtil.guess_animation(animation_path)
|
||||
|
||||
var character_node: Node = dialogic.current_state_info.portraits[character.resource_path].node
|
||||
|
||||
return _animate_node(character_node, animation_path, length, repeats, is_reversed)
|
||||
|
||||
|
||||
## Moves the given character to the given position. Only works with joined characters
|
||||
func move_character(character:DialogicCharacter, position_id:String, time:= 0.0, easing:=Tween.EASE_IN_OUT, trans:=Tween.TRANS_SINE) -> void:
|
||||
if !is_character_joined(character):
|
||||
return
|
||||
|
||||
if dialogic.current_state_info.portraits[character.resource_path].position_id == position_id:
|
||||
return
|
||||
|
||||
_move_character(dialogic.current_state_info.portraits[character.resource_path].node, position_id, time, easing, trans)
|
||||
dialogic.current_state_info.portraits[character.resource_path].position_id = position_id
|
||||
character_moved.emit({'character':character, 'position_id':position_id, 'time':time})
|
||||
|
||||
|
||||
## Removes a character with a given animation or the default animation.
|
||||
func leave_character(character: DialogicCharacter, animation_name:= "", animation_length:= 0.0, animation_wait := false) -> void:
|
||||
if not is_character_joined(character):
|
||||
return
|
||||
|
||||
if animation_name.is_empty():
|
||||
animation_name = ProjectSettings.get_setting('dialogic/animations/leave_default', "Fade Out Down")
|
||||
animation_length = _get_leave_default_length()
|
||||
animation_wait = ProjectSettings.get_setting('dialogic/animations/leave_default_wait', true)
|
||||
|
||||
animation_name = DialogicPortraitAnimationUtil.guess_animation(animation_name, DialogicPortraitAnimationUtil.AnimationType.OUT)
|
||||
|
||||
if not animation_name.is_empty():
|
||||
var character_node := get_character_node(character)
|
||||
|
||||
var animation := _animate_node(character_node, animation_name, animation_length, 1, true)
|
||||
if animation_length > 0:
|
||||
if animation_wait:
|
||||
dialogic.current_state = DialogicGameHandler.States.ANIMATING
|
||||
await animation.finished
|
||||
dialogic.current_state = DialogicGameHandler.States.IDLE
|
||||
remove_character(character)
|
||||
else:
|
||||
animation.finished.connect(func(): remove_character(character))
|
||||
else:
|
||||
remove_character(character)
|
||||
|
||||
|
||||
## Removes all joined characters with a given animation or the default animation.
|
||||
func leave_all_characters(animation_name:="", animation_length:=0.0, animation_wait := false) -> void:
|
||||
for character in get_joined_characters():
|
||||
await leave_character(character, animation_name, animation_length, animation_wait)
|
||||
|
||||
|
||||
## Finds the character node for a [param character].
|
||||
## Return `null` if the [param character] is not part of the scene.
|
||||
func get_character_node(character: DialogicCharacter) -> Node:
|
||||
if is_character_joined(character):
|
||||
if is_instance_valid(dialogic.current_state_info['portraits'][character.resource_path].node):
|
||||
return dialogic.current_state_info['portraits'][character.resource_path].node
|
||||
return null
|
||||
|
||||
|
||||
## Removes the given characters portrait.
|
||||
## Only works with joined characters.
|
||||
func remove_character(character: DialogicCharacter) -> void:
|
||||
var character_node := get_character_node(character)
|
||||
|
||||
if is_instance_valid(character_node) and character_node is Node:
|
||||
var container := character_node.get_parent()
|
||||
container.get_parent().remove_child(container)
|
||||
container.queue_free()
|
||||
character_node.queue_free()
|
||||
character_left.emit({'character': character})
|
||||
|
||||
dialogic.current_state_info['portraits'].erase(character.resource_path)
|
||||
|
||||
|
||||
func get_current_character() -> DialogicCharacter:
|
||||
if dialogic.current_state_info.get('speaker', null):
|
||||
return load(dialogic.current_state_info.speaker)
|
||||
return null
|
||||
|
||||
|
||||
|
||||
## Returns true if the given character is currently joined.
|
||||
func is_character_joined(character: DialogicCharacter) -> bool:
|
||||
if character == null or not character.resource_path in dialogic.current_state_info['portraits']:
|
||||
return false
|
||||
|
||||
return true
|
||||
|
||||
|
||||
## Returns a list of the joined charcters (as resources)
|
||||
func get_joined_characters() -> Array[DialogicCharacter]:
|
||||
var chars: Array[DialogicCharacter] = []
|
||||
|
||||
for char_path: String in dialogic.current_state_info.get('portraits', {}).keys():
|
||||
chars.append(load(char_path))
|
||||
|
||||
return chars
|
||||
|
||||
|
||||
## Returns a dictionary with info on a given character.
|
||||
## Keys can be [joined, character, node (for the portrait node), position_id]
|
||||
## Only joined is included (and false) for not joined characters
|
||||
func get_character_info(character:DialogicCharacter) -> Dictionary:
|
||||
if is_character_joined(character):
|
||||
var info: Dictionary = dialogic.current_state_info['portraits'][character.resource_path]
|
||||
info['joined'] = true
|
||||
return info
|
||||
else:
|
||||
return {'joined':false}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region SPEAKER PORTRAIT CONTAINERS
|
||||
####################################################################################################
|
||||
|
||||
## Updates all portrait containers set to SPEAKER.
|
||||
func change_speaker(speaker: DialogicCharacter = null, portrait := "") -> void:
|
||||
for container: Node in get_tree().get_nodes_in_group('dialogic_portrait_con_speaker'):
|
||||
|
||||
var just_joined := true
|
||||
for character_node: Node in container.get_children():
|
||||
if not character_node.get_meta('character') == speaker:
|
||||
var leave_animation: String = ProjectSettings.get_setting('dialogic/animations/leave_default', "Fade Out")
|
||||
leave_animation = DialogicPortraitAnimationUtil.guess_animation(leave_animation, DialogicPortraitAnimationUtil.AnimationType.OUT)
|
||||
var leave_animation_length := _get_leave_default_length()
|
||||
|
||||
if leave_animation and leave_animation_length:
|
||||
var animate_out := _animate_node(character_node, leave_animation, leave_animation_length, 1, true)
|
||||
animate_out.finished.connect(character_node.queue_free)
|
||||
else:
|
||||
character_node.get_parent().remove_child(character_node)
|
||||
character_node.queue_free()
|
||||
else:
|
||||
just_joined = false
|
||||
|
||||
if speaker == null or speaker.portraits.is_empty():
|
||||
continue
|
||||
|
||||
if just_joined:
|
||||
_create_character_node(speaker, container)
|
||||
|
||||
elif portrait.is_empty():
|
||||
continue
|
||||
|
||||
if portrait.is_empty():
|
||||
portrait = speaker.default_portrait
|
||||
|
||||
var character_node := container.get_child(-1)
|
||||
|
||||
var fade_animation: String = ProjectSettings.get_setting('dialogic/animations/cross_fade_default', "Fade Cross")
|
||||
var fade_length: float = ProjectSettings.get_setting('dialogic/animations/cross_fade_default_length', 0.5)
|
||||
|
||||
fade_animation = DialogicPortraitAnimationUtil.guess_animation(fade_animation, DialogicPortraitAnimationUtil.AnimationType.CROSSFADE)
|
||||
|
||||
if container.portrait_prefix+portrait in speaker.portraits:
|
||||
portrait = container.portrait_prefix+portrait
|
||||
|
||||
_change_portrait(character_node, portrait, fade_animation, fade_length)
|
||||
|
||||
# if the character has no portraits _change_portrait won't actually add a child node
|
||||
if character_node.get_child_count() == 0:
|
||||
continue
|
||||
|
||||
if just_joined:
|
||||
# Change speaker is called before the text is changed.
|
||||
# In styles where the speaker is IN the textbox,
|
||||
# this can mean the portrait container isn't sized correctly yet.
|
||||
character_node.hide()
|
||||
if not container.is_visible_in_tree():
|
||||
await get_tree().process_frame
|
||||
character_node.show()
|
||||
var join_animation: String = ProjectSettings.get_setting('dialogic/animations/join_default', "Fade In Up")
|
||||
join_animation = DialogicPortraitAnimationUtil.guess_animation(join_animation, DialogicPortraitAnimationUtil.AnimationType.IN)
|
||||
var join_animation_length := _get_join_default_length()
|
||||
|
||||
if join_animation and join_animation_length:
|
||||
_animate_node(character_node, join_animation, join_animation_length)
|
||||
|
||||
_change_portrait_mirror(character_node)
|
||||
|
||||
if speaker:
|
||||
if speaker.resource_path != dialogic.current_state_info['speaker']:
|
||||
if dialogic.current_state_info['speaker'] and is_character_joined(load(dialogic.current_state_info['speaker'])):
|
||||
dialogic.current_state_info['portraits'][dialogic.current_state_info['speaker']].node.get_child(-1)._unhighlight()
|
||||
|
||||
if speaker and is_character_joined(speaker):
|
||||
dialogic.current_state_info['portraits'][speaker.resource_path].node.get_child(-1)._highlight()
|
||||
|
||||
elif dialogic.current_state_info['speaker'] and is_character_joined(load(dialogic.current_state_info['speaker'])):
|
||||
dialogic.current_state_info['portraits'][dialogic.current_state_info['speaker']].node.get_child(-1)._unhighlight()
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region TEXT EFFECTS
|
||||
####################################################################################################
|
||||
|
||||
## Called from the [portrait=something] text effect.
|
||||
func text_effect_portrait(_text_node:Control, _skipped:bool, argument:String) -> void:
|
||||
if argument:
|
||||
if dialogic.current_state_info.get('speaker', null):
|
||||
change_character_portrait(load(dialogic.current_state_info.speaker), argument)
|
||||
change_speaker(load(dialogic.current_state_info.speaker), argument)
|
||||
|
||||
|
||||
## Called from the [extra_data=something] text effect.
|
||||
func text_effect_extradata(_text_node:Control, _skipped:bool, argument:String) -> void:
|
||||
if argument:
|
||||
if dialogic.current_state_info.get('speaker', null):
|
||||
change_character_extradata(load(dialogic.current_state_info.speaker), argument)
|
||||
#endregion
|
||||
@@ -0,0 +1 @@
|
||||
uid://kgcapukun2he
|
||||
18
addons/dialogic/Modules/Character/update_mirror.svg
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="31" height="22" viewBox="0 0 31 22" fill="none" version="1.1" id="svg4" sodipodi:docname="update_mirror.svg" inkscape:version="1.2.2 (732a01da63, 2022-12-09)" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs id="defs8" />
|
||||
<sodipodi:namedview id="namedview6" pagecolor="#505050" bordercolor="#eeeeee" borderopacity="1" inkscape:showpageshadow="0" inkscape:pageopacity="0" inkscape:pagecheckerboard="0" inkscape:deskcolor="#505050" showgrid="true" inkscape:zoom="16" inkscape:cx="21.84375" inkscape:cy="14.0625" inkscape:window-width="1920" inkscape:window-height="1017" inkscape:window-x="-8" inkscape:window-y="-8" inkscape:window-maximized="1" inkscape:current-layer="svg4">
|
||||
<inkscape:grid type="xygrid" id="grid6918" originx="0" originy="0" />
|
||||
</sodipodi:namedview>
|
||||
<g inkscape:groupmode="layer" id="layer2" inkscape:label="Mirror" style="display:inline">
|
||||
<path id="path8742" style="fill:#ffffff;fill-opacity:1;stroke-width:0.759831" d="m 10.967882,3.1351682 c 0.863708,-0.038595 2.312143,1.467492 2.312143,3.2198562 v 0 c 0,1.7523639 -1.491571,3.2198509 -2.312143,3.2198509" sodipodi:nodetypes="cssc" class="UnoptimicedTransforms" transform="matrix(1.1995187,0,0,1.1995187,-2.6822942,-1.4596729)" />
|
||||
<path id="path16944" style="fill:#ffffff;fill-opacity:1;stroke-width:0.914608" d="m 7.5210109,10.015357 c -0.023367,7.6e-4 -0.046802,8.86e-4 -0.070302,0.0012 -0.9139878,0.009 -2.8630987,-1.7296781 -2.8630987,-3.8633837 0,-2.1337061 1.9491109,-3.8466572 2.8630988,-3.8634194 0.023497,-4.31e-4 0.046938,3.82e-4 0.070302,0.00113" sodipodi:nodetypes="csssc" />
|
||||
<path id="path8744" style="display:inline;fill:#ffffff;fill-opacity:1;stroke-width:0.866873" d="m 10.468766,9.4004107 c 0.0017,-5.3e-6 0.0035,-8.8e-6 0.0051,-8.8e-6 1.704613,0 3.086415,2.9100071 3.086415,6.4996661 v 0 c 0,1.999827 -1.381802,1.999829 -3.086415,1.999829 h -0.0052" />
|
||||
<path id="path16885" style="display:inline;fill:#ffffff;fill-opacity:1;stroke-width:0.874663" d="m 7.5210109,17.899897 c -1.7328976,-2e-6 -3.1367969,-0.002 -3.1367969,-1.999829 0,-3.586045 1.4039606,-6.4938047 3.1369101,-6.4996573" />
|
||||
<path style="display:none;fill:none;fill-opacity:0.980952;stroke:#ffffff;stroke-width:1.4;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none" d="M 4.3862586,18.660184 H 13.902208" id="path11459" />
|
||||
<path style="display:none;fill:none;fill-opacity:0.980952;stroke:#ffffff;stroke-width:1.4;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none" d="m 5.0553488,16.987459 -1.3381805,1.635554 1.3010089,1.970099" id="path11461" />
|
||||
<path style="display:none;fill:none;fill-opacity:0.980952;stroke:#ffffff;stroke-width:1.4;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none" d="m 13.567664,16.875944 0.854949,1.821412 -0.817777,1.9701" id="path11463" />
|
||||
<path style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1.37801;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:0.981752" d="m 9.0131471,1.539982 -0.03659,16.903546" id="path16998" />
|
||||
</g>
|
||||
<path id="path26928" style="display:inline;fill:#ff4596;fill-opacity:1;stroke-width:0.613366" inkscape:label="path26928" d="m 17.19844,8.281361 c -0.272575,-8.2e-6 -0.500185,9.5e-6 -0.687018,0.012976 -0.194489,0.013249 -0.37819,0.041877 -0.556302,0.1156474 -0.4133,0.1711984 -0.741702,0.4995528 -0.912902,0.9128597 -0.08914,0.2151709 -0.113203,0.4419435 -0.122463,0.6884219 -0.0075,0.198126 -0.107439,0.363433 -0.25499,0.44863 -0.147562,0.08519 -0.340728,0.08912 -0.516018,-0.0037 -0.218061,-0.115251 -0.426533,-0.207727 -0.657444,-0.238134 -0.443521,-0.05839 -0.892077,0.06181 -1.246989,0.33413 -0.152944,0.117382 -0.269558,0.262171 -0.378298,0.423977 -0.104461,0.155439 -0.218268,0.352519 -0.354578,0.588618 l -0.01552,0.02687 c -0.136286,0.236087 -0.250093,0.433158 -0.332475,0.601337 -0.08575,0.17508 -0.152839,0.348492 -0.178013,0.53963 -0.05839,0.443529 0.06182,0.892086 0.334128,1.247025 0.141774,0.184685 0.326035,0.319018 0.534849,0.450213 0.167922,0.105499 0.261112,0.274802 0.2611,0.445256 -4e-6,0.170395 -0.09319,0.339684 -0.2611,0.445179 -0.208839,0.131218 -0.393112,0.265542 -0.534887,0.450286 -0.272334,0.354894 -0.39255,0.803431 -0.334165,1.246956 0.02519,0.191135 0.09222,0.364576 0.178014,0.53963 0.08239,0.168183 0.196157,0.365293 0.332477,0.601374 l 0.01552,0.02687 c 0.136299,0.236083 0.250113,0.433152 0.354577,0.588576 0.108764,0.161802 0.225385,0.306641 0.378336,0.423982 0.35491,0.272332 0.803465,0.392553 1.246989,0.334165 0.230896,-0.03043 0.439318,-0.122887 0.657371,-0.238137 0.175301,-0.09269 0.368508,-0.08873 0.516089,-0.0034 0.147577,0.08519 0.247617,0.250486 0.255026,0.448666 0.0092,0.246453 0.03333,0.473216 0.122463,0.688386 0.171199,0.413282 0.4996,0.741708 0.912902,0.912899 0.178115,0.0738 0.361807,0.102372 0.556303,0.115607 0.186836,0.01298 0.414443,0.01298 0.687018,0.01298 h 0.03098 c 0.272641,0 0.500197,0 0.687087,-0.01298 0.194489,-0.01325 0.378223,-0.04182 0.556344,-0.11562 0.413285,-0.171184 0.741671,-0.499617 0.912862,-0.912901 0.08914,-0.21517 0.113203,-0.441908 0.122409,-0.68842 0.0075,-0.198111 0.107425,-0.36345 0.254987,-0.448709 0.147577,-0.08522 0.340795,-0.08914 0.516092,0.0034 0.218051,0.115251 0.426474,0.207726 0.657404,0.2381 0.443522,0.05839 0.892099,-0.06174 1.246993,-0.334094 0.152961,-0.117441 0.269546,-0.262206 0.378297,-0.424009 0.104448,-0.155439 0.218252,-0.352497 0.354541,-0.588579 l 0.01569,-0.02687 c 0.136272,-0.236049 0.2501,-0.433192 0.332472,-0.601376 0.08573,-0.17506 0.152807,-0.348467 0.178015,-0.539596 0.05839,-0.443585 -0.06185,-0.89213 -0.334163,-1.247026 C 22.966705,15.585721 22.782388,15.451451 22.573601,15.320252 22.405679,15.214753 22.3125,15.045453 22.3125,14.875 c 0,-0.170395 0.09314,-0.339612 0.261028,-0.445112 0.208903,-0.131191 0.393243,-0.265477 0.534992,-0.450283 0.272333,-0.354903 0.392559,-0.803461 0.334166,-1.246992 -0.0252,-0.191132 -0.09228,-0.364516 -0.178014,-0.539595 -0.08236,-0.168164 -0.196157,-0.365264 -0.332511,-0.601337 l -0.01552,-0.02685 c -0.136362,-0.236031 -0.25012,-0.433148 -0.354576,-0.588582 -0.108763,-0.161803 -0.225359,-0.306611 -0.378332,-0.423976 -0.354895,-0.27233 -0.80344,-0.392521 -1.247026,-0.33413 -0.230874,0.03042 -0.439283,0.122886 -0.657331,0.238135 -0.17532,0.09266 -0.368517,0.08873 -0.516097,0.0034 -0.147577,-0.0852 -0.247635,-0.250542 -0.25506,-0.448696 C 19.499068,9.7645223 19.474933,9.5377607 19.385811,9.3226061 19.21463,8.9093853 18.886236,8.5810255 18.472951,8.4098311 18.294838,8.336061 18.111106,8.3074462 17.916607,8.2941837 17.729734,8.281208 17.502159,8.281208 17.229518,8.281208 Z m 0.01569,4.293575 c 1.270347,0 2.300127,1.029802 2.300127,2.300124 0,1.270344 -1.02978,2.300124 -2.300127,2.300124 -1.270314,0 -2.300123,-1.02978 -2.300123,-2.300124 0,-1.270322 1.029809,-2.300124 2.300123,-2.300124 z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.9 KiB |
44
addons/dialogic/Modules/Character/update_mirror.svg.import
Normal file
@@ -0,0 +1,44 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://c735ss4h37y8i"
|
||||
path="res://.godot/imported/update_mirror.svg-d6fa4832a7758cad02a7f32282433230.ctex"
|
||||
metadata={
|
||||
"has_editor_variant": true,
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/dialogic/Modules/Character/update_mirror.svg"
|
||||
dest_files=["res://.godot/imported/update_mirror.svg-d6fa4832a7758cad02a7f32282433230.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
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/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
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
|
||||
svg/scale=1.0
|
||||
editor/scale_with_editor_scale=true
|
||||
editor/convert_colors_with_editor_theme=true
|
||||
9
addons/dialogic/Modules/Character/update_portrait.svg
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="31" height="22" viewBox="0 0 31 22" fill="none" version="1.1" id="svg4" sodipodi:docname="update_portrait.svg" inkscape:version="1.2.2 (732a01da63, 2022-12-09)" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs id="defs8" />
|
||||
<sodipodi:namedview id="namedview6" pagecolor="#505050" bordercolor="#eeeeee" borderopacity="1" inkscape:showpageshadow="0" inkscape:pageopacity="0" inkscape:pagecheckerboard="0" inkscape:deskcolor="#505050" showgrid="true" inkscape:zoom="16" inkscape:cx="23.75" inkscape:cy="14.0625" inkscape:window-width="1920" inkscape:window-height="1017" inkscape:window-x="-8" inkscape:window-y="-8" inkscape:window-maximized="1" inkscape:current-layer="svg4">
|
||||
<inkscape:grid type="xygrid" id="grid6918" originx="0" originy="0" />
|
||||
</sodipodi:namedview>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="m 9.9375,15.875 c 3.576743,0 6.476256,-2.960429 6.476256,-6.612317 0,-3.6518789 -2.899513,-6.612317 -6.476256,-6.612317 -3.5767353,0 -6.4762575,2.9604381 -6.4762575,6.612317 0,3.651888 2.8995222,6.612317 6.4762575,6.612317 z M 5.9096842,8.375405 c 0.332121,-0.339136 0.7825817,-0.5296473 1.2522769,-0.5296473 0.4696953,0 0.9201559,0.1905113 1.2522768,0.5296473 L 8.6852232,8.652084 9.339464,7.984097 9.0684787,7.7074187 C 8.5628126,7.1911667 7.8770324,6.9011417 7.1619611,6.9011417 c -0.7150713,0 -1.4008514,0.290025 -1.9064807,0.806277 L 4.9845045,7.984097 5.6386991,8.652084 Z M 12.713037,7.8457577 c -0.469713,0 -0.920183,0.1905113 -1.252322,0.5296473 L 11.189823,8.652084 10.535537,7.984097 10.806521,7.7074187 c 0.505703,-0.516252 1.191445,-0.806277 1.906516,-0.806277 0.715072,0 1.400815,0.290025 1.906519,0.806277 L 14.890541,7.984097 14.236254,8.652084 13.965361,8.375405 C 13.633222,8.036269 13.182751,7.8457577 12.713037,7.8457577 Z M 9.9375,13.985766 c -1.8503592,0 -3.2381288,-1.889233 -3.7007186,-2.833849 h 7.4014356 c -0.46259,0.944616 -1.850358,2.833849 -3.700717,2.833849 z" fill="#ffffff" id="path2" style="display:inline;stroke-width:0.934854" inkscape:label="Portrait" />
|
||||
<path id="path26928" style="display:inline;fill:#ff4596;fill-opacity:1;stroke-width:0.613366" inkscape:label="path26928" d="m 19.13594,6.968861 c -0.272575,-8.2e-6 -0.500185,9.5e-6 -0.687018,0.012976 -0.194489,0.013249 -0.37819,0.041877 -0.556302,0.1156474 -0.4133,0.1711984 -0.741702,0.4995528 -0.912902,0.9128597 -0.08914,0.2151709 -0.113203,0.4419435 -0.122463,0.6884214 -0.0075,0.1981263 -0.107439,0.3634338 -0.25499,0.4486307 -0.147562,0.085189 -0.340728,0.089123 -0.516018,-0.00369 -0.218061,-0.1152514 -0.426533,-0.207727 -0.657444,-0.2381338 -0.443521,-0.058391 -0.892077,0.061805 -1.246989,0.3341293 -0.152944,0.1173821 -0.269558,0.2621716 -0.378298,0.4239769 -0.104461,0.1554392 -0.218268,0.3525194 -0.354578,0.5886184 l -0.01552,0.02687 c -0.136286,0.236087 -0.250093,0.433158 -0.332475,0.601337 -0.08575,0.17508 -0.152839,0.348492 -0.178013,0.53963 -0.05839,0.443529 0.06182,0.892086 0.334128,1.247025 0.141774,0.184685 0.326035,0.319018 0.534849,0.450213 0.167922,0.105499 0.261112,0.274802 0.2611,0.445256 -4e-6,0.170395 -0.09319,0.339684 -0.2611,0.445179 -0.208839,0.131218 -0.393112,0.265542 -0.534887,0.450286 -0.272334,0.354894 -0.39255,0.803431 -0.334165,1.246956 0.02519,0.191135 0.09222,0.364576 0.178014,0.53963 0.08239,0.168183 0.196157,0.365293 0.332477,0.601374 l 0.01552,0.02687 c 0.136299,0.236083 0.250113,0.433152 0.354577,0.588576 0.108764,0.161802 0.225385,0.306641 0.378336,0.423982 0.35491,0.272332 0.803465,0.392553 1.246989,0.334165 0.230896,-0.03043 0.439318,-0.122887 0.657371,-0.238137 0.175301,-0.09269 0.368508,-0.08873 0.516089,-0.0034 0.147577,0.08519 0.247617,0.250486 0.255026,0.448666 0.0092,0.246453 0.03333,0.473216 0.122463,0.688386 0.171199,0.413282 0.4996,0.741708 0.912902,0.912899 0.178115,0.0738 0.361807,0.102372 0.556303,0.115607 0.186836,0.01298 0.414443,0.01298 0.687018,0.01298 h 0.03098 c 0.272641,0 0.500197,0 0.687087,-0.01298 0.194489,-0.01325 0.378223,-0.04182 0.556344,-0.11562 0.413285,-0.171184 0.741671,-0.499617 0.912862,-0.912901 0.08914,-0.21517 0.113203,-0.441908 0.122409,-0.68842 0.0075,-0.198111 0.107425,-0.36345 0.254987,-0.448709 0.147577,-0.08522 0.340795,-0.08914 0.516092,0.0034 0.218051,0.115251 0.426474,0.207726 0.657404,0.2381 0.443522,0.05839 0.892099,-0.06174 1.246993,-0.334094 0.152961,-0.117441 0.269546,-0.262206 0.378297,-0.424009 0.104448,-0.155439 0.218252,-0.352497 0.354541,-0.588579 l 0.01569,-0.02687 c 0.136272,-0.236049 0.2501,-0.433192 0.332472,-0.601376 0.08573,-0.17506 0.152807,-0.348467 0.178015,-0.539596 0.05839,-0.443585 -0.06185,-0.89213 -0.334163,-1.247026 C 24.904205,14.273221 24.719888,14.138951 24.511101,14.007752 24.343179,13.902253 24.25,13.732953 24.25,13.5625 c 0,-0.170395 0.09314,-0.339612 0.261028,-0.445112 0.208903,-0.131191 0.393243,-0.265477 0.534992,-0.450283 0.272333,-0.354903 0.392559,-0.803461 0.334166,-1.246992 -0.0252,-0.191132 -0.09228,-0.364516 -0.178014,-0.539595 -0.08236,-0.168164 -0.196157,-0.365264 -0.332511,-0.601337 l -0.01552,-0.02685 C 24.717779,10.016297 24.604021,9.8191797 24.499565,9.6637461 24.390802,9.5019435 24.274206,9.3571349 24.121233,9.2397705 23.766338,8.9674396 23.317793,8.8472493 22.874207,8.9056399 22.643333,8.9360576 22.434924,9.0285264 22.216876,9.143775 22.041556,9.236435 21.848359,9.232501 21.700779,9.147185 21.553202,9.0619873 21.453144,8.8966429 21.445719,8.6984893 21.436568,8.4520223 21.412433,8.2252607 21.323311,8.0101061 21.15213,7.5968853 20.823736,7.2685255 20.410451,7.0973311 20.232338,7.023561 20.048606,6.9949462 19.854107,6.9816837 19.667234,6.968708 19.439659,6.968708 19.167018,6.968708 Z m 0.01569,4.293575 c 1.270347,0 2.300127,1.029802 2.300127,2.300124 0,1.270344 -1.02978,2.300124 -2.300127,2.300124 -1.270314,0 -2.300123,-1.02978 -2.300123,-2.300124 0,-1.270322 1.029809,-2.300124 2.300123,-2.300124 z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.9 KiB |
44
addons/dialogic/Modules/Character/update_portrait.svg.import
Normal file
@@ -0,0 +1,44 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://qx5bntelnslj"
|
||||
path="res://.godot/imported/update_portrait.svg-b90fa6163d3720d34df8578ce2aa35e1.ctex"
|
||||
metadata={
|
||||
"has_editor_variant": true,
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/dialogic/Modules/Character/update_portrait.svg"
|
||||
dest_files=["res://.godot/imported/update_portrait.svg-b90fa6163d3720d34df8578ce2aa35e1.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
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/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
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
|
||||
svg/scale=1.0
|
||||
editor/scale_with_editor_scale=true
|
||||
editor/convert_colors_with_editor_theme=true
|
||||
18
addons/dialogic/Modules/Character/update_position.svg
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="31" height="22" viewBox="0 0 31 22" fill="none" version="1.1" id="svg4" sodipodi:docname="update_position.svg" inkscape:version="1.2.2 (732a01da63, 2022-12-09)" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs id="defs8" />
|
||||
<sodipodi:namedview id="namedview6" pagecolor="#505050" bordercolor="#eeeeee" borderopacity="1" inkscape:showpageshadow="0" inkscape:pageopacity="0" inkscape:pagecheckerboard="0" inkscape:deskcolor="#505050" showgrid="true" inkscape:zoom="16" inkscape:cx="23.84375" inkscape:cy="14.0625" inkscape:window-width="1920" inkscape:window-height="1017" inkscape:window-x="-8" inkscape:window-y="-8" inkscape:window-maximized="1" inkscape:current-layer="svg4">
|
||||
<inkscape:grid type="xygrid" id="grid6918" originx="0" originy="0" />
|
||||
</sodipodi:namedview>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="m 9.6329576,18.73815 c 4.1893454,0 7.5854694,-3.467473 7.5854694,-7.744834 0,-4.2773499 -3.396124,-7.7448337 -7.5854694,-7.7448337 -4.1893365,0 -7.5854711,3.4674838 -7.5854711,7.7448337 0,4.277361 3.3961346,7.744834 7.5854711,7.744834 z M 4.9152823,9.9540703 c 0.3890046,-0.397221 0.9166174,-0.6203616 1.4667592,-0.6203616 0.5501418,0 1.0777545,0.2231406 1.4667591,0.6203616 L 8.1661985,10.278137 8.9324937,9.4957421 8.6150957,9.1716755 C 8.0228222,8.5670037 7.2195858,8.2273042 6.3820415,8.2273042 c -0.8375444,0 -1.6407807,0.3396995 -2.233011,0.9443713 l -0.317387,0.3240666 0.766241,0.7823949 z M 12.883872,9.3337087 c -0.550163,0 -1.077787,0.2231406 -1.466813,0.6203616 L 11.099771,10.278137 10.333423,9.4957421 10.650819,9.1716755 c 0.592317,-0.6046718 1.395509,-0.9443713 2.233053,-0.9443713 0.837545,0 1.640738,0.3396995 2.233056,0.9443713 l 0.317397,0.3240666 -0.766349,0.7823949 -0.31729,-0.3240667 C 13.96166,9.5568493 13.434035,9.3337087 12.883872,9.3337087 Z M 9.6329576,16.52534 c -2.1672773,0 -3.7927356,-2.21281 -4.3345549,-3.319213 h 8.6691083 c -0.54182,1.106403 -2.167276,3.319213 -4.3345534,3.319213 z" fill="#ffffff" id="path2" style="display:none;stroke-width:1.09497" inkscape:label="Portrait" />
|
||||
<path style="display:none;fill:none;fill-opacity:0.980952;stroke:#ffffff;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none" d="m 17.531776,3.4508426 1.936447,3.0983145 3.063553,4.9016859 -5,8" id="path4576" sodipodi:nodetypes="cccc" />
|
||||
<g inkscape:groupmode="layer" id="layer3" inkscape:label="Position" style="display:inline">
|
||||
<path d="m 15.435727,5.7204944 c 0,2.118883 -1.717741,3.8365686 -3.836615,3.8365686 -2.1188833,0 -3.8365806,-1.7176856 -3.8365806,-3.8365686 0,-2.1188838 1.7176973,-3.8365775 3.8365806,-3.8365775 2.118874,0 3.836615,1.7176937 3.836615,3.8365775 z" fill="#ffffff" id="path19723" style="stroke-width:1.05506" />
|
||||
<path d="m 16.202965,15.244259 c 0,1.985936 -2.061163,1.985936 -4.603853,1.985936 -2.542658,0 -4.6038923,0 -4.6038923,-1.985936 0,-3.564724 2.0612343,-6.454507 4.6038923,-6.454507 2.54269,0 4.603853,2.889783 4.603853,6.454507 z" fill="#ffffff" id="path19725" style="stroke-width:1.05506" />
|
||||
<path style="fill:none;stroke:#ffffff;stroke-width:1.744;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0.236785;stroke-opacity:1" d="m 7.2613947,9.27472 h -4" id="path22754" sodipodi:nodetypes="cc" />
|
||||
<path style="fill:none;stroke:#ffffff;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0.236785;stroke-opacity:1" d="m 5.2613947,6.2747209 -2,2.9999991 2,3" id="path22756" sodipodi:nodetypes="ccc" />
|
||||
<path style="fill:none;stroke:#ffffff;stroke-width:1.64208;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0.236785;stroke-opacity:1" d="m 15.767666,9.21222 h 3.487458" id="path25041" sodipodi:nodetypes="cc" />
|
||||
<path style="fill:none;stroke:#ffffff;stroke-width:1.60066;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0.236785;stroke-opacity:1" d="M 17.511395,6.1617262 19.255124,9.21222 17.511395,12.262715" id="path25043" sodipodi:nodetypes="ccc" />
|
||||
</g>
|
||||
<path id="path26928" style="display:inline;fill:#ff4596;fill-opacity:1;stroke-width:0.613366" inkscape:label="path26928" d="m 20.13594,8.406361 c -0.272575,-8.2e-6 -0.500185,9.5e-6 -0.687018,0.012976 -0.194489,0.013249 -0.37819,0.041877 -0.556302,0.1156474 -0.4133,0.1711984 -0.741702,0.4995528 -0.912902,0.9128597 -0.08914,0.2151709 -0.113203,0.4419435 -0.122463,0.6884219 -0.0075,0.198126 -0.107439,0.363433 -0.25499,0.44863 -0.147562,0.08519 -0.340728,0.08912 -0.516018,-0.0037 -0.218061,-0.115251 -0.426533,-0.207727 -0.657444,-0.238134 -0.443521,-0.05839 -0.892077,0.06181 -1.246989,0.33413 -0.152944,0.117382 -0.269558,0.262171 -0.378298,0.423977 -0.104461,0.155439 -0.218268,0.352519 -0.354578,0.588618 l -0.01552,0.02687 c -0.136286,0.236087 -0.250093,0.433158 -0.332475,0.601337 -0.08575,0.17508 -0.152839,0.348492 -0.178013,0.53963 -0.05839,0.443529 0.06182,0.892086 0.334128,1.247025 0.141774,0.184685 0.326035,0.319018 0.534849,0.450213 0.167922,0.105499 0.261112,0.274802 0.2611,0.445256 -4e-6,0.170395 -0.09319,0.339684 -0.2611,0.445179 -0.208839,0.131218 -0.393112,0.265542 -0.534887,0.450286 -0.272334,0.354894 -0.39255,0.803431 -0.334165,1.246956 0.02519,0.191135 0.09222,0.364576 0.178014,0.53963 0.08239,0.168183 0.196157,0.365293 0.332477,0.601374 l 0.01552,0.02687 c 0.136299,0.236083 0.250113,0.433152 0.354577,0.588576 0.108764,0.161802 0.225385,0.306641 0.378336,0.423982 0.35491,0.272332 0.803465,0.392553 1.246989,0.334165 0.230896,-0.03043 0.439318,-0.122887 0.657371,-0.238137 0.175301,-0.09269 0.368508,-0.08873 0.516089,-0.0034 0.147577,0.08519 0.247617,0.250486 0.255026,0.448666 0.0092,0.246453 0.03333,0.473216 0.122463,0.688386 0.171199,0.413282 0.4996,0.741708 0.912902,0.912899 0.178115,0.0738 0.361807,0.102372 0.556303,0.115607 0.186836,0.01298 0.414443,0.01298 0.687018,0.01298 h 0.03098 c 0.272641,0 0.500197,0 0.687087,-0.01298 0.194489,-0.01325 0.378223,-0.04182 0.556344,-0.11562 0.413285,-0.171184 0.741671,-0.499617 0.912862,-0.912901 0.08914,-0.21517 0.113203,-0.441908 0.122409,-0.68842 0.0075,-0.198111 0.107425,-0.36345 0.254987,-0.448709 0.147577,-0.08522 0.340795,-0.08914 0.516092,0.0034 0.218051,0.115251 0.426474,0.207726 0.657404,0.2381 0.443522,0.05839 0.892099,-0.06174 1.246993,-0.334094 0.152961,-0.117441 0.269546,-0.262206 0.378297,-0.424009 0.104448,-0.155439 0.218252,-0.352497 0.354541,-0.588579 l 0.01569,-0.02687 c 0.136272,-0.236049 0.2501,-0.433192 0.332472,-0.601376 0.08573,-0.17506 0.152807,-0.348467 0.178015,-0.539596 0.05839,-0.443585 -0.06185,-0.89213 -0.334163,-1.247026 C 25.904205,15.710721 25.719888,15.576451 25.511101,15.445252 25.343179,15.339753 25.25,15.170453 25.25,15 c 0,-0.170395 0.09314,-0.339612 0.261028,-0.445112 0.208903,-0.131191 0.393243,-0.265477 0.534992,-0.450283 0.272333,-0.354903 0.392559,-0.803461 0.334166,-1.246992 -0.0252,-0.191132 -0.09228,-0.364516 -0.178014,-0.539595 -0.08236,-0.168164 -0.196157,-0.365264 -0.332511,-0.601337 l -0.01552,-0.02685 c -0.136362,-0.236031 -0.25012,-0.433148 -0.354576,-0.588582 -0.108763,-0.161803 -0.225359,-0.306611 -0.378332,-0.423976 -0.354895,-0.27233 -0.80344,-0.392521 -1.247026,-0.33413 -0.230874,0.03042 -0.439283,0.122886 -0.657331,0.238135 -0.17532,0.09266 -0.368517,0.08873 -0.516097,0.0034 -0.147577,-0.0852 -0.247635,-0.250542 -0.25506,-0.448696 C 22.436568,9.8895223 22.412433,9.6627607 22.323311,9.4476061 22.15213,9.0343853 21.823736,8.7060255 21.410451,8.5348311 21.232338,8.461061 21.048606,8.4324462 20.854107,8.4191837 20.667234,8.406208 20.439659,8.406208 20.167018,8.406208 Z m 0.01569,4.293575 c 1.270347,0 2.300127,1.029802 2.300127,2.300124 0,1.270344 -1.02978,2.300124 -2.300127,2.300124 -1.270314,0 -2.300123,-1.02978 -2.300123,-2.300124 0,-1.270322 1.029809,-2.300124 2.300123,-2.300124 z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.9 KiB |
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="31" height="22" viewBox="0 0 31 22" fill="none" version="1.1" id="svg4" sodipodi:docname="update_position.svg" inkscape:version="1.2.2 (732a01da63, 2022-12-09)" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs id="defs8" />
|
||||
<sodipodi:namedview id="namedview6" pagecolor="#505050" bordercolor="#eeeeee" borderopacity="1" inkscape:showpageshadow="0" inkscape:pageopacity="0" inkscape:pagecheckerboard="0" inkscape:deskcolor="#505050" showgrid="true" inkscape:zoom="16" inkscape:cx="23.84375" inkscape:cy="14.0625" inkscape:window-width="1920" inkscape:window-height="1017" inkscape:window-x="-8" inkscape:window-y="-8" inkscape:window-maximized="1" inkscape:current-layer="svg4">
|
||||
<inkscape:grid type="xygrid" id="grid6918" originx="0" originy="0" />
|
||||
</sodipodi:namedview>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="m 9.6329576,18.73815 c 4.1893454,0 7.5854694,-3.467473 7.5854694,-7.744834 0,-4.2773499 -3.396124,-7.7448337 -7.5854694,-7.7448337 -4.1893365,0 -7.5854711,3.4674838 -7.5854711,7.7448337 0,4.277361 3.3961346,7.744834 7.5854711,7.744834 z M 4.9152823,9.9540703 c 0.3890046,-0.397221 0.9166174,-0.6203616 1.4667592,-0.6203616 0.5501418,0 1.0777545,0.2231406 1.4667591,0.6203616 L 8.1661985,10.278137 8.9324937,9.4957421 8.6150957,9.1716755 C 8.0228222,8.5670037 7.2195858,8.2273042 6.3820415,8.2273042 c -0.8375444,0 -1.6407807,0.3396995 -2.233011,0.9443713 l -0.317387,0.3240666 0.766241,0.7823949 z M 12.883872,9.3337087 c -0.550163,0 -1.077787,0.2231406 -1.466813,0.6203616 L 11.099771,10.278137 10.333423,9.4957421 10.650819,9.1716755 c 0.592317,-0.6046718 1.395509,-0.9443713 2.233053,-0.9443713 0.837545,0 1.640738,0.3396995 2.233056,0.9443713 l 0.317397,0.3240666 -0.766349,0.7823949 -0.31729,-0.3240667 C 13.96166,9.5568493 13.434035,9.3337087 12.883872,9.3337087 Z M 9.6329576,16.52534 c -2.1672773,0 -3.7927356,-2.21281 -4.3345549,-3.319213 h 8.6691083 c -0.54182,1.106403 -2.167276,3.319213 -4.3345534,3.319213 z" fill="#ffffff" id="path2" style="display:none;stroke-width:1.09497" inkscape:label="Portrait" />
|
||||
<path style="display:none;fill:none;fill-opacity:0.980952;stroke:#ffffff;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none" d="m 17.531776,3.4508426 1.936447,3.0983145 3.063553,4.9016859 -5,8" id="path4576" sodipodi:nodetypes="cccc" />
|
||||
<g inkscape:groupmode="layer" id="layer3" inkscape:label="Position" style="display:inline">
|
||||
<path d="m 15.435727,5.7204944 c 0,2.118883 -1.717741,3.8365686 -3.836615,3.8365686 -2.1188833,0 -3.8365806,-1.7176856 -3.8365806,-3.8365686 0,-2.1188838 1.7176973,-3.8365775 3.8365806,-3.8365775 2.118874,0 3.836615,1.7176937 3.836615,3.8365775 z" fill="#ffffff" id="path19723" style="stroke-width:1.05506" />
|
||||
<path d="m 16.202965,15.244259 c 0,1.985936 -2.061163,1.985936 -4.603853,1.985936 -2.542658,0 -4.6038923,0 -4.6038923,-1.985936 0,-3.564724 2.0612343,-6.454507 4.6038923,-6.454507 2.54269,0 4.603853,2.889783 4.603853,6.454507 z" fill="#ffffff" id="path19725" style="stroke-width:1.05506" />
|
||||
<path style="fill:none;stroke:#ffffff;stroke-width:1.744;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0.236785;stroke-opacity:1" d="m 7.2613947,9.27472 h -4" id="path22754" sodipodi:nodetypes="cc" />
|
||||
<path style="fill:none;stroke:#ffffff;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0.236785;stroke-opacity:1" d="m 5.2613947,6.2747209 -2,2.9999991 2,3" id="path22756" sodipodi:nodetypes="ccc" />
|
||||
<path style="fill:none;stroke:#ffffff;stroke-width:1.64208;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0.236785;stroke-opacity:1" d="m 15.767666,9.21222 h 3.487458" id="path25041" sodipodi:nodetypes="cc" />
|
||||
<path style="fill:none;stroke:#ffffff;stroke-width:1.60066;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0.236785;stroke-opacity:1" d="M 17.511395,6.1617262 19.255124,9.21222 17.511395,12.262715" id="path25043" sodipodi:nodetypes="ccc" />
|
||||
</g>
|
||||
<path id="path26928" style="display:inline;fill:#ff4596;fill-opacity:1;stroke-width:0.613366" inkscape:label="path26928" d="m 20.13594,8.406361 c -0.272575,-8.2e-6 -0.500185,9.5e-6 -0.687018,0.012976 -0.194489,0.013249 -0.37819,0.041877 -0.556302,0.1156474 -0.4133,0.1711984 -0.741702,0.4995528 -0.912902,0.9128597 -0.08914,0.2151709 -0.113203,0.4419435 -0.122463,0.6884219 -0.0075,0.198126 -0.107439,0.363433 -0.25499,0.44863 -0.147562,0.08519 -0.340728,0.08912 -0.516018,-0.0037 -0.218061,-0.115251 -0.426533,-0.207727 -0.657444,-0.238134 -0.443521,-0.05839 -0.892077,0.06181 -1.246989,0.33413 -0.152944,0.117382 -0.269558,0.262171 -0.378298,0.423977 -0.104461,0.155439 -0.218268,0.352519 -0.354578,0.588618 l -0.01552,0.02687 c -0.136286,0.236087 -0.250093,0.433158 -0.332475,0.601337 -0.08575,0.17508 -0.152839,0.348492 -0.178013,0.53963 -0.05839,0.443529 0.06182,0.892086 0.334128,1.247025 0.141774,0.184685 0.326035,0.319018 0.534849,0.450213 0.167922,0.105499 0.261112,0.274802 0.2611,0.445256 -4e-6,0.170395 -0.09319,0.339684 -0.2611,0.445179 -0.208839,0.131218 -0.393112,0.265542 -0.534887,0.450286 -0.272334,0.354894 -0.39255,0.803431 -0.334165,1.246956 0.02519,0.191135 0.09222,0.364576 0.178014,0.53963 0.08239,0.168183 0.196157,0.365293 0.332477,0.601374 l 0.01552,0.02687 c 0.136299,0.236083 0.250113,0.433152 0.354577,0.588576 0.108764,0.161802 0.225385,0.306641 0.378336,0.423982 0.35491,0.272332 0.803465,0.392553 1.246989,0.334165 0.230896,-0.03043 0.439318,-0.122887 0.657371,-0.238137 0.175301,-0.09269 0.368508,-0.08873 0.516089,-0.0034 0.147577,0.08519 0.247617,0.250486 0.255026,0.448666 0.0092,0.246453 0.03333,0.473216 0.122463,0.688386 0.171199,0.413282 0.4996,0.741708 0.912902,0.912899 0.178115,0.0738 0.361807,0.102372 0.556303,0.115607 0.186836,0.01298 0.414443,0.01298 0.687018,0.01298 h 0.03098 c 0.272641,0 0.500197,0 0.687087,-0.01298 0.194489,-0.01325 0.378223,-0.04182 0.556344,-0.11562 0.413285,-0.171184 0.741671,-0.499617 0.912862,-0.912901 0.08914,-0.21517 0.113203,-0.441908 0.122409,-0.68842 0.0075,-0.198111 0.107425,-0.36345 0.254987,-0.448709 0.147577,-0.08522 0.340795,-0.08914 0.516092,0.0034 0.218051,0.115251 0.426474,0.207726 0.657404,0.2381 0.443522,0.05839 0.892099,-0.06174 1.246993,-0.334094 0.152961,-0.117441 0.269546,-0.262206 0.378297,-0.424009 0.104448,-0.155439 0.218252,-0.352497 0.354541,-0.588579 l 0.01569,-0.02687 c 0.136272,-0.236049 0.2501,-0.433192 0.332472,-0.601376 0.08573,-0.17506 0.152807,-0.348467 0.178015,-0.539596 0.05839,-0.443585 -0.06185,-0.89213 -0.334163,-1.247026 C 25.904205,15.710721 25.719888,15.576451 25.511101,15.445252 25.343179,15.339753 25.25,15.170453 25.25,15 c 0,-0.170395 0.09314,-0.339612 0.261028,-0.445112 0.208903,-0.131191 0.393243,-0.265477 0.534992,-0.450283 0.272333,-0.354903 0.392559,-0.803461 0.334166,-1.246992 -0.0252,-0.191132 -0.09228,-0.364516 -0.178014,-0.539595 -0.08236,-0.168164 -0.196157,-0.365264 -0.332511,-0.601337 l -0.01552,-0.02685 c -0.136362,-0.236031 -0.25012,-0.433148 -0.354576,-0.588582 -0.108763,-0.161803 -0.225359,-0.306611 -0.378332,-0.423976 -0.354895,-0.27233 -0.80344,-0.392521 -1.247026,-0.33413 -0.230874,0.03042 -0.439283,0.122886 -0.657331,0.238135 -0.17532,0.09266 -0.368517,0.08873 -0.516097,0.0034 -0.147577,-0.0852 -0.247635,-0.250542 -0.25506,-0.448696 C 22.436568,9.8895223 22.412433,9.6627607 22.323311,9.4476061 22.15213,9.0343853 21.823736,8.7060255 21.410451,8.5348311 21.232338,8.461061 21.048606,8.4324462 20.854107,8.4191837 20.667234,8.406208 20.439659,8.406208 20.167018,8.406208 Z m 0.01569,4.293575 c 1.270347,0 2.300127,1.029802 2.300127,2.300124 0,1.270344 -1.02978,2.300124 -2.300127,2.300124 -1.270314,0 -2.300123,-1.02978 -2.300123,-2.300124 0,-1.270322 1.029809,-2.300124 2.300123,-2.300124 z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.9 KiB |
@@ -0,0 +1,44 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://deu1h3rsp3p8y"
|
||||
path="res://.godot/imported/update_position.svg.2023_09_23_08_37_47.0.svg-d66e70a05e9de92a595b70fa88fca0d4.ctex"
|
||||
metadata={
|
||||
"has_editor_variant": true,
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/dialogic/Modules/Character/update_position.svg.2023_09_23_08_37_47.0.svg"
|
||||
dest_files=["res://.godot/imported/update_position.svg.2023_09_23_08_37_47.0.svg-d66e70a05e9de92a595b70fa88fca0d4.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
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/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
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
|
||||
svg/scale=1.0
|
||||
editor/scale_with_editor_scale=true
|
||||
editor/convert_colors_with_editor_theme=true
|
||||
44
addons/dialogic/Modules/Character/update_position.svg.import
Normal file
@@ -0,0 +1,44 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://rslog4jar4gu"
|
||||
path="res://.godot/imported/update_position.svg-4be50608dc0768e715ff659ca62cf187.ctex"
|
||||
metadata={
|
||||
"has_editor_variant": true,
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/dialogic/Modules/Character/update_position.svg"
|
||||
dest_files=["res://.godot/imported/update_position.svg-4be50608dc0768e715ff659ca62cf187.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
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/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
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
|
||||
svg/scale=1.0
|
||||
editor/scale_with_editor_scale=true
|
||||
editor/convert_colors_with_editor_theme=true
|
||||
14
addons/dialogic/Modules/Character/update_z_index.svg
Normal file
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="31" height="22" viewBox="0 0 31 22" fill="none" version="1.1" id="svg4" sodipodi:docname="update_z_index.svg" inkscape:version="1.2.2 (732a01da63, 2022-12-09)" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs id="defs8" />
|
||||
<sodipodi:namedview id="namedview6" pagecolor="#505050" bordercolor="#eeeeee" borderopacity="1" inkscape:showpageshadow="0" inkscape:pageopacity="0" inkscape:pagecheckerboard="0" inkscape:deskcolor="#505050" showgrid="true" inkscape:zoom="16" inkscape:cx="23.84375" inkscape:cy="14.0625" inkscape:window-width="1920" inkscape:window-height="1017" inkscape:window-x="-8" inkscape:window-y="-8" inkscape:window-maximized="1" inkscape:current-layer="svg4">
|
||||
<inkscape:grid type="xygrid" id="grid6918" originx="0" originy="0" />
|
||||
</sodipodi:namedview>
|
||||
<g inkscape:groupmode="layer" id="layer1" inkscape:label="Z_Index" style="display:inline" transform="matrix(0.90945359,0,0,0.90945359,0.03431233,1.6441321)">
|
||||
<path style="fill:none;fill-opacity:0.980952;stroke:#ffffff;stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none" d="M 4.0841125,6.8565774 V 16.856578 H 12.084113 V 6.8565774 Z" id="path6916" sodipodi:nodetypes="ccccc" />
|
||||
<path style="fill:none;fill-opacity:0.980952;stroke:#ffffff;stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none" d="m 12.084113,13.856578 h 3 V 3.8565774 H 7.0841125 v 3" id="path6920" sodipodi:nodetypes="ccccc" />
|
||||
<path style="fill:none;fill-opacity:0.980952;stroke:#ffffff;stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none" d="m 15.084113,10.856578 h 3 V 0.8565774 h -8.000001 v 3" id="path6922" sodipodi:nodetypes="ccccc" />
|
||||
<path style="fill:none;fill-opacity:0.980952;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none" d="m 6.5841125,9.8565775 h 3 l -3,4.0000005 h 3" id="path6924" sodipodi:nodetypes="cccc" />
|
||||
</g>
|
||||
<path id="path26928" style="display:inline;fill:#ff4596;fill-opacity:1;stroke-width:0.613366" inkscape:label="path26928" d="m 19.07344,7.281361 c -0.272575,-8.2e-6 -0.500185,9.5e-6 -0.687018,0.012976 -0.194489,0.013249 -0.37819,0.041877 -0.556302,0.1156474 -0.4133,0.1711984 -0.741702,0.4995528 -0.912902,0.9128597 -0.08914,0.2151709 -0.113203,0.4419435 -0.122463,0.6884214 -0.0075,0.1981263 -0.107439,0.3634338 -0.25499,0.4486307 -0.147562,0.085189 -0.340728,0.089123 -0.516018,-0.00369 -0.218061,-0.1152514 -0.426533,-0.207727 -0.657444,-0.2381338 -0.443521,-0.058391 -0.892077,0.061805 -1.246989,0.3341293 -0.152944,0.1173821 -0.269558,0.2621716 -0.378298,0.4239769 -0.104461,0.1554394 -0.218268,0.3525194 -0.354578,0.5886184 l -0.01552,0.02687 c -0.136286,0.236087 -0.250093,0.433158 -0.332475,0.601337 -0.08575,0.17508 -0.152839,0.348492 -0.178013,0.53963 -0.05839,0.443529 0.06182,0.892086 0.334128,1.247025 0.141774,0.184685 0.326035,0.319018 0.534849,0.450213 0.167922,0.105499 0.261112,0.274802 0.2611,0.445256 -4e-6,0.170395 -0.09319,0.339684 -0.2611,0.445179 -0.208839,0.131218 -0.393112,0.265542 -0.534887,0.450286 -0.272334,0.354894 -0.39255,0.803431 -0.334165,1.246956 0.02519,0.191135 0.09222,0.364576 0.178014,0.53963 0.08239,0.168183 0.196157,0.365293 0.332477,0.601374 l 0.01552,0.02687 c 0.136299,0.236083 0.250113,0.433152 0.354577,0.588576 0.108764,0.161802 0.225385,0.306641 0.378336,0.423982 0.35491,0.272332 0.803465,0.392553 1.246989,0.334165 0.230896,-0.03043 0.439318,-0.122887 0.657371,-0.238137 0.175301,-0.09269 0.368508,-0.08873 0.516089,-0.0034 0.147577,0.08519 0.247617,0.250486 0.255026,0.448666 0.0092,0.246453 0.03333,0.473216 0.122463,0.688386 0.171199,0.413282 0.4996,0.741708 0.912902,0.912899 0.178115,0.0738 0.361807,0.102372 0.556303,0.115607 0.186836,0.01298 0.414443,0.01298 0.687018,0.01298 h 0.03098 c 0.272641,0 0.500197,0 0.687087,-0.01298 0.194489,-0.01325 0.378223,-0.04182 0.556344,-0.11562 0.413285,-0.171184 0.741671,-0.499617 0.912862,-0.912901 0.08914,-0.21517 0.113203,-0.441908 0.122409,-0.68842 0.0075,-0.198111 0.107425,-0.36345 0.254987,-0.448709 0.147577,-0.08522 0.340795,-0.08914 0.516092,0.0034 0.218051,0.115251 0.426474,0.207726 0.657404,0.2381 0.443522,0.05839 0.892099,-0.06174 1.246993,-0.334094 0.152961,-0.117441 0.269546,-0.262206 0.378297,-0.424009 0.104448,-0.155439 0.218252,-0.352497 0.354541,-0.588579 l 0.01569,-0.02687 c 0.136272,-0.236049 0.2501,-0.433192 0.332472,-0.601376 0.08573,-0.17506 0.152807,-0.348467 0.178015,-0.539596 0.05839,-0.443585 -0.06185,-0.89213 -0.334163,-1.247026 C 24.841705,14.585721 24.657388,14.451451 24.448601,14.320252 24.280679,14.214753 24.1875,14.045453 24.1875,13.875 c 0,-0.170395 0.09314,-0.339612 0.261028,-0.445112 0.208903,-0.131191 0.393243,-0.265477 0.534992,-0.450283 0.272333,-0.354903 0.392559,-0.803461 0.334166,-1.246992 -0.0252,-0.191132 -0.09228,-0.364516 -0.178014,-0.539595 -0.08236,-0.168164 -0.196157,-0.365264 -0.332511,-0.601337 l -0.01552,-0.02685 C 24.655279,10.328797 24.541521,10.13168 24.437065,9.9762461 24.328302,9.8144435 24.211706,9.6696349 24.058733,9.5522705 23.703838,9.2799396 23.255293,9.1597493 22.811707,9.2181399 22.580833,9.2485576 22.372424,9.3410264 22.154376,9.456275 21.979056,9.548935 21.785859,9.545001 21.638279,9.459685 21.490702,9.3744873 21.390644,9.2091429 21.383219,9.0109893 21.374068,8.7645223 21.349933,8.5377607 21.260811,8.3226061 21.08963,7.9093853 20.761236,7.5810255 20.347951,7.4098311 20.169838,7.336061 19.986106,7.3074462 19.791607,7.2941837 19.604734,7.281208 19.377159,7.281208 19.104518,7.281208 Z m 0.01569,4.293575 c 1.270347,0 2.300127,1.029802 2.300127,2.300124 0,1.270344 -1.02978,2.300124 -2.300127,2.300124 -1.270314,0 -2.300123,-1.02978 -2.300123,-2.300124 0,-1.270322 1.029809,-2.300124 2.300123,-2.300124 z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.8 KiB |
44
addons/dialogic/Modules/Character/update_z_index.svg.import
Normal file
@@ -0,0 +1,44 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://c5xa3i541igyk"
|
||||
path="res://.godot/imported/update_z_index.svg-204064db9241de79bf8dfd23af57c6c6.ctex"
|
||||
metadata={
|
||||
"has_editor_variant": true,
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/dialogic/Modules/Character/update_z_index.svg"
|
||||
dest_files=["res://.godot/imported/update_z_index.svg-204064db9241de79bf8dfd23af57c6c6.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
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/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
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
|
||||
svg/scale=1.0
|
||||
editor/scale_with_editor_scale=true
|
||||
editor/convert_colors_with_editor_theme=true
|
||||