]> Untitled Git - wolf-seeking-sheep.git/blob - addons/dialogic/Modules/Variable/event_variable.gd
Initial Godot project with Dialogic 2.0-Alpha-17
[wolf-seeking-sheep.git] / addons / dialogic / Modules / Variable / event_variable.gd
1 @tool
2 class_name DialogicVariableEvent
3 extends DialogicEvent
4
5 ## Event that allows changing a dialogic variable or a property of an autoload.
6
7
8 enum Operations {SET, ADD, SUBSTRACT, MULTIPLY, DIVIDE}
9 enum VarValueType {
10         STRING = 0,
11         NUMBER = 1,
12         VARIABLE = 2,
13         BOOL = 3,
14         EXPRESSION = 4,
15         RANDOM_NUMBER = 5,
16 }
17
18 ## Settings
19
20 ## Name/Path of the variable that should be changed.
21 var name := "":
22         set(_value):
23                 name = _value
24                 if Engine.is_editor_hint() and not value:
25                         match DialogicUtil.get_variable_type(name):
26                                 DialogicUtil.VarTypes.ANY, DialogicUtil.VarTypes.STRING:
27                                         _value_type = VarValueType.STRING
28                                 DialogicUtil.VarTypes.FLOAT, DialogicUtil.VarTypes.INT:
29                                         _value_type = VarValueType.NUMBER
30                                 DialogicUtil.VarTypes.BOOL:
31                                         _value_type = VarValueType.BOOL
32                         ui_update_needed.emit()
33                 update_editor_warning()
34
35 ## The operation to perform.
36 var operation := Operations.SET:
37         set(value):
38                 operation = value
39                 if operation != Operations.SET and _value_type == VarValueType.STRING:
40                         _value_type = VarValueType.NUMBER
41                         ui_update_needed.emit()
42                 update_editor_warning()
43
44 ## The value that is used. Can be a variable as well.
45 var value: Variant = ""
46 var _value_type := 0 :
47         set(_value):
48                 _value_type = _value
49                 if not _suppress_default_value:
50                         match _value_type:
51                                 VarValueType.STRING, VarValueType.VARIABLE, VarValueType.EXPRESSION:
52                                         value = ""
53                                 VarValueType.NUMBER:
54                                         value = 0
55                                 VarValueType.BOOL:
56                                         value = false
57                                 VarValueType.RANDOM_NUMBER:
58                                         value = null
59                         ui_update_needed.emit()
60                 update_editor_warning()
61
62 ## If true, a random number between [random_min] and [random_max] is used instead of [value].
63 var random_min: int = 0
64 var random_max: int = 100
65
66 ## Used to suppress _value_type from overwriting value with a default value when the type changes
67 ## This is only used when initializing the event_variable.
68 var _suppress_default_value := false
69
70
71 ################################################################################
72 ##                                              EXECUTE
73 ################################################################################
74
75 func _execute() -> void:
76         if name:
77                 var original_value: Variant = dialogic.VAR.get_variable(name, null, operation == Operations.SET and "[" in name)
78
79                 if value != null and (original_value != null or (operation == Operations.SET and "[" in name)):
80
81                         var interpreted_value: Variant
82                         var result: Variant
83
84                         match _value_type:
85                                 VarValueType.STRING:
86                                         interpreted_value = dialogic.VAR.get_variable('"' + value + '"')
87                                 VarValueType.VARIABLE:
88                                         interpreted_value = dialogic.VAR.get_variable('{' + value + '}')
89                                 VarValueType.NUMBER, VarValueType.BOOL, VarValueType.EXPRESSION, VarValueType.RANDOM_NUMBER:
90                                         interpreted_value = dialogic.VAR.get_variable(str(value))
91
92                         if operation != Operations.SET and (not str(original_value).is_valid_float() or not str(interpreted_value).is_valid_float()):
93                                 printerr("[Dialogic] Set Variable event failed because one value wasn't a float! [", original_value, ", ",interpreted_value,"]")
94                                 finish()
95                                 return
96
97                         if operation == Operations.SET:
98                                 result = interpreted_value
99
100                         else:
101                                 original_value = float(original_value)
102                                 interpreted_value = float(interpreted_value)
103
104                                 match operation:
105                                         Operations.ADD:
106                                                 result = original_value + interpreted_value
107                                         Operations.SUBSTRACT:
108                                                 result = original_value - interpreted_value
109                                         Operations.MULTIPLY:
110                                                 result = original_value * interpreted_value
111                                         Operations.DIVIDE:
112                                                 result = original_value / interpreted_value
113
114                         dialogic.VAR.set_variable(name, result)
115                         dialogic.VAR.variable_was_set.emit(
116                                 {
117                                         'variable' : name,
118                                         'value' : interpreted_value,
119                                         'value_str' : value,
120                                         'orig_value' : original_value,
121                                         'new_value' : result,
122                                 })
123
124                 else:
125                         printerr("[Dialogic] Set Variable event failed because one value wasn't set!")
126
127         finish()
128
129
130 ################################################################################
131 ##                                              INITIALIZE
132 ################################################################################
133
134 func _init() -> void:
135         event_name = "Set Variable"
136         set_default_color('Color6')
137         event_category = "Logic"
138         event_sorting_index = 0
139         help_page_path = "https://docs.dialogic.pro/variables.html#23-set-variable-event"
140
141
142 ################################################################################
143 ##                                              SAVING/LOADING
144 ################################################################################
145
146 func to_text() -> String:
147         var string := "set "
148         if name:
149                 string += "{" + name.trim_prefix('{').trim_suffix('}') + "}"
150                 match operation:
151                         Operations.SET:
152                                 string+= " = "
153                         Operations.ADD:
154                                 string+= " += "
155                         Operations.SUBSTRACT:
156                                 string+= " -= "
157                         Operations.MULTIPLY:
158                                 string+= " *= "
159                         Operations.DIVIDE:
160                                 string+= " /= "
161
162                 value = str(value)
163                 match _value_type:
164                         VarValueType.STRING: # String
165                                 string += '"'+value.replace('"', '\\"')+'"'
166                         VarValueType.NUMBER,VarValueType.BOOL,VarValueType.EXPRESSION: # Float Bool, or Expression
167                                 string += str(value)
168                         VarValueType.VARIABLE: # Variable
169                                 string += '{'+value+'}'
170                         VarValueType.RANDOM_NUMBER:
171                                 string += 'range('+str(random_min)+','+str(random_max)+').pick_random()'
172
173         return string
174
175
176 func from_text(string:String) -> void:
177         var reg := RegEx.new()
178         reg.compile("set(?<name>[^=+\\-*\\/]*)?(?<operation>=|\\+=|-=|\\*=|\\/=)?(?<value>.*)")
179         var result := reg.search(string)
180         if !result:
181                 return
182         name = result.get_string('name').strip_edges().replace("{", "").replace("}", "")
183         match result.get_string('operation').strip_edges():
184                 '=':
185                         operation = Operations.SET
186                 '-=':
187                         operation = Operations.SUBSTRACT
188                 '+=':
189                         operation = Operations.ADD
190                 '*=':
191                         operation = Operations.MULTIPLY
192                 '/=':
193                         operation = Operations.DIVIDE
194
195         _suppress_default_value = true
196         value = result.get_string('value').strip_edges()
197         if not value.is_empty():
198                 if value.begins_with('"') and value.ends_with('"') and value.count('"')-value.count('\\"') == 2:
199                         value = result.get_string('value').strip_edges().replace('"', '')
200                         _value_type = VarValueType.STRING
201                 elif value.begins_with('{') and value.ends_with('}') and value.count('{') == 1:
202                         value = result.get_string('value').strip_edges().trim_suffix('}').trim_prefix('{')
203                         _value_type = VarValueType.VARIABLE
204                 elif value in ["true", "false"]:
205                         value = value == "true"
206                         _value_type = VarValueType.BOOL
207                 elif value.begins_with('range(') and value.ends_with(').pick_random()'):
208                         _value_type = VarValueType.RANDOM_NUMBER
209                         var randinf := str(value).trim_prefix('range(').trim_suffix(').pick_random()').split(',')
210                         random_min = int(randinf[0])
211                         random_max = int(randinf[1])
212                 else:
213                         value = result.get_string('value').strip_edges()
214                         if value.is_valid_float():
215                                 _value_type = VarValueType.NUMBER
216                         else:
217                                 _value_type = VarValueType.EXPRESSION
218         else:
219                 value = null
220         _suppress_default_value = false
221
222
223 func is_valid_event(string:String) -> bool:
224         return string.begins_with('set')
225
226
227 ################################################################################
228 ##                                              EDITOR REPRESENTATION
229 ################################################################################
230
231 func build_event_editor() -> void:
232         add_header_edit('name', ValueType.DYNAMIC_OPTIONS, {
233                         'left_text'             : 'Set',
234                         'suggestions_func'      : get_var_suggestions,
235                         'icon'                                  : load("res://addons/dialogic/Editor/Images/Pieces/variable.svg"),
236                         'placeholder'                   :'Select Variable'}
237                         )
238         add_header_edit('operation', ValueType.FIXED_OPTIONS, {
239                 'options': [
240                         {
241                                 'label': 'to be',
242                                 'icon': load("res://addons/dialogic/Editor/Images/Dropdown/set.svg"),
243                                 'value': Operations.SET
244                         },{
245                                 'label': 'to itself plus',
246                                 'icon': load("res://addons/dialogic/Editor/Images/Dropdown/plus.svg"),
247                                 'value': Operations.ADD
248                         },{
249                                 'label': 'to itself minus',
250                                 'icon': load("res://addons/dialogic/Editor/Images/Dropdown/minus.svg"),
251                                 'value': Operations.SUBSTRACT
252                         },{
253                                 'label': 'to itself multiplied by',
254                                 'icon': load("res://addons/dialogic/Editor/Images/Dropdown/multiply.svg"),
255                                 'value': Operations.MULTIPLY
256                         },{
257                                 'label': 'to itself divided by',
258                                 'icon': load("res://addons/dialogic/Editor/Images/Dropdown/divide.svg"),
259                                 'value': Operations.DIVIDE
260                         }
261                 ]
262         }, '!name.is_empty()')
263         add_header_edit('_value_type', ValueType.FIXED_OPTIONS, {
264                 'options': [
265                         {
266                                 'label': 'String',
267                                 'icon': ["String", "EditorIcons"],
268                                 'value': VarValueType.STRING
269                         },{
270                                 'label': 'Number',
271                                 'icon': ["float", "EditorIcons"],
272                                 'value': VarValueType.NUMBER
273                         },{
274                                 'label': 'Variable',
275                                 'icon': load("res://addons/dialogic/Editor/Images/Pieces/variable.svg"),
276                                 'value': VarValueType.VARIABLE
277                         },{
278                                 'label': 'Bool',
279                                 'icon': ["bool", "EditorIcons"],
280                                 'value': VarValueType.BOOL
281                         },{
282                                 'label': 'Expression',
283                                 'icon': ["Variant", "EditorIcons"],
284                                 'value': VarValueType.EXPRESSION
285                         },{
286                                 'label': 'Random Number',
287                                 'icon': ["RandomNumberGenerator", "EditorIcons"],
288                                 'value': VarValueType.RANDOM_NUMBER
289                         }],
290                 'symbol_only':true},
291                 '!name.is_empty()')
292         add_header_edit('value', ValueType.SINGLELINE_TEXT, {}, '!name.is_empty() and (_value_type == VarValueType.STRING or _value_type == VarValueType.EXPRESSION) ')
293         add_header_edit('value', ValueType.BOOL, {}, '!name.is_empty() and (_value_type == VarValueType.BOOL) ')
294         add_header_edit('value', ValueType.NUMBER, {}, '!name.is_empty()  and _value_type == VarValueType.NUMBER')
295         add_header_edit('value', ValueType.DYNAMIC_OPTIONS,
296                         {'suggestions_func' : get_value_suggestions, 'placeholder':'Select Variable'},
297                         '!name.is_empty() and _value_type == VarValueType.VARIABLE')
298         add_header_label('a number between', '_value_type == VarValueType.RANDOM_NUMBER')
299         add_header_edit('random_min', ValueType.NUMBER, {'right_text':'and', 'mode':1}, '!name.is_empty() and  _value_type == VarValueType.RANDOM_NUMBER')
300         add_header_edit('random_max', ValueType.NUMBER, {'mode':1}, '!name.is_empty() and _value_type == VarValueType.RANDOM_NUMBER')
301         add_header_button('', _on_variable_editor_pressed, 'Variable Editor', ["ExternalLink", "EditorIcons"])
302
303
304 func get_var_suggestions(filter:String) -> Dictionary:
305         var suggestions := {}
306         if filter:
307                 suggestions[filter] = {'value':filter, 'editor_icon':["GuiScrollArrowRight", "EditorIcons"]}
308         for var_path in DialogicUtil.list_variables(DialogicUtil.get_default_variables()):
309                 suggestions[var_path] = {'value':var_path, 'icon':load("res://addons/dialogic/Editor/Images/Pieces/variable.svg")}
310         return suggestions
311
312
313 func get_value_suggestions(_filter:String) -> Dictionary:
314         var suggestions := {}
315
316         for var_path in DialogicUtil.list_variables(DialogicUtil.get_default_variables()):
317                 suggestions[var_path] = {'value':var_path, 'icon':load("res://addons/dialogic/Editor/Images/Pieces/variable.svg")}
318         return suggestions
319
320
321 func _on_variable_editor_pressed() -> void:
322         var editor_manager := editor_node.find_parent('EditorsManager')
323         if editor_manager:
324                 editor_manager.open_editor(editor_manager.editors['VariablesEditor']['node'], true)
325
326
327 func update_editor_warning() -> void:
328         if _value_type == VarValueType.STRING and operation != Operations.SET:
329                 ui_update_warning.emit('You cannot do this operation with a string!')
330         elif operation != Operations.SET:
331                 var type := DialogicUtil.get_variable_type(name)
332                 if not type in [DialogicUtil.VarTypes.INT, DialogicUtil.VarTypes.FLOAT, DialogicUtil.VarTypes.ANY]:
333                         ui_update_warning.emit('The selected variable is not a number!')
334                 else:
335                         ui_update_warning.emit('')
336         else:
337                 ui_update_warning.emit('')
338
339
340
341 ####################### CODE COMPLETION ########################################
342 ################################################################################
343
344 func _get_code_completion(CodeCompletionHelper:Node, TextNode:TextEdit, line:String, _word:String, symbol:String) -> void:
345         if CodeCompletionHelper.get_line_untill_caret(line) == 'set ':
346                 TextNode.add_code_completion_option(CodeEdit.KIND_MEMBER, '{', '{', TextNode.syntax_highlighter.variable_color)
347         if symbol == '{':
348                 CodeCompletionHelper.suggest_variables(TextNode)
349
350
351 func _get_start_code_completion(_CodeCompletionHelper:Node, TextNode:TextEdit) -> void:
352         TextNode.add_code_completion_option(CodeEdit.KIND_PLAIN_TEXT, 'set', 'set ', event_color.lerp(TextNode.syntax_highlighter.normal_color, 0.5))
353
354
355 #################### SYNTAX HIGHLIGHTING #######################################
356 ################################################################################
357
358 func _get_syntax_highlighting(Highlighter:SyntaxHighlighter, dict:Dictionary, line:String) -> Dictionary:
359         dict[line.find('set')] = {"color":event_color.lerp(Highlighter.normal_color, 0.5)}
360         dict[line.find('set')+3] = {"color":Highlighter.normal_color}
361         dict = Highlighter.color_region(dict, Highlighter.string_color, line, '"', '"', line.find('set'))
362         dict = Highlighter.color_region(dict, Highlighter.variable_color, line, '{', '}', line.find('set'))
363         return dict