]> Untitled Git - wolf-seeking-sheep.git/blob - addons/dialogic/Modules/Background/subsystem_backgrounds.gd
Adding import files
[wolf-seeking-sheep.git] / addons / dialogic / Modules / Background / subsystem_backgrounds.gd
1 extends DialogicSubsystem
2 ## Subsystem for managing backgrounds.
3 ##
4 ## This subsystem has many different helper methods for managing backgrounds.
5 ## For instance, you can listen to background changes via
6 ## [signal background_changed].
7
8
9 ## Whenever a new background is set, this signal is emitted and contains a
10 ## dictionary with the following keys: [br]
11 ## [br]
12 ## Key         |   Value Type  | Value [br]
13 ## ----------- | ------------- | ----- [br]
14 ## `scene`     | [type String] | The scene path of the new background. [br]
15 ## `argument`  | [type String] | Information given to the background on its update routine. [br]
16 ## `fade_time` | [type float]  | The time the background may take to transition in. [br]
17 ## `same_scene`| [type bool]   | If the new background uses the same Godot scene. [br]
18 signal background_changed(info: Dictionary)
19
20 ## The default background scene Dialogic will use.
21 var default_background_scene: PackedScene = load(get_script().resource_path.get_base_dir().path_join('DefaultBackgroundScene/default_background.tscn'))
22 ## The default transition Dialogic will use.
23 var default_transition: String = get_script().resource_path.get_base_dir().path_join("Transitions/Defaults/simple_fade.gd")
24
25
26 #region STATE
27 ####################################################################################################
28
29 ## Empties the current background state.
30 func clear_game_state(_clear_flag := DialogicGameHandler.ClearFlags.FULL_CLEAR) -> void:
31         update_background()
32
33 ## Loads the background state from the current state info.
34 func load_game_state(_load_flag := LoadFlags.FULL_LOAD) -> void:
35         update_background(dialogic.current_state_info.get('background_scene', ''), dialogic.current_state_info.get('background_argument', ''), 0.0, default_transition, true)
36
37 #endregion
38
39
40 #region MAIN METHODS
41 ####################################################################################################
42
43 ## Method that adds a given scene as child of the DialogicNode_BackgroundHolder.
44 ## It will call [_update_background()] on that scene with the given argument [argument].
45 ## It will call [_fade_in()] on that scene with the given fade time.
46 ## Will call fade_out on previous backgrounds scene.
47 ##
48 ## If the scene is the same as the last background you can bypass another instantiating
49 ## and use the same scene.
50 ## To do so implement [_should_do_background_update()] on the custom background scene.
51 ## Then  [_update_background()] will be called directly on that previous scene.
52 func update_background(scene := "", argument := "", fade_time := 0.0, transition_path:=default_transition, force := false) -> void:
53         var background_holder: DialogicNode_BackgroundHolder
54         if dialogic.has_subsystem('Styles'):
55                 background_holder = dialogic.Styles.get_first_node_in_layout('dialogic_background_holders')
56         else:
57                 background_holder = get_tree().get_first_node_in_group('dialogic_background_holders')
58
59         var info := {'scene':scene, 'argument':argument, 'fade_time':fade_time, 'same_scene':false}
60         if background_holder == null:
61                 background_changed.emit(info)
62                 return
63
64
65         var bg_set := false
66
67         # First try just updating the existing scene.
68         if scene == dialogic.current_state_info.get('background_scene', ''):
69
70                 if not force and argument == dialogic.current_state_info.get('background_argument', ''):
71                         return
72
73                 for old_bg in background_holder.get_children():
74                         if !old_bg.has_meta('node') or not old_bg.get_meta('node') is DialogicBackground:
75                                 continue
76
77                         var prev_bg_node: DialogicBackground = old_bg.get_meta('node')
78                         if prev_bg_node._should_do_background_update(argument):
79                                 prev_bg_node._update_background(argument, fade_time)
80                                 bg_set = true
81                                 info['same_scene'] = true
82
83         dialogic.current_state_info['background_scene'] = scene
84         dialogic.current_state_info['background_argument'] = argument
85
86         if bg_set:
87                 background_changed.emit(info)
88                 return
89
90         var old_viewport: SubViewportContainer = null
91         if background_holder.has_meta('current_viewport'):
92                 old_viewport = background_holder.get_meta('current_viewport', null)
93
94         var new_viewport: SubViewportContainer
95         if scene.ends_with('.tscn') and ResourceLoader.exists(scene):
96                 new_viewport = add_background_node(load(scene), background_holder)
97         elif argument:
98                 new_viewport = add_background_node(default_background_scene, background_holder)
99         else:
100                 new_viewport = null
101
102         var trans_script: Script = load(DialogicResourceUtil.guess_special_resource("BackgroundTransition", transition_path, {"path":default_transition}).path)
103         var trans_node := Node.new()
104         trans_node.set_script(trans_script)
105         trans_node = (trans_node as DialogicBackgroundTransition)
106         trans_node.bg_holder = background_holder
107         trans_node.time = fade_time
108
109         if old_viewport:
110                 trans_node.prev_scene = old_viewport.get_meta('node', null)
111                 trans_node.prev_texture = old_viewport.get_child(0).get_texture()
112                 old_viewport.get_meta('node')._custom_fade_out(fade_time)
113                 old_viewport.hide()
114                 # TODO We have to call this again here because of https://github.com/godotengine/godot/issues/23729
115                 old_viewport.get_child(0).render_target_update_mode = SubViewport.UPDATE_ALWAYS
116                 trans_node.transition_finished.connect(old_viewport.queue_free)
117         if new_viewport:
118                 trans_node.next_scene = new_viewport.get_meta('node', null)
119                 trans_node.next_texture = new_viewport.get_child(0).get_texture()
120                 new_viewport.get_meta('node')._update_background(argument, fade_time)
121                 new_viewport.get_meta('node')._custom_fade_in(fade_time)
122         else:
123                 background_holder.remove_meta('current_viewport')
124
125         add_child(trans_node)
126         if fade_time == 0:
127                 trans_node.transition_finished.emit()
128                 _on_transition_finished(background_holder, trans_node)
129         else:
130                 trans_node.transition_finished.connect(_on_transition_finished.bind(background_holder, trans_node))
131                 # We need to break this connection if the background_holder get's removed during the transition
132                 background_holder.tree_exited.connect(trans_node.disconnect.bind("transition_finished", _on_transition_finished))
133                 trans_node._fade()
134
135         background_changed.emit(info)
136
137
138 func _on_transition_finished(background_node:DialogicNode_BackgroundHolder, transition_node:DialogicBackgroundTransition) -> void:
139         if background_node.has_meta("current_viewport"):
140                 if background_node.get_meta("current_viewport").get_meta("node", null) == transition_node.next_scene:
141                         background_node.get_meta("current_viewport").show()
142         background_node.material = null
143         background_node.color = Color.TRANSPARENT
144         transition_node.queue_free()
145
146
147 ## Adds sub-viewport with the given background scene as child to
148 ## Dialogic scene.
149 func add_background_node(scene:PackedScene, parent:DialogicNode_BackgroundHolder) -> SubViewportContainer:
150         var v_con := SubViewportContainer.new()
151         var viewport := SubViewport.new()
152         var b_scene := scene.instantiate()
153         if not b_scene is DialogicBackground:
154                 printerr("[Dialogic] Given background scene was not of type DialogicBackground! Make sure the scene has a script that extends DialogicBackground.")
155                 v_con.queue_free()
156                 viewport.queue_free()
157                 b_scene.queue_free()
158                 return null
159
160         parent.add_child(v_con)
161         v_con.hide()
162         v_con.stretch = true
163         v_con.size = parent.size
164         v_con.set_anchors_preset(Control.PRESET_FULL_RECT)
165
166         v_con.add_child(viewport)
167         viewport.transparent_bg = true
168         viewport.disable_3d = true
169         viewport.render_target_update_mode = SubViewport.UPDATE_ALWAYS
170         viewport.canvas_item_default_texture_filter = ProjectSettings.get_setting("rendering/textures/canvas_textures/default_texture_filter")
171
172         viewport.add_child(b_scene)
173         b_scene.viewport = viewport
174         b_scene.viewport_container = v_con
175
176         parent.set_meta('current_viewport', v_con)
177         v_con.set_meta('node', b_scene)
178
179         return v_con
180
181
182 ## Whether a background is set.
183 func has_background() -> bool:
184         return !dialogic.current_state_info.get('background_scene', '').is_empty() or !dialogic.current_state_info.get('background_argument','').is_empty()
185
186 #endregion