Made a toolset folder, and added the Dialogic plugin.

This commit is contained in:
PersonGuyGit
2022-07-31 11:30:54 -06:00
parent ecf2d792cb
commit 09f1961112
886 changed files with 34865 additions and 0 deletions

View File

@ -0,0 +1,7 @@
Copyright © 2021 Alessandro Senese (ceceppa)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,318 @@
class_name DialogicAnimaPropertiesHelper
#
# Different node types have different property names
#
# Example:
# Control: position is "rect_position"
# Node2D : position is "offset"
#
# So, this utility class helps the animations to figure out which
# property to animate :)
#
enum PIVOT {
CENTER,
CENTER_BOTTOM,
TOP_CENTER,
TOP_LEFT,
LEFT_BOTTOM,
RIGHT_BOTTOM
}
static func get_position(node: Node) -> Vector2:
if node is Control:
return node.rect_position
if node is Node2D:
return node.global_position
return node.global_transform.origin
static func get_size(node: Node) -> Vector2:
if node is Control:
return node.get_size()
elif node is AnimatedSprite:
var frames = (node as AnimatedSprite).frames
var animation = (node as AnimatedSprite).animation
# scale can be negative
var scale = Vector2(abs(node.scale.x), abs(node.scale.y))
return frames.get_frame(animation, 0).get_size() * scale
elif node is Node2D and "texture" in node:
# scale can be negative
var scale = Vector2(abs(node.scale.x), abs(node.scale.y))
return node.texture.get_size() * scale
return Vector2.ZERO
static func get_scale(node: Node) -> Vector2:
if node is Control:
return node.rect_scale
return node.scale
static func get_rotation(node: Node):
if node is Control:
return node.rect_rotation
elif node is Node2D:
return node.rotation_degrees
return node.rotation
static func set_2D_pivot(node: Node, pivot: int) -> void:
var size: Vector2 = get_size(node)
match pivot:
PIVOT.TOP_CENTER:
if node is Control:
node.set_pivot_offset(Vector2(size.x / 2, 0))
else:
var position = node.global_position
node.offset = Vector2(0, size.y / 2)
node.global_position = position - node.offset
PIVOT.TOP_LEFT:
if node is Control:
node.set_pivot_offset(Vector2(0, 0))
else:
var position = node.global_position
node.offset = Vector2(size.x / 2, 0)
node.global_position = position - node.offset
PIVOT.CENTER:
if node is Control:
node.set_pivot_offset(size / 2)
PIVOT.CENTER_BOTTOM:
if node is Control:
node.set_pivot_offset(Vector2(size.x / 2, size.y / 2))
else:
var position = node.global_position
node.offset = Vector2(0, -size.y / 2)
node.global_position = position - node.offset
PIVOT.LEFT_BOTTOM:
if node is Control:
node.set_pivot_offset(Vector2(0, size.y))
else:
var position = node.global_position
node.offset = Vector2(size.x / 2, size.y)
node.global_position = position - node.offset
PIVOT.RIGHT_BOTTOM:
if node is Control:
node.set_pivot_offset(Vector2(size.x, size.y / 2))
else:
var position = node.global_position
node.offset = Vector2(-size.x / 2, size.y / 2)
node.global_position = position - node.offset
_:
printerr('Pivot point not handled yet')
static func get_property_initial_value(node: Node, property: String):
property = property.to_lower()
match property:
"x", "position:x":
var position = get_position(node)
return position.x
"y", "position:y":
var position = get_position(node)
return position.y
"z", "position:z":
var position = get_position(node)
return position.z
"position":
return get_position(node)
"rotation":
return get_rotation(node)
"rotation:x":
return get_rotation(node).x
"rotation:y":
return get_rotation(node).y
"rotation:z":
return get_rotation(node).z
"opacity":
return node.modulate.a
"skew:x":
return node.get_global_transform().y.x
"skew:y":
return node.get_global_transform().x.y
var p = property.split(':')
var property_name: String = p[0]
var rect_property_name: String = 'rect_' + property_name
var node_property_name: String
var key = p[1] if p.size() > 1 else null
if node.get(property_name):
node_property_name = property_name
if node.get(rect_property_name):
node_property_name = rect_property_name
if p[0] == 'shader_param':
var material: ShaderMaterial
if node is MeshInstance:
material = node.get_surface_material(0)
else:
material = node.material
return material.get_shader_param(p[1])
if node_property_name:
if key:
return node[node_property_name][key]
return node[node_property_name]
if property.find('__') == 0:
return 0
return property_name
static func map_property_to_godot_property(node: Node, property: String) -> Dictionary:
property = property.to_lower()
match property:
"x", "position:x":
if node is Control:
return {
property_name = "rect_position",
key = "x",
}
return {
property_name = "global_transform",
key = "origin",
subkey = "x"
}
"y", "position:y":
if node is Control:
return {
property_name = "rect_position",
key = "y",
}
return {
property_name = "global_transform",
key = "origin",
subkey = "y"
}
"z", "position:z":
if node is Control:
printerr('position:z is not supported by Control nodes')
return {
property_name = "global_transform",
key = "origin",
subkey = "z"
}
"position":
if node is Control:
return {
property_name = "rect_position"
}
return {
property_name = "global_transform",
key = "origin"
}
"opacity":
return {
property_name = "modulate",
key = "a"
}
"rotation":
var property_name = "rotation"
if node is Control:
property_name = "rect_rotation"
elif node is Node2D:
property_name = "rotation_degrees"
return {
property_name = property_name
}
"rotation:x":
return {
property_name = "rotation",
key = "x"
}
"rotation:y":
return {
property_name = "rotation",
key = "y"
}
"rotation:z":
return {
property_name = "rotation",
key = "z"
}
"skew:x":
return {
property_name = "transform",
key = "y",
subkey = "x"
}
"skew:y":
return {
property_name = "transform",
key = "x",
subkey = "y"
}
var p = property.split(':')
var property_name: String = p[0]
var rect_property_name: String = 'rect_' + property_name
var node_property_name: String
var key = p[1] if p.size() > 1 else null
var subkey = p[2] if p.size() > 2 else null
if node.get(property_name):
node_property_name = property_name
if node.get(rect_property_name):
node_property_name = rect_property_name
if p[0] == 'shader_param':
var material: ShaderMaterial
if node is MeshInstance:
material = node.get_surface_material(0)
else:
material = node.material
return {
callback = funcref(material, 'set_shader_param'),
param = p[1]
}
if node_property_name:
if key:
return {
property_name = node_property_name,
key = key
}
if subkey:
return {
property_name = node_property_name,
key = key,
subkey = subkey
}
return {
property_name = node_property_name
}
if property.find('__') == 0:
return {
property_name = property
}
return {
property_name = property
}

View File

@ -0,0 +1,83 @@
extends Node
class_name DialogicAnimaResources
const BASE_PATH := 'res://addons/dialogic/Nodes/Anima/animations/'
static func get_animation_script(animation_name: String):
# for custom_animation in _custom_animations:
# if custom_animation.name == animation_name:
# return custom_animation.script
var resource_file = get_animation_script_with_path(animation_name)
if resource_file:
return load(resource_file).new()
printerr('No animation found with name: ', animation_name)
return null
static func get_animation_script_with_path(animation_name: String) -> String:
if not animation_name.ends_with('.gd'):
animation_name += '.gd'
animation_name = from_camel_to_snack_case(animation_name)
for file_name in get_available_animations():
if file_name is String and file_name.ends_with(animation_name):
return file_name
return ''
static func get_available_animations() -> Array:
var list = _get_animations_list()
var filtered := []
for file in list:
if file.find('.gd.') < 0:
filtered.push_back(file.replace('.gdc', '.gd'))
return filtered #+ _custom_animations
static func _get_animations_list() -> Array:
var files = _get_scripts_in_dir(BASE_PATH)
var filtered := []
files.sort()
return files
static func _get_scripts_in_dir(path: String, files: Array = []) -> Array:
var dir = Directory.new()
if dir.open(path) != OK:
return files
dir.list_dir_begin()
var file_name = dir.get_next()
while file_name != "":
if file_name != "." and file_name != "..":
if dir.current_is_dir():
_get_scripts_in_dir(path + file_name + '/', files)
else:
files.push_back(path + file_name)
file_name = dir.get_next()
return files
static func from_camel_to_snack_case(string:String) -> String:
var result = PoolStringArray()
var is_first_char = true
for character in string:
if character == character.to_lower() or is_first_char:
result.append(character.to_lower())
else:
result.append('_' + character.to_lower())
is_first_char = false
return result.join('').replace(' ', '_')

View File

