├── .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 | ![alt text](https://github.com/D2klaas/Godot-4-VectorFieldNavigation/blob/main/addons/VectorFieldNavigation/examples/screenshot.jpg?raw=true) 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 | ![one](/addons/VectorFieldNavigation/docs/ex_spreading_forces_1.jpg) 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 | ![one](/addons/VectorFieldNavigation/docs/ex_spreading_forces_2.jpg) 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 | ![one](/addons/VectorFieldNavigation/docs/ex_spreading_forces_3.jpg) 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 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 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 | 4 | 5 | 6 | 7 | 8 | VFN 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 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 | --------------------------------------------------------------------------------