├── .gitattributes
├── .gitignore
├── LICENSE
├── README.md
└── addons
└── VectorFieldNavigation
├── LICENSE
├── classes
├── VFNConnection.gd
├── VFNField.gd
├── VFNMap.gd
├── VFNModField.gd
└── VFNNode.gd
├── docs
├── DOCUMENTATION.md
├── ex_spreading_forces_1.jpg
├── ex_spreading_forces_1.jpg.import
├── ex_spreading_forces_2.jpg
├── ex_spreading_forces_2.jpg.import
├── ex_spreading_forces_3.jpg
└── ex_spreading_forces_3.jpg.import
├── examples
├── GUI.gd
├── Portal.gd
├── VectorFieldNavigation-Example.tscn
├── example.gd
├── heightmap.png
├── heightmap.png.import
├── screenshot.jpg
├── screenshot.jpg.import
├── unit.gd
└── unit.tscn
├── materials
└── matVectorFieldNavigationDebugMap.tres
├── plugin.cfg
├── plugin.gd
├── vfn_icon.svg
├── vfn_icon.svg.import
├── vfn_icon_mono.png
├── vfn_icon_mono.png.import
├── vfn_icon_mono.svg
└── vfn_icon_mono.svg.import
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Normalize EOL for all files that Git considers text files.
2 | * text=auto eol=lf
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Godot 4+ specific ignores
2 | .godot/
3 |
4 | # Godot-specific ignores
5 | .import/
6 | export.cfg
7 | export_presets.cfg
8 |
9 | # Imported translations (automatically generated from CSV files)
10 | *.translation
11 |
12 | #my ignores
13 | addons/godot-git-plugin
14 | project.godot
15 | default_env.tres
16 | icon.png
17 | icon.png.import
18 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 D2klaas
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Godot-4-VectorFieldNavigation
2 |
3 | **This project is currently in an early stage. Please report any issues you encounter! Comments and suggestions also appreciated !**
4 |
5 |
6 |
7 | This addon add's another pathfinding method besides astar and navmesh-navigation to Godot 4.
8 |
9 | Vector field navigation is espacialy usefull for large hordes or particle pathfinding.
10 |
11 | When you have many entities that should navigate to one (or many) targets you can either
12 | calculate a path for every entity or group those entities and share one path for all.
13 | Calculating a path for hundreds of entities can hit your performance substantially. Most of the time
14 | all calculated paths merge into one optimal path. When all entities march this path and
15 | tick of their navigation points they often push each other away from those points. This leads to
16 | ugly movements at choke points. Sure this can be optimized but this comes at an additional
17 | cost.
18 |
19 | Vectorfield navigation (VFN) calculates a navigation solution for all cells (nodes) of a grid based
20 | map. Therefor i doesn't matter where the entity is positioned, there is allways a path to a target and
21 | therefor the entity dont have to walk predefined waypoints.
22 |
23 | 
24 |
25 | This VFN addon implements a planar(2D/3D) solution wich can be used in 3D space. Currently it does not
26 | support underpaths, bridges or alike. This may be change in future realases, but a real 3D node based
27 | solution is more complex and will not be as performant as a "2D" solution. The performance is quit good,
28 | a 128 x 128 grid with medium complexity will compute in around 130ms on a AMD Ryzen 5. Even on low end
29 | devices its about 350ms. This means you can constantly track a target and receive at least 2 updates per second.
30 | One of the cool features of this algorythm is that the number of targets does not hit the performance.
31 |
32 | ## Features:
33 | * multipy solutions with different modifiers for a single map
34 | * threaded calculation for stutter free usage
35 | * map preperation tools (e.g. use heightmaps)
36 | * reasonable fast (as gdscript can)
37 | * connection-cache (+10% performance)
38 | * flexible modifier layers for static or dynamic movement penalties
39 | * serialisation for easy storage of pre-processed maps
40 |
41 | ## Install
42 | Download files and add them to your addons folder in your godot project.\
43 | Enable the plugin in project-settings.
44 |
45 | ## Usage
46 | A short overview
47 |
48 | ### Map
49 | Create a VFNMap-node in your scene-tree
50 | You can use the build-in heightmap or initialize the map via scripting.
51 | (Have look in the example script)
52 |
53 | **!! DO NOT MODIFY THE MAP WHILE CALCULATING A SOLUTION !!** this can result in chrashes
54 |
55 | ### ModFields
56 | ModFields modifing the effort to reach a node. Its mostly a penalty for a node like rough terrain, rubble, dangerous (fire, acid, gunfire), blocked etc.
57 | ModFields can be static or dynamic. Static ModFields can be cached but dynamic one's not.
58 | ModFields can be numeric or boolean. Numerics will be added to the effort while booleans will block the access completly.
59 |
60 | **modifying the modfield while calcualting a solution can result in undesired results**
61 |
62 | ## Field
63 | The VFN-field stores the target-nodes and calculates the field solution and provides methodes to read the movement vector. Each map can have many fields.
64 | Each fields has a set of factors to modify the weighting of the calculation (different entities may have different movement penalties).
65 |
66 | ## DOCS
67 |
68 | [Documentation](/addons/VectorFieldNavigation/docs/DOCUMENTATION.md)
69 |
70 | ## Improving AI movement with modfields
71 |
72 | The modfields have great potential to improve the ais behaviour.\
73 | Let's assume youhave a game where countless hordes of zombies attacking. You, a solider, have to defend your fortifikation.
74 |
75 | Usually a pathfinding algorythm provides allways the path with the least effort ... usually the shortes path from a to b.
76 |
77 | 
78 |
79 | in this example this leads directly into the kill zone ... the narrow obstacles also line them up, ready to get slaughterd.
80 |
81 | 
82 |
83 | If you use a dynamic modfield, lets name it "occupy_field" and constantly add a small mount of effort to it for each zombies location (pink)
84 | you are increasing the effort to pathes allready favored by some zombies. This diverts other zombies to avoid the heavly
85 | used path of the others, leading to much more divers attack pattern.\
86 |
87 | 
88 |
89 | To unblock the favorised pathes you can call fade() on the modfield to slowly diminish the increased effort, giving way for another
90 | attack on this line.
91 |
92 | This technic can also be used for other purposes. Maybe you have placed some turrets on tactical locations, gunning down the zombies from there
93 | spawnpoint to the fortification. Add a dynamic modfield "killzone_field", whenever a zombie gets killed mark the place with a penalty. After
94 | enough casulties the zombies will avoid this area and try to find a way around. If there is no other way, well, then they will walk on despite the danger.
95 |
96 | Also open fields could penaliest over soft or hardcover fields. Making this dependent on range and orientation to the player, enemies will get pretty
97 | clever in there movement, making them activly avoid getting gunned down.
98 |
99 | Modfields bring a wide range of easy to use possibilities to pathfinding and ai. The examples above could be refined to bring even more complex
100 | ai behaviour into play.
101 |
--------------------------------------------------------------------------------
/addons/VectorFieldNavigation/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 D2klaas
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/addons/VectorFieldNavigation/classes/VFNConnection.gd:
--------------------------------------------------------------------------------
1 | extends RefCounted
2 | class_name VFNConnection
3 |
4 | ##physical distance from one node to the other
5 | #var distance:float = 0
6 | #the connected node
7 | var other_node:VFNNode
8 | #the effort (mostly distance) from this node to node_b
9 | var effort:float = 0
10 | #the physical steepness between the nodes
11 | var steepness:float = 0
12 | #connection disabled
13 | var disabled:bool = false
14 |
15 | ##serialize this object into buffer stream
16 | func serialize( data:StreamPeer ):
17 | data.put_16(other_node.pos.x)
18 | data.put_16(other_node.pos.y)
19 | data.put_8(int(disabled))
20 | data.put_float(effort)
21 | data.put_float(steepness)
22 |
23 |
24 | ##unserialize this object from buffer stream
25 | func unserialize( data:StreamPeer ):
26 | var op:Vector2i
27 | op.x = data.get_16()
28 | op.y = data.get_16()
29 | other_node = other_node.map.get_node_at(op)
30 | disabled = data.get_8()
31 | effort = data.get_float()
32 | steepness = data.get_float()
33 |
--------------------------------------------------------------------------------
/addons/VectorFieldNavigation/classes/VFNField.gd:
--------------------------------------------------------------------------------
1 | extends RefCounted
2 | class_name VFNField
3 |
4 | ##print debug message to the console
5 | var debug:bool = true
6 | ##the map used for this field (do not change)
7 | var map:VFNMap
8 | ##set targets
9 | var targets:Array
10 | var index_of_targets:Dictionary
11 | ##heighest effort used on the field
12 | var heighest_ef:float
13 | ##stop calculation if more nodes processed than n * node_count
14 | var calc_cutoff_factor:int = 10
15 |
16 | ##current thread
17 | var thread:Thread
18 | var _kill_thread:bool
19 | var field_mutex:Mutex
20 |
21 | var field_ef:PackedFloat32Array
22 | var field_target:PackedInt32Array
23 | var field_aim:PackedInt32Array
24 | var _field_vector:PackedVector3Array #working vectorfield
25 | var field_vector:PackedVector3Array
26 | var field_open_mask:PackedInt32Array
27 |
28 | #connection cache vars
29 | var connection_cache:PackedFloat32Array
30 | var connection_cache_index:PackedInt32Array
31 | var connection_cache_current_index:int = -1
32 |
33 | const VERY_HIGH_NUMBER:int = 9999999999
34 |
35 | ## modifiers for calculations
36 | var effort_cutoff:float = VERY_HIGH_NUMBER :
37 | set(value):
38 | effort_cutoff = value
39 |
40 | ## the factor on upward direction, the higher the more effort on climbs
41 | var climb_factor:float = 0.0 :
42 | set(value):
43 | if value == climb_factor:
44 | return
45 | climb_factor = value
46 | connection_cache_current_index = -1
47 |
48 | ## the cutoff in upward direction, if a connection is more steep than this, it wont be used
49 | var climb_cutoff:float = VERY_HIGH_NUMBER :
50 | set(value):
51 | if value == climb_cutoff:
52 | return
53 | climb_cutoff = value
54 | connection_cache_current_index = -1
55 |
56 | ## the factor on downward direction, the higher the more effort on drops
57 | var drop_factor:float = 0.0 :
58 | set(value):
59 | if value == drop_factor:
60 | return
61 | drop_factor = value
62 | connection_cache_current_index = -1
63 |
64 | ## the cutoff in downward direction, if a connection is more steep than this, it wont be used
65 | var drop_cutoff:float = VERY_HIGH_NUMBER :
66 | set(value):
67 | if value == drop_cutoff:
68 | return
69 | drop_cutoff = value
70 | connection_cache_current_index = -1
71 |
72 | ## the factor used on mod fields
73 | var field_effort_factor:float = 1 :
74 | set(value):
75 | if value == field_effort_factor:
76 | return
77 | field_effort_factor = value
78 | connection_cache_current_index = -1
79 |
80 |
81 |
82 | signal thread_finished
83 | ## the calculation finished successful:bool true/false
84 | signal calculated
85 |
86 |
87 | func _init( _map:VFNMap ):
88 | field_mutex = Mutex.new()
89 | connect("thread_finished",self._on_thread_finished,CONNECT_DEFERRED)
90 | _map.connect("map_changed", self._on_map_changed )
91 | _map.connect("connections_changed", self._on_connections_changed )
92 | _map.connect("nodes_changed", self._on_nodes_changed )
93 |
94 | map = _map
95 |
96 |
97 | func _on_map_changed():
98 | connection_cache_current_index = -1
99 |
100 |
101 | func _on_connections_changed():
102 | connection_cache_current_index = -1
103 |
104 |
105 | func _on_nodes_changed():
106 | connection_cache_current_index = -1
107 |
108 |
109 | # everything about targets
110 | func ______TARGETS():
111 | pass
112 |
113 |
114 | ## clear all set targets
115 | func clear_targets():
116 | targets.clear()
117 |
118 |
119 | ##adds a target for this field at x:int,y:int
120 | ##data can be any additional information for this target
121 | func add_target( pos:Vector2i, data=null ) -> VFNTarget:
122 | var c_index = pos.x * map.size.x + pos.y
123 | if c_index < 0 and c_index >= map.nodes.size():
124 | return null
125 |
126 | var target:VFNTarget = VFNTarget.new()
127 | target.pos = pos
128 | target.data = data
129 | target.node = map.nodes[c_index]
130 | targets.append( target )
131 |
132 | return target
133 |
134 |
135 | ##adds a target for this field at world position
136 | ##data can be any additional information for this target
137 | func add_target_from_world( wpos:Vector3, data=null, clamp=true ) -> VFNTarget:
138 | var p:Vector3 = map.to_local( wpos )
139 | p = p.round() / map.field_scale
140 | var n:Vector2i = Vector2i(p.x,p.z)
141 | if clamp:
142 | n = Vector2i(p.x,p.z).clamp(Vector2i.ZERO,map.size)
143 | return add_target( n, data )
144 |
145 |
146 | ## remove a target
147 | func remove_target( pos ):
148 | if pos is Vector2i:
149 | for i in targets.size():
150 | if targets[i].pos.x == pos.x and targets[i].pos.y == pos.y:
151 | targets.remove_at(i)
152 | return true
153 | return false
154 |
155 | if pos is VFNTarget:
156 | for i in targets.size():
157 | if targets[i] == pos:
158 | targets.remove_at(i)
159 | return true
160 | return false
161 |
162 |
163 | ## remove multiply target
164 | func remove_targets( destinations:Array[Vector2i] ):
165 | var del:Array[int]
166 | for d in destinations:
167 | remove_target( d )
168 | del.append( d.x*map.size.x + d.y )
169 |
170 |
171 | # everything about calculating
172 | func ______MODFIELD():
173 | pass
174 |
175 |
176 | var modfield_weights:Dictionary
177 |
178 | ##weight for a modfield of the map
179 | func set_modfield( name:String, weight:float ):
180 | for mf in map.mod_fields:
181 | if mf.name == name:
182 | modfield_weights[name] = weight
183 | return true
184 | return false
185 |
186 |
187 | func ______CALCULATION():
188 | pass
189 |
190 |
191 | ## kills the running calculation thread
192 | func stop_calculation():
193 | _kill_thread = true
194 |
195 |
196 | ## calculate the field solution in a thread, add a callback to be called if finished
197 | func calculate_threaded( callback = null, kill_existing_thread:bool=true ):
198 | if thread:
199 | if kill_existing_thread and thread.is_started():
200 | emit_signal("calculated",false) # dispatch old callback or else race condition will occure
201 | _kill_thread = true
202 | await calculated
203 | else:
204 | return false
205 |
206 | thread = Thread.new()
207 |
208 | if callback is Callable:
209 | connect("calculated", callback, CONNECT_ONE_SHOT)
210 |
211 | d("--- start calculation thread")
212 | init_fields()
213 | thread.start( self.calculate )
214 | d("thread running")
215 | return true
216 |
217 |
218 | func _on_thread_finished():
219 | if thread:
220 | d("wait thread to finish")
221 | var r = thread.wait_to_finish()
222 | if r:
223 | d("thread finished successful")
224 | field_vector = _field_vector
225 |
226 | #release some memory
227 | _field_vector = PackedVector3Array()
228 | field_open_mask.clear()
229 | thread = null
230 | emit_signal("calculated", true)
231 | else:
232 | d("thread failed")
233 | thread = null
234 | emit_signal("calculated", false)
235 |
236 |
237 |
238 | ## clear the connections cache
239 | func clear_cache():
240 | d("init cache field")
241 | connection_cache.resize( map.connection_count )
242 | connection_cache.fill(0)
243 | connection_cache_index.resize( map.size.x * map.size.y )
244 | connection_cache_index.fill(-1)
245 | connection_cache_current_index = 0
246 |
247 |
248 | ## reinit all data fields
249 | func init_fields():
250 | field_mutex.lock()
251 |
252 | #resize and clear the effort field
253 | field_ef.resize( map.size.x * map.size.y )
254 | field_ef.fill(VERY_HIGH_NUMBER)
255 |
256 | #fill field aims list with null
257 | field_aim.resize( map.size.x * map.size.y )
258 | field_aim.fill(-1)
259 |
260 | field_target.resize( map.size.x * map.size.y )
261 | field_target.fill(-1)
262 |
263 | _field_vector.clear()
264 | _field_vector.resize( map.size.x * map.size.y )
265 |
266 | field_mutex.unlock()
267 |
268 |
269 | ## calculate unthreaded
270 | ## call init_fields when use manualy
271 | func calculate():
272 | var t_start = Time.get_ticks_msec()
273 |
274 | if connection_cache_current_index == -1:
275 | clear_cache()
276 |
277 | field_open_mask.resize( map.size.x * map.size.y )
278 | field_open_mask.fill(0)
279 |
280 | #init the open list
281 | var openlist:Array[int]
282 | for t in targets:
283 | #insert targets into the openlist
284 | openlist.append( t.node.field_index )
285 | field_ef[ t.node.field_index ] = 0.0
286 | field_aim[ t.node.field_index ] = t.node.field_index
287 | field_open_mask[ t.node.field_index ] = 1
288 | field_target[ t.node.field_index ] = t.node.field_index
289 | index_of_targets[t.pos.x * map.size.x + t.pos.y] = t
290 |
291 | #neighbour tile index
292 | var nx:int
293 | var ny:int
294 | var ef:float
295 | var _ef:float
296 | var c_node_ef:float
297 | var c_node:VFNNode
298 | var n_node:VFNNode
299 | var dist:float
300 |
301 | var max_steps:int = field_ef.size() * calc_cutoff_factor
302 | var steps:int = 0
303 | heighest_ef = 0.0
304 |
305 | var n_index:int
306 | var c_index:int
307 | var cache_index:int
308 |
309 | var skips_1:int
310 | var skips_2:int
311 | var skips_cache:int
312 | var from_cache:int = 0
313 | var cached:int = 0
314 |
315 | var con_index:int = 0
316 |
317 | var mf:VFNModField
318 | var static_mod_fields:Array
319 | var static_mod_fields_weights:Array[float]
320 | var dynamic_mod_fields:Array
321 | var dynamic_mod_fields_weights:Array[float]
322 |
323 | for _mf in map.mod_fields:
324 | if _mf.dynamic:
325 | if modfield_weights.has(_mf.name):
326 | if modfield_weights[_mf.name] > 0:
327 | dynamic_mod_fields.append(_mf)
328 | dynamic_mod_fields_weights.append(modfield_weights[_mf.name])
329 | else:
330 | pass
331 | else:
332 | dynamic_mod_fields.append(_mf)
333 | dynamic_mod_fields_weights.append(1)
334 | else:
335 | if modfield_weights.has(_mf.name):
336 | if modfield_weights[_mf.name] > 0:
337 | static_mod_fields.append(_mf)
338 | static_mod_fields_weights.append(modfield_weights[_mf.name])
339 | else:
340 | pass
341 | else:
342 | static_mod_fields.append(_mf)
343 | static_mod_fields_weights.append(1)
344 |
345 |
346 | while openlist.size() > 0:
347 | steps += 1
348 | if steps > max_steps:
349 | d("calculation limit reached")
350 | d("openlist count: "+str(openlist.size()))
351 | emit_signal("thread_finished")
352 | return false
353 |
354 | if _kill_thread:
355 | _kill_thread = false
356 | d("thread terminated")
357 | emit_signal("thread_finished")
358 | return false
359 |
360 | c_index = openlist.pop_front()
361 | field_open_mask[c_index] = 0
362 | c_node = map.nodes[c_index]
363 |
364 | #if current node is disabled, skip calculation
365 | if c_node.disabled:
366 | continue
367 |
368 | # init cache if not present
369 | cache_index = connection_cache_index[c_index]
370 | if cache_index == -1:
371 | cache_index = connection_cache_current_index
372 | connection_cache_index[c_index] = connection_cache_current_index
373 | connection_cache_current_index += c_node.connections.size()
374 |
375 | # dynamic mod field penaltys for this c_node
376 | c_node_ef = 0
377 | for i in dynamic_mod_fields.size():
378 | mf = dynamic_mod_fields[i]
379 | if mf.boolean and mf.field[c_index] == -1:
380 | continue
381 | c_node_ef += mf.field[c_index] * field_effort_factor * dynamic_mod_fields_weights[i]
382 |
383 |
384 | con_index = -1
385 | for c in c_node.connections:
386 | con_index += 1
387 |
388 | #load cache
389 | _ef = connection_cache[cache_index + con_index]
390 |
391 | if _ef == -1:
392 | skips_cache += 1
393 | continue
394 |
395 | if not c:
396 | connection_cache[cache_index + con_index] = -1
397 | cached += 1
398 | continue
399 |
400 | n_node = c.other_node
401 | n_index = n_node.field_index
402 |
403 | if field_ef[c_index] > field_ef[n_index]:
404 | skips_1 += 1
405 | continue
406 |
407 | #calculate effort
408 | ef = field_ef[c_index] + c_node_ef
409 | if _ef == 0:
410 | #cache is empty ... calculate effort
411 | cached += 1
412 |
413 | if c.steepness == 0:
414 | pass
415 | elif c.steepness > 0:
416 | if climb_cutoff < c.steepness:
417 | _ef = -1
418 | else:
419 | _ef += climb_factor * c.steepness
420 | else:
421 | if drop_cutoff < -c.steepness:
422 | _ef = -1
423 | else:
424 | _ef += drop_factor * -c.steepness
425 |
426 | if n_node.disabled:
427 | _ef = -1
428 |
429 | if _ef == -1:
430 | connection_cache[cache_index + con_index] = -1
431 |
432 | #dont cut corners
433 | match con_index:
434 | 0:
435 | #disable nw and ne
436 | connection_cache[cache_index + 4] = -1
437 | connection_cache[cache_index + 7] = -1
438 | #print("!")
439 | 1:
440 | #disable ne and se
441 | connection_cache[cache_index + 4] = -1
442 | connection_cache[cache_index + 5] = -1
443 | 2:
444 | #disable se and sw
445 | connection_cache[cache_index + 5] = -1
446 | connection_cache[cache_index + 6] = -1
447 | 3:
448 | #disable nw and sw
449 | connection_cache[cache_index + 6] = -1
450 | connection_cache[cache_index + 7] = -1
451 |
452 | continue
453 |
454 | #add connection's effort
455 | _ef += c.effort
456 |
457 | #add static mod fields
458 | for i in static_mod_fields.size():
459 | mf = static_mod_fields[i]
460 | if mf.boolean and mf.field[c_index] == -1:
461 | connection_cache[cache_index + con_index] = -1
462 | continue
463 | _ef += mf.field[c_index] * field_effort_factor * static_mod_fields_weights[i]
464 |
465 | connection_cache[cache_index + con_index] = _ef
466 | else:
467 | from_cache += 1
468 |
469 | ef += _ef
470 |
471 | #next node to current node effort is smaller
472 | if ef < field_ef[n_index] and ef < effort_cutoff:
473 | field_ef[n_index] = ef
474 | field_aim[n_index] = c_index
475 | _field_vector[n_index] = n_node.world_position.direction_to(c_node.world_position)
476 | field_target[n_index] = field_target[c_index]
477 | if field_open_mask[n_index] != 1:
478 | openlist.append( n_index )
479 | field_open_mask[n_index] = 1
480 | heighest_ef = max(heighest_ef,ef)
481 |
482 | var t_end = Time.get_ticks_msec()
483 | d("Steps taken: "+str(steps)+"["+str(map.size.x*map.size.y)+"] in "+str(t_end-t_start)+"msec heighest effort:"+str(heighest_ef))
484 | d("Skips by effort check: "+str(skips_1))
485 | d("Skips by cache: "+str(skips_cache))
486 | d("from cache: "+str(from_cache))
487 | d("cached: "+str(cached))
488 | emit_signal("thread_finished")
489 |
490 | return true
491 |
492 |
493 | func ______RETRIEVING():
494 | pass
495 |
496 |
497 | ## get the index number of the node where this node is pointing to from world position
498 | func get_aim_world( global_position:Vector3, clamp:bool=true ) -> int:
499 | var p:Vector3 = map.to_local( global_position )
500 | p = p.round() / map.field_scale
501 | var n:Vector2i = Vector2i(p.x,p.z)
502 | if clamp:
503 | n = Vector2i(p.x,p.z).clamp(Vector2i.ZERO,map.size)
504 | var index = n.x*map.size.x+n.y
505 | if index < 0 or index >= field_vector.size():
506 | return -1
507 | else:
508 | return field_aim[index]
509 |
510 |
511 | ## get VFNNode for world position
512 | func get_node_world( wpos:Vector3, clamp:bool=true ) -> VFNNode:
513 | var p:Vector3 = map.to_local( wpos )
514 | p = p.round() / map.field_scale
515 | var n:Vector2i = Vector2i(p.x,p.z)
516 | if clamp:
517 | n = Vector2i(p.x,p.z).clamp(Vector2i.ZERO,map.size)
518 | var index = n.x*map.size.x+n.y
519 | if index < 0 or index >= field_vector.size():
520 | return null
521 | else:
522 | return map.nodes[index]
523 |
524 |
525 | ## get VFNTarget for world position
526 | func get_target_world( wpos:Vector3, clamp:bool=true ) -> VFNTarget:
527 | var p:Vector3 = map.to_local( wpos )
528 | p = p.round() / map.field_scale
529 | var n:Vector2i = Vector2i(p.x,p.z)
530 | if clamp:
531 | n = Vector2i(p.x,p.z).clamp(Vector2i.ZERO,map.size)
532 | var index = n.x*map.size.x+n.y
533 | if index < 0 or index >= field_vector.size():
534 | return null
535 | else:
536 | return index_of_targets[field_target[index]]
537 |
538 |
539 | func get_vector_world( wpos:Vector3, clamp:bool=true ) -> Vector3:
540 | var p:Vector3 = map.to_local( wpos )
541 | p = p.round() / map.field_scale
542 | var n:Vector2i = Vector2i(p.x,p.z)
543 | if clamp:
544 | n = Vector2i(p.x,p.z).clamp(Vector2i.ZERO,map.size)
545 | var index = n.x*map.size.x+n.y
546 | if index < 0 or index >= field_vector.size():
547 | return Vector3(0,0,0)
548 | else:
549 | return field_vector[index]
550 |
551 |
552 | ## get movement vector for world position smoothed by the neighboring fields
553 | func get_vector_smooth_world( wpos:Vector3, clamp:bool=true ) -> Vector3:
554 | var p:Vector3 = map.to_local( wpos )
555 | p = p.round() / map.field_scale
556 | var n:Vector2i = Vector2i(p.x,p.z)
557 | if clamp:
558 | n = Vector2i(p.x,p.z).clamp(Vector2i.ZERO,map.size)
559 | var index = n.x*map.size.x+n.y
560 | if index < 0 or index >= field_vector.size():
561 | return Vector3(0,0,0)
562 | else:
563 | var node:VFNNode = map.nodes[index]
564 | var d:float = wpos.distance_to(node.world_position)
565 | var v:Vector3 = field_vector[index]
566 | for c in node.connections:
567 | if not c:
568 | continue
569 | d = wpos.distance_to(c.other_node.world_position)
570 | v += field_vector[c.other_node.field_index] * ( d / 3 )
571 | return v.normalized()
572 |
573 |
574 | func ______DEBUG():
575 | pass
576 |
577 |
578 | ## generates a heatmap based on the tiles effort to the closest target
579 | func get_effort_heatmap() -> Image:
580 | var img:Image = Image.create( map.size.x, map.size.y, false, Image.FORMAT_RGB8 )
581 | var c:Color
582 | var ef:float
583 | for n in map.nodes:
584 | ef = field_ef[n.field_index]
585 | c = Color.from_hsv( ef / heighest_ef, 1, 1 )
586 | if ef == 0:
587 | c = Color.BLACK
588 | img.set_pixelv( n.pos, c )
589 | return img
590 |
591 |
592 | ## generates a heatmap based on the tiles designated target
593 | func get_target_heatmap() -> Image:
594 | var img:Image = Image.create( map.size.x, map.size.y, false, Image.FORMAT_RGB8 )
595 | var c:Color
596 | var ef:float
597 | for n in map.nodes:
598 | ef = field_ef[n.field_index]
599 | if field_target[n.field_index]:
600 | c = map.nodes[field_target[n.field_index]].color
601 | c.v = 1.0 - ef / heighest_ef
602 | else:
603 | c = Color.GRAY
604 | if ef == 0:
605 | c = Color.BLACK
606 | img.set_pixelv( n.pos, c )
607 | return img
608 |
609 |
610 | func get_penalty_heatmap() -> Image:
611 | var img:Image = Image.create( map.size.x, map.size.y, false, Image.FORMAT_RGB8 )
612 | var c:Color = Color.WHITE
613 | var ef:float
614 | for n in map.nodes:
615 | c.v = 1
616 | for mf in map.mod_fields:
617 | c.v -= mf.get_value(n.pos) * 0.05
618 | img.set_pixelv( n.pos, c )
619 | return img
620 |
621 |
622 | func d( value ):
623 | if debug:
624 | print("VFN-Field: "+str(value) )
625 |
626 |
627 | class VFNTarget extends RefCounted:
628 | var pos:Vector2i
629 | var data = null
630 | var id:int
631 | var node:VFNNode
632 | var color:Color
633 |
634 | func _init():
635 | color = Color.from_hsv(randf(),1,1)
636 |
--------------------------------------------------------------------------------
/addons/VectorFieldNavigation/classes/VFNMap.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends Node3D
3 | class_name VFNMap
4 |
5 |
6 | ## Vector-Field-Navigation-Map
7 | ##
8 | ## This is the base class for a grid map for VFN-Navigation.
9 | ## It holds all nodes of the grid and features map modification tools
10 |
11 |
12 | ##print debug message to the console
13 | var debug:bool = true
14 | ## all nodes of the grid
15 | var nodes:Array[VFNNode]
16 |
17 | ## scale of a map tile
18 | ## (1.5 means every tile is 1.5 by 1.5)
19 | @export var field_scale:float = 1.0 :
20 | set( value ):
21 | field_scale = value
22 | if _is_init:
23 | for x in size.x:
24 | for y in size.y:
25 | #all nodes must refresh their world position
26 | nodes[x*size.x+y].height = nodes[x*size.x+y].height
27 | update_debug_mesh()
28 | emit_signal("nodes_changed")
29 |
30 | ## scale of height
31 | @export var height_scale:float = 1.0 :
32 | set( value ):
33 | height_scale = value
34 | if _is_init:
35 | for x in size.x:
36 | for y in size.y:
37 | #all nodes must refresh their world position
38 | nodes[x*size.x+y].height = nodes[x*size.x+y].height
39 | update_debug_mesh()
40 | emit_signal("nodes_changed")
41 |
42 | ## the maps width and depth
43 | @export var size:Vector2i :
44 | set( value ):
45 | if size == value:
46 | return
47 | size = value
48 | update_debug_mesh()
49 | init()
50 |
51 | ## draw a debug mesh
52 | @export var draw_debug:bool :
53 | set( value ):
54 | draw_debug = value
55 | update_debug_mesh()
56 |
57 | var _debug_mesh:MeshInstance3D
58 | var _is_init:bool
59 | var _is_ready:bool
60 |
61 | ## use this image to fill the maps data
62 | @export var heightmap:Texture2D :
63 | set( value ):
64 | heightmap = value
65 | if _is_init and use_heightmap:
66 | create_from_image( heightmap.get_image() )
67 | update_debug_mesh()
68 |
69 | ## enable heightmap usage
70 | @export var use_heightmap:bool :
71 | set( value ):
72 | use_heightmap = value
73 | if _is_init and heightmap and use_heightmap:
74 | create_from_image( heightmap.get_image() )
75 | update_debug_mesh()
76 |
77 | ## count of all connections in all nodes
78 | var connection_count:int = 0
79 |
80 | const NODE_N:int = 0
81 | const NODE_E:int = 1
82 | const NODE_S:int = 2
83 | const NODE_W:int = 3
84 | const NODE_NE:int = 4
85 | const NODE_SE:int = 5
86 | const NODE_SW:int = 6
87 | const NODE_NW:int = 7
88 |
89 | const CONS = [
90 | Vector2i( 0, -1),
91 | Vector2i( 1, 0),
92 | Vector2i( 0, 1),
93 | Vector2i(-1, 0),
94 | Vector2i( 1, -1),
95 | Vector2i( 1, 1),
96 | Vector2i(-1, 1),
97 | Vector2i(-1, -1),
98 | ]
99 |
100 | ##the map has significant changes in the structure
101 | signal map_changed
102 | ##some connections have changed
103 | signal connections_changed
104 | ##some nodes have changed
105 | signal nodes_changed
106 |
107 |
108 | func _ready():
109 | await get_tree().process_frame #await first frame, so that the heightmap can be used
110 | _is_ready = true
111 | if heightmap and use_heightmap:
112 | d("processing export heightmap")
113 | var img = heightmap.get_image()
114 | create_from_image( img )
115 | else:
116 | init()
117 | _is_init = true
118 | update_debug_mesh()
119 |
120 |
121 | ## initializes the data structure for the map
122 | func init( ):
123 | if not _is_ready:
124 | return
125 |
126 | d("init map with "+str(size))
127 | var protonode = VFNNode.new()
128 | var node
129 | mod_fields.clear()
130 | nodes.clear()
131 | nodes.resize(size.x*size.y)
132 | connection_count = 0
133 | for x in size.x:
134 | for y in size.y:
135 | node = protonode.duplicate()
136 | connection_count += 8
137 | node.map = self
138 | node.pos = Vector2i(x,y)
139 | nodes[node.field_index] = node
140 |
141 | var c_node:VFNNode
142 | var n_node:VFNNode
143 | var n_index:int
144 | var connection:VFNConnection
145 | var c:Vector2i
146 | for x in size.x:
147 | for y in size.y:
148 | c_node = nodes[x*size.x+y]
149 | for ci in CONS.size():
150 | c = CONS[ci]
151 | n_index = (x+c.x) * size.x + (y+c.y)
152 | if n_index >= 0 and n_index < nodes.size():
153 | n_node = nodes[n_index]
154 | connection = VFNConnection.new()
155 | connection.other_node = n_node
156 | connection.effort = c_node.world_position.distance_to(n_node.world_position)
157 | connection.steepness = (c_node.world_position.y - n_node.world_position.y) / c_node.world_position_2d.distance_to(n_node.world_position_2d)
158 | c_node.connections[ci] = connection
159 |
160 | d("created "+str(nodes.size())+" nodes with "+str(connection_count)+" connections")
161 |
162 | emit_signal("map_changed")
163 |
164 |
165 | ##get node object at position pos
166 | func get_node_at( pos:Vector2i ) -> VFNNode:
167 | var id = pos.x*size.x+pos.y
168 | if id >= 0 and id < size.x*size.y:
169 | return nodes[id]
170 | return null
171 |
172 |
173 | ## create a navigation field from this map
174 | func create_field( ) -> VFNField:
175 | var field:VFNField
176 | field = VFNField.new( self )
177 |
178 | return field
179 |
180 |
181 | ## set the tiles heights based on an image
182 | func create_from_image( img:Image, g_channel:VFNModField = null, b_channel:VFNModField = null, a_channel:VFNModField = null ):
183 | if not img:
184 | return
185 | var _size = img.get_size()
186 | if _size.x == 0 or _size.y == 0:
187 | return
188 |
189 | size = _size
190 |
191 | var nx:int
192 | var ny:int
193 | var c:Color
194 | img.decompress()
195 | for x in size.x:
196 | for y in size.y:
197 | c = img.get_pixel(x,y)
198 | set_height( Vector2i(x, y), c.r )
199 | if g_channel:
200 | g_channel.set_value( Vector2i(x,y), c.g)
201 | if b_channel:
202 | b_channel.set_value( Vector2i(x,y), c.g)
203 | if a_channel:
204 | a_channel.set_value( Vector2i(x,y), c.g)
205 |
206 | for c_node in nodes:
207 | for connection in c_node.connections:
208 | if connection:
209 | connection.effort = c_node.world_position.distance_to(connection.other_node.world_position)
210 | # connection.steepness = (c_node.world_position.y - connection.other_node.world_position.y) / c_node.world_position_2d.distance_to(connection.other_node.world_position_2d)
211 | connection.steepness = (connection.other_node.height - c_node.height) / c_node.rel_position.distance_to(connection.other_node.rel_position)
212 |
213 |
214 | func ______MODIFY():
215 | pass
216 |
217 |
218 | ## adds a penalty to every node around cliffs or drops
219 | func add_penalty_height_margin( field:VFNModField, margin:int, strength:float ):
220 | var c_node:VFNNode
221 | var n_node:VFNNode
222 | var n_index:int
223 | var dh:float
224 | var penalty:float
225 | var dist:float
226 |
227 | for x in size.x:
228 | for y in size.y:
229 | c_node = nodes[x*size.x+y]
230 | penalty = 0
231 | for _x in range(-margin,margin+1):
232 | for _y in range(-margin,margin+1):
233 | n_index = (x+_x) * size.x + (y+_y)
234 | if n_index >= 0 and n_index < nodes.size():
235 | n_node = nodes[n_index]
236 | dist = Vector2(x,y).distance_to(Vector2(x+_x,y+_y))
237 | if dist > 0:
238 | dh = (c_node.height - n_node.height) / dist
239 | dh = abs(dh)
240 | field.set_value(Vector2i(x,y),dh * strength)
241 |
242 |
243 | func ______MODIFY_NODES():
244 | pass
245 |
246 |
247 | ## set the height on node at x,y
248 | func set_height( pos:Vector2i, height:float ):
249 | nodes[pos.x*size.x+pos.y].height = height
250 | emit_signal("nodes_changed")
251 |
252 |
253 | ## get the height off node at x,y
254 | func get_height( pos:Vector2i ) -> float:
255 | return nodes[pos.x*size.x+pos.y].height
256 |
257 |
258 | ## connect non neighboring nodes
259 | func add_portal( a:Vector2i, b:Vector2i ) -> VFNConnection:
260 | var c_node:VFNNode = get_node_at( a )
261 | var n_node:VFNNode = get_node_at( b )
262 |
263 | if c_node and n_node:
264 | var vfc:VFNConnection = VFNConnection.new()
265 | vfc.effort = 0.1
266 | vfc.other_node = n_node
267 | c_node.connections.append( vfc )
268 | connection_count += 1
269 |
270 | emit_signal("connections_changed")
271 | return vfc
272 | else:
273 | return null
274 |
275 |
276 | ## disables the node at pos
277 | func disable_node( pos:Vector2i ):
278 | var n:VFNNode = get_node_at( pos )
279 | if n:
280 | n.disabled = true
281 |
282 |
283 | ## enables the node at pos
284 | func enable_node( pos:Vector2i ):
285 | var n:VFNNode = get_node_at( pos )
286 | if n:
287 | n.disabled = false
288 |
289 |
290 | func ______RETRIEVING():
291 | pass
292 |
293 |
294 | # get a node by its index number
295 | func get_node_from_index( index:int ) -> VFNNode:
296 | if index < 0 or index >= nodes.size():
297 | return null
298 | else:
299 | return nodes[index]
300 |
301 |
302 | func ______MOD_FIELDS():
303 | pass
304 |
305 |
306 | var mod_fields:Array[VFNModField]
307 |
308 | ## adds a modification field to this map with a name
309 | func add_mod_field( name:String ) -> VFNModField:
310 | var mf = VFNModField.new(self)
311 | mf.name = name
312 | mod_fields.append(mf)
313 | return mf
314 |
315 |
316 | func ______SERIALIZATION():
317 | pass
318 |
319 |
320 | ##serialize this map to a PackedByteArray
321 | func serialize() -> PackedByteArray:
322 | var data:StreamPeerBuffer = StreamPeerBuffer.new()
323 | data.put_string("v0.1") #Version
324 | data.put_float(field_scale)
325 | data.put_float(height_scale)
326 | data.put_u16(size.x)
327 | data.put_u16(size.y)
328 |
329 | for n in nodes:
330 | n.serialize( data )
331 |
332 | data.put_u8(mod_fields.size())
333 | for mf in mod_fields:
334 | mf.serialize( data )
335 |
336 | d("serialized data ("+str(data.data_array.size())+" bytes)")
337 | return data.data_array
338 |
339 |
340 | ##unserialize this map from a PackedByteArray
341 | func unserialize( _data:PackedByteArray ):
342 | var data:StreamPeerBuffer = StreamPeerBuffer.new()
343 | data.data_array = _data
344 |
345 | var v = data.get_string()
346 | if v != "v0.1":
347 | d("cannot unserialze data version is "+v+" but must be v0.1")
348 | return false
349 | d("unserialze data version "+v)
350 |
351 | field_scale = data.get_float()
352 | height_scale = data.get_float()
353 | var _size:Vector2i
354 | _size.x = data.get_u16()
355 | _size.y = data.get_u16()
356 | size = _size
357 | init()
358 |
359 | var n
360 | for node in nodes:
361 | node.unserialize( data )
362 |
363 | var modfield_count = data.get_u8()
364 | var mf:VFNModField
365 | for i in modfield_count:
366 | mf = add_mod_field("")
367 | mf.unserialize( data )
368 | d("extracted "+str(modfield_count)+" modfields")
369 |
370 |
371 | func ______DEBUG():
372 | pass
373 |
374 |
375 | ## redraw/update the debug mesh
376 | func update_debug_mesh( field:VFNField=null ):
377 | if not draw_debug:
378 | return
379 |
380 | if not _is_init:
381 | return
382 |
383 | if size.x == 0 or size.y == 0:
384 | return
385 |
386 | if nodes.size() == 0 or size.x*size.y != nodes.size():
387 | return
388 |
389 | if not is_instance_valid(_debug_mesh):
390 | _debug_mesh = get_node_or_null("__VectorFieldNavigationMapDebugMesh__")
391 |
392 | if not _debug_mesh:
393 | _debug_mesh = MeshInstance3D.new()
394 | add_child(_debug_mesh)
395 | _debug_mesh.mesh = ImmediateMesh.new()
396 | _debug_mesh.material_override = load("res://addons/VectorFieldNavigation/materials/matVectorFieldNavigationDebugMap.tres")
397 |
398 | _debug_mesh.mesh.clear_surfaces()
399 | _debug_mesh.mesh.surface_begin( Mesh.PRIMITIVE_POINTS )
400 |
401 |
402 | var c:Color
403 | for n in nodes:
404 | if field:
405 | if field.field_target[n.field_index]:
406 | c = nodes[field.field_target[n.field_index]].color
407 | c.v = 1.0 - field.field_ef[n.field_index] / field.heighest_ef
408 | else:
409 | c = Color.GRAY
410 | else:
411 | c.v = n.height
412 | _debug_mesh.mesh.surface_set_color( c )
413 | _debug_mesh.mesh.surface_add_vertex( n.world_position )
414 | _debug_mesh.mesh.surface_end()
415 |
416 |
417 | func d( value ):
418 | if debug:
419 | print("VFN-Map: "+str(value) )
420 |
421 |
422 |
--------------------------------------------------------------------------------
/addons/VectorFieldNavigation/classes/VFNModField.gd:
--------------------------------------------------------------------------------
1 | extends RefCounted
2 | class_name VFNModField
3 |
4 | ## Modifier field for VectorFieldMap
5 | ##
6 | ## This field mdofies the effort needed to reach nodes
7 | ## The higher the value for a node the less "attractive" the node is to use
8 |
9 |
10 | ## the field is dynamic, value do not get cached
11 | var dynamic:bool = false
12 | ## only the highest number get set
13 | var upmost:bool = false
14 | ## nodes with a field value of < 0.5 cannot be walked on
15 | var boolean:bool = false
16 | ##the fields effort value
17 | var field:PackedFloat32Array
18 | ## the associated map
19 | var map:VFNMap
20 | ## name of the modfield
21 | var name:String
22 |
23 |
24 | func _init( _map:VFNMap ):
25 | map = _map
26 | map.connect("map_changed",self._reinit)
27 | _reinit()
28 |
29 |
30 | func _reinit():
31 | field.resize( map.nodes.size() )
32 |
33 |
34 | ## reset the whole filed to zero
35 | func clear():
36 | field.fill(0)
37 |
38 |
39 | ## set the node value at pos
40 | func set_value( pos:Vector2i, value:float ):
41 | var i = pos.x*map.size.x+pos.y
42 |
43 | if boolean:
44 | if round(value) > 0:
45 | value = 1
46 | else:
47 | value = -1
48 |
49 | if upmost:
50 | value = max( field[i], value )
51 |
52 | field[i] = value
53 |
54 |
55 | ## set the node value at pos
56 | func set_value_from_world( wpos:Vector3, value:float, clamp:bool=true ):
57 | var p:Vector3 = map.to_local( wpos )
58 | p = p.round() / map.field_scale
59 | var n:Vector2i = Vector2i(p.x,p.z)
60 | if clamp:
61 | n = Vector2i(p.x,p.z).clamp(Vector2i.ZERO,map.size)
62 | set_value( n, value )
63 |
64 |
65 | ## set the node value at pos
66 | func add_value( pos:Vector2i, value:float ):
67 | var i = pos.x*map.size.x+pos.y
68 |
69 | if upmost:
70 | value = max( field[i], value )
71 | field[i] = value
72 | return
73 |
74 |
75 | if boolean:
76 | if round(value) > 0:
77 | value = 1
78 | else:
79 | value = -1
80 | field[i] = value
81 | return
82 |
83 | field[i] += value
84 |
85 |
86 | ## set the node value at pos
87 | func add_value_from_world( wpos:Vector3, value:float, clamp:bool=true ):
88 | var p:Vector3 = map.to_local( wpos )
89 | p = p.round() / map.field_scale
90 | var n:Vector2i = Vector2i(p.x,p.z)
91 | if clamp:
92 | n = Vector2i(p.x,p.z).clamp(Vector2i.ZERO,map.size)
93 | add_value( n, value )
94 |
95 |
96 | ## get the nodes value at pos
97 | func get_value( pos:Vector2i ):
98 | return field[pos.x*map.size.x+pos.y]
99 |
100 |
101 | ## fade the whole field by factor f
102 | ## (0.9 means the field gets faded by 10%)
103 | func fade( f:float ):
104 | for i in field.size():
105 | field[i] *= f
106 |
107 | ## not yet implemented
108 | func blur_fade( f:float ):
109 | var _f:float
110 | var i:int
111 | var _field:PackedFloat32Array = field.duplicate()
112 | for x in range(1,map.size.x-1):
113 | for y in range(1,map.size.y-1):
114 | i = x*map.size.x + y
115 | for _x in range(-1,2):
116 | for _y in range(-1,2):
117 | _field[i] += field[(x+_x)*map.size.x + y+_y]
118 | _field[i] /= 9
119 | field = _field
120 | fade(f)
121 |
122 |
123 | ##serialize this object into buffer stream
124 | func serialize( data:StreamPeer ):
125 | data.put_string(name)
126 | data.put_u8(int(dynamic))
127 | data.put_u8(int(upmost))
128 | data.put_u8(int(boolean))
129 | data.put_var(field)
130 |
131 |
132 | ##unserialize this object from buffer stream
133 | func unserialize( data:StreamPeer ):
134 | name = data.get_string()
135 | dynamic = data.get_u8()
136 | upmost = data.get_u8()
137 | boolean = data.get_u8()
138 | field = data.get_var()
139 |
--------------------------------------------------------------------------------
/addons/VectorFieldNavigation/classes/VFNNode.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends Resource
3 | class_name VFNNode
4 |
5 | ## the node class for the VectorFieldMap
6 | ##
7 | ## This field mdofies the effort needed to reach nodes
8 | ## The higher the value for a node the less "attractive" the node is to use
9 |
10 | ## the associated map
11 | var map:VFNMap
12 | ## all connections that lead to this field
13 | var connections:Array[VFNConnection]
14 | ## the positon scaled by the scale factors, relative to the map node
15 | var world_position:Vector3
16 | ## the positon scaled by the scale factors, relative to the map node, only in the x,z plane
17 | var world_position_2d:Vector2
18 | ## the relative position on the grid
19 | var rel_position:Vector3
20 | ## this's nodes index number in field arrays
21 | var field_index:int
22 | ## a random color for debug purposes
23 | var color:Color
24 | ## node is disabled, gets excluded from calculation
25 | var disabled:bool = false
26 | ## position on the grid
27 | var pos:Vector2i :
28 | set( value ):
29 | pos = value
30 | field_index = pos.x * map.size.x + pos.y
31 |
32 | ## height of the node
33 | var height:float :
34 | set( value ):
35 | height = value
36 | world_position = Vector3(map.field_scale,0,map.field_scale) / 2.0 + Vector3( pos.x * map.field_scale, height * map.height_scale, pos.y * map.field_scale )
37 | world_position_2d = Vector2(map.field_scale,map.field_scale) / 2.0 + Vector2( pos.x * map.field_scale, pos.y * map.field_scale )
38 | rel_position = Vector3(pos.x,height,pos.y)
39 |
40 |
41 | func _init():
42 | color = Color.from_hsv(randf(),1,1)
43 | connections.resize(8)
44 |
45 |
46 | ##serialize this object into buffer stream
47 | func serialize( data:StreamPeer ):
48 | data.put_8(int(disabled))
49 | data.put_float(height)
50 | data.put_u8(connections.size())
51 | var cs:Array = []
52 | for c in connections:
53 | if c:
54 | data.put_8(1)
55 | c.serialize( data )
56 | else:
57 | data.put_8(-1)
58 |
59 |
60 | ##unserialize this object from buffer stream
61 | func unserialize( data:StreamPeer ):
62 | disabled = data.get_u8()
63 | height = data.get_float()
64 | var connection_count = data.get_u8()
65 |
66 | for i in connection_count:
67 | if data.get_8() == 1:
68 | if i < 8:
69 | connections[i].unserialize( data )
70 | else:
71 | map.add_portal( pos, pos ).unserialize( data )
72 |
--------------------------------------------------------------------------------
/addons/VectorFieldNavigation/docs/DOCUMENTATION.md:
--------------------------------------------------------------------------------
1 | # Godot-4-VectorFieldNavigation - Dokumentation
2 |
3 | ### VFNMap
4 | The base data of the navigation map.
5 |
6 | **Properties**
7 | * `field_scale:float = 1`\
8 | scale of a map tile\
9 | (1.5 means every tile is 1.5 by 1.5)
10 |
11 | * `height_scale:float = 1`\
12 | scale of height\
13 | (tiles height is height (0 to 1) multiplied by height_scale
14 |
15 | * `size:Vector2i`\
16 | dimensions of the map
17 |
18 | * `draw_debug:bool = false`\
19 | wether draw a pointcloud for visual reference
20 |
21 | * `heightmap:Texture2D`\
22 | use this image to initialize the map
23 |
24 | * `use_heightmap:bool = false`\
25 | use the heightmap
26 |
27 | **Signals**
28 |
29 | * `map_changed`\
30 | _emited when the map changed substantially
31 |
32 | * `connections_changed`\
33 | _emited when connections changed (cache will be cleared)
34 |
35 | * `nodes_changed`\
36 | _emited when nodes changed (cache will be cleared)
37 |
38 | **Methods**
39 |
40 | * `init( ) -> void`\
41 | initializes the maps data structure\
42 | must not be called manually
43 |
44 | * `get_node_at( pos:vector2i ) -> VFNNode`\
45 | get node-object at index position pos
46 |
47 |
48 | * `create_field( ) -> VFNField`\
49 | create field based on this map for calculation solutions
50 |
51 |
52 | * `create_from_image( img:Image, g_channel:VFNModField=null, b_channel:VFNModField=null, a_channel:VFNModField=null )`\
53 | initializes this map based on an heightmap image\
54 | r channel is allways the node height\
55 | g, b and a channel can be used for modfields
56 |
57 |
58 | * `add_penalty_height_margin( field:VFNModField, margin:int, strength:float )`\
59 | adds penalty to a modfield around slopes and cliffs\
60 | useful for keeping entities from gliding along walls to reach there targets
61 |
62 |
63 | * `set_height( pos:Vector2i, height:float )`\
64 | set nodes height at pos to height\
65 | height should be between 0 and 1, scale the height with the height_scale property
66 |
67 |
68 | * `get_height( pos:Vector2i ) -> float`\
69 | get nodes height at grid position pos
70 |
71 |
72 | * `add_portal( a:Vector2i, b:Vector2i ) -> VFNConnection`\
73 | adds a portal connection from a to b\
74 | returns a connection object where you can set effort etc.
75 |
76 |
77 | * `disable_node( pos:Vector2i )`\
78 | disables the node at pos\
79 | The node will be excluded when calculating
80 |
81 |
82 | * `enable_node( pos:Vector2i )`\
83 | enables the node at pos\
84 | The node will be included when calculating
85 |
86 |
87 | * `update_debug_mesh( field:VFNField=null )`\
88 | redraws the debug mesh\
89 | when a field is given, effort will be shown with color
90 |
91 |
92 | * `add_mod_field( name:String ) -> VFNModField`\
93 | adds a named modfield to the map\
94 | see modfields for further explanations
95 |
96 |
97 | * `get_node_from_index( index:int ) -> VFNNode`\
98 | get VFNNode object from index number or -1 if not exist/valid
99 |
100 |
101 | * `serialize() -> PackedByteArray`\
102 | serializes all data from this map to a packedByteArray\
103 | useful to store pre-processed maps into files
104 |
105 |
106 | * `unserialize( data:PackedByteArray )`\
107 | rebuild map data from this serialized PackedByteArray
108 | useful to restore pre-processed maps from files
109 |
110 |
111 |
112 | ### VFNField
113 | Field for calculating solutions based on a VFNMap.
114 |
115 | **Properties**
116 |
117 | * `effort_cutoff:float`\
118 | stop calculation further when final effort is higher as this number
119 |
120 | * `climb_factor:float = 0.0`\
121 | additional penalty factor for upward steepness
122 |
123 | * `climb_cutoff:float = `\
124 | the cutoff in upward direction, if a connection is more steep than this, it wont be used
125 |
126 | * `drop_factor:float = 0.0`\
127 | additional penalty factor for downward steepness
128 |
129 | * `drop_cutoff:float`\
130 | the cutoff in downward direction, if a connection is more steep than this, it wont be used
131 |
132 |
133 | * `field_effort_factor:float = 1`\
134 | additionaly penalty factor on modfields
135 |
136 |
137 | **Signals**
138 |
139 | * `calculated( succesful:bool )`\
140 | the calculation has finished
141 |
142 |
143 | **Methods**
144 |
145 | * `add_target( pos:Vector2i, data=null ) -> VFNTarget`\
146 | adds a new target at pos
147 |
148 |
149 | * `clear_targets()`\
150 | remove all targets
151 |
152 |
153 | * `remove_target( pos )`\
154 | remove target at pos Vector2i or VFNTarget
155 |
156 |
157 | * `remove_targets( destinations:Array[Vector2i]`\
158 | remove targets at positions
159 |
160 | * `set_modfield( name:String, weight:float )`\
161 | weights the modfield by weight\
162 | weight 0 disables the influenz of the modfield\
163 | weight multiplies the field effort like ...\
164 | effort += modffield_node_value * field_effort_factor * modfield_weight
165 |
166 |
167 | * `calculate_threaded( callback = null, kill_existing_thread:bool=true )`\
168 | starts threaded calculation\
169 | calls callback after finish when successful
170 |
171 |
172 | * `stop_calculation()`\
173 | kills the running calculation thread.\
174 | Signal calculated will still be called with flag unsuccessful
175 |
176 |
177 | * `get_aim_world( global_position:Vector3, clamp:bool=true ) -> int`\
178 | get the index number of the node where this node is pointing to from world position
179 |
180 |
181 | * `get_target_world( global_position:Vector3, clamp:bool=true ) -> VFNTarget`\
182 | gets target for world position global_position, clamp true will clamp position to the map
183 |
184 |
185 | * `get_vector_world( global_position:Vector3, clamp:bool=true ) -> Vector3`\
186 | gets movement vector for world position global_position, clamp true will clamp position to the map
187 |
188 |
189 | * `get_vector_smooth_world( global_position:Vector3, clamp:bool=true ) -> Vector3`\
190 | gets movement vector for world position global_position, clamp true will clamp position to the map
191 | will smooth vector with neighbouring fields
192 |
193 | * `get_effort_heatmap() -> Image`\
194 | visual representation of effort for debug purpose
195 |
196 |
197 | * `get_penalty_heatmap() -> Image`\
198 | visual representation of penalties for debug purpose\
199 | not yet implemented
200 |
201 |
202 | ### VFNModField
203 | Field for modifing pathfinding effort.
204 |
205 | **Properties**
206 | * `dynamic:bool = false`\
207 | field is dynamic and will not be cached
208 |
209 | * `upmost:bool = false`\
210 | when setting penalty only the heighest number will reside
211 |
212 | * `boolean:bool = false`\
213 | this field is boolean, if value is higher then 0.5 node is enabled else node is disabled
214 |
215 | **Methods**
216 |
217 | * `clear()`\
218 | clears the field completly
219 |
220 |
221 | * `set_value( pos:Vector2i, value:float )`\
222 | sets penalty value on pos
223 |
224 |
225 | * `set_value_from_world( world_pos:Vector3, value:float, clamp:bool=true )`\
226 | sets penalty value on world pos
227 |
228 |
229 | * `add_value( pos:Vector2i, value:float )`\
230 | adds penalty value on pos
231 |
232 |
233 | * `add_value_from_world( world_pos:Vector3, value:float, clamp:bool=true )`\
234 | adds penalty value on world pos
235 |
236 |
237 | * `get_value( pos:Vector2i )`\
238 | gets penalty value on pos
239 |
240 |
241 | * `fade( f:float )`\
242 | fades every value in the field, multiplys the value by f
243 |
244 |
245 | * `blur_fade( f:float )`\
246 | blurs the neighbouring fields and\
247 | fades every value in the field, multiplys the value by f
248 |
249 |
250 | ### VFNConnection
251 | Connection between fields
252 |
253 | **Properties**
254 | * `node_b:VFNNode`\
255 | the other node
256 |
257 | * `effort:float = 0`\
258 | effort to walk this connection (mostly the distance)
259 |
260 | * `steepness:float = 0`\
261 | the connections steepness
262 |
263 | * `disabled:bool = false`\
264 | connections is disabled or not
265 |
266 |
--------------------------------------------------------------------------------
/addons/VectorFieldNavigation/docs/ex_spreading_forces_1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/D2klaas/Godot-4-VectorFieldNavigation/1f266ab1532c7b7854ca9629a726352aaba966bc/addons/VectorFieldNavigation/docs/ex_spreading_forces_1.jpg
--------------------------------------------------------------------------------
/addons/VectorFieldNavigation/docs/ex_spreading_forces_1.jpg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://bvsoalroi0ddg"
6 | path="res://.godot/imported/ex_spreading_forces_1.jpg-bf992ed8febfb6ca86bbc9acb799c1b5.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://addons/VectorFieldNavigation/docs/ex_spreading_forces_1.jpg"
14 | dest_files=["res://.godot/imported/ex_spreading_forces_1.jpg-bf992ed8febfb6ca86bbc9acb799c1b5.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 |
--------------------------------------------------------------------------------
/addons/VectorFieldNavigation/docs/ex_spreading_forces_2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/D2klaas/Godot-4-VectorFieldNavigation/1f266ab1532c7b7854ca9629a726352aaba966bc/addons/VectorFieldNavigation/docs/ex_spreading_forces_2.jpg
--------------------------------------------------------------------------------
/addons/VectorFieldNavigation/docs/ex_spreading_forces_2.jpg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://bodpgp28yelxa"
6 | path="res://.godot/imported/ex_spreading_forces_2.jpg-8f06cd09b5d8c45974d20cc360f743e4.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://addons/VectorFieldNavigation/docs/ex_spreading_forces_2.jpg"
14 | dest_files=["res://.godot/imported/ex_spreading_forces_2.jpg-8f06cd09b5d8c45974d20cc360f743e4.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 |
--------------------------------------------------------------------------------
/addons/VectorFieldNavigation/docs/ex_spreading_forces_3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/D2klaas/Godot-4-VectorFieldNavigation/1f266ab1532c7b7854ca9629a726352aaba966bc/addons/VectorFieldNavigation/docs/ex_spreading_forces_3.jpg
--------------------------------------------------------------------------------
/addons/VectorFieldNavigation/docs/ex_spreading_forces_3.jpg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://c63vkv0uxbirw"
6 | path="res://.godot/imported/ex_spreading_forces_3.jpg-d75496a12a7da0d79260aae7e1836406.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://addons/VectorFieldNavigation/docs/ex_spreading_forces_3.jpg"
14 | dest_files=["res://.godot/imported/ex_spreading_forces_3.jpg-d75496a12a7da0d79260aae7e1836406.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 |
--------------------------------------------------------------------------------
/addons/VectorFieldNavigation/examples/GUI.gd:
--------------------------------------------------------------------------------
1 | extends Control
2 |
3 | var gen_targets:float = 1 :
4 | set(value):
5 | gen_targets = value
6 | %_gen_targets.text = str(value)
7 | %gen_targets.value = value
8 |
9 | var effort_cutoff:float :
10 | set(value):
11 | effort_cutoff = value
12 | %_effort_cutoff.text = str(value)
13 | %effort_cutoff.value = value
14 |
15 | var climb_factor:float :
16 | set(value):
17 | climb_factor = value
18 | %_climb_factor.text = str(value)
19 | %climb_factor.value = value
20 |
21 | var climb_cutoff:float :
22 | set(value):
23 | climb_cutoff = value
24 | %_climb_cutoff.text = str(value)
25 | %climb_cutoff.value = value
26 |
27 | var drop_factor:float :
28 | set(value):
29 | drop_factor = value
30 | %_drop_factor.text = str(value)
31 | %drop_factor.value = value
32 |
33 | var drop_cutoff:float :
34 | set(value):
35 | drop_cutoff = value
36 | %_drop_cutoff.text = str(value)
37 | %drop_cutoff.value = value
38 |
39 | var field_effort_factor:float :
40 | set(value):
41 | field_effort_factor = value
42 | %_field_effort_factor.text = str(value)
43 | %field_effort_factor.value = value
44 |
45 | #var field_penalty_factor:float :
46 | # set(value):
47 | # field_penalty_factor = value
48 | # %_field_penalty_factor.text = str(value)
49 | # %field_penalty_factor.value = value
50 |
51 |
52 |
53 | func _on_effort_cutoff_value_changed(value):
54 | effort_cutoff = value
55 |
56 |
57 | func _on_climb_factor_value_changed(value):
58 | climb_factor = value
59 |
60 |
61 | func _on_climb_cutoff_value_changed(value):
62 | climb_cutoff = value
63 |
64 |
65 | func _on_drop_factor_value_changed(value):
66 | drop_factor = value
67 |
68 |
69 | func _on_drop_cutoff_value_changed(value):
70 | drop_cutoff = value
71 |
72 |
73 | func _on_field_effort_factor_value_changed(value):
74 | field_effort_factor = value
75 |
76 |
77 | #func _on_field_penalty_factor_value_changed(value):
78 | # field_penalty_factor = value
79 |
80 |
81 | func _on_gen_targets_value_changed(value):
82 | gen_targets = value
83 |
--------------------------------------------------------------------------------
/addons/VectorFieldNavigation/examples/Portal.gd:
--------------------------------------------------------------------------------
1 | extends Area3D
2 |
3 | @export_node_path("Area3D") var portal_end
4 |
5 |
6 | # Called when the node enters the scene tree for the first time.
7 | func _ready():
8 | connect("body_entered",self._on_body_entered)
9 |
10 |
11 | # Called every frame. 'delta' is the elapsed time since the previous frame.
12 | func _on_body_entered(body):
13 | if body.just_teleported == true:
14 | body.just_teleported = false
15 | return
16 | body.just_teleported = true
17 | body.global_transform.origin = get_node(portal_end).global_transform.origin + Vector3(0,0.5,0)
18 |
--------------------------------------------------------------------------------
/addons/VectorFieldNavigation/examples/VectorFieldNavigation-Example.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=11 format=3 uid="uid://bq1okk6qaxpfr"]
2 |
3 | [ext_resource type="Script" path="res://addons/VectorFieldNavigation/examples/example.gd" id="1_l5mr5"]
4 | [ext_resource type="Texture2D" uid="uid://3mxy8pc7xvjg" path="res://addons/VectorFieldNavigation/examples/heightmap.png" id="2_d7bo2"]
5 | [ext_resource type="Script" path="res://addons/VectorFieldNavigation/examples/GUI.gd" id="2_gdncv"]
6 | [ext_resource type="Script" path="res://addons/VectorFieldNavigation/classes/VFNMap.gd" id="4_n068j"]
7 | [ext_resource type="Environment" uid="uid://m4fyiam5c8q0" path="res://default_env.tres" id="6_5pmrx"]
8 | [ext_resource type="Script" path="res://addons/VectorFieldNavigation/examples/Portal.gd" id="7_00jh6"]
9 |
10 | [sub_resource type="HeightMapShape3D" id="HeightMapShape3D_v1r8j"]
11 | map_width = 128
12 | map_depth = 128
13 | map_data = PackedFloat32Array(3, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
14 |
15 | [sub_resource type="StandardMaterial3D" id="StandardMaterial3D_k8nl8"]
16 | albedo_texture_force_srgb = true
17 | texture_filter = 0
18 |
19 | [sub_resource type="BoxShape3D" id="BoxShape3D_6hq0x"]
20 |
21 | [sub_resource type="BoxMesh" id="BoxMesh_r4fcx"]
22 |
23 | [node name="VFN Example Scene" type="Node3D"]
24 | script = ExtResource("1_l5mr5")
25 |
26 | [node name="Timer" type="Timer" parent="."]
27 | wait_time = 0.25
28 | autostart = true
29 |
30 | [node name="GUI" type="Control" parent="."]
31 | layout_mode = 3
32 | anchors_preset = 15
33 | anchor_right = 1.0
34 | anchor_bottom = 1.0
35 | grow_horizontal = 2
36 | grow_vertical = 2
37 | script = ExtResource("2_gdncv")
38 |
39 | [node name="MarginContainer2" type="MarginContainer" parent="GUI"]
40 | layout_mode = 1
41 | anchors_preset = 1
42 | anchor_left = 1.0
43 | anchor_right = 1.0
44 | offset_left = -299.0
45 | offset_bottom = 261.0
46 | grow_horizontal = 0
47 | theme_override_constants/margin_left = 10
48 | theme_override_constants/margin_top = 10
49 | theme_override_constants/margin_right = 10
50 | theme_override_constants/margin_bottom = 10
51 |
52 | [node name="VBoxContainer" type="VBoxContainer" parent="GUI/MarginContainer2"]
53 | layout_mode = 2
54 |
55 | [node name="GridContainer" type="GridContainer" parent="GUI/MarginContainer2/VBoxContainer"]
56 | layout_mode = 2
57 | theme_override_constants/h_separation = 10
58 | columns = 3
59 |
60 | [node name="Label8" type="Label" parent="GUI/MarginContainer2/VBoxContainer/GridContainer"]
61 | layout_mode = 2
62 | text = "Generate # targets"
63 |
64 | [node name="gen_targets" type="HSlider" parent="GUI/MarginContainer2/VBoxContainer/GridContainer"]
65 | unique_name_in_owner = true
66 | custom_minimum_size = Vector2(100, 26)
67 | layout_mode = 2
68 | min_value = 1.0
69 | value = 10.0
70 | rounded = true
71 | allow_greater = true
72 |
73 | [node name="_gen_targets" type="Label" parent="GUI/MarginContainer2/VBoxContainer/GridContainer"]
74 | unique_name_in_owner = true
75 | custom_minimum_size = Vector2(50, 0)
76 | layout_mode = 2
77 | text = "1"
78 |
79 | [node name="Label" type="Label" parent="GUI/MarginContainer2/VBoxContainer/GridContainer"]
80 | layout_mode = 2
81 | text = "Effort cutoff"
82 |
83 | [node name="effort_cutoff" type="HSlider" parent="GUI/MarginContainer2/VBoxContainer/GridContainer"]
84 | unique_name_in_owner = true
85 | custom_minimum_size = Vector2(100, 26)
86 | layout_mode = 2
87 | max_value = 1000.0
88 | value = 500.0
89 | rounded = true
90 | allow_greater = true
91 |
92 | [node name="_effort_cutoff" type="Label" parent="GUI/MarginContainer2/VBoxContainer/GridContainer"]
93 | unique_name_in_owner = true
94 | custom_minimum_size = Vector2(50, 0)
95 | layout_mode = 2
96 | text = "0"
97 |
98 | [node name="Label2" type="Label" parent="GUI/MarginContainer2/VBoxContainer/GridContainer"]
99 | layout_mode = 2
100 | text = "Climb factor"
101 |
102 | [node name="climb_factor" type="HSlider" parent="GUI/MarginContainer2/VBoxContainer/GridContainer"]
103 | unique_name_in_owner = true
104 | custom_minimum_size = Vector2(100, 26)
105 | layout_mode = 2
106 | max_value = 20.0
107 | step = 0.1
108 | value = 1.0
109 | allow_greater = true
110 |
111 | [node name="_climb_factor" type="Label" parent="GUI/MarginContainer2/VBoxContainer/GridContainer"]
112 | unique_name_in_owner = true
113 | custom_minimum_size = Vector2(50, 0)
114 | layout_mode = 2
115 | text = "0"
116 |
117 | [node name="Label3" type="Label" parent="GUI/MarginContainer2/VBoxContainer/GridContainer"]
118 | layout_mode = 2
119 | text = "Climb cutoff"
120 |
121 | [node name="climb_cutoff" type="HSlider" parent="GUI/MarginContainer2/VBoxContainer/GridContainer"]
122 | unique_name_in_owner = true
123 | custom_minimum_size = Vector2(100, 26)
124 | layout_mode = 2
125 | max_value = 1.0
126 | step = 0.01
127 | value = 0.5
128 |
129 | [node name="_climb_cutoff" type="Label" parent="GUI/MarginContainer2/VBoxContainer/GridContainer"]
130 | unique_name_in_owner = true
131 | custom_minimum_size = Vector2(50, 0)
132 | layout_mode = 2
133 | text = "0"
134 |
135 | [node name="Label4" type="Label" parent="GUI/MarginContainer2/VBoxContainer/GridContainer"]
136 | layout_mode = 2
137 | text = "Drop factor"
138 |
139 | [node name="drop_factor" type="HSlider" parent="GUI/MarginContainer2/VBoxContainer/GridContainer"]
140 | unique_name_in_owner = true
141 | custom_minimum_size = Vector2(100, 26)
142 | layout_mode = 2
143 | min_value = 1.0
144 | max_value = 20.0
145 | step = 0.1
146 | value = 1.0
147 | allow_greater = true
148 |
149 | [node name="_drop_factor" type="Label" parent="GUI/MarginContainer2/VBoxContainer/GridContainer"]
150 | unique_name_in_owner = true
151 | custom_minimum_size = Vector2(50, 0)
152 | layout_mode = 2
153 | text = "0"
154 |
155 | [node name="Label5" type="Label" parent="GUI/MarginContainer2/VBoxContainer/GridContainer"]
156 | layout_mode = 2
157 | text = "Drop cutoff"
158 |
159 | [node name="drop_cutoff" type="HSlider" parent="GUI/MarginContainer2/VBoxContainer/GridContainer"]
160 | unique_name_in_owner = true
161 | custom_minimum_size = Vector2(100, 26)
162 | layout_mode = 2
163 | max_value = 1.0
164 | step = 0.01
165 | value = 0.5
166 |
167 | [node name="_drop_cutoff" type="Label" parent="GUI/MarginContainer2/VBoxContainer/GridContainer"]
168 | unique_name_in_owner = true
169 | custom_minimum_size = Vector2(50, 0)
170 | layout_mode = 2
171 | text = "0"
172 |
173 | [node name="Label6" type="Label" parent="GUI/MarginContainer2/VBoxContainer/GridContainer"]
174 | layout_mode = 2
175 | text = "Field effort factor"
176 |
177 | [node name="field_effort_factor" type="HSlider" parent="GUI/MarginContainer2/VBoxContainer/GridContainer"]
178 | unique_name_in_owner = true
179 | custom_minimum_size = Vector2(100, 26)
180 | layout_mode = 2
181 | max_value = 10.0
182 | step = 0.1
183 | value = 1.0
184 | allow_greater = true
185 |
186 | [node name="_field_effort_factor" type="Label" parent="GUI/MarginContainer2/VBoxContainer/GridContainer"]
187 | unique_name_in_owner = true
188 | custom_minimum_size = Vector2(50, 0)
189 | layout_mode = 2
190 | text = "0"
191 |
192 | [node name="GoButton" type="Button" parent="GUI/MarginContainer2/VBoxContainer"]
193 | layout_mode = 2
194 | text = "Generate Random Targets"
195 |
196 | [node name="MarginContainer" type="MarginContainer" parent="GUI"]
197 | layout_mode = 1
198 | anchors_preset = 12
199 | anchor_top = 1.0
200 | anchor_right = 1.0
201 | anchor_bottom = 1.0
202 | offset_top = -148.0
203 | grow_horizontal = 2
204 | grow_vertical = 0
205 | theme_override_constants/margin_left = 10
206 | theme_override_constants/margin_top = 10
207 | theme_override_constants/margin_right = 10
208 | theme_override_constants/margin_bottom = 10
209 |
210 | [node name="GridContainer" type="GridContainer" parent="GUI/MarginContainer"]
211 | layout_mode = 2
212 | theme_override_constants/h_separation = 10
213 | theme_override_constants/v_separation = 10
214 | columns = 4
215 |
216 | [node name="Label" type="Label" parent="GUI/MarginContainer/GridContainer"]
217 | layout_mode = 2
218 | text = "Source map"
219 | horizontal_alignment = 1
220 |
221 | [node name="Label2" type="Label" parent="GUI/MarginContainer/GridContainer"]
222 | layout_mode = 2
223 | text = "Target map"
224 | horizontal_alignment = 1
225 |
226 | [node name="Label3" type="Label" parent="GUI/MarginContainer/GridContainer"]
227 | layout_mode = 2
228 | text = "Penalty map"
229 | horizontal_alignment = 1
230 |
231 | [node name="Label4" type="Label" parent="GUI/MarginContainer/GridContainer"]
232 | layout_mode = 2
233 | text = "Effort map"
234 | horizontal_alignment = 1
235 |
236 | [node name="OrgMap" type="TextureRect" parent="GUI/MarginContainer/GridContainer"]
237 | unique_name_in_owner = true
238 | texture_filter = 1
239 | layout_mode = 2
240 | texture = ExtResource("2_d7bo2")
241 |
242 | [node name="TargetMap" type="TextureRect" parent="GUI/MarginContainer/GridContainer"]
243 | unique_name_in_owner = true
244 | texture_filter = 1
245 | custom_minimum_size = Vector2(128, 128)
246 | layout_mode = 2
247 |
248 | [node name="PenaltyMap" type="TextureRect" parent="GUI/MarginContainer/GridContainer"]
249 | unique_name_in_owner = true
250 | texture_filter = 1
251 | custom_minimum_size = Vector2(128, 128)
252 | layout_mode = 2
253 |
254 | [node name="EffortMap" type="TextureRect" parent="GUI/MarginContainer/GridContainer"]
255 | unique_name_in_owner = true
256 | texture_filter = 1
257 | custom_minimum_size = Vector2(128, 128)
258 | layout_mode = 2
259 |
260 | [node name="VectorMap" type="Node3D" parent="."]
261 | script = ExtResource("4_n068j")
262 | height_scale = 5.0
263 | heightmap = ExtResource("2_d7bo2")
264 |
265 | [node name="cam_base" type="Node3D" parent="."]
266 | transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 64, 0, 64)
267 |
268 | [node name="Camera3D" type="Camera3D" parent="cam_base"]
269 | transform = Transform3D(-1, 6.04793e-08, -6.31268e-08, 0, 0.722086, 0.691803, 8.74228e-08, 0.691803, -0.722086, 0, 60, -80)
270 |
271 | [node name="scenery" type="Node3D" parent="."]
272 |
273 | [node name="terrain" type="StaticBody3D" parent="scenery"]
274 |
275 | [node name="shape" type="CollisionShape3D" parent="scenery/terrain"]
276 | shape = SubResource("HeightMapShape3D_v1r8j")
277 |
278 | [node name="mesh" type="MeshInstance3D" parent="scenery/terrain"]
279 | transform = Transform3D(1, 0, 0, 0, 10, 0, 0, 0, 1, 0, 0, 0)
280 | material_override = SubResource("StandardMaterial3D_k8nl8")
281 | skeleton = NodePath("../..")
282 |
283 | [node name="WorldEnvironment" type="WorldEnvironment" parent="."]
284 | environment = ExtResource("6_5pmrx")
285 |
286 | [node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
287 | transform = Transform3D(0.71446, 0.480756, 0.50835, 0, -0.726551, 0.687113, 0.699676, -0.490915, -0.519092, 0, 15.0457, 0)
288 |
289 | [node name="PortalA" type="Area3D" parent="."]
290 | transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 25, 0.5, 60)
291 | collision_layer = 0
292 | collision_mask = 2
293 | script = ExtResource("7_00jh6")
294 | portal_end = NodePath("../PortalB")
295 |
296 | [node name="CollisionShape3D" type="CollisionShape3D" parent="PortalA"]
297 | shape = SubResource("BoxShape3D_6hq0x")
298 |
299 | [node name="MeshInstance3D" type="MeshInstance3D" parent="PortalA"]
300 | mesh = SubResource("BoxMesh_r4fcx")
301 |
302 | [node name="PortalB" type="Area3D" parent="."]
303 | transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 80, 0.5, 44)
304 | collision_layer = 0
305 | collision_mask = 2
306 | script = ExtResource("7_00jh6")
307 | portal_end = NodePath("../PortalA")
308 |
309 | [node name="CollisionShape3D" type="CollisionShape3D" parent="PortalB"]
310 | shape = SubResource("BoxShape3D_6hq0x")
311 |
312 | [node name="MeshInstance3D" type="MeshInstance3D" parent="PortalB"]
313 | mesh = SubResource("BoxMesh_r4fcx")
314 |
315 | [connection signal="timeout" from="Timer" to="." method="_on_timer_timeout"]
316 | [connection signal="value_changed" from="GUI/MarginContainer2/VBoxContainer/GridContainer/gen_targets" to="GUI" method="_on_gen_targets_value_changed"]
317 | [connection signal="value_changed" from="GUI/MarginContainer2/VBoxContainer/GridContainer/effort_cutoff" to="GUI" method="_on_effort_cutoff_value_changed"]
318 | [connection signal="value_changed" from="GUI/MarginContainer2/VBoxContainer/GridContainer/climb_factor" to="GUI" method="_on_climb_factor_value_changed"]
319 | [connection signal="value_changed" from="GUI/MarginContainer2/VBoxContainer/GridContainer/climb_cutoff" to="GUI" method="_on_climb_cutoff_value_changed"]
320 | [connection signal="value_changed" from="GUI/MarginContainer2/VBoxContainer/GridContainer/drop_factor" to="GUI" method="_on_drop_factor_value_changed"]
321 | [connection signal="value_changed" from="GUI/MarginContainer2/VBoxContainer/GridContainer/drop_cutoff" to="GUI" method="_on_drop_cutoff_value_changed"]
322 | [connection signal="value_changed" from="GUI/MarginContainer2/VBoxContainer/GridContainer/field_effort_factor" to="GUI" method="_on_field_effort_factor_value_changed"]
323 | [connection signal="pressed" from="GUI/MarginContainer2/VBoxContainer/GoButton" to="." method="_on_button_pressed"]
324 |
--------------------------------------------------------------------------------
/addons/VectorFieldNavigation/examples/example.gd:
--------------------------------------------------------------------------------
1 | extends Node3D
2 |
3 | ## the VFN field
4 | var field:VFNField
5 | var occupied_field:VFNModField
6 | var update:bool = false
7 |
8 | func _ready():
9 | # set default values
10 | $GUI.effort_cutoff = 800
11 | $GUI.climb_factor = 4.1
12 | $GUI.climb_cutoff = 0.2
13 | $GUI.drop_factor = 4.1
14 | $GUI.drop_cutoff = 0.2
15 | $GUI.field_effort_factor = 1.0
16 |
17 | # wait first rendered frame to get the image
18 | await get_tree().process_frame
19 | var img:Image = %OrgMap.texture.get_image()
20 | # get the map
21 | var map:VFNMap = $VectorMap
22 | # init the map from an image
23 | map.create_from_image( img )
24 |
25 | #add portals between two fields (both directions)
26 | map.add_portal(Vector2i(25,60),Vector2i(80,44))
27 | map.add_portal(Vector2i(80,44),Vector2i(25,60))
28 |
29 | # create a penalty field for edge penalties
30 | # keeping entities from gliding along the walls
31 | var penalty_field:VFNModField = map.add_mod_field("margin")
32 | penalty_field.upmost = true
33 |
34 | # here is another penalty field as descriped in the readme
35 | # but its for later ... not now
36 | # occupied_field = map.add_mod_field("occupied")
37 | # occupied_field.dynamic = true
38 |
39 |
40 | # add some penalty margin arround cliffs in the created modField
41 | map.add_penalty_height_margin(penalty_field,3,10)
42 |
43 | # center the camera over the terrain
44 | $cam_base.position = Vector3(map.size.x/2, 0, map.size.y/2)
45 | # init the terrain collider
46 | $scenery/terrain/shape.shape.map_width = map.size.x
47 | $scenery/terrain/shape.shape.map_depth = map.size.y
48 | $scenery/terrain/shape.position = map.position * -1
49 |
50 | # create some units
51 | var u
52 | var _unit = load("res://addons/VectorFieldNavigation/examples/unit.tscn")
53 | for i in 100:
54 | u = _unit.instantiate()
55 | add_child(u)
56 | u.occupied_field = occupied_field
57 | u.linear_velocity = Vector3(randf_range(-1,1),randf_range(-1,1),randf_range(-1,1)) * 5
58 | u.linear_velocity = Vector3(0,0,0)
59 | u.position = Vector3(randi_range(10,map.size.x-10),10,randi_range(10,map.size.y-10))
60 |
61 | $scenery/terrain/shape.position = Vector3(map.size.x/2, 0, map.size.y/2)
62 | for x in map.size.x:
63 | for y in map.size.y:
64 | $scenery/terrain/shape.shape.map_data[x*map.size.x+y] = map.get_height(Vector2i(y,x)) * map.height_scale
65 |
66 | $scenery/terrain/mesh.scale.y = map.height_scale
67 | $scenery/terrain/mesh.mesh = create_heightmap_mesh( map.size.x, map.size.y, map )
68 |
69 |
70 | func _on_button_pressed():
71 | var map = $VectorMap
72 | if not field:
73 | #create a field
74 | field = map.create_field( )
75 | #connect units with the field
76 | var units = get_tree().get_nodes_in_group("unit")
77 | for unit in units:
78 | unit.field = field
79 |
80 | # if you want to weight the influence of a modfield you can do it like this
81 | field.set_modfield("margin",1) # factor 1 is default
82 |
83 | #comes later
84 | # occupied_field.clear()
85 |
86 | # set gui values to field modifiers
87 | field.effort_cutoff = $GUI.effort_cutoff
88 | field.climb_factor = $GUI.climb_factor
89 | field.climb_cutoff = $GUI.climb_cutoff
90 | field.drop_factor = $GUI.drop_factor
91 | field.drop_cutoff = $GUI.drop_cutoff
92 | field.field_effort_factor = $GUI.field_effort_factor
93 |
94 | # clear all assigned target nodes
95 | field.clear_targets()
96 |
97 | var pos:Vector2i
98 | if true:
99 | for i in $GUI.gen_targets:
100 | var h:float = 1
101 | while h > 0.1:
102 | pos.x = randi_range(10,map.size.x-10)
103 | pos.y = randi_range(10,map.size.y-10)
104 | h = map.get_height( pos )
105 | if h < 0.1:
106 | field.add_target( pos )
107 | else:
108 | field.add_target( Vector2i(105,15) )
109 |
110 | update = false
111 | field.calculate_threaded( self._on_calculated.bind(field), true )
112 |
113 |
114 | func _on_calculated( succesful, field ):
115 | if not succesful:
116 | return
117 | var tex
118 | $VectorMap.update_debug_mesh( field )
119 | tex = ImageTexture.create_from_image(field.get_target_heatmap())
120 | %TargetMap.texture = tex
121 | tex = ImageTexture.create_from_image(field.get_penalty_heatmap())
122 | %PenaltyMap.texture = tex
123 | tex = ImageTexture.create_from_image(field.get_effort_heatmap())
124 | %EffortMap.texture = tex
125 | $scenery/terrain/mesh.material_override.albedo_texture = %TargetMap.texture
126 |
127 | update = true
128 |
129 |
130 | func _process(delta):
131 | $cam_base.rotate_y(delta*0.05)
132 |
133 |
134 | func create_heightmap_mesh( _x:int, _y:int, heights=null ):
135 | var st:SurfaceTool = SurfaceTool.new()
136 |
137 | st.begin(Mesh.PRIMITIVE_TRIANGLES)
138 | var v:Vector3
139 | var h:float
140 | for x in _x-1:
141 | for y in _y-1:
142 | h = heights.get_height(Vector2i(x,y))
143 | v = Vector3(x,h,y)
144 | v.y = heights.get_height(Vector2i(v.x,v.z))
145 | st.set_uv(Vector2(v.x/_x,v.z/_y))
146 | st.add_vertex(v)
147 | v = Vector3(x+1,h,y)
148 | v.y = heights.get_height(Vector2i(v.x,v.z))
149 | st.set_uv(Vector2(v.x/_x,v.z/_y))
150 | st.add_vertex(v)
151 | v = Vector3(x+1,h,y+1)
152 | v.y = heights.get_height(Vector2i(v.x,v.z))
153 | st.set_uv(Vector2(v.x/_x,v.z/_y))
154 | st.add_vertex(v)
155 |
156 | v = Vector3(x,h,y)
157 | v.y = heights.get_height(Vector2i(v.x,v.z))
158 | st.set_uv(Vector2(v.x/_x,v.z/_y))
159 | st.add_vertex(v)
160 | v = Vector3(x+1,h,y+1)
161 | v.y = heights.get_height(Vector2i(v.x,v.z))
162 | st.set_uv(Vector2(v.x/_x,v.z/_y))
163 | st.add_vertex(v)
164 | v = Vector3(x,h,y+1)
165 | v.y = heights.get_height(Vector2i(v.x,v.z))
166 | st.set_uv(Vector2(v.x/_x,v.z/_y))
167 | st.add_vertex(v)
168 |
169 | st.generate_normals()
170 | st.generate_tangents()
171 | return st.commit()
172 |
173 |
174 | func _on_timer_timeout():
175 | #comes later
176 | return
177 | occupied_field.blur_fade(0.8)
178 | if update:
179 | update = false
180 | field.calculate_threaded( self._on_calculated.bind(field) )
181 |
182 |
--------------------------------------------------------------------------------
/addons/VectorFieldNavigation/examples/heightmap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/D2klaas/Godot-4-VectorFieldNavigation/1f266ab1532c7b7854ca9629a726352aaba966bc/addons/VectorFieldNavigation/examples/heightmap.png
--------------------------------------------------------------------------------
/addons/VectorFieldNavigation/examples/heightmap.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://3mxy8pc7xvjg"
6 | path="res://.godot/imported/heightmap.png-a2711110f4b5f8e5ce7d7f276b7e4533.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://addons/VectorFieldNavigation/examples/heightmap.png"
14 | dest_files=["res://.godot/imported/heightmap.png-a2711110f4b5f8e5ce7d7f276b7e4533.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 |
--------------------------------------------------------------------------------
/addons/VectorFieldNavigation/examples/screenshot.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/D2klaas/Godot-4-VectorFieldNavigation/1f266ab1532c7b7854ca9629a726352aaba966bc/addons/VectorFieldNavigation/examples/screenshot.jpg
--------------------------------------------------------------------------------
/addons/VectorFieldNavigation/examples/screenshot.jpg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://di43fwalowfca"
6 | path="res://.godot/imported/screenshot.jpg-a4b1e5d9395ca3a332a05d7f4038783a.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://addons/VectorFieldNavigation/examples/screenshot.jpg"
14 | dest_files=["res://.godot/imported/screenshot.jpg-a4b1e5d9395ca3a332a05d7f4038783a.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 |
--------------------------------------------------------------------------------
/addons/VectorFieldNavigation/examples/unit.gd:
--------------------------------------------------------------------------------
1 | extends RigidBody3D
2 |
3 |
4 | var max_speed:float = 5 + randf_range(-2,2)
5 | var vf_force:float = 80 + randf_range(-20,20)
6 | var field:VFNField
7 | var wiggle_force:float = 15
8 | var vf_vec:Vector3
9 | var just_teleported:bool = false
10 | var occupied_field:VFNModField
11 |
12 | func _ready():
13 | $Timer.wait_time = randf_range(0.5,1.0)
14 |
15 |
16 | # Called every frame. 'delta' is the elapsed time since the previous frame.
17 | func _physics_process(delta):
18 |
19 | ## when a field is calculated
20 | if field:
21 | #comes later
22 | # occupied_field.add_value_from_world( global_position, 0.5 )
23 | #get the smoothed navigation vector for this position
24 | vf_vec = field.get_vector_smooth_world(global_position)*vf_force
25 |
26 | if vf_vec.length() > 0.1:# if vector points anywhere ... push in this direction
27 | vf_vec.y = -10
28 | apply_central_force( vf_vec )
29 | else: #if the vector is ZERO push randomly
30 | apply_impulse( Vector3(randf_range(-1,1), 0, randf_range(-1,1))*wiggle_force )
31 |
32 | if global_position.y < -100: #when falling from table ... reset
33 | global_position = Vector3(10,3,10)
34 |
35 |
36 | func _integrate_forces(state):
37 | #limit the units speed
38 | state.linear_velocity = state.linear_velocity.limit_length( max_speed )
39 |
40 |
41 | func _on_timer_timeout():
42 | # add some wiggily motion
43 | var v:Vector3
44 | v = vf_vec.normalized()
45 | var v2:Vector3
46 | v2.x = v.z
47 | v2.z = v.x
48 | v2 *= randf_range(-wiggle_force,wiggle_force)
49 | apply_impulse( v2 )
50 |
--------------------------------------------------------------------------------
/addons/VectorFieldNavigation/examples/unit.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=7 format=3 uid="uid://bcvvvevh62vfq"]
2 |
3 | [ext_resource type="Script" path="res://addons/VectorFieldNavigation/examples/unit.gd" id="1_nd542"]
4 |
5 | [sub_resource type="PhysicsMaterial" id="PhysicsMaterial_p2swa"]
6 | friction = 0.0
7 |
8 | [sub_resource type="CapsuleShape3D" id="CapsuleShape3D_otaef"]
9 |
10 | [sub_resource type="SphereShape3D" id="SphereShape3D_pbmih"]
11 |
12 | [sub_resource type="StandardMaterial3D" id="StandardMaterial3D_jn7ln"]
13 | albedo_color = Color(1, 0.160784, 0.294118, 1)
14 |
15 | [sub_resource type="SphereMesh" id="SphereMesh_1hfm6"]
16 | radial_segments = 12
17 | rings = 6
18 |
19 | [node name="unit" type="RigidBody3D" groups=["unit"]]
20 | collision_layer = 3
21 | mass = 5.0
22 | physics_material_override = SubResource("PhysicsMaterial_p2swa")
23 | lock_rotation = true
24 | script = ExtResource("1_nd542")
25 |
26 | [node name="CollisionShape3D" type="CollisionShape3D" parent="."]
27 | transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, 0)
28 | visible = false
29 | shape = SubResource("CapsuleShape3D_otaef")
30 | disabled = true
31 |
32 | [node name="CollisionShape3D2" type="CollisionShape3D" parent="."]
33 | shape = SubResource("SphereShape3D_pbmih")
34 |
35 | [node name="MeshInstance3D" type="MeshInstance3D" parent="."]
36 | material_override = SubResource("StandardMaterial3D_jn7ln")
37 | mesh = SubResource("SphereMesh_1hfm6")
38 |
39 | [node name="Timer" type="Timer" parent="."]
40 | autostart = true
41 |
42 | [connection signal="timeout" from="Timer" to="." method="_on_timer_timeout"]
43 |
--------------------------------------------------------------------------------
/addons/VectorFieldNavigation/materials/matVectorFieldNavigationDebugMap.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="StandardMaterial3D" format=3 uid="uid://ccnt27v8357r8"]
2 |
3 | [resource]
4 | shading_mode = 0
5 | vertex_color_use_as_albedo = true
6 | vertex_color_is_srgb = true
7 | use_point_size = true
8 | point_size = 3.0
9 |
--------------------------------------------------------------------------------
/addons/VectorFieldNavigation/plugin.cfg:
--------------------------------------------------------------------------------
1 | [plugin]
2 |
3 | name="VectorFieldNavigation"
4 | description="Planar navigation-system for hordes based on a vector field."
5 | author="Klaas Janneck"
6 | version="0.1"
7 | script="plugin.gd"
8 |
--------------------------------------------------------------------------------
/addons/VectorFieldNavigation/plugin.gd:
--------------------------------------------------------------------------------
1 | @tool
2 | extends EditorPlugin
3 |
4 |
5 | func _enter_tree():
6 | add_custom_type("VFNMap","Node3D",preload("res://addons/VectorFieldNavigation/classes/VFNMap.gd"),preload("res://addons/VectorFieldNavigation/vfn_icon_mono.png"))
7 |
8 |
9 | func _exit_tree():
10 | remove_custom_type("VFNMap")
11 |
--------------------------------------------------------------------------------
/addons/VectorFieldNavigation/vfn_icon.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
40 |
--------------------------------------------------------------------------------
/addons/VectorFieldNavigation/vfn_icon.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://dumru3c4g4o3n"
6 | path="res://.godot/imported/vfn_icon.svg-e146a8e0d2656fd8627b9de169d653eb.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://addons/VectorFieldNavigation/vfn_icon.svg"
14 | dest_files=["res://.godot/imported/vfn_icon.svg-e146a8e0d2656fd8627b9de169d653eb.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 | svg/scale=1.0
36 | editor/scale_with_editor_scale=false
37 | editor/convert_colors_with_editor_theme=false
38 |
--------------------------------------------------------------------------------
/addons/VectorFieldNavigation/vfn_icon_mono.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/D2klaas/Godot-4-VectorFieldNavigation/1f266ab1532c7b7854ca9629a726352aaba966bc/addons/VectorFieldNavigation/vfn_icon_mono.png
--------------------------------------------------------------------------------
/addons/VectorFieldNavigation/vfn_icon_mono.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://xv7ru8m3uikd"
6 | path="res://.godot/imported/vfn_icon_mono.png-6a4953739654325b23509f5024933161.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://addons/VectorFieldNavigation/vfn_icon_mono.png"
14 | dest_files=["res://.godot/imported/vfn_icon_mono.png-6a4953739654325b23509f5024933161.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 |
--------------------------------------------------------------------------------
/addons/VectorFieldNavigation/vfn_icon_mono.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
30 |
--------------------------------------------------------------------------------
/addons/VectorFieldNavigation/vfn_icon_mono.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://6nlrpnom20g5"
6 | path="res://.godot/imported/vfn_icon_mono.svg-2f436902d45be9ae8fb57a56d7e703b1.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://addons/VectorFieldNavigation/vfn_icon_mono.svg"
14 | dest_files=["res://.godot/imported/vfn_icon_mono.svg-2f436902d45be9ae8fb57a56d7e703b1.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 | svg/scale=1.0
36 | editor/scale_with_editor_scale=false
37 | editor/convert_colors_with_editor_theme=false
38 |
--------------------------------------------------------------------------------