@ -0,0 +1,571 @@
extends Tween
var loop = 1
signal finished_animation
var _animation_data = []
enum PLAY_MODE {
NORMAL,
BACKWARDS
}
# Needed to use interpolate_property
var _fake_property: Dictionary = {}
var _callbacks := {}
func _ready():
connect("tween_started", self, '_on_tween_started')
connect("tween_step", self, '_on_tween_step_with_easing')
connect("tween_step", self, '_on_tween_step_with_easing_callback')
connect("tween_step", self, '_on_tween_step_with_easing_funcref')
connect("tween_step", self, '_on_tween_step_without_easing')
connect("tween_completed", self, '_on_tween_completed')
func play(node, animation_name, duration):
var script = DialogicAnimaResources.get_animation_script(animation_name.strip_edges())
if not script:
printerr('animation not found: %s' % animation_name)
return duration
var real_duration = script.generate_animation(self, {'node':node, 'duration':duration, 'wait_time':0})
if real_duration is float:
duration = real_duration
var index := 0
for animation_data in _animation_data:
var easing_points
if animation_data.has('easing'):
if animation_data.easing is FuncRef:
easing_points = animation_data.easing
else:
easing_points = get_easing_points(animation_data.easing)
if animation_data.has('easing_points'):
easing_points = animation_data.easing_points
animation_data._easing_points = easing_points
animation_data._animation_callback = funcref(self, '_calculate_from_and_to')
if easing_points is Array:
animation_data._use_step_callback = '_on_tween_step_with_easing'
elif easing_points is String:
animation_data._use_step_callback = '_on_tween_step_with_easing_callback'
elif easing_points is FuncRef:
animation_data._use_step_callback = '_on_tween_step_with_easing_funcref'
else:
animation_data._use_step_callback = '_on_tween_step_without_easing'
index += 1
var started := start()
if not started:
printerr('something went wrong while trying to start the tween')
if is_connected("tween_all_completed", self, 'finished_once'): disconnect("tween_all_completed", self, 'finished_once')
connect('tween_all_completed', self, 'finished_once', [node, animation_name, duration])
func finished_once(node, animation, duration):
loop -= 1
if loop > 0:
play(node, animation, duration)
else:
emit_signal('finished_animation')
# Given an array of frames generates the animation data using relative end value
#
# frames = [{
# percentage = the percentage of the animation
# to = the relative end value
# easing_points = the easing points for the bezier curver (optional)
# }]
#
func add_relative_frames(data: Dictionary, property: String, frames: Array) -> float:
return _add_frames(data, property, frames, true)
#
# Given an array of frames generates the animation data using absolute end value
#
# frames = [{
# percentage = the percentage of the animation
# to = the relative end value
# easing_points = the easing points for the bezier curver (optional)
# }]
#
func add_frames(data: Dictionary, property: String, frames: Array) -> float:
return _add_frames(data, property, frames)
func _add_frames(data: Dictionary, property: String, frames: Array, relative: bool = false) -> float:
var duration: float = data.duration if data.has('duration') else 0.0
var _wait_time: float = data._wait_time if data.has('_wait_time') else 0.0
var last_duration := 0.0
var keys_to_ignore = ['duration', '_wait_time']
for frame in frames:
var percentage = frame.percentage if frame.has('percentage') else 100.0
percentage /= 100.0
var frame_duration = max(0.000001, duration * percentage)
var diff = frame_duration - last_duration
var is_first_frame = true
var is_last_frame = percentage == 1
var animation_data = {
property = property,
relative = relative,
duration = diff,
_wait_time = _wait_time
}
# We need to restore the animation just before the node is animated
# but we also need to consider that a node can have multiple
# properties animated, so we need to restore it only before the first
# animation starts
for animation in _animation_data:
if animation.node == data.node:
is_first_frame = false
if animation.has('_is_last_frame'):
is_last_frame = false
if is_first_frame:
animation_data._is_first_frame = true
if is_last_frame:
animation_data._is_last_frame = true
for key in frame:
if key != 'percentage':
animation_data[key] = frame[key]
for key in data:
if key == 'callback' and percentage < 1:
animation_data.erase(key)
elif keys_to_ignore.find(key) < 0:
animation_data[key] = data[key]
add_animation_data(animation_data)
last_duration = frame_duration
_wait_time += diff
return _wait_time
func add_animation_data(animation_data: Dictionary, play_mode: int = PLAY_MODE.NORMAL) -> void:
_animation_data.push_back(animation_data)
var index = str(_animation_data.size())
var duration = animation_data.duration if animation_data.has('duration') else 1
var property_key = 'p' + index
_fake_property[property_key] = 0.0
if animation_data.has('on_completed') and animation_data.has('_is_last_frame'):
_callbacks[property_key] = animation_data.on_completed
var from := 0.0 if play_mode == PLAY_MODE.NORMAL else 1.0
var to := 1.0 - from
interpolate_property(
self,
'_fake_property:' + property_key,
from,
to,
duration,
Tween.TRANS_LINEAR,
Tween.EASE_IN_OUT,
animation_data._wait_time
)
func _on_tween_step_with_easing(object: Object, key: NodePath, _time: float, elapsed: float):
var index := _get_animation_data_index(key)
if _animation_data[index]._use_step_callback != '_on_tween_step_with_easing':
return
var easing_points = _animation_data[index]._easing_points
var p1 = easing_points[0]
var p2 = easing_points[1]
var p3 = easing_points[2]
var p4 = easing_points[3]
var easing_elapsed = _cubic_bezier(Vector2.ZERO, Vector2(p1, p2), Vector2(p3, p4), Vector2(1, 1), elapsed)
_animation_data[index]._animation_callback.call_func(index, easing_elapsed)
func _on_tween_step_with_easing_callback(object: Object, key: NodePath, _time: float, elapsed: float):
var index := _get_animation_data_index(key)
if _animation_data[index]._use_step_callback != '_on_tween_step_with_easing_callback':
return
var easing_points_function = _animation_data[index]._easing_points
var easing_callback = funcref(self, easing_points_function)
var easing_elapsed = easing_callback.call_func(elapsed)
_animation_data[index]._animation_callback.call_func(index, easing_elapsed)
func _on_tween_step_with_easing_funcref(object: Object, key: NodePath, _time: float, elapsed: float):
var index := _get_animation_data_index(key)
if _animation_data[index]._use_step_callback != '_on_tween_step_with_easing_funcref':
return
var easing_callback = _animation_data[index]._easing_points
var easing_elapsed = easing_callback.call_func(elapsed)
_animation_data[index]._animation_callback.call_func(index, easing_elapsed)
func _on_tween_step_without_easing(object: Object, key: NodePath, _time: float, elapsed: float):
var index := _get_animation_data_index(key)
if _animation_data[index]._use_step_callback != '_on_tween_step_without_easing':
return
_animation_data[index]._animation_callback.call_func(index, elapsed)
func _get_animation_data_index(key: NodePath) -> int:
var s = str(key)
return int(s.replace('_fake_property:p', '')) - 1
func _cubic_bezier(p0: Vector2, p1: Vector2, p2: Vector2, p3: Vector2, t: float) -> float:
var q0 = p0.linear_interpolate(p1, t)
var q1 = p1.linear_interpolate(p2, t)
var q2 = p2.linear_interpolate(p3, t)
var r0 = q0.linear_interpolate(q1, t)
var r1 = q1.linear_interpolate(q2, t)
var s = r0.linear_interpolate(r1, t)
return s.y
func _calculate_from_and_to(index: int, value: float) -> void:
var animation_data = _animation_data[index]
var node = animation_data.node
var do_calculate = true
if animation_data.has('_recalculate_from_to') and not animation_data._recalculate_from_to and animation_data.has('_property_data'):
do_calculate = false
if do_calculate:
_do_calculate_from_to(node, animation_data)
if animation_data._property_data.has('subkey'):
animation_data._animation_callback = funcref(self, '_on_animation_with_subkey')
elif animation_data._property_data.has('key'):
animation_data._animation_callback = funcref(self, '_on_animation_with_key')
else:
animation_data._animation_callback = funcref(self, '_on_animation_without_key')
_animation_data[index]._animation_callback.call_func(index, value)
func _do_calculate_from_to(node: Node, animation_data: Dictionary) -> void:
var from
var to
var relative = animation_data.relative if animation_data.has('relative') else false
var node_from = DialogicAnimaPropertiesHelper.get_property_initial_value(node, animation_data.property)
if animation_data.has('from'):
from = _maybe_convert_from_deg_to_rad(node, animation_data, animation_data.from)
from = _maybe_calculate_relative_value(relative, from, node_from)
else:
from = node_from
animation_data.__from = from
if animation_data.has('to'):
to = _maybe_convert_from_deg_to_rad(node, animation_data, animation_data.to)
to = _maybe_calculate_relative_value(relative, to, from)
else:
to = from
animation_data.__to = to
if animation_data.has('pivot'):
if node is Spatial:
printerr('3D Pivot not supported yet')
else:
DialogicAnimaPropertiesHelper.set_2D_pivot(animation_data.node, animation_data.pivot)
animation_data._property_data = DialogicAnimaPropertiesHelper.map_property_to_godot_property(node, animation_data.property)
animation_data._property_data.diff = to - from
animation_data._property_data.from = from
func _maybe_calculate_relative_value(relative, value, current_node_value):
if not relative:
return value
return value + current_node_value
func _maybe_convert_from_deg_to_rad(node: Node, animation_data: Dictionary, value):
if not node is Spatial or animation_data.property.find('rotation') < 0:
return value
if value is Vector3:
return Vector3(deg2rad(value.x), deg2rad(value.y), deg2rad(value.z))
return deg2rad(value)
func _on_animation_with_key(index: int, elapsed: float) -> void:
var animation_data = _animation_data[index]
var property_data = _animation_data[index]._property_data
var node = animation_data.node
var value = property_data.from + (property_data.diff * elapsed)
node[property_data.property_name][property_data.key] = value
func _on_animation_with_subkey(index: int, elapsed: float) -> void:
var animation_data = _animation_data[index]
var property_data = _animation_data[index]._property_data
var node = animation_data.node
var value = property_data.from + (property_data.diff * elapsed)
node[property_data.property_name][property_data.key][property_data.subkey] = value
func _on_animation_without_key(index: int, elapsed: float) -> void:
var animation_data = _animation_data[index]
var property_data = _animation_data[index]._property_data
var node = animation_data.node
var value = property_data.from + (property_data.diff * elapsed)
if property_data.has('callback'):
property_data.callback.call_func(property_data.param, value)
return
node[property_data.property_name] = value
#
# We don't want the user to specify the from/to value as color
# we animate opacity.
# So this function converts the "from = #" -> Color(.., .., .., #)
# same for the to value
#
func _maybe_adjust_modulate_value(animation_data: Dictionary, value):
var property = animation_data.property
var node = animation_data.node
if not property == 'opacity':
return value
if value is int or value is float:
var color = node.modulate
color.a = value
return color
return value
func _on_tween_completed(_ignore, property_name: String) -> void:
var property_key = property_name.replace(':_fake_property:', '')
if _callbacks.has(property_key):
var callback = _callbacks[property_key]
if not callback is Array or callback.size() == 1:
callback[0].call_func()
else:
callback[0].call_funcv(callback[1])
func _on_tween_started(_ignore, key) -> void:
var index := _get_animation_data_index(key)
#var hide_strategy = _visibility_strategy
var animation_data = _animation_data[index]
# if animation_data.has('hide_strategy'):
# hide_strategy = animation_data.hide_strategy
var node = animation_data.node
var should_restore_visibility := false
var should_restore_modulate := false
# if hide_strategy == Anima.VISIBILITY.HIDDEN_ONLY:
# should_restore_visibility = true
# elif hide_strategy == Anima.VISIBILITY.HIDDEN_AND_TRANSPARENT:
# should_restore_modulate = true
# should_restore_visibility = true
# elif hide_strategy == Anima.VISIBILITY.TRANSPARENT_ONLY:
# should_restore_modulate = true
if should_restore_modulate:
var old_modulate = node.get_meta('_old_modulate')
if old_modulate:
node.modulate = old_modulate
if should_restore_visibility:
node.show()
var should_trigger_on_started: bool = animation_data.has('_is_first_frame') and animation_data._is_first_frame and animation_data.has('on_started')
if should_trigger_on_started:
var fn: FuncRef
var args: Array = []
if animation_data.on_started is Array:
fn = animation_data.on_started[0]
args = animation_data.on_started.slice(1, -1)
else:
fn = animation_data.on_started
fn.call_funcv(args)
####################################################################################################
####################################################################################################
## FROM ANIMA EASING
####################################################################################################
####################################################################################################
enum EASING {
LINEAR,
EASE,
EASE_IN_OUT,
EASE_IN,
EASE_OUT,
EASE_IN_SINE,
EASE_OUT_SINE,
EASE_IN_OUT_SINE,
EASE_IN_QUAD,
EASE_OUT_QUAD,
EASE_IN_OUT_QUAD,
EASE_IN_CUBIC,
EASE_OUT_CUBIC,
EASE_IN_OUT_CUBIC,
EASE_IN_QUART,
EASE_OUT_QUART,
EASE_IN_OUT_QUART,
EASE_IN_QUINT,
EASE_OUT_QUINT,
EASE_IN_OUT_QUINT,
EASE_IN_EXPO,
EASE_OUT_EXPO,
EASE_IN_OUT_EXPO,
EASE_IN_CIRC,
EASE_OUT_CIRC,
EASE_IN_OUT_CIRC,
EASE_IN_BACK,
EASE_OUT_BACK,
EASE_IN_OUT_BACK,
EASE_IN_ELASTIC,
EASE_OUT_ELASTIC,
EASE_IN_OUT_ELASTIC,
EASE_IN_BOUNCE,
EASE_OUT_BOUNCE,
EASE_IN_OUT_BOUNCE,
}
const _easing_mapping = {
EASING.LINEAR: null,
EASING.EASE: [0.25, 0.1, 0.25, 1],
EASING.EASE_IN_OUT: [0.42, 0, 0.58, 1],
EASING.EASE_IN: [0.42, 0, 1, 1],
EASING.EASE_OUT: [0, 0, 0.58, 1],
EASING.EASE_IN_SINE: [0, 0, 1, .5],
EASING.EASE_OUT_SINE: [0.61, 1, 0.88, 1],
EASING.EASE_IN_OUT_SINE: [0.37, 0, 0.63, 1],
EASING.EASE_IN_QUAD: [0.11, 0, 0.5, 0],
EASING.EASE_OUT_QUAD: [0.5, 1.0, 0.89, 1],
EASING.EASE_IN_OUT_QUAD: [0.45, 0, 0.55, 1],
EASING.EASE_IN_CUBIC: [0.32, 0, 0.67, 0],
EASING.EASE_OUT_CUBIC: [0.33, 1, 0.68, 1],
EASING.EASE_IN_OUT_CUBIC: [0.65, 0, 0.35, 1],
EASING.EASE_IN_QUART: [0.5, 0, 0.75, 0],
EASING.EASE_OUT_QUART: [0.25, 1, 0.5, 1],
EASING.EASE_IN_OUT_QUART: [0.76, 0, 0.24, 1],
EASING.EASE_IN_QUINT: [0.64, 0, 0.78, 0],
EASING.EASE_OUT_QUINT: [0.22, 1, 0.36, 1],
EASING.EASE_IN_OUT_QUINT: [0.83, 0, 0.17, 1],
EASING.EASE_IN_EXPO: [0.7, 0, 0.84, 0],
EASING.EASE_OUT_EXPO: [0.16, 1, 0.3, 1],
EASING.EASE_IN_OUT_EXPO: [0.87, 0, 0.13, 1],
EASING.EASE_IN_CIRC: [0.55, 0, 0.1, 0.45],
EASING.EASE_OUT_CIRC: [0, 0.55, 0.45, 1],
EASING.EASE_IN_OUT_CIRC: [0.85, 0, 0.15, 1],
EASING.EASE_IN_BACK: [0.36, 0, 0.66, -0.56],
EASING.EASE_OUT_BACK: [0.36, 1.56, 0.64, 1],
EASING.EASE_IN_OUT_BACK: [0.68, -0.6, 0.32, 1.6],
EASING.EASE_IN_ELASTIC: 'ease_in_elastic',
EASING.EASE_OUT_ELASTIC: 'ease_out_elastic',
EASING.EASE_IN_OUT_ELASTIC: 'ease_in_out_elastic',
EASING.EASE_IN_BOUNCE: 'ease_in_bounce',
EASING.EASE_OUT_BOUNCE: 'ease_out_bounce',
EASING.EASE_IN_OUT_BOUNCE: 'ease_in_out_bounce'
}
const _ELASTIC_C4: float = (2.0 * PI) / 3.0
const _ELASTIC_C5: float = (2.0 * PI) / 4.5
static func get_easing_points(easing_name):
if _easing_mapping.has(easing_name):
return _easing_mapping[easing_name]
printerr('Easing not found: ' + str(easing_name))
return _easing_mapping[EASING.LINEAR]
static func ease_in_elastic(elapsed: float) -> float:
if elapsed == 0:
return 0.0
elif elapsed == 1:
return 1.0
return -pow(2, 10 * elapsed - 10) * sin((elapsed * 10 - 10.75) * _ELASTIC_C4)
static func ease_out_elastic(elapsed: float) -> float:
if elapsed == 0:
return 0.0
elif elapsed == 1:
return 1.0
return pow(2, -10 * elapsed) * sin((elapsed * 10 - 0.75) * _ELASTIC_C4) + 1
static func ease_in_out_elastic(elapsed: float) -> float:
if elapsed == 0:
return 0.0
elif elapsed == 1:
return 1.0
elif elapsed < 0.5:
return -(pow(2, 20 * elapsed - 10) * sin((20 * elapsed - 11.125) * _ELASTIC_C5)) / 2
return (pow(2, -20 * elapsed + 10) * sin((20 * elapsed - 11.125) * _ELASTIC_C5)) / 2 + 1
const n1 = 7.5625;
const d1 = 2.75;
static func ease_in_bounce(elapsed: float) -> float:
return 1 - ease_out_bounce(1.0 - elapsed)
static func ease_out_bounce(elapsed: float) -> float:
if elapsed < 1 / d1:
return n1 * elapsed * elapsed;
elif elapsed < 2 / d1:
elapsed -= 1.5 / d1
return n1 * elapsed * elapsed + 0.75;
elif elapsed < 2.5 / d1:
elapsed -= 2.25 / d1
return n1 * elapsed * elapsed + 0.9375;
elapsed -= 2.625 / d1
return n1 * elapsed * elapsed + 0.984375;
static func ease_in_out_bounce(elapsed: float) -> float:
if elapsed < 0.5:
return (1 - ease_out_bounce(1 - 2 * elapsed)) / 2
return (1 + ease_out_bounce(2 * elapsed - 1)) / 2

View File

@ -0,0 +1,29 @@
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
#var delay: float = data._wait_time
var bounce_frames = [
{ percentage = 0, to = 0 },
{ percentage = 20, to = 0 },
{ percentage = 40, to = -30, easing_points = [0.7555, 0.5, 0.8555, 0.06] },
{ percentage = 43, to = 0, easing_points = [0.7555, 0.5, 0.8555, 0.06] },
{ percentage = 53, to = +30 },
{ percentage = 70, to = -15, easing_points = [0.755, 0.05, 0.855, 0.06] },
{ percentage = 80, to = +15 },
{ percentage = 90, to = -4 },
{ percentage = 100, to = +4 },
]
var scale = DialogicAnimaPropertiesHelper.get_scale(data.node)
var scale_frames = [
{ percentage = 0, to = 1 * scale.y },
{ percentage = 20, to = 1 * scale.y },
{ percentage = 40, to = 1.1 * scale.y, easing_points = [0.7555, 0.5, 0.8555, 0.06] },
{ percentage = 43, to = 1.1 * scale.y, easing_points = [0.7555, 0.5, 0.8555, 0.06] },
{ percentage = 53, to = 1 * scale.y },
{ percentage = 70, to = 1.05 * scale.y, easing_points = [0.755, 0.05, 0.855, 0.06] },
{ percentage = 80, to = 0.95 * scale.y },
{ percentage = 90, to = 1.02 * scale.y },
{ percentage = 100, to = 1 * scale.y },
]
anima_tween.add_relative_frames(data, "Y", bounce_frames)
anima_tween.add_frames(data, "scale:y", scale_frames)

