You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
364 lines
13 KiB
364 lines
13 KiB
6 months ago
|
@tool
|
||
|
class_name DialogicVariableEvent
|
||
|
extends DialogicEvent
|
||
|
|
||
|
## Event that allows changing a dialogic variable or a property of an autoload.
|
||
|
|
||
|
|
||
|
enum Operations {SET, ADD, SUBSTRACT, MULTIPLY, DIVIDE}
|
||
|
enum VarValueType {
|
||
|
STRING = 0,
|
||
|
NUMBER = 1,
|
||
|
VARIABLE = 2,
|
||
|
BOOL = 3,
|
||
|
EXPRESSION = 4,
|
||
|
RANDOM_NUMBER = 5,
|
||
|
}
|
||
|
|
||
|
## Settings
|
||
|
|
||
|
## Name/Path of the variable that should be changed.
|
||
|
var name: String = "":
|
||
|
set(_value):
|
||
|
name = _value
|
||
|
if Engine.is_editor_hint() and not value:
|
||
|
match DialogicUtil.get_variable_type(name):
|
||
|
DialogicUtil.VarTypes.ANY, DialogicUtil.VarTypes.STRING:
|
||
|
_value_type = VarValueType.STRING
|
||
|
DialogicUtil.VarTypes.FLOAT, DialogicUtil.VarTypes.INT:
|
||
|
_value_type = VarValueType.NUMBER
|
||
|
DialogicUtil.VarTypes.BOOL:
|
||
|
_value_type = VarValueType.BOOL
|
||
|
ui_update_needed.emit()
|
||
|
update_editor_warning()
|
||
|
|
||
|
## The operation to perform.
|
||
|
var operation: int = Operations.SET:
|
||
|
set(value):
|
||
|
operation = value
|
||
|
if operation != Operations.SET and _value_type == VarValueType.STRING:
|
||
|
_value_type = VarValueType.NUMBER
|
||
|
ui_update_needed.emit()
|
||
|
update_editor_warning()
|
||
|
|
||
|
## The value that is used. Can be a variable as well.
|
||
|
var value: Variant = ""
|
||
|
var _value_type := 0 :
|
||
|
set(_value):
|
||
|
_value_type = _value
|
||
|
if not _suppress_default_value:
|
||
|
match _value_type:
|
||
|
VarValueType.STRING, VarValueType.VARIABLE, VarValueType.EXPRESSION:
|
||
|
value = ""
|
||
|
VarValueType.NUMBER:
|
||
|
value = 0
|
||
|
VarValueType.BOOL:
|
||
|
value = false
|
||
|
VarValueType.RANDOM_NUMBER:
|
||
|
value = null
|
||
|
ui_update_needed.emit()
|
||
|
update_editor_warning()
|
||
|
|
||
|
## If true, a random number between [random_min] and [random_max] is used instead of [value].
|
||
|
var random_min: int = 0
|
||
|
var random_max: int = 100
|
||
|
|
||
|
## Used to suppress _value_type from overwriting value with a default value when the type changes
|
||
|
## This is only used when initializing the event_variable.
|
||
|
var _suppress_default_value: bool = false
|
||
|
|
||
|
|
||
|
################################################################################
|
||
|
## EXECUTE
|
||
|
################################################################################
|
||
|
|
||
|
func _execute() -> void:
|
||
|
if name:
|
||
|
var original_value: Variant = dialogic.VAR.get_variable(name, null, operation == Operations.SET and "[" in name)
|
||
|
|
||
|
if value != null and (original_value != null or (operation == Operations.SET and "[" in name)):
|
||
|
|
||
|
var interpreted_value: Variant
|
||
|
var result: Variant
|
||
|
|
||
|
match _value_type:
|
||
|
VarValueType.STRING:
|
||
|
interpreted_value = dialogic.VAR.get_variable('"' + value + '"')
|
||
|
VarValueType.VARIABLE:
|
||
|
interpreted_value = dialogic.VAR.get_variable('{' + value + '}')
|
||
|
VarValueType.NUMBER, VarValueType.BOOL, VarValueType.EXPRESSION, VarValueType.RANDOM_NUMBER:
|
||
|
interpreted_value = dialogic.VAR.get_variable(str(value))
|
||
|
|
||
|
if operation != Operations.SET and (not str(original_value).is_valid_float() or not str(interpreted_value).is_valid_float()):
|
||
|
printerr("[Dialogic] Set Variable event failed because one value wasn't a float! [", original_value, ", ",interpreted_value,"]")
|
||
|
finish()
|
||
|
return
|
||
|
|
||
|
if operation == Operations.SET:
|
||
|
result = interpreted_value
|
||
|
|
||
|
else:
|
||
|
original_value = float(original_value)
|
||
|
interpreted_value = float(interpreted_value)
|
||
|
|
||
|
match operation:
|
||
|
Operations.ADD:
|
||
|
result = original_value + interpreted_value
|
||
|
Operations.SUBSTRACT:
|
||
|
result = original_value - interpreted_value
|
||
|
Operations.MULTIPLY:
|
||
|
result = original_value * interpreted_value
|
||
|
Operations.DIVIDE:
|
||
|
result = original_value / interpreted_value
|
||
|
|
||
|
dialogic.VAR.set_variable(name, result)
|
||
|
dialogic.VAR.variable_was_set.emit(
|
||
|
{
|
||
|
'variable' : name,
|
||
|
'value' : interpreted_value,
|
||
|
'value_str' : value,
|
||
|
'orig_value' : original_value,
|
||
|
'new_value' : result,
|
||
|
})
|
||
|
|
||
|
else:
|
||
|
printerr("[Dialogic] Set Variable event failed because one value wasn't set!")
|
||
|
|
||
|
finish()
|
||
|
|
||
|
|
||
|
################################################################################
|
||
|
## INITIALIZE
|
||
|
################################################################################
|
||
|
|
||
|
func _init() -> void:
|
||
|
event_name = "Set Variable"
|
||
|
set_default_color('Color6')
|
||
|
event_category = "Logic"
|
||
|
event_sorting_index = 0
|
||
|
help_page_path = "https://docs.dialogic.pro/variables.html#23-set-variable-event"
|
||
|
|
||
|
|
||
|
################################################################################
|
||
|
## SAVING/LOADING
|
||
|
################################################################################
|
||
|
|
||
|
func to_text() -> String:
|
||
|
var string := "set "
|
||
|
if name:
|
||
|
string += "{" + name.trim_prefix('{').trim_suffix('}') + "}"
|
||
|
match operation:
|
||
|
Operations.SET:
|
||
|
string+= " = "
|
||
|
Operations.ADD:
|
||
|
string+= " += "
|
||
|
Operations.SUBSTRACT:
|
||
|
string+= " -= "
|
||
|
Operations.MULTIPLY:
|
||
|
string+= " *= "
|
||
|
Operations.DIVIDE:
|
||
|
string+= " /= "
|
||
|
|
||
|
value = str(value)
|
||
|
match _value_type:
|
||
|
VarValueType.STRING: # String
|
||
|
string += '"'+value.replace('"', '\\"')+'"'
|
||
|
VarValueType.NUMBER,VarValueType.BOOL,VarValueType.EXPRESSION: # Float Bool, or Expression
|
||
|
string += str(value)
|
||
|
VarValueType.VARIABLE: # Variable
|
||
|
string += '{'+value+'}'
|
||
|
VarValueType.RANDOM_NUMBER:
|
||
|
string += 'range('+str(random_min)+','+str(random_max)+').pick_random()'
|
||
|
|
||
|
return string
|
||
|
|
||
|
|
||
|
func from_text(string:String) -> void:
|
||
|
var reg := RegEx.new()
|
||
|
reg.compile("set(?<name>[^=+\\-*\\/]*)?(?<operation>=|\\+=|-=|\\*=|\\/=)?(?<value>.*)")
|
||
|
var result := reg.search(string)
|
||
|
if !result:
|
||
|
return
|
||
|
name = result.get_string('name').strip_edges().replace("{", "").replace("}", "")
|
||
|
match result.get_string('operation').strip_edges():
|
||
|
'=':
|
||
|
operation = Operations.SET
|
||
|
'-=':
|
||
|
operation = Operations.SUBSTRACT
|
||
|
'+=':
|
||
|
operation = Operations.ADD
|
||
|
'*=':
|
||
|
operation = Operations.MULTIPLY
|
||
|
'/=':
|
||
|
operation = Operations.DIVIDE
|
||
|
|
||
|
_suppress_default_value = true
|
||
|
value = result.get_string('value').strip_edges()
|
||
|
if not value.is_empty():
|
||
|
if value.begins_with('"') and value.ends_with('"') and value.count('"')-value.count('\\"') == 2:
|
||
|
value = result.get_string('value').strip_edges().replace('"', '')
|
||
|
_value_type = VarValueType.STRING
|
||
|
elif value.begins_with('{') and value.ends_with('}') and value.count('{') == 1:
|
||
|
value = result.get_string('value').strip_edges().trim_suffix('}').trim_prefix('{')
|
||
|
_value_type = VarValueType.VARIABLE
|
||
|
elif value in ["true", "false"]:
|
||
|
value = value == "true"
|
||
|
_value_type = VarValueType.BOOL
|
||
|
elif value.begins_with('range(') and value.ends_with(').pick_random()'):
|
||
|
_value_type = VarValueType.RANDOM_NUMBER
|
||
|
var randinf := str(value).trim_prefix('range(').trim_suffix(').pick_random()').split(',')
|
||
|
random_min = int(randinf[0])
|
||
|
random_max = int(randinf[1])
|
||
|
else:
|
||
|
value = result.get_string('value').strip_edges()
|
||
|
if value.is_valid_float():
|
||
|
_value_type = VarValueType.NUMBER
|
||
|
else:
|
||
|
_value_type = VarValueType.EXPRESSION
|
||
|
else:
|
||
|
value = null
|
||
|
_suppress_default_value = false
|
||
|
|
||
|
|
||
|
func is_valid_event(string:String) -> bool:
|
||
|
return string.begins_with('set')
|
||
|
|
||
|
|
||
|
################################################################################
|
||
|
## EDITOR REPRESENTATION
|
||
|
################################################################################
|
||
|
|
||
|
func build_event_editor():
|
||
|
add_header_edit('name', ValueType.DYNAMIC_OPTIONS, {
|
||
|
'left_text' : 'Set',
|
||
|
'suggestions_func' : get_var_suggestions,
|
||
|
'icon' : load("res://addons/dialogic/Editor/Images/Pieces/variable.svg"),
|
||
|
'placeholder' :'Select Variable'}
|
||
|
)
|
||
|
add_header_edit('operation', ValueType.FIXED_OPTIONS, {
|
||
|
'options': [
|
||
|
{
|
||
|
'label': 'to be',
|
||
|
'icon': load("res://addons/dialogic/Editor/Images/Dropdown/set.svg"),
|
||
|
'value': Operations.SET
|
||
|
},{
|
||
|
'label': 'to itself plus',
|
||
|
'icon': load("res://addons/dialogic/Editor/Images/Dropdown/plus.svg"),
|
||
|
'value': Operations.ADD
|
||
|
},{
|
||
|
'label': 'to itself minus',
|
||
|
'icon': load("res://addons/dialogic/Editor/Images/Dropdown/minus.svg"),
|
||
|
'value': Operations.SUBSTRACT
|
||
|
},{
|
||
|
'label': 'to itself multiplied by',
|
||
|
'icon': load("res://addons/dialogic/Editor/Images/Dropdown/multiply.svg"),
|
||
|
'value': Operations.MULTIPLY
|
||
|
},{
|
||
|
'label': 'to itself divided by',
|
||
|
'icon': load("res://addons/dialogic/Editor/Images/Dropdown/divide.svg"),
|
||
|
'value': Operations.DIVIDE
|
||
|
}
|
||
|
]
|
||
|
}, '!name.is_empty()')
|
||
|
add_header_edit('_value_type', ValueType.FIXED_OPTIONS, {
|
||
|
'options': [
|
||
|
{
|
||
|
'label': 'String',
|
||
|
'icon': ["String", "EditorIcons"],
|
||
|
'value': VarValueType.STRING
|
||
|
},{
|
||
|
'label': 'Number',
|
||
|
'icon': ["float", "EditorIcons"],
|
||
|
'value': VarValueType.NUMBER
|
||
|
},{
|
||
|
'label': 'Variable',
|
||
|
'icon': load("res://addons/dialogic/Editor/Images/Pieces/variable.svg"),
|
||
|
'value': VarValueType.VARIABLE
|
||
|
},{
|
||
|
'label': 'Bool',
|
||
|
'icon': ["bool", "EditorIcons"],
|
||
|
'value': VarValueType.BOOL
|
||
|
},{
|
||
|
'label': 'Expression',
|
||
|
'icon': ["Variant", "EditorIcons"],
|
||
|
'value': VarValueType.EXPRESSION
|
||
|
},{
|
||
|
'label': 'Random Number',
|
||
|
'icon': ["RandomNumberGenerator", "EditorIcons"],
|
||
|
'value': VarValueType.RANDOM_NUMBER
|
||
|
}],
|
||
|
'symbol_only':true},
|
||
|
'!name.is_empty()')
|
||
|
add_header_edit('value', ValueType.SINGLELINE_TEXT, {}, '!name.is_empty() and (_value_type == VarValueType.STRING or _value_type == VarValueType.EXPRESSION) ')
|
||
|
add_header_edit('value', ValueType.BOOL, {}, '!name.is_empty() and (_value_type == VarValueType.BOOL) ')
|
||
|
add_header_edit('value', ValueType.NUMBER, {}, '!name.is_empty() and _value_type == VarValueType.NUMBER')
|
||
|
add_header_edit('value', ValueType.DYNAMIC_OPTIONS,
|
||
|
{'suggestions_func' : get_value_suggestions, 'placeholder':'Select Variable'},
|
||
|
'!name.is_empty() and _value_type == VarValueType.VARIABLE')
|
||
|
add_header_label('a number between', '_value_type == VarValueType.RANDOM_NUMBER')
|
||
|
add_header_edit('random_min', ValueType.NUMBER, {'right_text':'and', 'mode':1}, '!name.is_empty() and _value_type == VarValueType.RANDOM_NUMBER')
|
||
|
add_header_edit('random_max', ValueType.NUMBER, {'mode':1}, '!name.is_empty() and _value_type == VarValueType.RANDOM_NUMBER')
|
||
|
add_header_button('', _on_variable_editor_pressed, 'Variable Editor', ["ExternalLink", "EditorIcons"])
|
||
|
|
||
|
|
||
|
func get_var_suggestions(filter:String) -> Dictionary:
|
||
|
var suggestions := {}
|
||
|
if filter:
|
||
|
suggestions[filter] = {'value':filter, 'editor_icon':["GuiScrollArrowRight", "EditorIcons"]}
|
||
|
for var_path in DialogicUtil.list_variables(DialogicUtil.get_default_variables()):
|
||
|
suggestions[var_path] = {'value':var_path, 'icon':load("res://addons/dialogic/Editor/Images/Pieces/variable.svg")}
|
||
|
return suggestions
|
||
|
|
||
|
|
||
|
func get_value_suggestions(filter:String) -> Dictionary:
|
||
|
var suggestions := {}
|
||
|
|
||
|
for var_path in DialogicUtil.list_variables(DialogicUtil.get_default_variables()):
|
||
|
suggestions[var_path] = {'value':var_path, 'icon':load("res://addons/dialogic/Editor/Images/Pieces/variable.svg")}
|
||
|
return suggestions
|
||
|
|
||
|
|
||
|
func _on_variable_editor_pressed():
|
||
|
var editor_manager := _editor_node.find_parent('EditorsManager')
|
||
|
if editor_manager:
|
||
|
editor_manager.open_editor(editor_manager.editors['VariablesEditor']['node'], true)
|
||
|
|
||
|
|
||
|
func update_editor_warning() -> void:
|
||
|
if _value_type == VarValueType.STRING and operation != Operations.SET:
|
||
|
ui_update_warning.emit('You cannot do this operation with a string!')
|
||
|
elif operation != Operations.SET:
|
||
|
var type := DialogicUtil.get_variable_type(name)
|
||
|
if not type in [DialogicUtil.VarTypes.INT, DialogicUtil.VarTypes.FLOAT, DialogicUtil.VarTypes.ANY]:
|
||
|
ui_update_warning.emit('The selected variable is not a number!')
|
||
|
else:
|
||
|
ui_update_warning.emit('')
|
||
|
else:
|
||
|
ui_update_warning.emit('')
|
||
|
|
||
|
|
||
|
|
||
|
####################### CODE COMPLETION ########################################
|
||
|
################################################################################
|
||
|
|
||
|
func _get_code_completion(CodeCompletionHelper:Node, TextNode:TextEdit, line:String, word:String, symbol:String) -> void:
|
||
|
if CodeCompletionHelper.get_line_untill_caret(line) == 'set ':
|
||
|
TextNode.add_code_completion_option(CodeEdit.KIND_MEMBER, '{', '{', TextNode.syntax_highlighter.variable_color)
|
||
|
if symbol == '{':
|
||
|
CodeCompletionHelper.suggest_variables(TextNode)
|
||
|
|
||
|
|
||
|
func _get_start_code_completion(CodeCompletionHelper:Node, TextNode:TextEdit) -> void:
|
||
|
TextNode.add_code_completion_option(CodeEdit.KIND_PLAIN_TEXT, 'set', 'set ', event_color.lerp(TextNode.syntax_highlighter.normal_color, 0.5))
|
||
|
|
||
|
|
||
|
#################### SYNTAX HIGHLIGHTING #######################################
|
||
|
################################################################################
|
||
|
|
||
|
func _get_syntax_highlighting(Highlighter:SyntaxHighlighter, dict:Dictionary, line:String) -> Dictionary:
|
||
|
dict[line.find('set')] = {"color":event_color.lerp(Highlighter.normal_color, 0.5)}
|
||
|
dict[line.find('set')+3] = {"color":Highlighter.normal_color}
|
||
|
dict = Highlighter.color_region(dict, Highlighter.string_color, line, '"', '"', line.find('set'))
|
||
|
dict = Highlighter.color_region(dict, Highlighter.variable_color, line, '{', '}', line.find('set'))
|
||
|
return dict
|