Add addons
This commit is contained in:
parent
2c862b2235
commit
3367bad24f
527 changed files with 36197 additions and 0 deletions
52
Sprout/addons/dialogic/Resources/CharacterResourceLoader.gd
Normal file
52
Sprout/addons/dialogic/Resources/CharacterResourceLoader.gd
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
@tool
|
||||
extends ResourceFormatLoader
|
||||
|
||||
# Needed by godot
|
||||
class_name DialogicCharacterFormatLoader
|
||||
|
||||
|
||||
# returns all excepted extenstions
|
||||
func _get_recognized_extensions() -> PackedStringArray:
|
||||
return PackedStringArray(["dch"])
|
||||
|
||||
|
||||
# Returns "Rrsource" if this file can/should be loaded by this script
|
||||
func _get_resource_type(path: String) -> String:
|
||||
var ext = path.get_extension().to_lower()
|
||||
if ext == "dch":
|
||||
return "Resource"
|
||||
|
||||
return ""
|
||||
|
||||
|
||||
# Return true if this type is handled
|
||||
func _handles_type(typename: StringName) -> bool:
|
||||
return ClassDB.is_parent_class(typename, "Resource")
|
||||
|
||||
|
||||
# parse the file and return a resource
|
||||
func _load(path: String, original_path: String, use_sub_threads: bool, cache_mode: int):
|
||||
# print('[Dialogic] Reimporting character "' , path, '"')
|
||||
if FileAccess.file_exists(path):
|
||||
var file = FileAccess.open(path, FileAccess.READ)
|
||||
return dict_to_inst(str_to_var(file.get_as_text()))
|
||||
else:
|
||||
push_error("File does not exists")
|
||||
return false
|
||||
|
||||
|
||||
func _get_dependencies(path:String, add_type:bool):
|
||||
var depends_on : PackedStringArray
|
||||
var character:DialogicCharacter = load(path)
|
||||
for p in character.portraits.values():
|
||||
if 'path' in p and p.path:
|
||||
depends_on.append(p.path)
|
||||
return depends_on
|
||||
|
||||
func _rename_dependencies(path: String, renames: Dictionary):
|
||||
var character:DialogicCharacter = load(path)
|
||||
for p in character.portraits:
|
||||
if 'path' in character.portraits[p] and character.portraits[p].path in renames:
|
||||
character.portraits[p].path = renames[character.portraits[p].path]
|
||||
ResourceSaver.save(character, path)
|
||||
return OK
|
||||
26
Sprout/addons/dialogic/Resources/CharacterResourceSaver.gd
Normal file
26
Sprout/addons/dialogic/Resources/CharacterResourceSaver.gd
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
@tool
|
||||
extends ResourceFormatSaver
|
||||
class_name DialogicCharacterFormatSaver
|
||||
|
||||
|
||||
func _get_recognized_extensions(resource: Resource) -> PackedStringArray:
|
||||
return PackedStringArray(["dch"])
|
||||
|
||||
|
||||
# Return true if this resource should be loaded as a DialogicCharacter
|
||||
func _recognize(resource: Resource) -> bool:
|
||||
# Cast instead of using "is" keyword in case is a subclass
|
||||
resource = resource as DialogicCharacter
|
||||
|
||||
if resource:
|
||||
return true
|
||||
|
||||
return false
|
||||
|
||||
|
||||
# Save the resource
|
||||
func _save(resource: Resource, path: String = '', flags: int = 0):
|
||||
var file := FileAccess.open(path, FileAccess.WRITE)
|
||||
var result := var_to_str(inst_to_dict(resource))
|
||||
file.store_string(result)
|
||||
# print('[Dialogic] Saved character "' , path, '"')
|
||||
50
Sprout/addons/dialogic/Resources/TimelineResourceLoader.gd
Normal file
50
Sprout/addons/dialogic/Resources/TimelineResourceLoader.gd
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
@tool
|
||||
extends ResourceFormatLoader
|
||||
|
||||
# Needed by godot
|
||||
class_name DialogicTimelineFormatLoader
|
||||
|
||||
|
||||
# returns all excepted extenstions
|
||||
func _get_recognized_extensions() -> PackedStringArray:
|
||||
return PackedStringArray(["dtl"])
|
||||
|
||||
|
||||
# Returns "Rrsource" if this file can/should be loaded by this script
|
||||
func _get_resource_type(path: String) -> String:
|
||||
var ext = path.get_extension().to_lower()
|
||||
if ext == "dtl":
|
||||
return "Resource"
|
||||
|
||||
return ""
|
||||
|
||||
|
||||
# Return true if this type is handled
|
||||
func _handles_type(typename: StringName) -> bool:
|
||||
return ClassDB.is_parent_class(typename, "Resource")
|
||||
|
||||
|
||||
# parse the file and return a resource
|
||||
func _load(path: String, original_path: String, use_sub_threads: bool, cache_mode: int):
|
||||
# print('[Dialogic] Reimporting timeline "' , path, '"')
|
||||
if FileAccess.file_exists(path):
|
||||
var file := FileAccess.open(path, FileAccess.READ)
|
||||
var res := DialogicTimeline.new()
|
||||
var text : String = file.get_as_text()
|
||||
|
||||
# Parse the lines as seperate events and insert them in an array, so they can be converted to DialogicEvent's when processed later
|
||||
var prev_indent := ""
|
||||
var events := []
|
||||
|
||||
var lines := text.split('\n', true)
|
||||
var idx := -1
|
||||
|
||||
while idx < len(lines)-1:
|
||||
idx += 1
|
||||
var line :String = lines[idx]
|
||||
var line_stripped :String = line.strip_edges(true, true)
|
||||
events.append(line)
|
||||
|
||||
res.events = events
|
||||
res.events_processed = false
|
||||
return res
|
||||
96
Sprout/addons/dialogic/Resources/TimelineResourceSaver.gd
Normal file
96
Sprout/addons/dialogic/Resources/TimelineResourceSaver.gd
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
@tool
|
||||
extends ResourceFormatSaver
|
||||
class_name DialogicTimelineFormatSaver
|
||||
|
||||
|
||||
func _get_recognized_extensions(resource: Resource) -> PackedStringArray:
|
||||
return PackedStringArray(["dtl"])
|
||||
|
||||
|
||||
# Return true if this resource should be loaded as a DialogicTimeline
|
||||
func _recognize(resource: Resource) -> bool:
|
||||
# Cast instead of using "is" keyword in case is a subclass
|
||||
resource = resource as DialogicTimeline
|
||||
|
||||
if resource:
|
||||
return true
|
||||
|
||||
return false
|
||||
|
||||
|
||||
# Save the resource
|
||||
func _save(resource: Resource, path: String = '', flags: int = 0) -> int:
|
||||
if resource.get_meta("timeline_not_saved", false):
|
||||
if len(resource.events) == 0:
|
||||
printerr("[Dialogic] Timeline save was called, but there are no events. Timeline will not be saved, to prevent accidental data loss. Please delete the timeline file if you are trying to clear all of the events.")
|
||||
return ERR_INVALID_DATA
|
||||
|
||||
# print('[Dialogic] Beginning saving timeline. Safety checks will be performed before writing, and temporary file will be created and removed if saving is successful...')
|
||||
|
||||
#prepare everything before writing, we will only open the file if it's successfuly prepared, as that will clear the file contents
|
||||
|
||||
var timeline_as_text :String = ""
|
||||
# if events are resources, create text
|
||||
if resource.events_processed:
|
||||
|
||||
var indent := 0
|
||||
for idx in range(0, len(resource.events)):
|
||||
var event :DialogicEvent= resource.events[idx]
|
||||
if event.event_name == 'End Branch':
|
||||
indent -=1
|
||||
continue
|
||||
|
||||
for i in event.empty_lines_above:
|
||||
timeline_as_text += '\t'.repeat(indent) + '\n'
|
||||
|
||||
if event != null:
|
||||
timeline_as_text += "\t".repeat(indent)+ event.event_node_as_text + "\n"
|
||||
if event.can_contain_events:
|
||||
indent += 1
|
||||
if indent < 0:
|
||||
indent = 0
|
||||
|
||||
# if events are string lines, just save them
|
||||
else:
|
||||
for event in resource.events:
|
||||
timeline_as_text += event + "\n"
|
||||
|
||||
# Now do the actual saving
|
||||
if (len(timeline_as_text) > 0):
|
||||
var file := FileAccess.open(path.replace(".dtl", ".tmp"), FileAccess.WRITE)
|
||||
file.store_string(timeline_as_text)
|
||||
file = null
|
||||
|
||||
var dir = DirAccess.open("res://")
|
||||
if dir.file_exists(path.replace(".dtl", ".tmp")):
|
||||
file = FileAccess.open(path.replace(".dtl", ".tmp"), FileAccess.READ)
|
||||
var check_length = file.get_length()
|
||||
if check_length > 0:
|
||||
var check_result = file.get_as_text()
|
||||
file = null
|
||||
if timeline_as_text == check_result:
|
||||
dir.copy(path.replace(".dtl", ".tmp"), path)
|
||||
file = FileAccess.open(path, FileAccess.READ)
|
||||
var check_result2 = file.get_as_text()
|
||||
if timeline_as_text == check_result2:
|
||||
# print('[Dialogic] Completed saving timeline "' , path, '"')
|
||||
dir.remove(path.replace(".dtl", ".tmp"))
|
||||
else:
|
||||
printerr("[Dialogic] " + path + ": Overwriting .dtl file failed! Temporary file was saved as .tmp extension, please check to see if it matches your timeline, and rename to .dtl manually.")
|
||||
return ERR_INVALID_DATA
|
||||
else:
|
||||
printerr("[Dialogic] " + path + ": Temporary timeline file contents do not match what was written! Temporary file was saved as .tmp extension, please check to see if it matches your timeline, and rename to .dtl manually.")
|
||||
return ERR_INVALID_DATA
|
||||
else:
|
||||
printerr("[Dialogic] " + path + ": Temporary timeline file is empty! Timeline was not saved!")
|
||||
dir.remove(path.replace(".dtl", ".tmp"))
|
||||
return ERR_INVALID_DATA
|
||||
else:
|
||||
printerr("[Dialogic] " + path + ": Temporary timeline file failed to create! Timeline was not saved!")
|
||||
return ERR_INVALID_DATA
|
||||
|
||||
else:
|
||||
printerr("[Dialogic] " + path + ": Timeline failed to convert to text for saving! Timeline was not saved!")
|
||||
return ERR_INVALID_DATA
|
||||
|
||||
return OK
|
||||
33
Sprout/addons/dialogic/Resources/character.gd
Normal file
33
Sprout/addons/dialogic/Resources/character.gd
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
@tool
|
||||
extends Resource
|
||||
class_name DialogicCharacter
|
||||
|
||||
|
||||
@export var display_name:String = ""
|
||||
@export var nicknames:Array = []
|
||||
|
||||
@export var color:Color = Color()
|
||||
@export var description:String = ""
|
||||
|
||||
@export var scale:float = 1.0
|
||||
@export var offset:Vector2 = Vector2()
|
||||
@export var mirror:bool = false
|
||||
|
||||
@export var default_portrait:String = ""
|
||||
@export var portraits:Dictionary = {}
|
||||
|
||||
@export var custom_info:Dictionary = {}
|
||||
|
||||
func __get_property_list() -> Array:
|
||||
return []
|
||||
|
||||
|
||||
func _to_string() -> String:
|
||||
return "[{name}:{id}]".format({"name":get_character_name(), "id":get_instance_id()})
|
||||
|
||||
func _hide_script_from_inspector() -> bool:
|
||||
return true
|
||||
|
||||
## Returns the name of the file (without the extension).
|
||||
func get_character_name() -> String:
|
||||
return resource_path.get_file().trim_suffix('.dch')
|
||||
419
Sprout/addons/dialogic/Resources/event.gd
Normal file
419
Sprout/addons/dialogic/Resources/event.gd
Normal file
|
|
@ -0,0 +1,419 @@
|
|||
@tool
|
||||
class_name DialogicEvent
|
||||
extends Resource
|
||||
|
||||
## Base event class for all dialogic events.
|
||||
## Implements basic properties, translation, shortcode saving and usefull methods for creating
|
||||
## the editor UI.
|
||||
|
||||
|
||||
## Emmited when the event starts.
|
||||
## The signal is emmited with the event resource [code]event_resource[/code]
|
||||
signal event_started(event_resource)
|
||||
|
||||
## Emmited when the event finish.
|
||||
## The signal is emmited with the event resource [code]event_resource[/code]
|
||||
signal event_finished(event_resource)
|
||||
|
||||
|
||||
### Main Event Properties ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
## The event name that'll be displayed in the editor.
|
||||
var event_name:String = "Event"
|
||||
## Unique identifier used for translatable events.
|
||||
var _translation_id :String= ""
|
||||
## A reference to dialogic during execution, can be used the same as Dialogic (reference to the autoload)
|
||||
var dialogic = null
|
||||
|
||||
|
||||
### Special Event Properties ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
### (these properties store how this event affects indentation/flow of timeline)
|
||||
|
||||
## If true this event can not be toplevel (e.g. Choice)
|
||||
var needs_indentation : bool = false
|
||||
## If true this event will spawn with an END BRANCH event and higher the indentation
|
||||
var can_contain_events : bool = false
|
||||
## If [can_contain_events] is true this is a reference to the end branch event
|
||||
var end_branch_event : DialogicEndBranchEvent = null
|
||||
## If this is true this event expects a specific parent event.
|
||||
var needs_parent_event : bool = false
|
||||
## If true the next event will be played without awaiting input from the player
|
||||
var continue_at_end:bool = true
|
||||
|
||||
|
||||
### Saving/Loading Properties ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
## Stores the event in a text format. Does NOT automatically update.
|
||||
var event_node_as_text: String = ""
|
||||
## Flags if the event has been processed or is only stored as text
|
||||
var event_node_ready: bool = false
|
||||
## How many empty lines are before this event
|
||||
var empty_lines_above:int = 0
|
||||
|
||||
|
||||
### Editor UI Properties ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
## The event color that event node will take in the editor
|
||||
var event_color: Color = Color("FBB13C")
|
||||
## If you are using the default color palette
|
||||
var dialogic_color_name: String = ''
|
||||
## To sort the buttons shown in the editor. Lower index is placed at the top of a category
|
||||
var event_sorting_index: int = 0
|
||||
## If false the name is not displayed on the event.
|
||||
var display_name: bool = true
|
||||
## If true the event will not have a button in the visual editor sidebar
|
||||
var disable_editor_button: bool = false
|
||||
## If false the event will hide it's body by default. Recommended for most events
|
||||
var expand_by_default : bool = true
|
||||
## The URL to open when right_click>Documentation is selected
|
||||
var help_page_path : String = ""
|
||||
|
||||
## Reference to the node, that represents this event. Only works while in visual editor mode.
|
||||
## Use with care.
|
||||
var _editor_node : Control = null
|
||||
|
||||
## The categories and which one to put it in (in the visual editor sidebar)
|
||||
enum Category {Main, Logic, Timeline, AudioVisual, Godot, Other}
|
||||
var event_category:int = Category.Other
|
||||
|
||||
|
||||
### Editor UI creation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
## To differentiate fields that should go to the header and to the body
|
||||
enum Location {Header, Body}
|
||||
|
||||
## To differentiate the different types of fields for event properties in the visual editor
|
||||
enum ValueType {
|
||||
# Strings
|
||||
Label, MultilineText, SinglelineText, Condition,
|
||||
# Booleans
|
||||
Bool,
|
||||
# Resources
|
||||
ComplexPicker, File,
|
||||
# Array
|
||||
StringArray,
|
||||
# Integers
|
||||
FixedOptionSelector, Integer, Vector2,
|
||||
# Floats
|
||||
Float, Decibel,
|
||||
# Other
|
||||
Custom, Button,
|
||||
}
|
||||
## List that stores the fields for the editor
|
||||
var editor_list : Array = []
|
||||
|
||||
|
||||
## Makes this resource printable.
|
||||
func _to_string() -> String:
|
||||
return "[{name}:{id}]".format({"name":event_name, "id":get_instance_id()})
|
||||
|
||||
|
||||
################################################################################
|
||||
## EXECUTION
|
||||
################################################################################
|
||||
|
||||
## Executes the event behaviour. In subclasses [_execute] (not this one) should be overriden!
|
||||
func execute(_dialogic_game_handler) -> void:
|
||||
emit_signal("event_started", self)
|
||||
dialogic = _dialogic_game_handler
|
||||
call_deferred("_execute")
|
||||
|
||||
|
||||
## Ends the event behaviour.
|
||||
func finish() -> void:
|
||||
emit_signal("event_finished", self)
|
||||
|
||||
|
||||
## To be overridden by subclasses.
|
||||
func _execute() -> void:
|
||||
finish()
|
||||
|
||||
|
||||
################################################################################
|
||||
## OVERRIDABLES
|
||||
################################################################################
|
||||
|
||||
## to be overridden by sub-classes
|
||||
## if needs_parent_event is true, this needs to return true if the event is that event
|
||||
func is_expected_parent_event(event:DialogicEvent) -> bool:
|
||||
return false
|
||||
|
||||
|
||||
## to be overridden by sub-classes
|
||||
## only called if can_contain_events is true.
|
||||
## return a control node that should show on the END BRANCH node
|
||||
func get_end_branch_control() -> Control:
|
||||
return null
|
||||
|
||||
|
||||
## to be overridden by sub-classes
|
||||
## only called if can_contain_events is true and the previous event was an end-branch event
|
||||
## return true if this event should be executed if the previous event was an end-branch event
|
||||
## basically only important for the Condition event but who knows. Some day someone might need this.
|
||||
func should_execute_this_branch() -> bool:
|
||||
return false
|
||||
|
||||
|
||||
################################################################################
|
||||
## TRANSLATIONS
|
||||
################################################################################
|
||||
|
||||
## Overwrite if this events needs translation.
|
||||
func _get_translatable_properties() -> Array:
|
||||
return []
|
||||
|
||||
|
||||
## Overwrite if this events needs translation.
|
||||
func _get_property_original_translation(property_name:String) -> String:
|
||||
return ''
|
||||
|
||||
|
||||
## Returns true if there is any translatable properties on this event.
|
||||
## Overwrite [_get_translatable_properties()] to change this.
|
||||
func can_be_translated() -> bool:
|
||||
return !_get_translatable_properties().is_empty()
|
||||
|
||||
|
||||
## This is automatically called, no need to use this.
|
||||
func add_translation_id() -> String:
|
||||
_translation_id = DialogicUtil.get_next_translation_id()
|
||||
return _translation_id
|
||||
|
||||
|
||||
func remove_translation_id() -> void:
|
||||
_translation_id = ""
|
||||
|
||||
|
||||
func get_property_translation_key(property_name:String) -> String:
|
||||
return event_name.path_join(_translation_id).path_join(property_name)
|
||||
|
||||
|
||||
## Call this whenever you are using a translatable property
|
||||
func get_property_translated(property_name:String) -> String:
|
||||
if !_translation_id.is_empty() and DialogicUtil.get_project_setting('dialogic/translation_enabled', false):
|
||||
var translation = tr(get_property_translation_key(property_name))
|
||||
# if no translation is found tr() returns the id, but we want to fallback to the original
|
||||
return translation if translation != _translation_id else _get_property_original_translation(property_name)
|
||||
else:
|
||||
return _get_property_original_translation(property_name)
|
||||
|
||||
|
||||
################################################################################
|
||||
## SAVE / LOAD (internal, don't override)
|
||||
################################################################################
|
||||
### These functions are used by the timeline loader/saver
|
||||
### They mainly use the overridable behaviour below, but enforce the unique_id saving
|
||||
|
||||
## Used by the Timeline saver.
|
||||
func _store_as_string() -> String:
|
||||
if !_translation_id.is_empty() and can_be_translated():
|
||||
return to_text() + ' #id:'+str(_translation_id)
|
||||
else:
|
||||
return to_text()
|
||||
|
||||
|
||||
## Call this if you updated an event and want the changes to be saved.
|
||||
func update_text_version() -> void:
|
||||
event_node_as_text = _store_as_string()
|
||||
|
||||
|
||||
## Used by timeline processor (DGH).
|
||||
func _load_from_string(string:String) -> void:
|
||||
if '#id:' in string and can_be_translated():
|
||||
_translation_id = string.get_slice('#id:', 1).strip_edges()
|
||||
from_text(string.get_slice('#id:', 0))
|
||||
event_node_ready = true
|
||||
else:
|
||||
from_text(string)
|
||||
event_node_ready = true
|
||||
|
||||
|
||||
## Used by the timeline processor (DGH).
|
||||
func _test_event_string(string:String) -> bool:
|
||||
if '#id:' in string and can_be_translated():
|
||||
return is_valid_event(string.get_slice('#id:', 0))
|
||||
return is_valid_event(string.strip_edges())
|
||||
|
||||
|
||||
################################################################################
|
||||
## SAVE / LOAD
|
||||
################################################################################
|
||||
### All of these functions can/should be overridden by the sub classes
|
||||
|
||||
## if this uses the short-code format, return the shortcode
|
||||
func get_shortcode() -> String:
|
||||
return 'default_shortcode'
|
||||
|
||||
|
||||
## if this uses the short-code format, return the parameters and corresponding property names
|
||||
func get_shortcode_parameters() -> Dictionary:
|
||||
return {}
|
||||
|
||||
|
||||
## returns a readable presentation of the event (This is how it's stored)
|
||||
## by default it uses a shortcode format, but can be overridden
|
||||
func to_text() -> String:
|
||||
var result_string : String = "["+self.get_shortcode()
|
||||
var params : Dictionary = get_shortcode_parameters()
|
||||
for parameter in params.keys():
|
||||
if get(params[parameter]["property"]) != params[parameter]["default"]:
|
||||
if typeof(get(params[parameter]["property"])) == TYPE_OBJECT:
|
||||
result_string += " "+parameter+'="'+str(get(params[parameter]["property"]).resource_path)+'"'
|
||||
elif typeof(get(params[parameter]["property"])) == TYPE_STRING:
|
||||
result_string += " "+parameter+'="'+get(params[parameter]["property"]).replace('=', "\\=")+'"'
|
||||
else:
|
||||
result_string += " "+parameter+'="'+var_to_str(get(params[parameter]["property"])).replace('=', "\\=")+'"'
|
||||
result_string += "]"
|
||||
return result_string
|
||||
|
||||
|
||||
## loads the variables from the string stored above
|
||||
## by default it uses the shortcode format, but can be overridden
|
||||
func from_text(string:String) -> void:
|
||||
var data : Dictionary = parse_shortcode_parameters(string)
|
||||
var params : Dictionary = get_shortcode_parameters()
|
||||
for parameter in params.keys():
|
||||
if not parameter in data:
|
||||
continue
|
||||
|
||||
#if typeof(data[parameter]) == TYPE_STRING and (data[parameter].ends_with(".dtl") or data[parameter].ends_with(".dch")):
|
||||
if typeof(data[parameter]) == TYPE_STRING and (data[parameter].ends_with(".dch")):
|
||||
set(params[parameter]['property'], load(data[parameter]))
|
||||
else:
|
||||
var value :Variant
|
||||
if str_to_var(data[parameter].replace('\\=', '=')) != null:
|
||||
value = str_to_var(data[parameter].replace('\\=', '='))
|
||||
else:
|
||||
value = data[parameter].replace('\\=', '=')
|
||||
set(params[parameter]['property'], value)
|
||||
|
||||
|
||||
## has to return true, if the given string can be interpreted as this event
|
||||
## by default it uses the shortcode formta, but can be overridden
|
||||
func is_valid_event(string:String) -> bool:
|
||||
if string.strip_edges().begins_with('['+get_shortcode()):
|
||||
return true
|
||||
return false
|
||||
|
||||
|
||||
## has to return true if this string seems to be a full event of this kind
|
||||
## (only tested if is_valid_event() returned true)
|
||||
## if a shortcode it used it will default to true if the string ends with ']'
|
||||
func is_string_full_event(string:String) -> bool:
|
||||
if get_shortcode() != 'default_shortcode': return string.strip_edges().ends_with(']')
|
||||
return true
|
||||
|
||||
|
||||
## used to get all the shortcode parameters in a string as a dictionary
|
||||
func parse_shortcode_parameters(shortcode : String) -> Dictionary:
|
||||
var regex:RegEx = RegEx.new()
|
||||
regex.compile('((?<parameter>[^\\s=]*)\\s*=\\s*"(?<value>([^=]|\\\\=)*)(?<!\\\\)")')
|
||||
var dict : Dictionary = {}
|
||||
for result in regex.search_all(shortcode):
|
||||
dict[result.get_string('parameter')] = result.get_string('value')
|
||||
return dict
|
||||
|
||||
|
||||
################################################################################
|
||||
## EDITOR REPRESENTATION
|
||||
################################################################################
|
||||
|
||||
func _get_icon() -> Resource:
|
||||
var ext : String = '.png'
|
||||
var icon := load(self.get_script().get_path().get_base_dir() + "/icon" + ext)
|
||||
if icon:
|
||||
return icon
|
||||
return load("res://addons/dialogic/Editor/Images/Pieces/warning.svg")
|
||||
|
||||
|
||||
func set_default_color(value) -> void:
|
||||
dialogic_color_name = value
|
||||
event_color = DialogicUtil.get_color(value)
|
||||
|
||||
|
||||
func _get_property_list() -> Array:
|
||||
if Engine.is_editor_hint():
|
||||
if editor_list != null:
|
||||
editor_list.clear()
|
||||
else:
|
||||
editor_list = []
|
||||
|
||||
build_event_editor()
|
||||
return editor_list
|
||||
else:
|
||||
return []
|
||||
|
||||
|
||||
## to be overwritten by the sub_classes
|
||||
func build_event_editor() -> void:
|
||||
pass
|
||||
|
||||
## For the methods below the arguments are mostly similar:
|
||||
## @variable: String name of the property this field is for
|
||||
## @condition: String that will be executed as an expression. If it false
|
||||
## @editor_type: One of the ValueTypes (see ValueType enum). Defines type of field.
|
||||
## @left_text: Text that will be shown to the left of the field
|
||||
## @right_text: Text that will be shown to the right of the field
|
||||
## @extra_info: Allows passing a lot more info to the field.
|
||||
## What info can be passed is differnet for every field
|
||||
|
||||
func add_header_label(text:String, condition:String = "") -> void:
|
||||
editor_list.append({
|
||||
"name" : "something",
|
||||
"type" : TYPE_STRING,
|
||||
"location" : Location.Header,
|
||||
"usage" : PROPERTY_USAGE_EDITOR,
|
||||
"dialogic_type" : ValueType.Label,
|
||||
"display_info" : {"text":text},
|
||||
"condition" : condition
|
||||
})
|
||||
|
||||
|
||||
func add_header_edit(variable:String, editor_type = ValueType.Label, left_text:String = "", right_text:String = "", extra_info:Dictionary = {}, condition:String = "") -> void:
|
||||
editor_list.append({
|
||||
"name" : variable,
|
||||
"type" : typeof(get(variable)),
|
||||
"location" : Location.Header,
|
||||
"usage" : PROPERTY_USAGE_DEFAULT,
|
||||
"dialogic_type" : editor_type,
|
||||
"display_info" : extra_info,
|
||||
"left_text" : left_text,
|
||||
"right_text" : right_text,
|
||||
"condition" : condition,
|
||||
})
|
||||
|
||||
|
||||
func add_header_button(text:String, callable:Callable, tooltip:String, icon: Variant = null, condition:String = "") -> void:
|
||||
editor_list.append({
|
||||
"name" : "Button",
|
||||
"type" : TYPE_STRING,
|
||||
"location" : Location.Header,
|
||||
"usage" : PROPERTY_USAGE_DEFAULT,
|
||||
"dialogic_type" : ValueType.Button,
|
||||
"display_info" : {'text':text, 'tooltip':tooltip, 'callable':callable, 'icon':icon},
|
||||
"condition" : condition,
|
||||
})
|
||||
|
||||
|
||||
func add_body_edit(variable:String, editor_type = ValueType.Label, left_text:String= "", right_text:String="", extra_info:Dictionary = {}, condition:String = "") -> void:
|
||||
editor_list.append({
|
||||
"name" : variable,
|
||||
"type" : typeof(get(variable)),
|
||||
"location" : Location.Body,
|
||||
"usage" : PROPERTY_USAGE_DEFAULT,
|
||||
"dialogic_type" : editor_type,
|
||||
"display_info" : extra_info,
|
||||
"left_text" : left_text,
|
||||
"right_text" : right_text,
|
||||
"condition" : condition,
|
||||
})
|
||||
|
||||
|
||||
func add_body_line_break(condition:String = "") -> void:
|
||||
editor_list.append({
|
||||
"name" : "linebreak",
|
||||
"type" : TYPE_BOOL,
|
||||
"location" : Location.Body,
|
||||
"usage" : PROPERTY_USAGE_DEFAULT,
|
||||
"condition" : condition,
|
||||
})
|
||||
104
Sprout/addons/dialogic/Resources/timeline.gd
Normal file
104
Sprout/addons/dialogic/Resources/timeline.gd
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
@tool
|
||||
extends Resource
|
||||
class_name DialogicTimeline
|
||||
|
||||
@export var dialogic_version:String
|
||||
|
||||
|
||||
var events:Array = []:
|
||||
get:
|
||||
return events
|
||||
set(value):
|
||||
emit_changed()
|
||||
notify_property_list_changed()
|
||||
events = value
|
||||
|
||||
var events_processed:bool = false
|
||||
|
||||
|
||||
func set_events(_events:Array) -> void:
|
||||
events = _events
|
||||
emit_changed()
|
||||
notify_property_list_changed()
|
||||
|
||||
|
||||
func add_event(event, at_position:int =-1) -> void:
|
||||
var idx : int = at_position if at_position > -1 else events.size()
|
||||
events.insert(idx, event)
|
||||
emit_changed()
|
||||
notify_property_list_changed()
|
||||
|
||||
|
||||
func erase_event(event) -> void:
|
||||
events.erase(event)
|
||||
emit_changed()
|
||||
notify_property_list_changed()
|
||||
|
||||
|
||||
func remove_event(position:int) -> void:
|
||||
events.erase(position)
|
||||
emit_changed()
|
||||
notify_property_list_changed()
|
||||
|
||||
|
||||
func get_event(index):
|
||||
if index >= len(events):
|
||||
return null
|
||||
return events[index]
|
||||
|
||||
|
||||
func get_events() -> Array:
|
||||
return events.duplicate()
|
||||
|
||||
|
||||
func _set(property, value):
|
||||
if str(property).begins_with("event/"):
|
||||
var event_idx:int = str(property).split("/", true, 2)[1].to_int()
|
||||
if event_idx < events.size():
|
||||
events[event_idx] = value
|
||||
else:
|
||||
events.insert(event_idx, value)
|
||||
|
||||
emit_changed()
|
||||
notify_property_list_changed()
|
||||
|
||||
if property == "events":
|
||||
set_events(value)
|
||||
return true
|
||||
|
||||
return false
|
||||
|
||||
func _get(property):
|
||||
if str(property).begins_with("event/"):
|
||||
var event_idx:int = str(property).split("/", true, 2)[1].to_int()
|
||||
if event_idx < len(events):
|
||||
return events[event_idx]
|
||||
return true
|
||||
|
||||
func _init() -> void:
|
||||
events = []
|
||||
resource_name = get_class()
|
||||
|
||||
|
||||
func _to_string() -> String:
|
||||
return "[{class}:{file}]".format({"class":get_class(), "file":resource_path})
|
||||
|
||||
|
||||
func get_class() -> String: return "Timeline"
|
||||
|
||||
|
||||
func _get_property_list() -> Array:
|
||||
var p : Array = []
|
||||
var usage = PROPERTY_USAGE_SCRIPT_VARIABLE
|
||||
usage |= PROPERTY_USAGE_NO_EDITOR
|
||||
usage |= PROPERTY_USAGE_EDITOR # Comment this line to hide events from editor
|
||||
if events != null:
|
||||
for event_idx in events.size():
|
||||
p.append(
|
||||
{
|
||||
"name":"event/{idx}".format({"idx":event_idx}),
|
||||
"type":TYPE_OBJECT,
|
||||
"usage":PROPERTY_USAGE_DEFAULT|PROPERTY_USAGE_SCRIPT_VARIABLE
|
||||
}
|
||||
)
|
||||
return p
|
||||
Loading…
Add table
Add a link
Reference in a new issue