View File

@ -0,0 +1,10 @@
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
var frames = [
{ percentage = 0, from = 1 },
{ percentage = 25, to = 0 },
{ percentage = 50, to = 1 },
{ percentage = 75, to = 0 },
{ percentage = 100, to = 1 },
]
anima_tween.add_frames(data, "opacity", frames)

View File

@ -0,0 +1,27 @@
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
var start = DialogicAnimaPropertiesHelper.get_position(data.node)
var shake_frames = [
{ percentage = 0, from = 0 },
{ percentage = 6.5, to = -6 },
{ percentage = 18.5, to = +5 },
{ percentage = 31.5, to = -3 },
{ percentage = 43.5, to = +2 },
{ percentage = 50, to = 0 },
{ percentage = 100, to = 0 },
]
var rotate_frames = [
{ percentage = 0, to = 0 },
{ percentage = 6.5, to = -9 },
{ percentage = 18.5, to = +7 },
{ percentage = 31.5, to = -5 },
{ percentage = 43.5, to = +3 },
{ percentage = 50, to = 0 },
{ percentage = 100, to = 0 },
]
DialogicAnimaPropertiesHelper.set_2D_pivot(data.node, DialogicAnimaPropertiesHelper.PIVOT.CENTER)
anima_tween.add_relative_frames(data, "x", shake_frames)
anima_tween.add_frames(data, "rotation", rotate_frames)

View File

@ -0,0 +1,14 @@
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
var scale = DialogicAnimaPropertiesHelper.get_scale(data.node)
var frames = [
{ percentage = 0, from = scale * Vector2(1, 1) },
{ percentage = 14, to = scale * Vector2(1.3, 1.3) },
{ percentage = 28, to = scale * Vector2(1, 1) },
{ percentage = 42, to = scale * Vector2(1.3, 1.3) },
{ percentage = 70, to = scale * Vector2(1, 1) },
{ percentage = 100, to = scale * Vector2(1, 1) },
]
DialogicAnimaPropertiesHelper.set_2D_pivot(data.node, DialogicAnimaPropertiesHelper.PIVOT.CENTER)
anima_tween.add_frames(data, "scale", frames)

View File

@ -0,0 +1,32 @@
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
var start_x = data.node.get_global_transform().y.x
var start_y = data.node.get_global_transform().x.y
var skew_x := []
var skew_y := []
var values = [
{ percentage = 0, add = 0 },
{ percentage = 11.1, add = 0 },
{ percentage = 22.2, add = - 0.3 },
{ percentage = 33.3, add = + 0.265 },
{ percentage = 44.4, add = - 0.1325 },
{ percentage = 55.5, add = + 0.06625 },
{ percentage = 66.6, add = - 0.033125 },
{ percentage = 77.7, add = + 0.0165625 },
{ percentage = 88.8, add = - 0.00828125},
{ percentage = 100, add = 0 },
]
for value in values:
skew_x.push_back({ percentage = value.percentage, to = start_x + value.add })
skew_y.push_back({ percentage = value.percentage, to = start_y + value.add })
DialogicAnimaPropertiesHelper.set_2D_pivot(data.node, DialogicAnimaPropertiesHelper.PIVOT.CENTER)
# Skew works only with Node2D
if not data.node is Node2D:
return
anima_tween.add_frames(data, "skew:x", skew_x)
anima_tween.add_frames(data, "skew:y", skew_y)

View File

@ -0,0 +1,12 @@
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
var scale = DialogicAnimaPropertiesHelper.get_scale(data.node)
var frames = [
{ percentage = 0, from = scale * Vector2(1, 1) },
{ percentage = 50, to = scale * Vector2(1.05, 1.05), easing = anima_tween.EASING.EASE_IN_OUT_SINE },
{ percentage = 100, to = scale * Vector2(1, 1) },
]
DialogicAnimaPropertiesHelper.set_2D_pivot(data.node, DialogicAnimaPropertiesHelper.PIVOT.CENTER)
anima_tween.add_frames(data, "scale", frames)

View File

@ -0,0 +1,15 @@
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
var scale = DialogicAnimaPropertiesHelper.get_scale(data.node)
var frames = [
{ percentage = 0, from = scale * Vector2(1, 1) },
{ percentage = 30, to = scale * Vector2(1.25, 0.75) },
{ percentage = 40, to = scale * Vector2(0.75, 1.25) },
{ percentage = 50, to = scale * Vector2(1.15, 0.85) },
{ percentage = 65, to = scale * Vector2(0.95, 1.05) },
{ percentage = 75, to = scale * Vector2(1.05, 0.95) },
{ percentage = 100, to = scale * Vector2(1, 1) },
]
DialogicAnimaPropertiesHelper.set_2D_pivot(data.node, DialogicAnimaPropertiesHelper.PIVOT.CENTER)
anima_tween.add_frames(data, "scale", frames)

View File

@ -0,0 +1,16 @@
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
var frames = [
{ percentage = 0, to = 0 },
{ percentage = 10, to = -10 },
{ percentage = 20, to = +20 },
{ percentage = 30, to = -20 },
{ percentage = 40, to = +20 },
{ percentage = 50, to = -20 },
{ percentage = 60, to = +20 },
{ percentage = 70, to = -20 },
{ percentage = 80, to = +20 },
{ percentage = 90, to = -20 },
{ percentage = 100, to = +10 },
]
anima_tween.add_relative_frames(data, "x", frames)

View File

@ -0,0 +1,16 @@
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
var frames = [
{ percentage = 0, to = 0 },
{ percentage = 10, to = -10 },
{ percentage = 20, to = +20 },
{ percentage = 30, to = -20 },
{ percentage = 40, to = +20 },
{ percentage = 50, to = -20 },
{ percentage = 60, to = +20 },
{ percentage = 70, to = -20 },
{ percentage = 80, to = +20 },
{ percentage = 90, to = -20 },
{ percentage = 100, to = +10 },
]
anima_tween.add_relative_frames(data, "y", frames)

View File

@ -0,0 +1,12 @@
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
var frames = [
{ percentage = 0, from = 0 },
{ percentage = 20, to = 15 },
{ percentage = 40, to = -10 },
{ percentage = 60, to = 5 },
{ percentage = 80, to = -5 },
{ percentage = 100, to = 0 },
]
DialogicAnimaPropertiesHelper.set_2D_pivot(data.node, DialogicAnimaPropertiesHelper.PIVOT.TOP_CENTER)
anima_tween.add_frames(data, "rotation", frames)

View File

@ -0,0 +1,22 @@
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
var rotate_frames = [
{ percentage = 0, from = 0 },
]
var scale_frames = [
{ percentage = 0, from = DialogicAnimaPropertiesHelper.get_scale(data.node) * Vector2(1, 1) },
]
for index in range(2, 9):
var s = -1 if index % 2 == 0 else 1
var percent = index * 10.0
rotate_frames.push_back({ percentage = percent, to = 3 * s })
scale_frames.push_back({ percentage = percent, to = Vector2(1.1, 1.1) })
DialogicAnimaPropertiesHelper.set_2D_pivot(data.node, DialogicAnimaPropertiesHelper.PIVOT.CENTER)
rotate_frames.push_back({percentage = 100, to = 0})
scale_frames.push_back({percentage = 100, to = Vector2(1, 1)})
anima_tween.add_frames(data, "rotation", rotate_frames)
anima_tween.add_frames(data, "scale", scale_frames)

View File

@ -0,0 +1,28 @@
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
var node = data.node
var start_position = DialogicAnimaPropertiesHelper.get_position(node)
var size = DialogicAnimaPropertiesHelper.get_size(node)
var x_frames = [
{ percentage = 0, from = start_position.x },
{ percentage = 15, to = start_position.x + size.x * -0.25 },
{ percentage = 30, to = start_position.x + size.x * 0.2 },
{ percentage = 45, to = start_position.x + size.x * -0.15 },
{ percentage = 60, to = start_position.x + size.x * 0.1 },
{ percentage = 75, to = start_position.x + size.x * -0.05 },
{ percentage = 100, to = start_position.x },
]
var rotation_frames = [
{ percentage = 0, from = 0 },
{ percentage = 15, to = -5 },
{ percentage = 30, to = 3 },
{ percentage = 45, to = -3 },
{ percentage = 60, to = 2 },
{ percentage = 75, to = -1 },
{ percentage = 100, to = 0 },
]
DialogicAnimaPropertiesHelper.set_2D_pivot(data.node, DialogicAnimaPropertiesHelper.PIVOT.TOP_CENTER)
anima_tween.add_frames(data, "x", x_frames)
anima_tween.add_frames(data, "rotation", rotation_frames)

View File

@ -0,0 +1,5 @@
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
var opacity_frames = [
{ from = 0, to = 1, easing_points = [0.42, 0, 0.58, 1]},
]
anima_tween.add_frames(data, "opacity", opacity_frames)

View File

@ -0,0 +1,14 @@
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
var opacity_frames = [
{ from = 0, to = 1, easing_points = [0.42, 0, 0.58, 1] },
]
var size = DialogicAnimaPropertiesHelper.get_size(data.node)
var position_frames = [
{ percentage = 0, from = size.y/16, easing_points = [0.42, 0, 0.58, 1] },
{ percentage = 100, to = -size.y/16, easing_points = [0.42, 0, 0.58, 1] },
]
anima_tween.add_relative_frames(data, "y", position_frames)
anima_tween.add_frames(data, "opacity", opacity_frames)

View File

@ -0,0 +1,14 @@
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
var opacity_frames = [
{ from = 0, to = 1 },
]
var size = DialogicAnimaPropertiesHelper.get_size(data.node)
var position_frames = [
{ percentage = 0, from = 2000 },
{ percentage = 100, to = -2000 },
]
anima_tween.add_relative_frames(data, "y", position_frames)
anima_tween.add_frames(data, "opacity", opacity_frames)

View File

@ -0,0 +1,6 @@
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
var opacity_frames = [
{ from = 1, to = 0, easing_points = [0.42, 0, 0.58, 1]},
]
anima_tween.add_frames(data, "opacity", opacity_frames)

View File

@ -0,0 +1,13 @@
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
var opacity_frames = [
{ from = 1, to = 0, easing_points = [0.42, 0, 0.58, 1] },
]
var size = DialogicAnimaPropertiesHelper.get_size(data.node)
var position_frames = [
{ from = 0, to = size.y/16, easing_points = [0.42, 0, 0.58, 1]},
]
anima_tween.add_relative_frames(data, "y", position_frames)
anima_tween.add_frames(data, "opacity", opacity_frames)

View File

@ -0,0 +1,12 @@
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
var opacity_frames = [
{ from = 1, to = 0 },
]
var position_frames = [
{ percentage = 0, from = 0},
{ percentage = 100, to = 2000 },
]
anima_tween.add_relative_frames(data, "y", position_frames)
anima_tween.add_frames(data, "opacity", opacity_frames)

View File

@ -0,0 +1,25 @@
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
var y_frames = [
{ percentage = 0, to = -1200 },
{ percentage = 80, to = +1200 },
{ percentage = 100, to = 0 },
]
var scale = DialogicAnimaPropertiesHelper.get_scale(data.node)
var scale_frames = [
{ percentage = 0, from = scale * Vector2(0.7, 0.7) },
{ percentage = 80, to = scale * Vector2(0.7, 0.7) },
{ percentage = 100, to = scale * Vector2(1, 1) },
]
var opacity_frames = [
{ percentage = 0, from = 0.7 },
{ percentage = 80, to = 0.7 },
{ percentage = 100, to = 1 },
]
DialogicAnimaPropertiesHelper.set_2D_pivot(data.node, DialogicAnimaPropertiesHelper.PIVOT.CENTER)
anima_tween.add_relative_frames(data, "y", y_frames)
anima_tween.add_frames(data, "scale", scale_frames)
anima_tween.add_frames(data, "opacity", opacity_frames)

View File

@ -0,0 +1,25 @@
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
var x_frames = [
{ percentage = 0, to = -2000 },
{ percentage = 80, to = +2000 },
{ percentage = 100, to = 0 },
]
var scale = DialogicAnimaPropertiesHelper.get_scale(data.node)
var scale_frames = [
{ percentage = 0, from = scale * Vector2(0.7, 0.7) },
{ percentage = 80, to = scale * Vector2(0.7, 0.7) },
{ percentage = 100, to = scale * Vector2(1, 1) },
]
var opacity_frames = [
{ percentage = 0, from = 0.7 },
{ percentage = 80, to = 0.7 },
{ percentage = 100, to = 1 },
]
DialogicAnimaPropertiesHelper.set_2D_pivot(data.node, DialogicAnimaPropertiesHelper.PIVOT.CENTER)
anima_tween.add_relative_frames(data, "x", x_frames)
anima_tween.add_frames(data, "scale", scale_frames)
anima_tween.add_frames(data, "opacity", opacity_frames)

View File

@ -0,0 +1,25 @@
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
var x_frames = [
{ percentage = 0, to = 2000 },
{ percentage = 80, to = -2000 },
{ percentage = 100, to = 0 },
]
var scale = DialogicAnimaPropertiesHelper.get_scale(data.node)
var scale_frames = [
{ percentage = 0, from = scale * Vector2(0.7, 0.7) },
{ percentage = 80, to = scale * Vector2(0.7, 0.7) },
{ percentage = 100, to = scale * Vector2(1, 1) },
]
var opacity_frames = [
{ percentage = 0, from = 0.7 },
{ percentage = 80, to = 0.7 },
{ percentage = 100, to = 1 },
]
DialogicAnimaPropertiesHelper.set_2D_pivot(data.node, DialogicAnimaPropertiesHelper.PIVOT.CENTER)
anima_tween.add_relative_frames(data, "x", x_frames)
anima_tween.add_frames(data, "scale", scale_frames)
anima_tween.add_frames(data, "opacity", opacity_frames)

View File

@ -0,0 +1,25 @@
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
var y_frames = [
{ percentage = 0, to = 1200 },
{ percentage = 80, to = -1200 },
{ percentage = 100, to = 0 },
]
var scale = DialogicAnimaPropertiesHelper.get_scale(data.node)
var scale_frames = [
{ percentage = 0, from = scale * Vector2(0.7, 0.7) },
{ percentage = 80, to = scale * Vector2(0.7, 0.7) },
{ percentage = 100, to = scale * Vector2(1, 1) },
]
var opacity_frames = [
{ percentage = 0, from = 0.7 },
{ percentage = 80, to = 0.7 },
{ percentage = 100, to = 1 },
]
DialogicAnimaPropertiesHelper.set_2D_pivot(data.node, DialogicAnimaPropertiesHelper.PIVOT.CENTER)
anima_tween.add_relative_frames(data, "y", y_frames)
anima_tween.add_frames(data, "scale", scale_frames)
anima_tween.add_frames(data, "opacity", opacity_frames)

