]> Untitled Git - wolf-seeking-sheep.git/blob - addons/dialogic/Modules/Core/subsystem_input.gd
Squashed commit of the following:
[wolf-seeking-sheep.git] / addons / dialogic / Modules / Core / subsystem_input.gd
1 extends DialogicSubsystem
2 ## Subsystem that handles input, Auto-Advance, and skipping.
3 ##
4 ## This subsystem can be accessed via GDScript: `Dialogic.Inputs`.
5
6
7 signal dialogic_action_priority
8 signal dialogic_action
9
10 ## Whenever the Auto-Skip timer finishes, this signal is emitted.
11 ## Configure Auto-Skip settings via [member auto_skip].
12 signal autoskip_timer_finished
13
14
15 const _SETTING_INPUT_ACTION := "dialogic/text/input_action"
16 const _SETTING_INPUT_ACTION_DEFAULT := "dialogic_default_action"
17
18 var input_block_timer := Timer.new()
19 var _auto_skip_timer_left: float = 0.0
20 var action_was_consumed := false
21 var input_was_mouse_input := false
22
23 var auto_skip: DialogicAutoSkip = null
24 var auto_advance: DialogicAutoAdvance = null
25 var manual_advance: DialogicManualAdvance = null
26
27
28 #region SUBSYSTEM METHODS
29 ################################################################################
30
31 func clear_game_state(_clear_flag := DialogicGameHandler.ClearFlags.FULL_CLEAR) -> void:
32         if not is_node_ready():
33                 await ready
34
35         manual_advance.disabled_until_next_event = false
36         manual_advance.system_enabled = true
37
38
39 func pause() -> void:
40         auto_advance.autoadvance_timer.paused = true
41         input_block_timer.paused = true
42         set_process(false)
43
44
45 func resume() -> void:
46         auto_advance.autoadvance_timer.paused = false
47         input_block_timer.paused = false
48         var is_autoskip_timer_done := _auto_skip_timer_left > 0.0
49         set_process(!is_autoskip_timer_done)
50
51
52 func post_install() -> void:
53         dialogic.Settings.connect_to_change('autoadvance_delay_modifier', auto_advance._update_autoadvance_delay_modifier)
54         auto_skip.toggled.connect(_on_autoskip_toggled)
55         auto_skip._init()
56         add_child(input_block_timer)
57         input_block_timer.one_shot = true
58
59
60 #endregion
61
62
63 #region MAIN METHODS
64 ################################################################################
65
66 func handle_input() -> void:
67         if dialogic.paused or is_input_blocked():
68                 return
69
70         if not action_was_consumed:
71                 # We want to stop auto-advancing that cancels on user inputs.
72                 if (auto_advance.is_enabled()
73                         and auto_advance.enabled_until_user_input):
74                         auto_advance.enabled_until_user_input = false
75                         action_was_consumed = true
76
77                 # We want to stop auto-skipping if it's enabled, we are listening
78                 # to user inputs, and it's not instant skipping.
79                 if (auto_skip.disable_on_user_input
80                 and auto_skip.enabled):
81                         auto_skip.enabled = false
82                         action_was_consumed = true
83
84
85         dialogic_action_priority.emit()
86
87         if action_was_consumed:
88                 action_was_consumed = false
89                 return
90
91         dialogic_action.emit()
92         input_was_mouse_input = false
93
94
95 ## Unhandled Input is used for all NON-Mouse based inputs.
96 func _unhandled_input(event:InputEvent) -> void:
97         if is_input_pressed(event, true):
98                 if event is InputEventMouse or event is InputEventScreenTouch:
99                         return
100                 input_was_mouse_input = false
101                 handle_input()
102
103
104 ## Input is used for all mouse based inputs.
105 ## If any DialogicInputNode is present this won't do anything (because that node handles MouseInput then).
106 func _input(event:InputEvent) -> void:
107         if is_input_pressed(event):
108                 if not event is InputEventMouse:
109                         return
110                 if get_tree().get_nodes_in_group('dialogic_input').any(func(node):return node.is_visible_in_tree()):
111                         return
112                 input_was_mouse_input = true
113                 handle_input()
114
115
116 func is_input_pressed(event: InputEvent, exact := false) -> bool:
117         var action: String = ProjectSettings.get_setting(_SETTING_INPUT_ACTION, _SETTING_INPUT_ACTION_DEFAULT)
118         return (event is InputEventAction and event.action == action) or Input.is_action_just_pressed(action, exact)
119
120
121 ## This is called from the gui_input of the InputCatcher and DialogText nodes
122 func handle_node_gui_input(event:InputEvent) -> void:
123         if Input.is_action_just_pressed(ProjectSettings.get_setting(_SETTING_INPUT_ACTION, _SETTING_INPUT_ACTION_DEFAULT)):
124                 if event is InputEventMouseButton and event.pressed:
125                         input_was_mouse_input = true
126                         handle_input()
127
128
129 func is_input_blocked() -> bool:
130         return input_block_timer.time_left > 0.0
131
132
133 func block_input(time:=0.1) -> void:
134         if time > 0:
135                 input_block_timer.wait_time = max(time, input_block_timer.time_left)
136                 input_block_timer.start()
137
138
139 func _ready() -> void:
140         auto_skip = DialogicAutoSkip.new()
141         auto_advance = DialogicAutoAdvance.new()
142         manual_advance = DialogicManualAdvance.new()
143
144         # We use the process method to count down the auto-start_autoskip_timer timer.
145         set_process(false)
146
147
148 func stop_timers() -> void:
149         auto_advance.autoadvance_timer.stop()
150         input_block_timer.stop()
151         _auto_skip_timer_left = 0.0
152
153 #endregion
154
155
156 #region AUTO-SKIP
157 ################################################################################
158
159 ## This method will advance the timeline based on Auto-Skip settings.
160 ## The state, whether Auto-Skip is enabled, is ignored.
161 func start_autoskip_timer() -> void:
162         _auto_skip_timer_left = auto_skip.time_per_event
163         set_process(true)
164         await autoskip_timer_finished
165
166
167 ## If Auto-Skip disables, we want to stop the timer.
168 func _on_autoskip_toggled(enabled: bool) -> void:
169         if not enabled:
170                 _auto_skip_timer_left = 0.0
171
172
173 ## Handles fine-grained Auto-Skip logic.
174 ## The [method _process] method allows for a more precise timer than the
175 ## [Timer] class.
176 func _process(delta: float) -> void:
177         if _auto_skip_timer_left > 0:
178                 _auto_skip_timer_left -= delta
179
180                 if _auto_skip_timer_left <= 0:
181                         autoskip_timer_finished.emit()
182
183         else:
184                 autoskip_timer_finished.emit()
185                 set_process(false)
186
187 #endregion
188
189 #region TEXT EFFECTS
190 ################################################################################
191
192
193 func effect_input(_text_node:Control, skipped:bool, _argument:String) -> void:
194         if skipped:
195                 return
196         dialogic.Text.show_next_indicators()
197         await dialogic.Inputs.dialogic_action_priority
198         dialogic.Text.hide_next_indicators()
199         dialogic.Inputs.action_was_consumed = true
200
201
202 func effect_noskip(text_node:Control, skipped:bool, argument:String) -> void:
203         dialogic.Text.set_text_reveal_skippable(false, true)
204         manual_advance.disabled_until_next_event = true
205         effect_autoadvance(text_node, skipped, argument)
206
207
208 func effect_autoadvance(_text_node: Control, _skipped:bool, argument:String) -> void:
209         if argument.ends_with('?'):
210                 argument = argument.trim_suffix('?')
211         else:
212                 auto_advance.enabled_until_next_event = true
213
214         if argument.is_valid_float():
215                 auto_advance.override_delay_for_current_event = float(argument)
216
217 #endregion