]> Untitled Git - wolf-seeking-sheep.git/blob - addons/dialogic/Modules/Style/subsystem_styles.gd
Updated export config options
[wolf-seeking-sheep.git] / addons / dialogic / Modules / Style / subsystem_styles.gd
1 extends DialogicSubsystem
2
3 ## Subsystem that manages loading layouts with specific styles applied.
4
5 signal style_changed(info:Dictionary)
6
7
8 #region STATE
9 ####################################################################################################
10
11 func clear_game_state(_clear_flag := DialogicGameHandler.ClearFlags.FULL_CLEAR) -> void:
12         pass
13
14
15 func load_game_state(load_flag := LoadFlags.FULL_LOAD) -> void:
16         if load_flag == LoadFlags.ONLY_DNODES:
17                 return
18         load_style(dialogic.current_state_info.get('style', ''))
19
20 #endregion
21
22
23 #region MAIN METHODS
24 ####################################################################################################
25
26 ## This helper method calls load_style, but with the [parameter state_reload] as true,
27 ## which is commonly wanted if you expect a game to already be in progress.
28 func change_style(style_name := "", is_base_style := true) -> Node:
29         return load_style(style_name, null, is_base_style, true)
30
31
32 ## Loads a style. Consider using the simpler [method change_style] if you want to change the style while another style is already in use.
33 ## [br] If [param state_reload] is true, the current state will be loaded into a new layout scenes nodes.
34 ## That should not be done before calling start() or load() as it would be unnecessary or cause double-loading.
35 func load_style(style_name := "", parent: Node = null, is_base_style := true, state_reload := false) -> Node:
36         var style := DialogicUtil.get_style_by_name(style_name)
37
38         var signal_info := {'style':style_name}
39         dialogic.current_state_info['style'] = style_name
40
41         # is_base_style should only be wrong on temporary changes like character styles
42         if is_base_style:
43                 dialogic.current_state_info['base_style'] = style_name
44
45         var previous_layout := get_layout_node()
46         if is_instance_valid(previous_layout) and previous_layout.has_meta('style'):
47                 signal_info['previous'] = previous_layout.get_meta('style').name
48
49                 # If this is the same style and scene, do nothing
50                 if previous_layout.get_meta('style') == style:
51                         return previous_layout
52
53                 # If this has the same scene setup, just apply the new overrides
54                 elif previous_layout.get_meta('style') == style.get_inheritance_root():
55                         DialogicUtil.apply_scene_export_overrides(previous_layout, style.get_layer_inherited_info("").overrides)
56                         var index := 0
57                         for layer in previous_layout.get_layers():
58                                 DialogicUtil.apply_scene_export_overrides(
59                                         layer,
60                                         style.get_layer_inherited_info(style.get_layer_id_at_index(index)).overrides)
61                                 index += 1
62
63                         previous_layout.set_meta('style', style)
64                         style_changed.emit(signal_info)
65                         return
66
67                 else:
68                         parent = previous_layout.get_parent()
69
70                         previous_layout.get_parent().remove_child(previous_layout)
71                         previous_layout.queue_free()
72
73         # if this is another style:
74         var new_layout := create_layout(style, parent)
75         if state_reload:
76                 # Preserve process_mode on style changes
77                 if previous_layout:
78                         new_layout.process_mode = previous_layout.process_mode
79
80                 new_layout.ready.connect(reload_current_info_into_new_style)
81
82         style_changed.emit(signal_info)
83
84         return new_layout
85
86
87 ## Method that adds a layout scene with all the necessary layers.
88 ## The layout scene will be added to the tree root and returned.
89 func create_layout(style: DialogicStyle, parent: Node = null) -> DialogicLayoutBase:
90
91         # Load base scene
92         var base_scene: DialogicLayoutBase
93         var base_layer_info := style.get_layer_inherited_info("")
94         if base_layer_info.path.is_empty():
95                 base_scene = DialogicUtil.get_default_layout_base().instantiate()
96         else:
97                 base_scene = load(base_layer_info.path).instantiate()
98
99         base_scene.name = "DialogicLayout_"+style.name.to_pascal_case()
100
101         # Apply base scene overrides
102         DialogicUtil.apply_scene_export_overrides(base_scene, base_layer_info.overrides)
103
104         # Load layers
105         for layer_id in style.get_layer_inherited_list():
106                 var layer := style.get_layer_inherited_info(layer_id)
107
108                 if not ResourceLoader.exists(layer.path):
109                         continue
110
111                 var layer_scene: DialogicLayoutLayer = null
112
113                 if ResourceLoader.load_threaded_get_status(layer.path) == ResourceLoader.THREAD_LOAD_LOADED:
114                         layer_scene = ResourceLoader.load_threaded_get(layer.path).instantiate()
115                 else:
116                         layer_scene = load(layer.path).instantiate()
117
118                 base_scene.add_layer(layer_scene)
119
120                 # Apply layer overrides
121                 DialogicUtil.apply_scene_export_overrides(layer_scene, layer.overrides)
122
123         base_scene.set_meta('style', style)
124
125         if parent == null:
126                 parent = dialogic.get_parent()
127         parent.call_deferred("add_child", base_scene)
128
129         dialogic.get_tree().set_meta('dialogic_layout_node', base_scene)
130
131         return base_scene
132
133
134 ## When changing to a different layout scene,
135 ## we have to load all the info from the current_state_info (basically
136 func reload_current_info_into_new_style() -> void:
137         for subsystem in dialogic.get_children():
138                 subsystem.load_game_state(LoadFlags.ONLY_DNODES)
139
140
141 ## Returns the style currently in use
142 func get_current_style() -> String:
143         if has_active_layout_node():
144                 var style: DialogicStyle = get_layout_node().get_meta('style', null)
145                 if style:
146                         return style.name
147         return ''
148
149
150 func has_active_layout_node() -> bool:
151         return (
152                 get_tree().has_meta('dialogic_layout_node')
153                 and is_instance_valid(get_tree().get_meta('dialogic_layout_node'))
154                 and not get_tree().get_meta('dialogic_layout_node').is_queued_for_deletion()
155         )
156
157
158 func get_layout_node() -> DialogicLayoutBase:
159         if has_active_layout_node():
160                 return get_tree().get_meta('dialogic_layout_node')
161         return null
162
163
164 ## Similar to get_tree().get_first_node_in_group('group_name') but filtered to the active layout node subtree
165 func get_first_node_in_layout(group_name: String) -> Node:
166         var layout_node := get_layout_node()
167         if null == layout_node:
168                 return null
169         var nodes := get_tree().get_nodes_in_group(group_name)
170         for node in nodes:
171                 if layout_node.is_ancestor_of(node):
172                         return node
173         return null
174
175 #endregion