View File

@ -0,0 +1,25 @@
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
var y_frames = [
{ percentage = 0, to = 0 },
{ percentage = 20, to = 0 },
{ percentage = 100, to = -700 },
]
var scale = DialogicAnimaPropertiesHelper.get_scale(data.node)
var scale_frames = [
{ percentage = 0, from = scale * Vector2(1, 1) },
{ percentage = 20, to = scale * Vector2(0.7, 0.7) },
{ percentage = 100, to = scale * Vector2(0.7, 0.7) },
]
var opacity_frames = [
{ percentage = 0, from = 1 },
{ percentage = 20, to = 0.7 },
{ percentage = 100, to = 0.7 },
]
DialogicAnimaPropertiesHelper.set_2D_pivot(data.node, DialogicAnimaPropertiesHelper.PIVOT.CENTER)
anima_tween.add_relative_frames(data, "y", y_frames)
anima_tween.add_frames(data, "scale", scale_frames)
anima_tween.add_frames(data, "opacity", opacity_frames)

View File

@ -0,0 +1,25 @@
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
var x_frames = [
{ percentage = 0, to = 0 },
{ percentage = 20, to = 0 },
{ percentage = 100, to = -2000 },
]
var scale = DialogicAnimaPropertiesHelper.get_scale(data.node)
var scale_frames = [
{ percentage = 0, from = scale * Vector2(1, 1) },
{ percentage = 20, to = scale * Vector2(0.7, 0.7) },
{ percentage = 100, to = scale * Vector2(0.7, 0.7) },
]
var opacity_frames = [
{ percentage = 0, from = 1 },
{ percentage = 20, to = 0.7 },
{ percentage = 100, to = 0.7 },
]
DialogicAnimaPropertiesHelper.set_2D_pivot(data.node, DialogicAnimaPropertiesHelper.PIVOT.CENTER)
anima_tween.add_relative_frames(data, "x", x_frames)
anima_tween.add_frames(data, "scale", scale_frames)
anima_tween.add_frames(data, "opacity", opacity_frames)

View File

@ -0,0 +1,25 @@
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
var x_frames = [
{ percentage = 0, to = 0 },
{ percentage = 20, to = 0 },
{ percentage = 100, to = 2000 },
]
var scale = DialogicAnimaPropertiesHelper.get_scale(data.node)
var scale_frames = [
{ percentage = 0, from = scale * Vector2(1, 1) },
{ percentage = 20, to = scale * Vector2(0.7, 0.7) },
{ percentage = 100, to = scale * Vector2(0.7, 0.7) },
]
var opacity_frames = [
{ percentage = 0, from = 1 },
{ percentage = 20, to = 0.7 },
{ percentage = 100, to = 0.7 },
]
DialogicAnimaPropertiesHelper.set_2D_pivot(data.node, DialogicAnimaPropertiesHelper.PIVOT.CENTER)
anima_tween.add_relative_frames(data, "x", x_frames)
anima_tween.add_frames(data, "scale", scale_frames)
anima_tween.add_frames(data, "opacity", opacity_frames)

View File

@ -0,0 +1,25 @@
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
var y_frames = [
{ percentage = 0, to = 0 },
{ percentage = 20, to = 0 },
{ percentage = 100, to = 700 },
]
var scale = DialogicAnimaPropertiesHelper.get_scale(data.node)
var scale_frames = [
{ percentage = 0, from = scale * Vector2(1, 1) },
{ percentage = 20, to = scale * Vector2(0.7, 0.7) },
{ percentage = 100, to = scale * Vector2(0.7, 0.7) },
]
var opacity_frames = [
{ percentage = 0, from = 1 },
{ percentage = 20, to = 0.7 },
{ percentage = 100, to = 0.7 },
]
DialogicAnimaPropertiesHelper.set_2D_pivot(data.node, DialogicAnimaPropertiesHelper.PIVOT.CENTER)
anima_tween.add_relative_frames(data, "y", y_frames)
anima_tween.add_frames(data, "scale", scale_frames)
anima_tween.add_frames(data, "opacity", opacity_frames)

View File

@ -0,0 +1,22 @@
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
var scale = DialogicAnimaPropertiesHelper.get_scale(data.node)
var scale_frames = [
{ percentage = 0, from = scale * Vector2(1, 1) },
{ percentage = 20, to = scale * Vector2(0.9, 0.9) },
{ percentage = 50, to = scale * Vector2(1.1, 1.1) },
{ percentage = 55, to = scale * Vector2(1.1, 1.1) },
{ percentage = 100, to = scale * Vector2(0.3, 0.3) },
]
var opacity_frames = [
{ percentage = 0, from = 1 },
{ percentage = 20, to = 1 },
{ percentage = 50, to = 1 },
{ percentage = 55, to = 1 },
{ percentage = 100, to = 0 },
]
DialogicAnimaPropertiesHelper.set_2D_pivot(data.node, DialogicAnimaPropertiesHelper.PIVOT.CENTER)
anima_tween.add_frames(data, "scale", scale_frames)
anima_tween.add_frames(data, "opacity", opacity_frames)

View File

@ -0,0 +1,21 @@
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
var scale = DialogicAnimaPropertiesHelper.get_scale(data.node)
var scale_frames = [
{ percentage = 0, from = scale * Vector2(0.3, 0.3), easing_points = [0.215, 0.61, 0.355, 1] },
{ percentage = 20, to = scale * Vector2(1, 1), easing_points = [0.215, 0.61, 0.355, 1] },
{ percentage = 40, to = scale * Vector2(0.9, 0.9), easing_points = [0.215, 0.61, 0.355, 1] },
{ percentage = 60, to = scale * Vector2(1.03, 1.03), easing_points = [0.215, 0.61, 0.355, 1] },
{ percentage = 80, to = scale * Vector2(0.97, 0.97), easing_points = [0.215, 0.61, 0.355, 1] },
{ percentage = 100, to = scale * Vector2(1, 1) },
]
var opacity_frames = [
{ percentage = 0, from = 0 },
{ percentage = 60, to = 1 },
{ percentage = 100, to = 1 },
]
DialogicAnimaPropertiesHelper.set_2D_pivot(data.node, DialogicAnimaPropertiesHelper.PIVOT.CENTER)
anima_tween.add_frames(data, "scale", scale_frames)
anima_tween.add_frames(data, "opacity", opacity_frames)

View File

@ -0,0 +1,5 @@
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
var opacity_frames = [
{ from = 1, to = 1 },
]
anima_tween.add_frames(data, "opacity", opacity_frames)

View File

@ -0,0 +1,5 @@
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
var opacity_frames = [
{ from = 0, to = 0 },
]
anima_tween.add_frames(data, "opacity", opacity_frames)

View File

@ -0,0 +1,19 @@
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
var x_frames = [
{ percentage = 0, to = -2000 },
{ percentage = 80, to = +2000 },
{ percentage = 100, to = 0 },
]
var opacity_frames = [
{ percentage = 0, from = 0.7 },
{ percentage = 80, to = 0.7 },
{ percentage = 100, to = 1 },
]
DialogicAnimaPropertiesHelper.set_2D_pivot(data.node, DialogicAnimaPropertiesHelper.PIVOT.CENTER)
anima_tween.add_relative_frames(data, "x", x_frames)
#anima_tween.add_frames(data, "scale", scale_frames)
anima_tween.add_frames(data, "opacity", opacity_frames)

View File

@ -0,0 +1,25 @@
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
var x_frames = [
{ percentage = 0, to = 2000 },
{ percentage = 80, to = -2000 },
{ percentage = 100, to = 0 },
]
var scale = DialogicAnimaPropertiesHelper.get_scale(data.node)
var scale_frames = [
{ percentage = 0, from = scale * Vector2(0.7, 0.7) },
{ percentage = 80, to = scale * Vector2(0.7, 0.7) },
{ percentage = 100, to = scale * Vector2(1, 1) },
]
var opacity_frames = [
{ percentage = 0, from = 0.7 },
{ percentage = 80, to = 0.7 },
{ percentage = 100, to = 1 },
]
DialogicAnimaPropertiesHelper.set_2D_pivot(data.node, DialogicAnimaPropertiesHelper.PIVOT.CENTER)
anima_tween.add_relative_frames(data, "x", x_frames)
anima_tween.add_frames(data, "scale", scale_frames)
anima_tween.add_frames(data, "opacity", opacity_frames)

View File

@ -0,0 +1,17 @@
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
var x_frames = [
{ percentage = 0, to = 0 },
{ percentage = 20, to = 0 },
{ percentage = 100, to = -2000 },
]
var opacity_frames = [
{ percentage = 0, from = 1 },
{ percentage = 20, to = 0.7 },
{ percentage = 100, to = 0.7 },
]
DialogicAnimaPropertiesHelper.set_2D_pivot(data.node, DialogicAnimaPropertiesHelper.PIVOT.CENTER)
anima_tween.add_relative_frames(data, "x", x_frames)
anima_tween.add_frames(data, "opacity", opacity_frames)

View File

@ -0,0 +1,17 @@
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
var x_frames = [
{ percentage = 0, to = 0 },
{ percentage = 20, to = 0 },
{ percentage = 100, to = 2000 },
]
var opacity_frames = [
{ percentage = 0, from = 1 },
{ percentage = 20, to = 0.7 },
{ percentage = 100, to = 0.7 },
]
DialogicAnimaPropertiesHelper.set_2D_pivot(data.node, DialogicAnimaPropertiesHelper.PIVOT.CENTER)
anima_tween.add_relative_frames(data, "x", x_frames)
anima_tween.add_frames(data, "opacity", opacity_frames)

View File

@ -0,0 +1,48 @@
extends TextureRect
var native_dialogic_background = true
var tween
func _ready():
expand = true
name = 'Background'
anchor_right = 1
anchor_bottom = 1
if DialogicResources.get_settings_value('dialog', 'stretch_backgrounds', true):
stretch_mode = TextureRect.STRETCH_SCALE
else:
stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_COVERED
show_behind_parent = true
mouse_filter = Control.MOUSE_FILTER_IGNORE
func _init():
tween = Tween.new()
add_child(tween)
func fade_in(time = 1):
modulate = Color(1, 1,1,0)
tween.interpolate_property(self, "modulate",
null, Color(1,1,1,1), time,
Tween.TRANS_LINEAR, Tween.EASE_IN_OUT)
tween.start()
func fade_out(time = 1):
if tween:
tween.connect('tween_all_completed', self, '_on_tween_over')
tween.interpolate_property(self, "modulate",
Color(1,1,1,1), Color(1,1,1,0), time,
Tween.TRANS_LINEAR, Tween.EASE_IN_OUT)
tween.start()
else:
_on_tween_over()
func remove_with_delay(time =1):
var timer = Timer.new()
timer.connect("timeout", self, "queue_free")
add_child(timer)
timer.start(time+0.1)
func _on_tween_over():
queue_free()

View File

@ -0,0 +1,9 @@
[gd_scene load_steps=2 format=2]
[ext_resource path="res://addons/dialogic/Nodes/Background.gd" type="Script" id=1]
[node name="Background" type="TextureRect"]
script = ExtResource( 1 )
__meta__ = {
"_edit_use_anchors_": false
}

View File

@ -0,0 +1,62 @@
extends Control
class_name DialogicBackgroundMusic
onready var _track1 := $Track1
onready var _track2 := $Track2
var current_path = ""
var current_track = null
func _ready():
$Tween.connect("tween_completed", self, "_on_Tween_tween_completed")
func crossfade_to(path: String, audio_bus:String, volume:float, fade_length: float) -> void:
# find a better solution for this
if _track1.playing and _track2.playing:
return
var stream: AudioStream = load(path)
var fade_out_track = _track1
var fade_in_track = _track2
if _track2.playing:
fade_out_track = _track2
fade_in_track = _track1
# setup the new track
fade_in_track.stream = stream
fade_in_track.bus = audio_bus
fade_in_track.volume_db = -60
$Tween.interpolate_property(fade_out_track, "volume_db", null, -60, fade_length, Tween.TRANS_EXPO)
$Tween.interpolate_property(fade_in_track, "volume_db", -60, volume, fade_length, Tween.TRANS_EXPO)
$Tween.start()
# in case the audio is already playing we will attempt a fade into the new one from the current position
if current_path == path:
fade_in_track.play(fade_out_track.get_playback_position())
# else just play it from the beginning
else:
fade_in_track.play()
current_track = fade_in_track
current_path = path
func fade_out(fade_length:float = 1) -> void:
current_path = ""
current_track = null
$Tween.interpolate_property(_track1, "volume_db", null, -60, fade_length, Tween.TRANS_EXPO)
$Tween.interpolate_property(_track2, "volume_db", null, -60, fade_length, Tween.TRANS_EXPO)
$Tween.start()
func _on_Tween_tween_completed(object, key):
# if the stream was faded out
if object.volume_db == -60:
object.playing = false
object.stream = null
func get_current_info():
if current_track != null:
return {"file":current_path, "volume": current_track.volume_db, "audio_bus": current_track.bus}
return null

View File

