Add addons
This commit is contained in:
parent
2c862b2235
commit
3367bad24f
527 changed files with 36197 additions and 0 deletions
306
Sprout/addons/dialogic/Events/Character/subsystem_portraits.gd
Normal file
306
Sprout/addons/dialogic/Events/Character/subsystem_portraits.gd
Normal file
|
|
@ -0,0 +1,306 @@
|
|||
extends DialogicSubsystem
|
||||
|
||||
## Subsystem that manages portraits and portrait positions.
|
||||
|
||||
## The default portrait scene.
|
||||
var default_portrait_scene = load(get_script().resource_path.get_base_dir().path_join('default_portrait.tscn'))
|
||||
## Temporarily stores the default positions.
|
||||
var _default_positions: Dictionary = {}
|
||||
## Stores the current positions.
|
||||
var current_positions: Dictionary = {}
|
||||
|
||||
## A reference to the current [DialogicNode_PortraitHolder].
|
||||
var _portrait_holder_reference: Node = null
|
||||
|
||||
####################################################################################################
|
||||
## STATE
|
||||
####################################################################################################
|
||||
|
||||
func clear_game_state():
|
||||
for character in dialogic.current_state_info.get('portraits', {}).keys():
|
||||
remove_portrait(load(character))
|
||||
dialogic.current_state_info['portraits'] = {}
|
||||
|
||||
|
||||
func load_game_state():
|
||||
for character_path in dialogic.current_state_info['portraits']:
|
||||
add_portrait(
|
||||
load(character_path),
|
||||
dialogic.current_state_info['portraits'][character_path].portrait, dialogic.current_state_info['portraits'][character_path].position_index,
|
||||
false)
|
||||
|
||||
|
||||
func pause() -> void:
|
||||
for portrait in dialogic.current_state_info['portraits'].values():
|
||||
if portrait.has('animation_node'):
|
||||
portrait.animation_node.pause()
|
||||
|
||||
|
||||
func resume() -> void:
|
||||
for portrait in dialogic.current_state_info['portraits'].values():
|
||||
if portrait.has('animation_node'):
|
||||
portrait.animation_node.resume()
|
||||
|
||||
|
||||
####################################################################################################
|
||||
## MAIN METHODS
|
||||
####################################################################################################
|
||||
|
||||
## Joins a character and then calls change_portrait().
|
||||
func add_portrait(character:DialogicCharacter, portrait:String, position_idx:int, mirrored: bool = false, z_index: int = 0, extra_data:String = "") -> Node:
|
||||
var character_node = null
|
||||
|
||||
if portrait.is_empty():
|
||||
portrait = character.default_portrait
|
||||
|
||||
if not character:
|
||||
print_debug('[DialogicError] Cannot call add_portrait() with null character.')
|
||||
return null
|
||||
if not portrait in character.portraits:
|
||||
print_debug("[DialogicError] Tried joining ",character.display_name, " wit not-existing portrait '", portrait, "'. Will use default portrait instead.")
|
||||
portrait = character.default_portrait
|
||||
if portrait.is_empty():
|
||||
print_debug("[DialogicError] Character ",character.display_name, " has no default portrait to use.")
|
||||
return null
|
||||
|
||||
check_positions_and_holder()
|
||||
|
||||
character_node = Node2D.new()
|
||||
character_node.name = character.get_character_name()
|
||||
character_node.position = current_positions[position_idx]
|
||||
character_node.z_index = z_index
|
||||
character_node.set_meta("position", position_idx)
|
||||
_portrait_holder_reference.add_child(character_node)
|
||||
|
||||
if character_node:
|
||||
dialogic.current_state_info['portraits'][character.resource_path] = {'portrait':portrait, 'node':character_node, 'position_index':position_idx}
|
||||
if portrait:
|
||||
change_portrait(character, portrait, mirrored, z_index, false, extra_data)
|
||||
|
||||
return character_node
|
||||
|
||||
## Changes the portrait of a character. Only works with characters that joined previously.
|
||||
func change_portrait(character:DialogicCharacter, portrait:String, mirrored:bool = false, z_index: int = 0, update_zindex:bool = false, extra_data:String = "") -> void:
|
||||
if not character or not is_character_joined(character):
|
||||
print_debug('[DialogicError] Cannot change portrait of null/not joined character.')
|
||||
return null
|
||||
|
||||
if portrait.is_empty():
|
||||
portrait = character.default_portrait
|
||||
|
||||
if not portrait in character.portraits.keys():
|
||||
print_debug('[Dialogic] Change to not-existing portrait will be ignored!')
|
||||
return
|
||||
|
||||
var char_node :Node = dialogic.current_state_info.portraits[character.resource_path].node
|
||||
|
||||
if update_zindex:
|
||||
char_node.z_index = z_index
|
||||
|
||||
# path to the scene to use
|
||||
var scene_path :String = character.portraits[portrait].get('scene', '')
|
||||
|
||||
var portrait_node = null
|
||||
|
||||
# check if the scene is the same as the currently loaded scene
|
||||
if (char_node.get_child_count() and
|
||||
character.portraits[dialogic.current_state_info['portraits'][character.resource_path]['portrait']].get('scene', '') == scene_path and
|
||||
# also check if the scene supports changing to the given portrait
|
||||
(!char_node.get_child(0).has_method('_should_do_portrait_update') or char_node.get_child(0)._should_do_portrait_update(character, portrait))):
|
||||
portrait_node = char_node.get_child(0)
|
||||
else:
|
||||
# remove previous portrait
|
||||
if char_node.get_child_count():
|
||||
char_node.get_child(0).queue_free()
|
||||
|
||||
if scene_path.is_empty():
|
||||
portrait_node = default_portrait_scene.instantiate()
|
||||
else:
|
||||
var p = load(scene_path)
|
||||
if p:
|
||||
portrait_node = p.instantiate()
|
||||
else:
|
||||
push_error('Dialogic: Portrait node "' + str(scene_path) + '" for character [' + character.display_name + '] could not be loaded. Your portrait might not show up on the screen.')
|
||||
|
||||
if portrait_node:
|
||||
portrait_node.position = character.offset + character.portraits[portrait].get('offset', Vector2())
|
||||
|
||||
# ignore the character scale on custom portraits that have 'ignore_char_scale' set to true
|
||||
if scene_path.is_empty() or !character.portraits[portrait].get('ignore_char_scale', false):
|
||||
portrait_node.scale = Vector2(1,1)*character.scale * character.portraits[portrait].get('scale', 1)
|
||||
else:
|
||||
portrait_node.scale = Vector2(1,1)*character.portraits[portrait].get('scale', 1)
|
||||
|
||||
for property in character.portraits[portrait].get('export_overrides', {}).keys():
|
||||
portrait_node.set(property, str_to_var(character.portraits[portrait]['export_overrides'][property]))
|
||||
|
||||
if portrait_node.has_method('_update_portrait'):
|
||||
portrait_node._update_portrait(character, portrait)
|
||||
if portrait_node.has_method('_set_mirror'):
|
||||
portrait_node._set_mirror(mirrored)
|
||||
if portrait_node.has_method('_set_extra_data'):
|
||||
portrait_node._set_extra_data(extra_data)
|
||||
|
||||
if !portrait_node.is_inside_tree():
|
||||
char_node.add_child(portrait_node)
|
||||
dialogic.current_state_info['portraits'][character.resource_path]['portrait'] = portrait
|
||||
|
||||
## Animates the portrait of the given character with the given animation.
|
||||
func animate_portrait(character:DialogicCharacter, animation_path:String, length:float, repeats = 1) -> DialogicAnimation:
|
||||
if not character or not is_character_joined(character):
|
||||
print_debug('[DialogicError] Cannot animate portrait of null/not joined character.')
|
||||
return null
|
||||
|
||||
var char_node = dialogic.current_state_info['portraits'][character.resource_path].node
|
||||
|
||||
if dialogic.current_state_info['portraits'][character.resource_path].get('animation_node', null):
|
||||
if is_instance_valid(dialogic.current_state_info['portraits'][character.resource_path].animation_node):
|
||||
dialogic.current_state_info['portraits'][character.resource_path].animation_node.queue_free()
|
||||
var anim_script = load(animation_path)
|
||||
var anim_node = Node.new()
|
||||
anim_node.set_script(anim_script)
|
||||
anim_node = (anim_node as DialogicAnimation)
|
||||
anim_node.node = char_node
|
||||
anim_node.orig_pos = char_node.position
|
||||
anim_node.end_position = char_node.position
|
||||
anim_node.time = length
|
||||
anim_node.repeats = repeats
|
||||
add_child(anim_node)
|
||||
anim_node.animate()
|
||||
dialogic.current_state_info['portraits'][character.resource_path]['animation_node'] = anim_node
|
||||
return anim_node
|
||||
|
||||
|
||||
## Moves the portrait of the given character to the given positions. Also allows updating the z_index.
|
||||
## TODO: Question, why the z_index is set here and in change_portrait and doesn't have it's own method.
|
||||
func move_portrait(character:DialogicCharacter, position_idx:int, z_index:int = 0, update_zindex:bool = false, time:float = 0.0):
|
||||
if not character or not is_character_joined(character):
|
||||
print_debug('[DialogicError] Cannot move portrait of null/not joined character.')
|
||||
return null
|
||||
|
||||
var char_node = dialogic.current_state_info.portraits[character.resource_path].node
|
||||
|
||||
if update_zindex:
|
||||
char_node.z_index = z_index
|
||||
|
||||
char_node.set_meta('position', position_idx)
|
||||
|
||||
if time == 0.0:
|
||||
char_node.position = current_positions[position_idx]
|
||||
else:
|
||||
var tween = char_node.create_tween()
|
||||
tween.tween_property(char_node, "position", current_positions[position_idx], time)
|
||||
|
||||
dialogic.current_state_info.portraits[character.resource_path].position_index = position_idx
|
||||
|
||||
|
||||
func remove_portrait(character:DialogicCharacter) -> void:
|
||||
dialogic.current_state_info['portraits'][character.resource_path].node.queue_free()
|
||||
dialogic.current_state_info['portraits'].erase(character.resource_path)
|
||||
|
||||
|
||||
## Creates additional positions either from timeline or at runtime
|
||||
## If it's an existing position, will move that position to the coordinates instead
|
||||
## There's no need to actually remove them once added, but saves will need to track position updates as well, so the whole current_positions array will need to be saved
|
||||
## This will always be an absolute value for new positions, existing positions will be updated as absolute values by this
|
||||
func add_portrait_position(position_number: int, position:Vector2) -> void:
|
||||
|
||||
check_positions_and_holder()
|
||||
|
||||
if position_number in current_positions:
|
||||
move_portrait_position(position_number, position)
|
||||
else:
|
||||
# Add to both current and default positions
|
||||
_default_positions[position_number] = position
|
||||
current_positions[position_number] = position
|
||||
|
||||
func reset_portrait_positions(time:float = 0.0) -> void:
|
||||
for position in current_positions:
|
||||
move_portrait_position(position, _default_positions[position], false, time)
|
||||
|
||||
func reset_portrait_position(position:int, time:float = 0.0) -> void:
|
||||
move_portrait_position(position, _default_positions[position], false, time)
|
||||
|
||||
|
||||
func move_portrait_position(position_number: int, vector:Vector2, relative:bool = false, time:float = 0.0) -> void:
|
||||
check_positions_and_holder()
|
||||
|
||||
if !position_number in current_positions:
|
||||
if !relative:
|
||||
add_portrait_position(position_number, vector)
|
||||
else:
|
||||
print_debug('[DialogicError] Cannot move non-existent position. (Use SetAbsolute to create a new position)')
|
||||
return null
|
||||
|
||||
if !relative:
|
||||
current_positions[position_number] = vector
|
||||
else:
|
||||
current_positions[position_number] += vector
|
||||
|
||||
for child in _portrait_holder_reference.get_children():
|
||||
if child.get_meta('position') == position_number:
|
||||
if time != 0.0:
|
||||
var tween = child.create_tween()
|
||||
tween.tween_property(child, "position", current_positions[position_number], time)
|
||||
else:
|
||||
child.position = current_positions[position_number]
|
||||
|
||||
|
||||
####################################################################################################
|
||||
## HELPERS
|
||||
####################################################################################################
|
||||
|
||||
func is_character_joined(character:DialogicCharacter) -> bool:
|
||||
return character.resource_path in dialogic.current_state_info['portraits']
|
||||
|
||||
func get_joined_characters() -> Array:
|
||||
var chars = []
|
||||
for char_path in dialogic.current_state_info.get('portraits', {}).keys():
|
||||
chars.append(load(char_path))
|
||||
return chars
|
||||
|
||||
func update_rpg_portrait_mode(character:DialogicCharacter = null, portrait:String = "") -> void:
|
||||
if DialogicUtil.get_project_setting('dialogic/portrait_mode', 0) == DialogicCharacterEvent.PortraitModes.RPG:
|
||||
if !Dialogic.current_state_info.has('rpg_last_portrait'):
|
||||
Dialogic.current_state_info['rpg_last_portraits'] = {}
|
||||
|
||||
if character != null:
|
||||
if portrait == "":
|
||||
if Dialogic.current_state_info['rpg_last_portraits'].has(character.resource_path):
|
||||
portrait = Dialogic.current_state_info['rpg_last_portraits'][character.resource_path]
|
||||
else:
|
||||
portrait = character.default_portrait
|
||||
Dialogic.current_state_info['rpg_last_portraits'][character.resource_path] = portrait
|
||||
var char_joined = false
|
||||
for joined_character in dialogic.current_state_info.portraits:
|
||||
if not character or (joined_character != character.resource_path):
|
||||
var AnimationName = DialogicUtil.get_project_setting('dialogic/animations/leave_default',
|
||||
get_script().resource_path.get_base_dir().path_join('DefaultAnimations/fade_out_down.gd'))
|
||||
var AnimationLength = DialogicUtil.get_project_setting('dialogic/animations/leave_default_length', 0.5)
|
||||
|
||||
var anim = animate_portrait(load(joined_character), AnimationName, AnimationLength)
|
||||
|
||||
anim.finished.connect(remove_portrait.bind(load(joined_character)))
|
||||
else:
|
||||
char_joined = true
|
||||
|
||||
if (not char_joined) and character and portrait in character.portraits:
|
||||
var AnimationName = DialogicUtil.get_project_setting('dialogic/animations/join_default',
|
||||
get_script().resource_path.get_base_dir().path_join('DefaultAnimations/fade_in_up.gd'))
|
||||
var AnimationLength = DialogicUtil.get_project_setting('dialogic/animations/join_default_length', 0.5)
|
||||
add_portrait(character, portrait, 1, false)
|
||||
var anim = animate_portrait(character, AnimationName, AnimationLength)
|
||||
|
||||
# makes sure positions are listed and can be accessed
|
||||
func check_positions_and_holder() -> void:
|
||||
if _portrait_holder_reference == null and len(get_tree().get_nodes_in_group('dialogic_portrait_holder')) == 0:
|
||||
assert(false, '[Dialogic] If you want to display portraits, you need a PortraitHolder scene!')
|
||||
else:
|
||||
if _portrait_holder_reference == null:
|
||||
_portrait_holder_reference = get_tree().get_first_node_in_group('dialogic_portrait_holder')
|
||||
if _default_positions.size() == 0:
|
||||
for node in get_tree().get_nodes_in_group('dialogic_portrait_position'):
|
||||
_default_positions[node['position_index']] = node['position']
|
||||
|
||||
if current_positions.size() == 0:
|
||||
current_positions = _default_positions.duplicate()
|
||||
Loading…
Add table
Add a link
Reference in a new issue