@ -0,0 +1,19 @@
[gd_scene load_steps=2 format=2]
[ext_resource path="res://addons/dialogic/Nodes/BackgroundMusic.gd" type="Script" id=1]
[node name="BackgroundMusic" type="Control"]
margin_right = 40.0
margin_bottom = 40.0
script = ExtResource( 1 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Track1" type="AudioStreamPlayer" parent="."]
volume_db = -80.0
[node name="Track2" type="AudioStreamPlayer" parent="."]
volume_db = -80.0
[node name="Tween" type="Tween" parent="."]

View File

@ -0,0 +1,51 @@
extends AudioStreamPlayer
var stop_time:float
func play_voice(data:Dictionary) -> void:
if data == {}:
stop_voice()
return
if data.has('volume'):
volume_db = data['volume']
if data.has('audio_bus'):
bus = data['audio_bus']
if data.has('file'):
if data['file'] == '':
stop_voice()
return
var s:AudioStream = load(data['file'])
if s != null:
stream = s
#Will play from start_time when possible
if data.has('start_time'):
play(data['start_time'])
else:
play()
#Stop time will fall back to length of audiostream minus 0.1 secund
#if not defined otherwise. This should allow _process to stop the
#audio before it autorepeats
if data.has('stop_time'):
stop_time = data['stop_time']
if stop_time <= 0:
stop_time = s.get_length() - 0.1
else:
stop_time = s.get_length() - 0.1
else:
stop_voice()
func stop_voice():
stop()
#this is part of a hack, and could be replaced with something more elegant. - KvaGram
func remaining_time():
if !playing:
return 0
return stop_time - get_playback_position()
func _process(_delta):
#Will automatically stop playing when reaching stop_time
if(playing && get_playback_position() >= stop_time):
stop_voice()

View File

@ -0,0 +1,10 @@
extends Button
func _process(delta):
if Input.is_action_pressed(get_meta('input_next')):
if has_focus():
emit_signal("button_down")
if Input.is_action_just_released(get_meta('input_next')):
if has_focus():
emit_signal("button_up")
emit_signal("pressed")

View File

@ -0,0 +1,12 @@
[gd_scene load_steps=2 format=2]
[ext_resource path="res://addons/dialogic/Nodes/ChoiceButton.gd" type="Script" id=1]
[node name="ChoiceButton" type="Button"]
size_flags_horizontal = 4
size_flags_vertical = 4
text = "Testing button "
script = ExtResource( 1 )
__meta__ = {
"_edit_use_anchors_": false
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,184 @@
[gd_scene load_steps=14 format=2]
[ext_resource path="res://addons/dialogic/Nodes/TextBubble.tscn" type="PackedScene" id=1]
[ext_resource path="res://addons/dialogic/Example Assets/backgrounds/GlossaryBackground.tres" type="StyleBox" id=2]
[ext_resource path="res://addons/dialogic/Nodes/CharacterVoice.gd" type="Script" id=3]
[ext_resource path="res://addons/dialogic/Example Assets/Fonts/GlossaryFont.tres" type="DynamicFont" id=4]
[ext_resource path="res://addons/dialogic/Nodes/glossary_info.gd" type="Script" id=5]
[ext_resource path="res://addons/dialogic/Nodes/DialogNode.gd" type="Script" id=6]
[ext_resource path="res://addons/dialogic/Nodes/BackgroundMusic.tscn" type="PackedScene" id=7]
[ext_resource path="res://addons/dialogic/Nodes/random_audio_stream_player.gd" type="Script" id=8]
[ext_resource path="res://addons/dialogic/Example Assets/Sound Effects/Beep.wav" type="AudioStream" id=9]
[ext_resource path="res://addons/dialogic/Nodes/DialogicCustomEvents.gd" type="Script" id=10]
[ext_resource path="res://addons/dialogic/Nodes/History.tscn" type="PackedScene" id=11]
[sub_resource type="StyleBoxFlat" id=1]
bg_color = Color( 1, 1, 1, 0 )
expand_margin_left = 10.0
[sub_resource type="RectangleShape2D" id=2]
extents = Vector2( 1280, 720 )
[node name="DialogNode" type="Control"]
anchor_right = 1.0
anchor_bottom = 1.0
script = ExtResource( 6 )
[node name="Portraits" type="Control" parent="."]
anchor_left = 0.5
anchor_top = 1.0
anchor_right = 0.5
anchor_bottom = 1.0
margin_left = 640.0
margin_top = 720.0
margin_right = 640.0
margin_bottom = 720.0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="TextBubble" parent="." instance=ExtResource( 1 )]
margin_left = 185.0
margin_top = 513.0
margin_right = 1095.0
margin_bottom = 680.0
[node name="Options" type="VBoxContainer" parent="."]
visible = false
margin_right = 1280.0
margin_bottom = 720.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 2
alignment = 1
__meta__ = {
"_edit_use_anchors_": false
}
[node name="FX" type="Control" parent="."]
anchor_right = 1.0
anchor_bottom = 1.0
mouse_filter = 2
__meta__ = {
"_edit_group_": true,
"_edit_lock_": true,
"_edit_use_anchors_": false
}
[node name="BackgroundMusic" parent="FX" instance=ExtResource( 7 )]
[node name="CharacterVoice" type="AudioStreamPlayer" parent="FX"]
script = ExtResource( 3 )
[node name="Audio" type="Node" parent="FX"]
[node name="Typing" type="AudioStreamPlayer" parent="FX/Audio"]
script = ExtResource( 8 )
samples = [ ExtResource( 9 ) ]
random_strategy = 2
[node name="Waiting" type="AudioStreamPlayer" parent="FX/Audio"]
script = ExtResource( 8 )
samples = [ ExtResource( 9 ) ]
random_strategy = 2
[node name="Passing" type="AudioStreamPlayer" parent="FX/Audio"]
script = ExtResource( 8 )
samples = [ ExtResource( 9 ) ]
random_strategy = 2
[node name="Hovering" type="AudioStreamPlayer" parent="FX/Audio"]
script = ExtResource( 8 )
samples = [ ExtResource( 9 ) ]
random_strategy = 2
[node name="Selecting" type="AudioStreamPlayer" parent="FX/Audio"]
script = ExtResource( 8 )
samples = [ ExtResource( 9 ) ]
random_strategy = 2
[node name="DefinitionInfo" type="PanelContainer" parent="."]
visible = false
margin_right = 208.0
mouse_filter = 1
size_flags_horizontal = 3
size_flags_vertical = 3
custom_styles/panel = ExtResource( 2 )
script = ExtResource( 5 )
__meta__ = {
"_edit_group_": true,
"_edit_use_anchors_": false
}
[node name="VBoxContainer" type="VBoxContainer" parent="DefinitionInfo"]
margin_right = 208.0
margin_bottom = 143.0
size_flags_horizontal = 3
size_flags_vertical = 2
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Title" type="RichTextLabel" parent="DefinitionInfo/VBoxContainer"]
margin_right = 208.0
margin_bottom = 27.0
size_flags_horizontal = 3
size_flags_vertical = 4
custom_colors/default_color = Color( 1, 1, 1, 1 )
custom_fonts/normal_font = ExtResource( 4 )
custom_styles/normal = SubResource( 1 )
bbcode_enabled = true
bbcode_text = "This is the title"
text = "This is the title"
fit_content_height = true
scroll_active = false
[node name="Content" type="RichTextLabel" parent="DefinitionInfo/VBoxContainer"]
margin_top = 31.0
margin_right = 208.0
margin_bottom = 112.0
size_flags_horizontal = 3
custom_colors/default_color = Color( 0.756863, 0.756863, 0.756863, 1 )
custom_fonts/normal_font = ExtResource( 4 )
custom_styles/normal = SubResource( 1 )
bbcode_enabled = true
fit_content_height = true
scroll_active = false
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Extra" type="RichTextLabel" parent="DefinitionInfo/VBoxContainer"]
margin_top = 116.0
margin_right = 208.0
margin_bottom = 143.0
size_flags_horizontal = 3
custom_colors/default_color = Color( 0.756863, 0.756863, 0.756863, 1 )
custom_fonts/normal_font = ExtResource( 4 )
custom_styles/normal = SubResource( 1 )
bbcode_enabled = true
fit_content_height = true
scroll_active = false
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Timer" type="Timer" parent="DefinitionInfo"]
[node name="OptionsDelayedInput" type="Timer" parent="."]
[node name="DialogicTimer" type="Timer" parent="."]
one_shot = true
[node name="CustomEvents" type="Node" parent="."]
script = ExtResource( 10 )
[node name="History" parent="." instance=ExtResource( 11 )]
[node name="TouchScreenButton" type="TouchScreenButton" parent="."]
shape = SubResource( 2 )
shape_visible = false
action = "dialogic_default_action"
visibility_mode = 1
[connection signal="timeout" from="DefinitionInfo/Timer" to="." method="_on_Definition_Timer_timeout"]

View File

@ -0,0 +1,50 @@
extends Control
## The timeline to load when starting the scene
export(String, "TimelineDropdown") var timeline: String
export(bool) var add_canvas = true
export(bool) var reset_saves = true
func _ready():
if reset_saves:
Dialogic.reset_saves()
var d = Dialogic.start(timeline, '', "res://addons/dialogic/Nodes/DialogNode.tscn", add_canvas)
get_parent().call_deferred('add_child', d)
_copy_signals(d if not add_canvas else d.dialog_node)
queue_free()
func _copy_signals(dialogic:Node):
var sigs = self.get_signal_list()
for s in sigs:
if not s['name'] in _signals_to_copy:
continue
if not dialogic.has_signal(s['name']):
print("Cannot copy connections of signal " + s['name'] + " from " + self.to_string() + " to " + dialogic.to_string())
continue
var conns = self.get_signal_connection_list(s['name'])
for c in conns:
dialogic.connect(c['signal'], c['target'], c['method'], c['binds'], c['flags'])
var _signals_to_copy = [
'event_start',
'event_end',
'text_complete',
'timeline_start',
'timeline_end',
'dialogic_signal'
]
## -----------------------------------------------------------------------------
## SIGNALS (proxy copy of DialogNode signals)
## -----------------------------------------------------------------------------
# Event end/start
signal event_start(type, event)
signal event_end(type)
# Text Signals
signal text_complete(text_data)
# Timeline end/start
signal timeline_start(timeline_name)
signal timeline_end(timeline_name)
# Custom user signal
signal dialogic_signal(value)

View File

@ -0,0 +1,75 @@
tool
extends Node
class_name DialogicCustomEvents
# references to the nodes with the handler script
# to be used later by the "event_handler"
# keys: event_id
# values: reference to handler node.
var handlers : = {}
## -----------------------------------------------------------------------------
## Loops through the custom events folder and creates a handler node
## for every custom event.
##
## To handle a custom event simply check if the event_id is in the handlers dicionary keys,
## then get the value (which is the handler node) to call its hadler function
func update() -> void:
var path : String = DialogicResources.get_working_directories()["CUSTOM_EVENTS_DIR"]
var dir = Directory.new()
if dir.open(path) == OK:
dir.list_dir_begin()
var file_name = dir.get_next()
# goes through all the folders in the custom events folder
while file_name != "":
# if it found a folder
if dir.current_is_dir() and not file_name in ['.', '..']:
# look through that folder
#print("Found custom event folder: " + file_name)
var event = load(path.plus_file(file_name).plus_file('EventBlock.tscn')).instance()
if event:
var handler_script_path = path.plus_file(file_name).plus_file('event_'+event.event_data['event_id']+'.gd')
var event_id = event.event_data['event_id']
var event_name = event.event_name
# not necesary, we now have the data in the handlers dict
#custom_events[event.event_data['event_id']] = {
# 'event_script' : handler_script_path,
# 'event_name' : event.event_name,
#}
# Check if we already have a handler node for this event.
if handlers.has(event_id):
#print("Custom event ",event_id," already loaded")
#print("Continuing...")
file_name = dir.get_next()
continue
else:
#print("No handler node for event ",event_id," found.")
#print("Creating...")
# create a node for the custom event an attach the script
var handler = Node.new()
handler.set_script(load(handler_script_path))
handler.set_name(event_name)
# not really necessary, but just in case
handler.set_meta("event_id",event_id)
#add data to dictionary
handlers[event_id] = handler
#add node as a child of this
self.add_child(handler)
event.queue_free()
else:
print("[D] An error occurred when trying to access a custom event.")
else:
pass # files in the directory are ignored
file_name = dir.get_next()
else:
print("[D] An error occurred when trying to access the custom event folder.")

View File

@ -0,0 +1,311 @@
tool
extends Control
export(PackedScene) var HistoryRow = load("res://addons/dialogic/Example Assets/History/HistoryRow.tscn")
export(PackedScene) var HistoryDefaultBackground = load("res://addons/dialogic/Example Assets/History/HistoryBackground.tscn")
export(PackedScene) var HistoryOpenButton = load("res://addons/dialogic/Example Assets/History/HistoryButton.tscn")
export(PackedScene) var HistoryCloseButton = load("res://addons/dialogic/Example Assets/History/HistoryButton.tscn")
export(int) var Vertical_Separation = 16
onready var HistoryTimeline = $HistoryPopup/ScrollHistoryContainer/MarginContainer/HistoryTimeline
onready var scrollbar = $HistoryPopup/ScrollHistoryContainer.get_v_scrollbar()
onready var ScrollHistoryContainer = $HistoryPopup/ScrollHistoryContainer
onready var HistoryPopup = $HistoryPopup
onready var HistoryAudio = $HistoryPopup/HistoryAudio
var HistoryButton
var CloseButton
var HistoryBackground
var is_history_open = false
var is_mouse_on_button = false
var block_dialog_advance = false setget , history_advance_block
var lastQuestionNode = null
var curTheme = null
var prevState
var eventsToLog = ['dialogic_001', 'dialogic_010']
var logArrivals = false
var logExits = false
var scrollToBottom = true
var reverseTimeline = false
var characterNameColorOn = true
var lineBreakAfterName = true
var scrollToggle = false
func _ready():
var testHistoryRow = HistoryRow.instance()
assert(testHistoryRow.has_method('add_history'), 'HistoryRow Scene must implement add_history(string, string) method.')
testHistoryRow.queue_free()
HistoryBackground = HistoryDefaultBackground.instance()
HistoryPopup.add_child(HistoryBackground)
HistoryPopup.move_child(HistoryBackground, 0)
#Scrollbar only updates when visible, so need it to be handled
scrollbar.connect("changed",self,"handle_scrollbar_changed")
func handle_scrollbar_changed():
#It's firing every frame, we only want to check it once on opening
if(scrollToggle):
scrollToggle = false
if (scrollToBottom):
ScrollHistoryContainer.scroll_vertical = scrollbar.max_value
else:
ScrollHistoryContainer.scroll_vertical = 0
func initalize_history():
if get_parent().settings.get_value('history', 'enable_open_button', true):
HistoryButton = HistoryOpenButton.instance()
add_child(HistoryButton)
HistoryButton.connect("pressed", self, '_on_toggle_history')
HistoryButton.connect("mouse_entered", self, '_on_HistoryButton_mouse_entered')
HistoryButton.connect("mouse_exited", self, '_on_HistoryButton_mouse_exited')
HistoryButton.disabled = false
HistoryButton.show()
if get_parent().settings.get_value('history', 'enable_close_button', true):
CloseButton = HistoryCloseButton.instance()
add_child(CloseButton)
CloseButton.connect("pressed", self, '_on_toggle_history')
CloseButton.disabled = true
CloseButton.hide()
# See if we're logging arrivals and exits
logArrivals = get_parent().settings.get_value('history', 'log_arrivals', true)
logExits = get_parent().settings.get_value('history', 'log_exits', true)
if logExits or logArrivals:
eventsToLog.push_back('dialogic_002')
# Set the other selectable settings options
scrollToBottom = get_parent().settings.get_value('history', 'history_scroll_to_bottom', true)
reverseTimeline = get_parent().settings.get_value('history', 'history_reverse_timeline', false)
characterNameColorOn = get_parent().settings.get_value('history', 'history_name_color_on', true)
lineBreakAfterName = get_parent().settings.get_value('history', 'history_break_after_name', false)
# Grab some settings and make the boxes up right
var button_anchor = int(get_parent().settings.get_value('history', 'history_button_position', 2))
var screen_margin_x = get_parent().settings.get_value('history', 'history_screen_margin_x', 0)
var screen_margin_y = get_parent().settings.get_value('history', 'history_screen_margin_y', 0)
var container_margin_X = get_parent().settings.get_value('history', 'history_container_margin_x', 0)
var container_margin_y = get_parent().settings.get_value('history', 'history_container_margin_y', 0)
HistoryPopup.margin_left = screen_margin_x
HistoryPopup.margin_right = -screen_margin_x
HistoryPopup.margin_top = screen_margin_y
HistoryPopup.margin_bottom = -screen_margin_y
ScrollHistoryContainer.margin_left = container_margin_X
ScrollHistoryContainer.margin_right = -container_margin_X
ScrollHistoryContainer.margin_top = container_margin_y
ScrollHistoryContainer.margin_bottom = -container_margin_y
for button in [HistoryButton, CloseButton]:
if button == null:
continue
var reference = button.get_parent().rect_size
# Adding audio when focused or hovered
button.connect('focus_entered', get_parent(), '_on_option_hovered', [button])
button.connect('mouse_entered', get_parent(), '_on_option_focused')
# Button positioning
var anchor_values = [0,0,1,1]
var position_offset = Vector2(0,0)
# Top Left
if button_anchor == 0:
anchor_values = [0, 0, 0, 0]
position_offset.x = 0
position_offset.y = 0
# Top Center
elif button_anchor == 1:
anchor_values = [.5, 0, .5, 0]
position_offset.x = reference.x/2 - button.rect_size.x
position_offset.y = 0
# Top Right
elif button_anchor == 2:
anchor_values = [1, 0, 1, 0]
position_offset.x = reference.x - button.rect_size.x
position_offset.y = 0
# 3 - Number skip because of the separator
# Center Left
elif button_anchor == 4:
anchor_values = [0, .5, 0, .5]
position_offset.x = 0
position_offset.y = reference.y/2 - button.rect_size.y
# True Center
elif button_anchor == 5:
anchor_values = [.5, .5, .5, .5]
position_offset.x = reference.x/2 - button.rect_size.x
position_offset.y = reference.y/2 - button.rect_size.y
# Center Right
elif button_anchor == 6:
anchor_values = [1, .5, 1, .5]
position_offset.x = reference.x - button.rect_size.x
position_offset.y = reference.y/2 - button.rect_size.y
# Number skip because of the separator
elif button_anchor == 8:
anchor_values = [0, 1, 0, 1]
position_offset.x = 0
position_offset.y = reference.y - button.rect_size.y
elif button_anchor == 9:
anchor_values = [.5, 1, .5, 1]
position_offset.x = reference.x/2 - button.rect_size.x
position_offset.y = reference.y - button.rect_size.y
elif button_anchor == 10:
anchor_values = [1, 1, 1, 1]
position_offset.x = reference.x - button.rect_size.x
position_offset.y = reference.y - button.rect_size.y
button.anchor_left = anchor_values[0]
button.anchor_top = anchor_values[1]
button.anchor_right = anchor_values[2]
button.anchor_bottom = anchor_values[3]
button.rect_global_position = button.get_parent().rect_global_position + position_offset
# Add history based on the passed event, using some logic to get it right
func add_history_row_event(eventData):
# Abort if we aren't logging the event, or if its a character event of type update
if !eventsToLog.has(eventData.event_id) or (eventData.event_id == 'dialogic_002' and eventData.get('type') == 2 ):
return
# Abort if we aren't logging arrivals and its a character event of type arrival
if eventData.event_id == 'dialogic_002' and eventData.get('type') == 0 and !logArrivals:
return
# Abort if we aren't logging exits and its a character event of type exit
if eventData.event_id == 'dialogic_002' and eventData.get('type') == 1 and !logExits:
return
var newHistoryRow = HistoryRow.instance()
HistoryTimeline.add_child(newHistoryRow)
if(reverseTimeline):
HistoryTimeline.move_child(newHistoryRow,0)
if newHistoryRow.has_method('load_theme') and get_parent().settings.get_value('history', 'enable_dynamic_theme', false) == true:
newHistoryRow.load_theme(curTheme)
var characterPrefix = ''
if eventData.has('character') and eventData.character != '':
var characterData = DialogicUtil.get_character(eventData.character)
var characterName = characterData.get('name', '')
if eventData.has('character') and eventData.character == '[All]':
characterPrefix = str('Everyone')
elif characterData.data.get('display_name_bool', false) == true:
characterName = characterData.data.get('display_name', '')
if characterName != '':
var charDelimiter = get_parent().settings.get_value('history', 'history_character_delimiter', '')
var parsed_name = DialogicParser.parse_definitions(get_parent(), characterName, true, false)
var characterColor = characterData.data.get('color', Color.white)
if (!characterNameColorOn):
characterColor = Color.white
var lineBreak = ''
if (lineBreakAfterName):
lineBreak = '\n'
characterPrefix = str("[color=",characterColor,"]", parsed_name, "[/color]", charDelimiter, ' ', lineBreak)
var audioData = ''
if eventData.has('voice_data'):
if eventData['voice_data'].has('0'):
audioData = eventData['voice_data']['0'].file
newHistoryRow.AudioButton.connect('pressed', self, '_on_audio_trigger', [audioData])
# event logging handled here
# Text Events
if eventData.event_id == 'dialogic_001':
newHistoryRow.add_history(str(characterPrefix, eventData.text), audioData)
# Character Arrivals
elif eventData.event_id == 'dialogic_002':
var logText = get_parent().settings.get_value('history', 'text_arrivals', 'has arrived')
if eventData.get('type') == 1:
logText = get_parent().settings.get_value('history', 'text_exits', 'has left')
newHistoryRow.add_history(str(characterPrefix, ' ', logText), audioData)
# List Choices
elif eventData.event_id == 'dialogic_010':
newHistoryRow.add_history(str(characterPrefix, eventData.question), audioData)
if eventData.has('options') and get_parent().settings.get_value('history', 'log_choices', true):
var choiceString = "\n\t"
for choice in eventData['options']:
choiceString = str(choiceString, '[', choice.label, ']\t')
newHistoryRow.add_history(choiceString, audioData)
lastQuestionNode = newHistoryRow
func add_answer_to_question(stringData):
if lastQuestionNode != null:
lastQuestionNode.add_history(str('\n\t', stringData), lastQuestionNode.audioPath)
lastQuestionNode = null
func change_theme(newTheme: ConfigFile):
if get_parent().settings.get_value('history', 'enable_dynamic_theme', false):
curTheme = newTheme
func load_theme(theme: ConfigFile):
curTheme = theme
func _on_audio_trigger(audioFilepath):
HistoryAudio.stream = load(audioFilepath)
HistoryAudio.play()
func _on_HistoryPopup_popup_hide():
HistoryAudio.stop()
func _on_HistoryPopup_about_to_show():
if HistoryButton != null:
scrollToggle = true
HistoryButton.show()
func _on_HistoryButton_mouse_entered():
is_mouse_on_button = true
func _on_HistoryButton_mouse_exited():
is_mouse_on_button = false
func history_advance_block() -> bool:
return is_mouse_on_button or is_history_open
# Used to manually toggle the history visibility on or off
# This is most useful when you wish to make your own custom controls
func _on_toggle_history():
if HistoryPopup.visible == false:
_on_HistoryPopup_about_to_show()
HistoryPopup.show()
if HistoryButton != null:
HistoryButton.hide()
HistoryButton.disabled = true
if CloseButton != null:
CloseButton.disabled = false
CloseButton.show()
is_history_open = true
is_mouse_on_button = false
else:
_on_HistoryPopup_popup_hide()
HistoryPopup.hide()
if HistoryButton != null:
HistoryButton.show()
HistoryButton.disabled = false
if CloseButton != null:
CloseButton.disabled = true
CloseButton.hide()
is_history_open = false
is_mouse_on_button = false

View File

@ -0,0 +1,54 @@
[gd_scene load_steps=6 format=2]
[ext_resource path="res://addons/dialogic/Example Assets/History/HistoryBackground.tscn" type="PackedScene" id=1]
[ext_resource path="res://addons/dialogic/Example Assets/History/HistoryRow.tscn" type="PackedScene" id=2]
[ext_resource path="res://addons/dialogic/Nodes/History.gd" type="Script" id=3]
[ext_resource path="res://addons/dialogic/Example Assets/History/HistoryButton.tscn" type="PackedScene" id=4]
[ext_resource path="res://addons/dialogic/Example Assets/History/HistoryReturnButton.tscn" type="PackedScene" id=5]
[node name="History" type="Control"]
anchor_right = 1.0
anchor_bottom = 1.0
mouse_filter = 2
script = ExtResource( 3 )
__meta__ = {
"_edit_use_anchors_": false
}
HistoryRow = ExtResource( 2 )
HistoryDefaultBackground = ExtResource( 1 )
HistoryOpenButton = ExtResource( 4 )
HistoryCloseButton = ExtResource( 5 )
[node name="HistoryPopup" type="Control" parent="."]
visible = false
anchor_right = 1.0
anchor_bottom = 1.0
[node name="HistoryAudio" type="AudioStreamPlayer" parent="HistoryPopup"]
[node name="ScrollHistoryContainer" type="ScrollContainer" parent="HistoryPopup"]
anchor_right = 1.0
anchor_bottom = 1.0
size_flags_horizontal = 3
__meta__ = {
"_edit_use_anchors_": false
}
[node name="MarginContainer" type="MarginContainer" parent="HistoryPopup/ScrollHistoryContainer"]
margin_right = 1024.0
margin_bottom = 10.0
size_flags_horizontal = 3
custom_constants/margin_right = 5
custom_constants/margin_top = 5
custom_constants/margin_left = 5
custom_constants/margin_bottom = 5
__meta__ = {
"_edit_use_anchors_": false
}
[node name="HistoryTimeline" type="VBoxContainer" parent="HistoryPopup/ScrollHistoryContainer/MarginContainer"]
margin_left = 5.0
margin_top = 5.0
margin_right = 1019.0
margin_bottom = 5.0
custom_constants/separation = 16

View File

@ -0,0 +1,204 @@
extends Control
var z_index = 0
var character_data = {
'name': 'Default',
'image': "res://addons/dialogic/Example Assets/portraits/df-3.png",
'color': Color(0.973511, 1, 0.152344),
'file': '',
'mirror_portraits': false
}
var single_portrait_mode = false
var dim_time = 0.5
var direction = 'left'
var debug = false
var fading_out = false
var custom_instance : Node2D = null
var current_state := {'character':'', 'portrait':'', 'position':'', 'mirrored':false}
signal animation_finished
func init(expression: String = '') -> void:
set_portrait(expression)
func _ready():
if debug:
print('Character data loaded: ', character_data)
print(rect_position, $TextureRect.rect_size)
$AnimationTween.connect('finished_animation', self, 'emit_signal', ['animation_finished'])
func set_portrait(expression: String) -> void:
if expression == "(Don't change)":
return
if expression == '':
expression = 'Default'
current_state['portrait'] = expression
# Clearing old custom scenes
for n in get_children():
if 'DialogicCustomPortraitScene' in n.name:
n.queue_free()
custom_instance = null
var default
for p in character_data['portraits']:
if p['name'] == expression:
if is_scene(p['path']):
# Creating a scene portrait
var custom_node = load(p['path'])
custom_instance = custom_node.instance()
custom_instance.name = 'DialogicCustomPortraitScene'
add_child(custom_instance)
$TextureRect.texture = ImageTexture.new()
return
else:
# Creating an image portrait
if ResourceLoader.exists(p['path']):
$TextureRect.texture = load(p['path'])
else:
$TextureRect.texture = ImageTexture.new()
return
# Saving what the default is to fallback to it.
if p['name'] == 'Default':
default = p['path']
# Everything failed, go with the default one
if is_scene(default):
push_warning('[Dialogic] Portrait missing: "' + expression + '". Maybe you deleted it? Update your timeline.')
# Creating a scene portrait
var custom_node = load(default)
custom_instance = custom_node.instance()
custom_instance.name = 'DialogicCustomPortraitScene'
add_child(custom_instance)
$TextureRect.texture = ImageTexture.new()
return
else:
# Creating an image portrait
if ResourceLoader.exists(default):
$TextureRect.texture = load(default)
else:
$TextureRect.texture = ImageTexture.new()
return
func set_mirror(value):
current_state['mirrored'] = value
if character_data["data"].has('mirror_portraits'):
if character_data["data"]['mirror_portraits']:
if custom_instance != null:
custom_instance.scale.x *= get_mirror_scale(custom_instance.scale.x, !value)
else:
$TextureRect.flip_h = !value
else:
if custom_instance != null:
custom_instance.scale.x *= get_mirror_scale(custom_instance.scale.x, value)
else:
$TextureRect.flip_h = value
else:
if custom_instance != null:
custom_instance.scale.x *= get_mirror_scale(custom_instance.scale.x, value)
else:
$TextureRect.flip_h = value
func move_to_position(position_offset):
var positions = {
'left': Vector2(-400, 0),
'right': Vector2(+400, 0),
'center': Vector2(0, 0),
'center_right': Vector2(200, 0),
'center_left': Vector2(-200, 0)}
direction = position_offset
rect_position = positions[position_offset]
# Setting the scale of the portrait
var custom_scale = Vector2(1, 1)
if character_data.has('data'):
if character_data['data'].has('scale'):
custom_scale = Vector2(
float(character_data['data']['scale']) / 100,
float(character_data['data']['scale']) / 100
)
rect_scale = custom_scale
if character_data['data'].has('offset_x'):
rect_position += Vector2(
character_data['data']['offset_x'],
character_data['data']['offset_y']
)
if $TextureRect.get('texture'):
rect_position -= Vector2(
$TextureRect.texture.get_width() * 0.5,
$TextureRect.texture.get_height()
) * custom_scale
func animate(animation_name = '[No Animation]', time = 1, loop = 1, delete = false ):
if animation_name == "[No Animation]":
return
if '_in' in animation_name:
if custom_instance != null:
custom_instance.modulate.a = 0
else:
$TextureRect.modulate = Color(1,1,1,0)
$AnimationTween.loop = loop
if custom_instance != null:
$AnimationTween.play(custom_instance, animation_name, time)
else:
$AnimationTween.play($TextureRect, animation_name, time)
if delete:
if !$AnimationTween.is_connected("tween_all_completed", self, "queue_free"):
$AnimationTween.connect("tween_all_completed", self, "queue_free")
func focus():
if not fading_out:
tween_modulate(modulate, Color(1,1,1, 1))
func focusout(dim_color = Color(0.5, 0.5, 0.5, 1.0)):
if single_portrait_mode:
dim_color.a = 0
if not fading_out:
tween_modulate(modulate, dim_color)
func tween_modulate(from_value, to_value):
$ModulationTween.stop(self, 'modulation')
$ModulationTween.interpolate_property(
self, "modulate", from_value, to_value, dim_time,
Tween.TRANS_LINEAR, Tween.EASE_IN_OUT
)
$ModulationTween.start()
return $ModulationTween
func is_scene(path) -> bool:
if '.tscn' in path.to_lower():
return true
return false
func get_mirror_scale(current_scale:float, mirror_value:bool) -> int:
if mirror_value and current_scale > 0:
return -1
else:
return 1

View File

@ -0,0 +1,24 @@
[gd_scene load_steps=3 format=2]
[ext_resource path="res://addons/dialogic/Nodes/Anima/DialogicAnimaTween.gd" type="Script" id=1]
[ext_resource path="res://addons/dialogic/Nodes/Portrait.gd" type="Script" id=2]
[node name="Portrait" type="Control"]
rect_scale = Vector2( 0.7, 0.7 )
script = ExtResource( 2 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="TextureRect" type="TextureRect" parent="."]
stretch_mode = 6
__meta__ = {
"_edit_use_anchors_": false
}
[node name="AnimationTween" type="Tween" parent="."]
script = ExtResource( 1 )
[node name="ModulationTween" type="Tween" parent="."]
[node name="TweenPosition" type="Tween" parent="."]

View File

@ -0,0 +1,332 @@
tool
extends Control
var text_speed := 0.02 # Higher = lower speed
var theme_text_speed = text_speed
var theme_text_max_height = 0
#experimental database of current commands
var commands = []
#the regex matching object
var regex = RegEx.new()
var bbcoderemoverregex = RegEx.new()
onready var text_container = $TextContainer
onready var text_label = $TextContainer/RichTextLabel
onready var name_label = $NameLabel
onready var next_indicator = $NextIndicatorContainer/NextIndicator
var _finished := false
var _theme
signal text_completed()
signal letter_written()
signal signal_request(arg)
## *****************************************************************************
## PUBLIC METHODS
## *****************************************************************************
func update_name(name: String, color: Color = Color.white, autocolor: bool=false) -> void:
var name_is_hidden = _theme.get_value('name', 'is_hidden', false)
if name_is_hidden:
name_label.visible = false
return
if not name.empty():
name_label.visible = true
# Hack to reset the size
name_label.rect_min_size = Vector2(0, 0)
name_label.rect_size = Vector2(-1, 40)
# Setting the color and text
name_label.text = name
# Alignment
call_deferred('align_name_label')
if autocolor:
name_label.set('custom_colors/font_color', color)
else:
name_label.visible = false
func clear():
text_label.bbcode_text = ""
name_label.text = ""
$WritingTimer.stop()
func update_text(text:String):
var orig_text = text
text_label.bbcode_text = text
var text_bbcodefree = text_label.text
#regex moved from func scope to class scope
#regex compilation moved to _ready
# - KvaGram
#var regex = RegEx.new()
var result:RegExMatch = null
text_speed = theme_text_speed # Resetting the speed to the default
commands = []
### remove commands from text, and store where and what they are
#current regex: \[\s*(nw|(nw|speed|signal|play|pause)\s*=\s*(.+?)\s*)\](.*?)
#Note: The version defined in _ready will have aditional escape characers.
# DO NOT JUST COPY/PASTE
#remeber regex101.com is your friend. Do not shoot it. You may ask it to verify the code.
#The capture groups, and what they do:
# 0 everything ex [speed=5]
# 1 the "nw" single command or one of the variable commands ex "nw" or "speed=5"
# 2 the command, assuming it is an variable command ex "speed"
# 3 the argument, again assuming a variable command ex "5"
# 4 nothing (ignore it)
#keep this up to date whenever the regex string is updated! - KvaGram
result = regex.search(text_bbcodefree)
#loops until all commands are cleared from the text
while result:
if result.get_string(1) == "nw" || result.get_string(2) == "nw":
#The no wait command is handled elsewhere. Ignore it.
pass
else:
#Store an assigned varible command as an array by 0 index in text, 1 command-name, 2 argument
commands.append([result.get_start()-1, result.get_string(2).strip_edges(), result.get_string(3).strip_edges()])
text_bbcodefree = text_bbcodefree.substr(0, result.get_start()) + text_bbcodefree.substr(result.get_end())
text = text.replace(result.get_string(), "")
result = regex.search(text_bbcodefree)
text_label.bbcode_text = text
text_label.visible_characters = 0
## SIZING THE RICHTEXTLABEL
# The sizing is done in a very terrible way because the RichtTextLabel has
# a hard time knowing what size it will be and how to display this.
# for this reason the RichTextLabel ist first set to just go for the size it needs,
# even if this might be more than available.
text_label.size_flags_vertical = 0
text_label.rect_clip_content = 0
text_label.fit_content_height = true
# a frame later, when the sizes have been updated, it will check if there
# is enough space or the scrollbar should be activated.
call_deferred("update_sizing")
# updating the size alignment stuff
text_label.grab_focus()
start_text_timer()
return true
func update_sizing():
# this will enable/disable the scrollbar based on the size of the text
theme_text_max_height = text_container.rect_size.y
if text_label.rect_size.y >= theme_text_max_height:
text_label.fit_content_height = false
text_label.size_flags_vertical = Control.SIZE_EXPAND_FILL
else:
text_label.fit_content_height = true
text_label.size_flags_vertical = 0
#handle an activated command.
func handle_command(command:Array):
if(command[1] == "speed"):
text_speed = float(command[2]) * 0.01
$WritingTimer.stop()
start_text_timer()
elif(command[1] == "signal"):
emit_signal("signal_request", command[2])
elif(command[1] == "play"):
var path = "res://dialogic/sounds/" + command[2]
if ResourceLoader.exists(path, "AudioStream"):
var audio:AudioStream = ResourceLoader.load(path, "AudioStream")
$sounds.stream = audio
$sounds.play()
elif(command[1] == "pause"):
$WritingTimer.stop()
var x = text_label.visible_characters
get_parent().get_node("DialogicTimer").start(float(command[2]))
yield(get_parent().get_node("DialogicTimer"), "timeout")
# only continue, if no skip was performed
if text_label.visible_characters == x:
start_text_timer()
func skip():
text_label.visible_characters = -1
_handle_text_completed()
func reset():
name_label.text = ''
name_label.visible = false
func load_theme(theme: ConfigFile):
# Text
var theme_font = DialogicUtil.path_fixer_load(theme.get_value('text', 'font', 'res://addons/dialogic/Example Assets/Fonts/DefaultFont.tres'))
text_label.set('custom_fonts/normal_font', theme_font)
text_label.set('custom_fonts/bold_font', DialogicUtil.path_fixer_load(theme.get_value('text', 'bold_font', 'res://addons/dialogic/Example Assets/Fonts/DefaultBoldFont.tres')))
text_label.set('custom_fonts/italics_font', DialogicUtil.path_fixer_load(theme.get_value('text', 'italic_font', 'res://addons/dialogic/Example Assets/Fonts/DefaultItalicFont.tres')))
name_label.set('custom_fonts/font', DialogicUtil.path_fixer_load(theme.get_value('name', 'font', 'res://addons/dialogic/Example Assets/Fonts/NameFont.tres')))
# setting the vertical alignment
var alignment = theme.get_value('text', 'alignment',0)
if alignment <= 2: # top
text_container.alignment = BoxContainer.ALIGN_BEGIN
elif alignment <= 5: # center
text_container.alignment = BoxContainer.ALIGN_CENTER
elif alignment <= 8: # bottom
text_container.alignment = BoxContainer.ALIGN_END
var text_color = Color(theme.get_value('text', 'color', '#ffffffff'))
text_label.set('custom_colors/default_color', text_color)
name_label.set('custom_colors/font_color', text_color)
text_label.set('custom_colors/font_color_shadow', Color('#00ffffff'))
name_label.set('custom_colors/font_color_shadow', Color('#00ffffff'))
if theme.get_value('text', 'shadow', false):
var text_shadow_color = Color(theme.get_value('text', 'shadow_color', '#9e000000'))
text_label.set('custom_colors/font_color_shadow', text_shadow_color)
var shadow_offset = theme.get_value('text', 'shadow_offset', Vector2(2,2))
text_label.set('custom_constants/shadow_offset_x', shadow_offset.x)
text_label.set('custom_constants/shadow_offset_y', shadow_offset.y)
# Text speed
text_speed = theme.get_value('text','speed', 2) * 0.01
theme_text_speed = text_speed
# Margin
text_container.set('margin_left', theme.get_value('text', 'text_margin_left', 20))
text_container.set('margin_right', theme.get_value('text', 'text_margin_right', -20))
text_container.set('margin_top', theme.get_value('text', 'text_margin_top', 10))
text_container.set('margin_bottom', theme.get_value('text', 'text_margin_bottom', -10))
# Backgrounds
$TextureRect.texture = DialogicUtil.path_fixer_load(theme.get_value('background','image', "res://addons/dialogic/Example Assets/backgrounds/background-2.png"))
$ColorRect.color = Color(theme.get_value('background','color', "#ff000000"))
if theme.get_value('background', 'modulation', false):
$TextureRect.modulate = Color(theme.get_value('background', 'modulation_color', '#ffffffff'))
else:
$TextureRect.modulate = Color('#ffffffff')
$ColorRect.visible = theme.get_value('background', 'use_color', false)
$TextureRect.visible = theme.get_value('background', 'use_image', true)
$TextureRect.visible = theme.get_value('background', 'use_image', true)
$TextureRect.patch_margin_left = theme.get_value('ninepatch', 'ninepatch_margin_left', 0)
$TextureRect.patch_margin_right = theme.get_value('ninepatch', 'ninepatch_margin_right', 0)
$TextureRect.patch_margin_top = theme.get_value('ninepatch', 'ninepatch_margin_top', 0)
$TextureRect.patch_margin_bottom = theme.get_value('ninepatch', 'ninepatch_margin_bottom', 0)
# Next image
$NextIndicatorContainer.rect_position = Vector2(0,0)
next_indicator.texture = DialogicUtil.path_fixer_load(theme.get_value('next_indicator', 'image', 'res://addons/dialogic/Example Assets/next-indicator/next-indicator.png'))
# Reset for up and down animation
next_indicator.margin_top = 0
next_indicator.margin_bottom = 0
next_indicator.margin_left = 0
next_indicator.margin_right = 0
# Scale
var indicator_scale = theme.get_value('next_indicator', 'scale', 0.4)
next_indicator.rect_scale = Vector2(indicator_scale, indicator_scale)
# Offset
var offset = theme.get_value('next_indicator', 'offset', Vector2(13, 10))
next_indicator.rect_position = theme.get_value('box', 'size', Vector2(910, 167)) - (next_indicator.texture.get_size() * indicator_scale)
next_indicator.rect_position -= offset
# Character Name
$NameLabel/ColorRect.visible = theme.get_value('name', 'background_visible', false)
$NameLabel/ColorRect.color = Color(theme.get_value('name', 'background', '#282828'))
$NameLabel/TextureRect.visible = theme.get_value('name', 'image_visible', false)
$NameLabel/TextureRect.texture = DialogicUtil.path_fixer_load(theme.get_value('name','image', "res://addons/dialogic/Example Assets/backgrounds/background-2.png"))
var name_padding = theme.get_value('name', 'name_padding', Vector2( 10, 0 ))
var name_style = name_label.get('custom_styles/normal')
name_style.set('content_margin_left', name_padding.x)
name_style.set('content_margin_right', name_padding.x)
name_style.set('content_margin_bottom', name_padding.y)
name_style.set('content_margin_top', name_padding.y)
var name_shadow_offset = theme.get_value('name', 'shadow_offset', Vector2(2,2))
if theme.get_value('name', 'shadow_visible', true):
name_label.set('custom_colors/font_color_shadow', Color(theme.get_value('name', 'shadow', '#9e000000')))
name_label.set('custom_constants/shadow_offset_x', name_shadow_offset.x)
name_label.set('custom_constants/shadow_offset_y', name_shadow_offset.y)
name_label.rect_position.y = theme.get_value('name', 'bottom_gap', 48) * -1 - (name_padding.y)
if theme.get_value('name', 'modulation', false) == true:
$NameLabel/TextureRect.modulate = Color(theme.get_value('name', 'modulation_color', '#ffffffff'))
else:
$NameLabel/TextureRect.modulate = Color('#ffffffff')
# Setting next indicator animation
next_indicator.self_modulate = Color('#ffffff')
var animation = theme.get_value('next_indicator', 'animation', 'Up and down')
next_indicator.get_node('AnimationPlayer').play(animation)
# Saving reference to the current theme
_theme = theme
## *****************************************************************************
## PRIVATE METHODS
## *****************************************************************************
func _on_writing_timer_timeout():
if _finished == false:
text_label.visible_characters += 1
if(commands.size()>0 && commands[0][0] <= text_label.visible_characters):
handle_command(commands.pop_front()) #handles the command, and removes it from the queue
if text_label.visible_characters > text_label.get_total_character_count():
_handle_text_completed()
elif (
text_label.visible_characters > 0 and
#text_label.text.length() > text_label.visible_characters-1 and
text_label.text[text_label.visible_characters-1] != " "
):
emit_signal('letter_written')
else:
$WritingTimer.stop()
func start_text_timer():
if text_speed == 0:
text_label.visible_characters = -1
_handle_text_completed()
else:
$WritingTimer.start(text_speed)
_finished = false
func _handle_text_completed():
$WritingTimer.stop()
_finished = true
emit_signal("text_completed")
func align_name_label():
var name_padding = _theme.get_value('name', 'name_padding', Vector2( 10, 0 ))
var horizontal_offset = _theme.get_value('name', 'horizontal_offset', 0)
var name_label_position = _theme.get_value('name', 'position', 0)
var label_size = name_label.rect_size.x
if name_label_position == 0:
name_label.rect_global_position.x = rect_global_position.x + horizontal_offset
elif name_label_position == 1: # Center
name_label.rect_global_position.x = rect_global_position.x + (rect_size.x / 2) - (label_size / 2) + horizontal_offset
elif name_label_position == 2: # Right
name_label.rect_global_position.x = rect_global_position.x + rect_size.x - label_size + horizontal_offset
## *****************************************************************************
## OVERRIDES
## *****************************************************************************
func _ready():
reset()
$WritingTimer.connect("timeout", self, "_on_writing_timer_timeout")
text_label.meta_underlined = false
regex.compile("\\[\\s*(nw|(nw|speed|signal|play|pause)\\s*=\\s*(.+?)\\s*)\\](.*?)")

View File

@ -0,0 +1,194 @@
[gd_scene load_steps=11 format=2]
[ext_resource path="res://addons/dialogic/Example Assets/Fonts/DefaultFont.tres" type="DynamicFont" id=1]
[ext_resource path="res://addons/dialogic/Example Assets/backgrounds/background-2.png" type="Texture" id=2]
[ext_resource path="res://addons/dialogic/Example Assets/next-indicator/next-indicator.png" type="Texture" id=3]
[ext_resource path="res://addons/dialogic/Nodes/TextBubble.gd" type="Script" id=4]
[sub_resource type="StyleBoxEmpty" id=1]
[sub_resource type="StyleBoxFlat" id=2]
bg_color = Color( 1, 1, 1, 0 )
expand_margin_left = 10.0
[sub_resource type="Animation" id=3]
loop = true
tracks/0/type = "value"
tracks/0/path = NodePath(".:self_modulate")
tracks/0/interp = 2
tracks/0/loop_wrap = true
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/keys = {
"times": PoolRealArray( 0, 0.5 ),
"transitions": PoolRealArray( 1, 1 ),
"update": 0,
"values": [ Color( 1, 1, 1, 1 ), Color( 1, 1, 1, 0 ) ]
}
[sub_resource type="Animation" id=4]
[sub_resource type="Animation" id=5]
loop = true
tracks/0/type = "value"
tracks/0/path = NodePath("..:rect_position")
tracks/0/interp = 2
tracks/0/loop_wrap = true
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/keys = {
"times": PoolRealArray( 0, 0.5 ),
"transitions": PoolRealArray( 1, 1 ),
"update": 0,
"values": [ Vector2( 0, 0 ), Vector2( 0, -10 ) ]
}
[sub_resource type="StyleBoxFlat" id=6]
content_margin_left = 10.0
content_margin_right = 10.0
content_margin_top = 0.0
content_margin_bottom = 0.0
bg_color = Color( 1, 1, 1, 0 )
expand_margin_left = 10.0
[node name="TextBubble" type="Control"]
anchor_left = 0.5
anchor_top = 1.0
anchor_right = 0.5
anchor_bottom = 1.0
margin_left = -455.0
margin_top = 399.0
margin_right = 455.0
margin_bottom = 560.0
script = ExtResource( 4 )
[node name="ColorRect" type="ColorRect" parent="."]
visible = false
anchor_right = 1.0
anchor_bottom = 1.0
color = Color( 0, 0, 0, 1 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="TextureRect" type="NinePatchRect" parent="."]
anchor_right = 1.0
anchor_bottom = 1.0
texture = ExtResource( 2 )
[node name="TextContainer" type="VBoxContainer" parent="."]
anchor_right = 1.0
anchor_bottom = 1.0
margin_left = 10.0
margin_top = 12.0
margin_right = -10.0
margin_bottom = -12.0
size_flags_horizontal = 3
size_flags_vertical = 3
alignment = 1
__meta__ = {
"_edit_use_anchors_": false
}
[node name="RichTextLabel" type="RichTextLabel" parent="TextContainer"]
margin_top = 11.0
margin_right = 890.0
margin_bottom = 125.0
focus_mode = 2
custom_colors/default_color = Color( 1, 1, 1, 1 )
custom_colors/selection_color = Color( 0, 0, 0, 0 )
custom_colors/font_color_shadow = Color( 1, 1, 1, 0 )
custom_constants/shadow_offset_x = 2
custom_constants/shadow_offset_y = 2
custom_fonts/normal_font = ExtResource( 1 )
custom_styles/focus = SubResource( 1 )
custom_styles/normal = SubResource( 2 )
bbcode_enabled = true
bbcode_text = "Placeholder text for testing an formatting.
Placeholder text for testing an formatting.
adsd"
visible_characters = 0
percent_visible = 0.0
meta_underlined = false
text = "Placeholder text for testing an formatting.
Placeholder text for testing an formatting.
adsd"
fit_content_height = true
selection_enabled = true
__meta__ = {
"_edit_use_anchors_": false
}
[node name="NextIndicatorContainer" type="Control" parent="."]
margin_right = 40.0
margin_bottom = 40.0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="NextIndicator" type="TextureRect" parent="NextIndicatorContainer"]
margin_top = -10.0
margin_right = 51.0
margin_bottom = 41.0
texture = ExtResource( 3 )
stretch_mode = 4
__meta__ = {
"_edit_use_anchors_": false
}
[node name="AnimationPlayer" type="AnimationPlayer" parent="NextIndicatorContainer/NextIndicator"]
autoplay = "Up and down"
anims/Pulse = SubResource( 3 )
anims/Static = SubResource( 4 )
"anims/Up and down" = SubResource( 5 )
[node name="NameLabel" type="Label" parent="."]
visible = false
margin_top = -48.0
margin_right = 58.0
margin_bottom = -8.0
size_flags_vertical = 1
custom_colors/font_color = Color( 0.423529, 0.580392, 0.74902, 1 )
custom_colors/font_color_shadow = Color( 0, 0, 0, 0.619608 )
custom_constants/shadow_offset_x = 2
custom_constants/shadow_offset_y = 2
custom_fonts/font = ExtResource( 1 )
custom_styles/normal = SubResource( 6 )
align = 1
valign = 1
__meta__ = {
"_edit_use_anchors_": false
}
[node name="ColorRect" type="ColorRect" parent="NameLabel"]
visible = false
show_behind_parent = true
anchor_right = 1.0
anchor_bottom = 1.0
size_flags_horizontal = 15
size_flags_vertical = 15
color = Color( 0.156863, 0.156863, 0.156863, 1 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="TextureRect" type="TextureRect" parent="NameLabel"]
visible = false
show_behind_parent = true
anchor_right = 1.0
anchor_bottom = 1.0
size_flags_horizontal = 3
size_flags_vertical = 3
texture = ExtResource( 2 )
expand = true
stretch_mode = 1
__meta__ = {
"_edit_use_anchors_": false
}
[node name="WritingTimer" type="Timer" parent="."]
[node name="Tween" type="Tween" parent="."]
[node name="sounds" type="AudioStreamPlayer" parent="."]
autoplay = true

View File

@ -0,0 +1,78 @@
extends CanvasLayer
## Mirror node to Dialogic node that duplicate its signals
## and had a reference to that Dialogic node
# Copied
# Event end/start
signal event_start(type, event)
signal event_end(type)
# Timeline end/start
signal timeline_start(timeline_name)
signal timeline_end(timeline_name)
signal text_complete(text_event)
# Custom user signal
signal dialogic_signal(value)
var _dialog_node_scene = load("res://addons/dialogic/Nodes/DialogNode.tscn")
var dialog_node = null
func set_dialog_node_scene(scene) -> void:
_dialog_node_scene = scene
dialog_node = _dialog_node_scene.instance()
var _err:int
if dialog_node:
_err = dialog_node.connect("event_start", self, "_on_event_start")
assert(_err == OK)
_err = dialog_node.connect("event_end", self, "_on_event_end")
assert(_err == OK)
_err = dialog_node.connect("timeline_start", self, "_on_timeline_start")
assert(_err == OK)
_err = dialog_node.connect("timeline_end", self, "_on_timeline_end")
assert(_err == OK)
_err = dialog_node.connect("text_complete", self, "_on_text_complete")
assert(_err == OK)
_err = dialog_node.connect("dialogic_signal", self, "_on_dialogic_signal")
assert(_err == OK)
func _enter_tree() -> void:
if dialog_node:
add_child(dialog_node)
dialog_node.connect('tree_exited', self, 'dialog_finished')
func dialog_finished():
queue_free()
func _ready() -> void:
# change the canvas layer
var config = DialogicResources.get_settings_config()
layer = int(config.get_value("theme", "canvas_layer", 1))
func _on_event_start(type, event) -> void:
emit_signal("event_start", type, event)
func _on_event_end(type) -> void:
emit_signal("event_end", type)
func _on_timeline_start(timeline_name) -> void:
emit_signal("timeline_start", timeline_name)
func _on_timeline_end(timeline_name) -> void:
emit_signal("timeline_end", timeline_name)
func _on_text_complete(text_event) -> void:
emit_signal("text_complete", text_event)
func _on_dialogic_signal(value) -> void:
emit_signal("dialogic_signal", value)

View File

@ -0,0 +1,66 @@
tool
extends PanelContainer
onready var nodes = {
'title': $VBoxContainer/Title,
'body': $VBoxContainer/Content,
'extra': $VBoxContainer/Extra,
}
var in_theme_editor = false
var margin = 10
func _ready():
set_deferred('rect_size.y', 0)
nodes['title'].bbcode_enabled = true
nodes['body'].bbcode_enabled = true
nodes['extra'].bbcode_enabled = true
func _process(_delta):
if Engine.is_editor_hint() == false or in_theme_editor == true:
if visible:
if get_global_mouse_position().x < get_viewport().size.x * 0.5:
rect_global_position = get_global_mouse_position() - Vector2(0, rect_size.y + (margin * 2))
else:
rect_global_position = get_global_mouse_position() - rect_size - Vector2(0, (margin * 2))
rect_size.y = 0
#
func load_preview(info):
nodes['title'].visible = false
nodes['body'].visible = false
nodes['extra'].visible = false
if info['title'] != '':
nodes['title'].bbcode_text = info['title']
nodes['title'].visible = true
if info['body'] != '':
nodes['body'].bbcode_text = info['body']
nodes['body'].visible = true
if info['extra'] != '':
nodes['extra'].bbcode_text = info['extra']
nodes['extra'].visible = true
func load_theme(theme):
# Fonts
$VBoxContainer/Title.set(
'custom_fonts/normal_font',
DialogicUtil.path_fixer_load(theme.get_value('definitions', 'font', "res://addons/dialogic/Example Assets/Fonts/GlossaryFont.tres")))
$VBoxContainer/Title.set('custom_colors/default_color', theme.get_value('definitions', 'title_color', "#ffffffff"))
$VBoxContainer/Content.set(
'custom_fonts/normal_font',
DialogicUtil.path_fixer_load(theme.get_value('definitions', 'text_font', "res://addons/dialogic/Example Assets/Fonts/GlossaryFont.tres")))
$VBoxContainer/Content.set('custom_colors/default_color', theme.get_value('definitions', 'text_color', "#c1c1c1"))
$VBoxContainer/Extra.set(
'custom_fonts/normal_font',
DialogicUtil.path_fixer_load(theme.get_value('definitions', 'extra_font', "res://addons/dialogic/Example Assets/Fonts/GlossaryFont.tres")))
$VBoxContainer/Extra.set('custom_colors/default_color', theme.get_value('definitions', 'extra_color', "#c1c1c1"))
set("custom_styles/panel", load(theme.get_value('definitions', 'background_panel', "res://addons/dialogic/Example Assets/backgrounds/GlossaryBackground.tres")))

View File

@ -0,0 +1,91 @@
# Random Audio Stream PLayer Godot Engine Add-on
# Copyright (c) Tim Krief.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
tool
extends AudioStreamPlayer
export(Array, AudioStream) var samples = []
export(String, DIR) var select_samples_from_folder setget load_samples_from_folder
export(int, "Pure", "No consecutive repetition", "Use all samples before repeat") var random_strategy = 0
onready var base_volume = volume_db
export(float, 0, 80) var random_volume_range = 0
onready var base_pitch = pitch_scale
export(float, 0, 4) var random_pitch_range = 0
var playing_sample_nb : int = -1
var last_played_sample_nb : int = -1 # only used if random_strategy = 1
var to_play = [] # only used if random_strategy = 2
# You can use playing_sample_nb to choose what sample to use
func play(from_position=0.0, playing_sample_nb=-1):
var number_of_samples = len(samples)
if number_of_samples > 0:
if playing_sample_nb < 0:
if number_of_samples == 1:
playing_sample_nb = 0
else:
match random_strategy:
1:
playing_sample_nb = randi() % (number_of_samples - 1)
if last_played_sample_nb == playing_sample_nb:
playing_sample_nb += 1
last_played_sample_nb = playing_sample_nb
2:
if len(to_play) == 0:
for i in range(number_of_samples):
if i != last_played_sample_nb:
to_play.append(i)
to_play.shuffle()
playing_sample_nb = to_play.pop_back()
last_played_sample_nb = playing_sample_nb
_:
playing_sample_nb = randi() % number_of_samples
if random_volume_range != 0:
.set_volume_db(base_volume + (randf() - .5) * random_volume_range)
if random_pitch_range != 0:
.set_pitch_scale(max(0.0001, base_pitch + (randf() - .5) * random_pitch_range))
set_stream(samples[playing_sample_nb])
.play(from_position)
func set_volume_db(new_volume_db):
.set_volume_db(new_volume_db)
base_volume = new_volume_db
func set_pitch_scale(new_pitch):
.set_pitch_scale(max(0.0001, new_pitch))
base_pitch = new_pitch
func load_samples_from_folder(path):
if path != "":
samples.clear()
var dir = Directory.new()
if dir.open(path) == OK:
dir.list_dir_begin(true)
var file_name = dir.get_next()
while file_name != "":
if not dir.current_is_dir() and file_name.ends_with(".import"):
var resource_path = dir.get_current_dir() + "/" + file_name.replace('.import', '')
if resource_path.get_extension().to_lower() in ["wav", "ogg"]:
var resource = load(resource_path)
if resource != null:
samples.append(resource)
file_name = dir.get_next()
select_samples_from_folder = ""