summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitattributes2
-rw-r--r--.gitignore3
-rw-r--r--Readme.md2
-rw-r--r--icon.svg1
-rw-r--r--icon.svg.import38
-rw-r--r--main.tscn9
-rw-r--r--project.godot87
-rw-r--r--stage/assets/isometric-tile.krabin0 -> 56615 bytes
-rw-r--r--stage/assets/isometric-tile.kra~bin0 -> 58031 bytes
-rw-r--r--stage/assets/isometric-tile.pngbin0 -> 163 bytes
-rw-r--r--stage/assets/isometric-tile.png.import34
-rw-r--r--stage/assets/isometric-tile.png~bin0 -> 162 bytes
-rw-r--r--stage/assets/tilemap.tres194
-rw-r--r--stage/assets/tinyBlocks.pngbin0 -> 16548 bytes
-rw-r--r--stage/assets/tinyBlocks.png.import35
-rw-r--r--stage/assets/tinyBlocks.png~bin0 -> 16521 bytes
-rw-r--r--stage/dice_throw/dice.gd19
-rw-r--r--stage/dice_throw/dice.tscn74
-rw-r--r--stage/dice_throw/dice_throw.tscn66
-rw-r--r--stage/dice_throw/dice_throw_3d.gd11
-rw-r--r--stage/dice_throw/dice_throw_3d.tscn34
-rw-r--r--stage/grid_selector/grid_selector.gd108
-rw-r--r--stage/grid_selector/grid_selector.tscn85
-rw-r--r--stage/grid_selector/grid_selector_item.gdshader72
-rw-r--r--stage/grid_selector/state_cube_placement.gd241
-rw-r--r--stage/grid_selector/state_move_mode.gd75
-rw-r--r--stage/grid_selector/state_select.gd43
-rw-r--r--stage/hud.gd42
-rw-r--r--stage/stage.gd64
-rw-r--r--stage/stage.tscn62
-rw-r--r--unit/unit.tscn20
31 files changed, 1421 insertions, 0 deletions
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..8ad74f7
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,2 @@
+# Normalize EOL for all files that Git considers text files.
+* text=auto eol=lf
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..0af181c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+# Godot 4+ specific ignores
+.godot/
+/android/
diff --git a/Readme.md b/Readme.md
new file mode 100644
index 0000000..136c25b
--- /dev/null
+++ b/Readme.md
@@ -0,0 +1,2 @@
+Try this:
+ - https://agatedragon.blog/2024/02/12/simple-outline-shader/
diff --git a/icon.svg b/icon.svg
new file mode 100644
index 0000000..9d8b7fa
--- /dev/null
+++ b/icon.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128"><rect width="124" height="124" x="2" y="2" fill="#363d52" stroke="#212532" stroke-width="4" rx="14"/><g fill="#fff" transform="translate(12.322 12.322)scale(.101)"><path d="M105 673v33q407 354 814 0v-33z"/><path fill="#478cbf" d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 814 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H446l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z"/><path d="M483 600c0 34 58 34 58 0v-86c0-34-58-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042" transform="translate(12.322 12.322)scale(.101)"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></svg> \ No newline at end of file
diff --git a/icon.svg.import b/icon.svg.import
new file mode 100644
index 0000000..f230239
--- /dev/null
+++ b/icon.svg.import
@@ -0,0 +1,38 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://blanietpri1be"
+path.s3tc="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://icon.svg"
+dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
+svg/scale=1.0
+editor/scale_with_editor_scale=false
+editor/convert_colors_with_editor_theme=false
diff --git a/main.tscn b/main.tscn
new file mode 100644
index 0000000..cfae400
--- /dev/null
+++ b/main.tscn
@@ -0,0 +1,9 @@
+[gd_scene format=3 uid="uid://c3sdm0knce1fx"]
+
+[node name="Main" type="Control"]
+layout_mode = 3
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
diff --git a/project.godot b/project.godot
new file mode 100644
index 0000000..2f60eae
--- /dev/null
+++ b/project.godot
@@ -0,0 +1,87 @@
+; Engine configuration file.
+; It's best edited using the editor UI and not directly,
+; since the parameters that go here are not all obvious.
+;
+; Format:
+; [section] ; section goes between []
+; param=value ; assign values to parameters
+
+config_version=5
+
+[application]
+
+config/name="Dice Arena"
+run/main_scene="res://stage/stage.tscn"
+config/features=PackedStringArray("4.3", "GL Compatibility")
+config/icon="res://icon.svg"
+
+[display]
+
+window/size/viewport_width=480
+window/size/viewport_height=320
+window/stretch/mode="viewport"
+
+[input]
+
+right_click={
+"deadzone": 0.5,
+"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":2,"position":Vector2(299, 17),"global_position":Vector2(308, 63),"factor":1.0,"button_index":2,"canceled":false,"pressed":true,"double_click":false,"script":null)
+, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":1,"pressure":0.0,"pressed":true,"script":null)
+]
+}
+next_rotation={
+"deadzone": 0.5,
+"events": [Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":10,"pressure":0.0,"pressed":true,"script":null)
+]
+}
+previous_rotation={
+"deadzone": 0.5,
+"events": [Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":9,"pressure":0.0,"pressed":true,"script":null)
+]
+}
+next_cube_pattern={
+"deadzone": 0.5,
+"events": [Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":5,"axis_value":1.0,"script":null)
+]
+}
+previous_cube_pattern={
+"deadzone": 0.5,
+"events": [Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":4,"axis_value":1.0,"script":null)
+]
+}
+left_click={
+"deadzone": 0.5,
+"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":1,"position":Vector2(207, 13),"global_position":Vector2(216, 59),"factor":1.0,"button_index":1,"canceled":false,"pressed":true,"double_click":false,"script":null)
+, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":0,"pressure":0.0,"pressed":true,"script":null)
+]
+}
+test_1={
+"deadzone": 0.5,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":88,"key_label":0,"unicode":120,"location":0,"echo":false,"script":null)
+]
+}
+test_2={
+"deadzone": 0.5,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":90,"key_label":0,"unicode":121,"location":0,"echo":false,"script":null)
+]
+}
+test_3={
+"deadzone": 0.5,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":89,"key_label":0,"unicode":122,"location":0,"echo":false,"script":null)
+, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":4,"pressure":0.0,"pressed":true,"script":null)
+]
+}
+test_4={
+"deadzone": 0.5,
+"events": [Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":6,"pressure":0.0,"pressed":true,"script":null)
+]
+}
+
+[layer_names]
+
+2d_physics/layer_2="Units"
+
+[rendering]
+
+renderer/rendering_method="gl_compatibility"
+renderer/rendering_method.mobile="gl_compatibility"
diff --git a/stage/assets/isometric-tile.kra b/stage/assets/isometric-tile.kra
new file mode 100644
index 0000000..0f03d9f
--- /dev/null
+++ b/stage/assets/isometric-tile.kra
Binary files differ
diff --git a/stage/assets/isometric-tile.kra~ b/stage/assets/isometric-tile.kra~
new file mode 100644
index 0000000..92e834f
--- /dev/null
+++ b/stage/assets/isometric-tile.kra~
Binary files differ
diff --git a/stage/assets/isometric-tile.png b/stage/assets/isometric-tile.png
new file mode 100644
index 0000000..bf4d433
--- /dev/null
+++ b/stage/assets/isometric-tile.png
Binary files differ
diff --git a/stage/assets/isometric-tile.png.import b/stage/assets/isometric-tile.png.import
new file mode 100644
index 0000000..9093036
--- /dev/null
+++ b/stage/assets/isometric-tile.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://db0v50mdroaox"
+path="res://.godot/imported/isometric-tile.png-02c0183bb902cd3a77d9e77a290e5ca2.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://stage/assets/isometric-tile.png"
+dest_files=["res://.godot/imported/isometric-tile.png-02c0183bb902cd3a77d9e77a290e5ca2.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
diff --git a/stage/assets/isometric-tile.png~ b/stage/assets/isometric-tile.png~
new file mode 100644
index 0000000..107a521
--- /dev/null
+++ b/stage/assets/isometric-tile.png~
Binary files differ
diff --git a/stage/assets/tilemap.tres b/stage/assets/tilemap.tres
new file mode 100644
index 0000000..469dddd
--- /dev/null
+++ b/stage/assets/tilemap.tres
@@ -0,0 +1,194 @@
+[gd_resource type="TileSet" load_steps=3 format=3 uid="uid://dl0umywqpu3m8"]
+
+[ext_resource type="Texture2D" uid="uid://dtltt171temec" path="res://stage/assets/tinyBlocks.png" id="1_jgpum"]
+
+[sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_02yrw"]
+texture = ExtResource("1_jgpum")
+texture_region_size = Vector2i(18, 18)
+0:0/0 = 0
+0:0/0/texture_origin = Vector2i(0, -5)
+1:0/0 = 0
+1:0/0/texture_origin = Vector2i(0, -5)
+2:0/0 = 0
+2:0/0/texture_origin = Vector2i(0, -5)
+3:0/0 = 0
+3:0/0/texture_origin = Vector2i(0, -5)
+4:0/0 = 0
+4:0/0/texture_origin = Vector2i(0, -5)
+5:0/0 = 0
+5:0/0/texture_origin = Vector2i(0, -5)
+6:0/0 = 0
+6:0/0/texture_origin = Vector2i(0, -5)
+7:0/0 = 0
+7:0/0/texture_origin = Vector2i(0, -5)
+8:0/0 = 0
+8:0/0/texture_origin = Vector2i(0, -5)
+0:1/0 = 0
+0:1/0/texture_origin = Vector2i(0, -5)
+1:1/0 = 0
+1:1/0/texture_origin = Vector2i(0, -5)
+2:1/0 = 0
+2:1/0/texture_origin = Vector2i(0, -1)
+3:1/0 = 0
+3:1/0/texture_origin = Vector2i(0, -5)
+4:1/0 = 0
+4:1/0/texture_origin = Vector2i(0, -5)
+5:1/0 = 0
+5:1/0/texture_origin = Vector2i(0, -1)
+6:1/0 = 0
+6:1/0/texture_origin = Vector2i(0, -5)
+7:1/0 = 0
+7:1/0/texture_origin = Vector2i(0, 3)
+8:1/0 = 0
+8:1/0/texture_origin = Vector2i(0, -5)
+9:1/0 = 0
+9:1/0/texture_origin = Vector2i(0, -5)
+0:2/0 = 0
+0:2/0/texture_origin = Vector2i(0, -5)
+1:2/0 = 0
+1:2/0/texture_origin = Vector2i(0, -5)
+2:2/0 = 0
+2:2/0/texture_origin = Vector2i(0, -1)
+3:2/0 = 0
+3:2/0/texture_origin = Vector2i(0, -5)
+4:2/0 = 0
+4:2/0/texture_origin = Vector2i(0, -3)
+5:2/0 = 0
+5:2/0/texture_origin = Vector2i(0, -5)
+6:2/0 = 0
+6:2/0/texture_origin = Vector2i(0, -3)
+7:2/0 = 0
+7:2/0/texture_origin = Vector2i(0, -5)
+8:2/0 = 0
+8:2/0/texture_origin = Vector2i(0, -3)
+0:3/0 = 0
+0:3/0/texture_origin = Vector2i(0, -5)
+1:3/0 = 0
+1:3/0/texture_origin = Vector2i(0, -5)
+2:3/0 = 0
+2:3/0/texture_origin = Vector2i(0, -1)
+3:3/0 = 0
+3:3/0/texture_origin = Vector2i(0, -5)
+4:3/0 = 0
+4:3/0/texture_origin = Vector2i(0, -5)
+5:3/0 = 0
+5:3/0/texture_origin = Vector2i(0, -1)
+6:3/0 = 0
+6:3/0/texture_origin = Vector2i(0, -5)
+7:3/0 = 0
+7:3/0/texture_origin = Vector2i(0, -5)
+8:3/0 = 0
+0:4/0 = 0
+0:4/0/texture_origin = Vector2i(0, -5)
+1:4/0 = 0
+1:4/0/texture_origin = Vector2i(0, -5)
+2:4/0 = 0
+2:4/0/texture_origin = Vector2i(0, -5)
+3:4/0 = 0
+3:4/0/texture_origin = Vector2i(0, -5)
+4:4/0 = 0
+4:4/0/texture_origin = Vector2i(0, -5)
+5:4/0 = 0
+5:4/0/texture_origin = Vector2i(0, -5)
+6:4/0 = 0
+6:4/0/texture_origin = Vector2i(0, -5)
+7:4/0 = 0
+7:4/0/texture_origin = Vector2i(0, -5)
+8:4/0 = 0
+8:4/0/texture_origin = Vector2i(0, -5)
+0:5/0 = 0
+0:5/0/texture_origin = Vector2i(0, -5)
+1:5/0 = 0
+1:5/0/texture_origin = Vector2i(0, -5)
+2:5/0 = 0
+2:5/0/texture_origin = Vector2i(0, -5)
+3:5/0 = 0
+3:5/0/texture_origin = Vector2i(0, -5)
+4:5/0 = 0
+4:5/0/texture_origin = Vector2i(0, -5)
+5:5/0 = 0
+5:5/0/texture_origin = Vector2i(0, -5)
+6:5/0 = 0
+6:5/0/texture_origin = Vector2i(0, -5)
+7:5/0 = 0
+7:5/0/texture_origin = Vector2i(0, -5)
+8:5/0 = 0
+8:5/0/texture_origin = Vector2i(0, -5)
+0:6/0 = 0
+0:6/0/texture_origin = Vector2i(0, -5)
+1:6/0 = 0
+1:6/0/texture_origin = Vector2i(0, -1)
+1:6/0/custom_data_0 = "1"
+2:6/0 = 0
+2:6/0/texture_origin = Vector2i(0, -5)
+3:6/0 = 0
+3:6/0/texture_origin = Vector2i(0, -1)
+3:6/0/custom_data_0 = "2"
+4:6/0 = 0
+4:6/0/texture_origin = Vector2i(0, -5)
+5:6/0 = 0
+5:6/0/texture_origin = Vector2i(0, -1)
+6:6/0 = 0
+6:6/0/texture_origin = Vector2i(0, -5)
+7:6/0 = 0
+7:6/0/texture_origin = Vector2i(0, -1)
+0:7/0 = 0
+0:7/0/texture_origin = Vector2i(0, -5)
+1:7/0 = 0
+2:7/0 = 0
+2:7/0/texture_origin = Vector2i(0, -5)
+3:7/0 = 0
+3:7/0/texture_origin = Vector2i(0, -1)
+4:7/0 = 0
+4:7/0/texture_origin = Vector2i(0, -5)
+5:7/0 = 0
+5:7/0/texture_origin = Vector2i(0, -1)
+6:7/0 = 0
+6:7/0/texture_origin = Vector2i(0, -5)
+7:7/0 = 0
+7:7/0/texture_origin = Vector2i(0, -1)
+9:7/0 = 0
+0:8/0 = 0
+0:8/0/texture_origin = Vector2i(0, -5)
+1:8/0 = 0
+1:8/0/texture_origin = Vector2i(0, -5)
+2:8/0 = 0
+2:8/0/texture_origin = Vector2i(0, -5)
+3:8/0 = 0
+3:8/0/texture_origin = Vector2i(0, -5)
+4:8/0 = 0
+4:8/0/texture_origin = Vector2i(0, -5)
+5:8/0 = 0
+5:8/0/texture_origin = Vector2i(0, -5)
+6:8/0 = 0
+6:8/0/texture_origin = Vector2i(0, -5)
+8:8/0 = 0
+8:8/0/texture_origin = Vector2i(0, -5)
+9:8/0 = 0
+9:8/0/texture_origin = Vector2i(0, -5)
+0:9/0 = 0
+0:9/0/texture_origin = Vector2i(0, -5)
+1:9/0 = 0
+1:9/0/texture_origin = Vector2i(0, -5)
+2:9/0 = 0
+2:9/0/texture_origin = Vector2i(0, -5)
+3:9/0 = 0
+3:9/0/texture_origin = Vector2i(0, -5)
+4:9/0 = 0
+4:9/0/texture_origin = Vector2i(0, -5)
+5:9/0 = 0
+5:9/0/texture_origin = Vector2i(0, -5)
+6:9/0 = 0
+6:9/0/texture_origin = Vector2i(0, -5)
+8:9/0 = 0
+8:9/0/texture_origin = Vector2i(0, -5)
+9:9/0 = 0
+9:9/0/texture_origin = Vector2i(0, -5)
+
+[resource]
+tile_shape = 1
+tile_layout = 5
+tile_size = Vector2i(16, 8)
+custom_data_layer_0/name = "team"
+custom_data_layer_0/type = 4
+sources/1 = SubResource("TileSetAtlasSource_02yrw")
diff --git a/stage/assets/tinyBlocks.png b/stage/assets/tinyBlocks.png
new file mode 100644
index 0000000..7d0a964
--- /dev/null
+++ b/stage/assets/tinyBlocks.png
Binary files differ
diff --git a/stage/assets/tinyBlocks.png.import b/stage/assets/tinyBlocks.png.import
new file mode 100644
index 0000000..30cb612
--- /dev/null
+++ b/stage/assets/tinyBlocks.png.import
@@ -0,0 +1,35 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dtltt171temec"
+path.s3tc="res://.godot/imported/tinyBlocks.png-1cc999784a8c355a5b508974705cefda.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://stage/assets/tinyBlocks.png"
+dest_files=["res://.godot/imported/tinyBlocks.png-1cc999784a8c355a5b508974705cefda.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/stage/assets/tinyBlocks.png~ b/stage/assets/tinyBlocks.png~
new file mode 100644
index 0000000..c10c38a
--- /dev/null
+++ b/stage/assets/tinyBlocks.png~
Binary files differ
diff --git a/stage/dice_throw/dice.gd b/stage/dice_throw/dice.gd
new file mode 100644
index 0000000..127d968
--- /dev/null
+++ b/stage/dice_throw/dice.gd
@@ -0,0 +1,19 @@
+extends RigidBody3D
+
+
+func roll(direction := Vector3(1.0, 1.0, 1.0), strength: float = 20) -> void:
+ var position_impulse := Vector3(
+ [-1, 1].pick_random(),
+ randf_range(0.5, 1.0),
+ [-1, 1].pick_random()
+ )
+
+ apply_central_impulse(position_impulse.normalized() * direction * strength)
+
+ var rotation_impulse := Vector3(
+ [-1, 1].pick_random(),
+ [-1, 1].pick_random(),
+ [-1, 1].pick_random()
+ )
+
+ apply_torque_impulse(rotation_impulse.normalized())
diff --git a/stage/dice_throw/dice.tscn b/stage/dice_throw/dice.tscn
new file mode 100644
index 0000000..14f28b7
--- /dev/null
+++ b/stage/dice_throw/dice.tscn
@@ -0,0 +1,74 @@
+[gd_scene load_steps=12 format=3 uid="uid://dnq7fpof6w0mj"]
+
+[ext_resource type="Script" path="res://stage/dice_throw/dice.gd" id="1_gwnix"]
+[ext_resource type="Texture2D" uid="uid://blanietpri1be" path="res://icon.svg" id="2_6tbdd"]
+[ext_resource type="Texture2D" uid="uid://dtltt171temec" path="res://stage/assets/tinyBlocks.png" id="3_t0umq"]
+
+[sub_resource type="PhysicsMaterial" id="PhysicsMaterial_m7tx2"]
+bounce = 0.5
+
+[sub_resource type="BoxMesh" id="BoxMesh_gof22"]
+
+[sub_resource type="BoxShape3D" id="BoxShape3D_tqijt"]
+
+[sub_resource type="AtlasTexture" id="AtlasTexture_0hsac"]
+atlas = ExtResource("3_t0umq")
+region = Rect2(0, 18, 18, 18)
+
+[sub_resource type="AtlasTexture" id="AtlasTexture_2rcxj"]
+atlas = ExtResource("3_t0umq")
+region = Rect2(90, 36, 18, 18)
+
+[sub_resource type="AtlasTexture" id="AtlasTexture_l100r"]
+atlas = ExtResource("3_t0umq")
+region = Rect2(54, 72, 18, 18)
+
+[sub_resource type="AtlasTexture" id="AtlasTexture_l8don"]
+atlas = ExtResource("3_t0umq")
+region = Rect2(90, 90, 18, 18)
+
+[sub_resource type="AtlasTexture" id="AtlasTexture_ug301"]
+atlas = ExtResource("3_t0umq")
+region = Rect2(72, 144, 18, 18)
+
+[node name="Dice" type="RigidBody3D"]
+physics_material_override = SubResource("PhysicsMaterial_m7tx2")
+gravity_scale = 2.0
+script = ExtResource("1_gwnix")
+
+[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
+mesh = SubResource("BoxMesh_gof22")
+
+[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
+shape = SubResource("BoxShape3D_tqijt")
+
+[node name="Faces" type="Node3D" parent="."]
+
+[node name="Sprite3D" type="Sprite3D" parent="Faces"]
+transform = Transform3D(0.7, 0, 0, 0, 0.7, 0, 0, 0, 0.7, 0, 0, 0.51)
+texture = ExtResource("2_6tbdd")
+
+[node name="Sprite3D2" type="Sprite3D" parent="Faces"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -0.51)
+pixel_size = 0.05
+texture = SubResource("AtlasTexture_0hsac")
+
+[node name="Sprite3D3" type="Sprite3D" parent="Faces"]
+transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 0.51, 0, 0)
+pixel_size = 0.05
+texture = SubResource("AtlasTexture_2rcxj")
+
+[node name="Sprite3D4" type="Sprite3D" parent="Faces"]
+transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -0.51, 0, 0)
+pixel_size = 0.05
+texture = SubResource("AtlasTexture_l100r")
+
+[node name="Sprite3D5" type="Sprite3D" parent="Faces"]
+transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0.51, 0)
+pixel_size = 0.05
+texture = SubResource("AtlasTexture_l8don")
+
+[node name="Sprite3D6" type="Sprite3D" parent="Faces"]
+transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, -0.51, 0)
+pixel_size = 0.05
+texture = SubResource("AtlasTexture_ug301")
diff --git a/stage/dice_throw/dice_throw.tscn b/stage/dice_throw/dice_throw.tscn
new file mode 100644
index 0000000..1311285
--- /dev/null
+++ b/stage/dice_throw/dice_throw.tscn
@@ -0,0 +1,66 @@
+[gd_scene load_steps=5 format=3 uid="uid://dsy8atabknch"]
+
+[ext_resource type="PackedScene" uid="uid://dlkds7l1kw468" path="res://stage/dice_throw/dice_throw_3d.tscn" id="1_mg5cv"]
+
+[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_cqep4"]
+sky_horizon_color = Color(0.64625, 0.65575, 0.67075, 1)
+ground_horizon_color = Color(0.64625, 0.65575, 0.67075, 1)
+
+[sub_resource type="Sky" id="Sky_ij08j"]
+sky_material = SubResource("ProceduralSkyMaterial_cqep4")
+
+[sub_resource type="Environment" id="Environment_sn6lt"]
+background_mode = 2
+sky = SubResource("Sky_ij08j")
+tonemap_mode = 2
+
+[node name="DiceThrow" type="Control"]
+layout_mode = 3
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+
+[node name="HBoxContainer" type="HBoxContainer" parent="."]
+layout_mode = 1
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+
+[node name="PanelContainer" type="PanelContainer" parent="HBoxContainer"]
+layout_mode = 2
+
+[node name="VBoxContainer" type="VBoxContainer" parent="HBoxContainer/PanelContainer"]
+layout_mode = 2
+
+[node name="Label" type="Label" parent="HBoxContainer/PanelContainer/VBoxContainer"]
+layout_mode = 2
+text = "Movement Points"
+
+[node name="SubViewportContainer" type="SubViewportContainer" parent="HBoxContainer"]
+layout_mode = 2
+size_flags_horizontal = 3
+stretch = true
+
+[node name="SubViewport" type="SubViewport" parent="HBoxContainer/SubViewportContainer"]
+transparent_bg = true
+handle_input_locally = false
+size = Vector2i(340, 320)
+render_target_update_mode = 4
+
+[node name="DiceThrow3D" parent="HBoxContainer/SubViewportContainer/SubViewport" instance=ExtResource("1_mg5cv")]
+
+[node name="Camera3D" type="Camera3D" parent="HBoxContainer/SubViewportContainer/SubViewport"]
+transform = Transform3D(1, 0, 0, 0, 0.866025, 0.5, 0, -0.5, 0.866025, 0, 9, 10)
+projection = 1
+size = 10.0
+
+[node name="WorldEnvironment" type="WorldEnvironment" parent="HBoxContainer/SubViewportContainer/SubViewport"]
+environment = SubResource("Environment_sn6lt")
+
+[node name="DirectionalLight3D" type="DirectionalLight3D" parent="HBoxContainer/SubViewportContainer/SubViewport"]
+transform = Transform3D(1, 0, 0, 0, 0.173648, 0.984808, 0, -0.984808, 0.173648, 0, 25, 0)
+shadow_enabled = true
diff --git a/stage/dice_throw/dice_throw_3d.gd b/stage/dice_throw/dice_throw_3d.gd
new file mode 100644
index 0000000..c5734a0
--- /dev/null
+++ b/stage/dice_throw/dice_throw_3d.gd
@@ -0,0 +1,11 @@
+extends Node3D
+
+
+# Called when the node enters the scene tree for the first time.
+func _ready() -> void:
+ $Dice.roll()
+
+
+func _process(_delta: float) -> void:
+ if Input.is_action_just_pressed("ui_accept"):
+ $Dice.roll(Vector3(1,1,0))
diff --git a/stage/dice_throw/dice_throw_3d.tscn b/stage/dice_throw/dice_throw_3d.tscn
new file mode 100644
index 0000000..15be9f5
--- /dev/null
+++ b/stage/dice_throw/dice_throw_3d.tscn
@@ -0,0 +1,34 @@
+[gd_scene load_steps=4 format=3 uid="uid://dlkds7l1kw468"]
+
+[ext_resource type="PackedScene" uid="uid://dnq7fpof6w0mj" path="res://stage/dice_throw/dice.tscn" id="1_ovyq0"]
+[ext_resource type="Script" path="res://stage/dice_throw/dice_throw_3d.gd" id="1_w4qjs"]
+
+[sub_resource type="BoxShape3D" id="BoxShape3D_pbdn1"]
+size = Vector3(10, 0.1, 10)
+
+[node name="DiceThrow3D" type="Node3D"]
+script = ExtResource("1_w4qjs")
+
+[node name="StaticBody3D" type="StaticBody3D" parent="."]
+
+[node name="CollisionShape3D" type="CollisionShape3D" parent="StaticBody3D"]
+shape = SubResource("BoxShape3D_pbdn1")
+
+[node name="CollisionShape3D4" type="CollisionShape3D" parent="StaticBody3D"]
+transform = Transform3D(-4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0, 0, 1, 5, 5, 0)
+shape = SubResource("BoxShape3D_pbdn1")
+
+[node name="CollisionShape3D5" type="CollisionShape3D" parent="StaticBody3D"]
+transform = Transform3D(-4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0, 0, 1, -5, 5, 0)
+shape = SubResource("BoxShape3D_pbdn1")
+
+[node name="CollisionShape3D2" type="CollisionShape3D" parent="StaticBody3D"]
+transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 5, 5)
+shape = SubResource("BoxShape3D_pbdn1")
+
+[node name="CollisionShape3D3" type="CollisionShape3D" parent="StaticBody3D"]
+transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 5, -5)
+shape = SubResource("BoxShape3D_pbdn1")
+
+[node name="Dice" parent="." instance=ExtResource("1_ovyq0")]
+transform = Transform3D(1, 0, 0, 0, 0.707107, -0.707107, 0, 0.707107, 0.707107, 0, 2.83258, -2)
diff --git a/stage/grid_selector/grid_selector.gd b/stage/grid_selector/grid_selector.gd
new file mode 100644
index 0000000..20c4a3a
--- /dev/null
+++ b/stage/grid_selector/grid_selector.gd
@@ -0,0 +1,108 @@
+class_name GridSelector
+extends Node2D
+
+
+signal selected(node: Node2D)
+signal placed_tiles(grid_positions: Array)
+signal move_mode_confirmed(path: Array)
+signal move_mode_exited
+
+var movement_delta := 0.0
+var movement_delta_threshold := 0.0
+var movement_delta_speed := 8.0
+var movement_delta_speed_fast := 4.0
+var movement_delta_speed_increase_threshold := 0.5
+
+var base_position: Vector2
+
+var current_state: Node:
+ set = set_current_state
+
+@export var stage: Stage
+@export var ground_map: TileMapLayer
+@export var floor_map: TileMapLayer
+@export_flags_2d_physics var selection_collision_mask: int
+@export var current_team: String
+@export_group("Placement Tile", "placement_tile")
+@export var placement_tile_source_id: int
+@export var placement_tile_atlas_coordinates: Vector2i
+@export var placement_tile_alternative_tile: int
+
+@onready var visual: Node2D = $Visual
+
+
+func _ready() -> void:
+ # set necessary y-sort values
+ get_parent().y_sort_enabled = true
+ ground_map.z_index = -1
+ floor_map.y_sort_enabled = true
+
+ # set state
+ current_state = $StateSelect
+
+
+func _process(delta: float) -> void:
+ # rounded vector because we don't want it to be normalized diagonally
+ var input_vector := Input.get_vector("ui_up", "ui_down", "ui_right", "ui_left").round()
+ if input_vector != Vector2.ZERO:
+ movement_delta += delta
+ if movement_delta_threshold < movement_delta:
+ if movement_delta_speed_increase_threshold < movement_delta:
+ movement_delta_threshold += delta * movement_delta_speed_fast
+ else:
+ movement_delta_threshold += delta * movement_delta_speed
+
+ current_state.draw(ground_map.local_to_map(base_position) + Vector2i(input_vector))
+ else:
+ movement_delta = 0
+ movement_delta_threshold = 0
+
+
+func _input(event: InputEvent) -> void:
+ if event.is_action_pressed("test_3"):
+ var states := [$StateSelect, $StateCubePlacement]
+ current_state = states[(states.find(current_state) + 1) % states.size()]
+ if event.is_action_pressed("test_4"):
+ var teams := ["1", "2"]
+ var tiles := [Vector2i(1,6), Vector2i(3,6)]
+ placement_tile_atlas_coordinates = tiles[(tiles.find(placement_tile_atlas_coordinates) + 1) % tiles.size()]
+ current_team = teams[(teams.find(current_team) + 1) % teams.size()]
+
+
+func set_current_state(value: Node):
+ if current_state:
+ current_state._state_exit()
+ current_state.process_mode = Node.PROCESS_MODE_DISABLED
+ current_state = value
+ value.process_mode = Node.PROCESS_MODE_INHERIT
+ current_state._state_enter()
+
+
+func adjust_height(tile: Sprite2D) -> void:
+ var tile_size: Vector2i = ground_map.tile_set.tile_size
+ var tile_data: TileData = floor_map.get_cell_tile_data(ground_map.local_to_map(tile.global_position))
+
+ if tile_data != null:
+ tile.global_position.y -= tile_size.y * 0.5
+ tile.offset.y = 0
+ tile.z_index = 1
+ else:
+ tile.global_position.y -= 1
+ tile.offset.y = 1
+ tile.z_index = 0
+
+
+func _on_state_select_selected(node: Node2D) -> void:
+ selected.emit(node)
+
+
+func _on_state_cube_placement_placed_tiles(grid_positions: Array) -> void:
+ placed_tiles.emit(grid_positions)
+
+
+func _on_state_move_mode_confirmed(path: Array) -> void:
+ move_mode_confirmed.emit(path)
+
+
+func _on_state_move_mode_exited() -> void:
+ move_mode_exited.emit()
diff --git a/stage/grid_selector/grid_selector.tscn b/stage/grid_selector/grid_selector.tscn
new file mode 100644
index 0000000..49d416d
--- /dev/null
+++ b/stage/grid_selector/grid_selector.tscn
@@ -0,0 +1,85 @@
+[gd_scene load_steps=8 format=3 uid="uid://dfhnxccd41wo0"]
+
+[ext_resource type="Shader" path="res://stage/grid_selector/grid_selector_item.gdshader" id="1_3nh1t"]
+[ext_resource type="Script" path="res://stage/grid_selector/grid_selector.gd" id="1_3pk7u"]
+[ext_resource type="Texture2D" uid="uid://db0v50mdroaox" path="res://stage/assets/isometric-tile.png" id="2_jd6wm"]
+[ext_resource type="Script" path="res://stage/grid_selector/state_cube_placement.gd" id="4_bapxq"]
+[ext_resource type="Script" path="res://stage/grid_selector/state_select.gd" id="5_wl8h0"]
+[ext_resource type="Script" path="res://stage/grid_selector/state_move_mode.gd" id="6_w3vtp"]
+
+[sub_resource type="ShaderMaterial" id="ShaderMaterial_2b8fn"]
+shader = ExtResource("1_3nh1t")
+shader_parameter/color = Color(9.14484e-06, 0.808187, 0, 1)
+shader_parameter/color2 = Color(1.06369e-05, 0.734862, 9.62615e-07, 1)
+shader_parameter/width = 1.0
+shader_parameter/pattern = 0
+shader_parameter/inside = true
+shader_parameter/add_margins = false
+
+[node name="GridSelector" type="Node2D"]
+y_sort_enabled = true
+script = ExtResource("1_3pk7u")
+
+[node name="Visual" type="CanvasGroup" parent="."]
+y_sort_enabled = true
+
+[node name="Sprite2D" type="Sprite2D" parent="Visual"]
+modulate = Color(0.92549, 0.92549, 0, 1)
+texture_filter = 1
+material = SubResource("ShaderMaterial_2b8fn")
+texture = ExtResource("2_jd6wm")
+
+[node name="Sprite2D2" type="Sprite2D" parent="Visual"]
+modulate = Color(0.998313, 0.999999, 0.788964, 1)
+texture_filter = 1
+material = SubResource("ShaderMaterial_2b8fn")
+position = Vector2(-16, 0)
+texture = ExtResource("2_jd6wm")
+
+[node name="Sprite2D3" type="Sprite2D" parent="Visual"]
+modulate = Color(0.998313, 0.999999, 0.788964, 1)
+texture_filter = 1
+material = SubResource("ShaderMaterial_2b8fn")
+position = Vector2(0, -8)
+texture = ExtResource("2_jd6wm")
+
+[node name="Sprite2D4" type="Sprite2D" parent="Visual"]
+modulate = Color(0.998313, 0.999999, 0.788964, 1)
+texture_filter = 1
+material = SubResource("ShaderMaterial_2b8fn")
+position = Vector2(16, 0)
+texture = ExtResource("2_jd6wm")
+
+[node name="Sprite2D5" type="Sprite2D" parent="Visual"]
+modulate = Color(0.998313, 0.999999, 0.788964, 1)
+texture_filter = 1
+material = SubResource("ShaderMaterial_2b8fn")
+position = Vector2(0, 8)
+texture = ExtResource("2_jd6wm")
+
+[node name="Sprite2D6" type="Sprite2D" parent="Visual"]
+modulate = Color(1, 1, 0.788235, 1)
+texture_filter = 1
+material = SubResource("ShaderMaterial_2b8fn")
+position = Vector2(0, 16)
+texture = ExtResource("2_jd6wm")
+
+[node name="StateCubePlacement" type="Node2D" parent="."]
+process_mode = 4
+script = ExtResource("4_bapxq")
+
+[node name="StateSelect" type="Node2D" parent="."]
+process_mode = 4
+script = ExtResource("5_wl8h0")
+
+[node name="StateMoveMode" type="Node2D" parent="."]
+process_mode = 4
+script = ExtResource("6_w3vtp")
+
+[node name="Visual" type="CanvasGroup" parent="StateMoveMode"]
+y_sort_enabled = true
+
+[connection signal="placed_tiles" from="StateCubePlacement" to="." method="_on_state_cube_placement_placed_tiles"]
+[connection signal="selected" from="StateSelect" to="." method="_on_state_select_selected"]
+[connection signal="confirmed" from="StateMoveMode" to="." method="_on_state_move_mode_confirmed"]
+[connection signal="exited" from="StateMoveMode" to="." method="_on_state_move_mode_exited"]
diff --git a/stage/grid_selector/grid_selector_item.gdshader b/stage/grid_selector/grid_selector_item.gdshader
new file mode 100644
index 0000000..f1ec4a8
--- /dev/null
+++ b/stage/grid_selector/grid_selector_item.gdshader
@@ -0,0 +1,72 @@
+shader_type canvas_item;
+
+uniform vec4 color : source_color = vec4(1.0);
+uniform vec4 color2 : source_color = vec4(1.0);
+uniform float width : hint_range(0, 10) = 1.0;
+uniform int pattern : hint_range(0, 2) = 0; // diamond, circle, square
+uniform bool inside = false;
+uniform bool add_margins = true; // only useful when inside is false
+
+void vertex() {
+ if (add_margins) {
+ VERTEX += (UV * 2.0 - 1.0) * width;
+ }
+}
+
+bool hasContraryNeighbour(vec2 uv, vec2 texture_pixel_size, sampler2D texture) {
+ for (float i = -ceil(width); i <= ceil(width); i++) {
+ float x = abs(i) > width ? width * sign(i) : i;
+ float offset;
+
+ if (pattern == 0) {
+ offset = width - abs(x);
+ } else if (pattern == 1) {
+ offset = floor(sqrt(pow(width + 0.5, 2) - x * x));
+ } else if (pattern == 2) {
+ offset = width;
+ }
+
+ for (float j = -ceil(offset); j <= ceil(offset); j++) {
+ float y = abs(j) > offset ? offset * sign(j) : j;
+ vec2 xy = uv + texture_pixel_size * vec2(x, y);
+
+ if ((xy != clamp(xy, vec2(0.0), vec2(1.0)) || texture(texture, xy).a <= 0.0) == inside) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+void fragment() {
+ vec2 uv = UV;
+
+ if (add_margins) {
+ vec2 texture_pixel_size = vec2(1.0) / (vec2(1.0) / TEXTURE_PIXEL_SIZE + vec2(width * 2.0));
+
+ uv = (uv - texture_pixel_size * width) * TEXTURE_PIXEL_SIZE / texture_pixel_size;
+
+ if (uv != clamp(uv, vec2(0.0), vec2(1.0))) {
+ COLOR.a = 0.0;
+ } else {
+ COLOR = texture(TEXTURE, uv);
+ }
+ } else {
+ //COLOR = texture(TEXTURE, uv);
+ }
+
+ if ((COLOR.a > 0.0) == inside && hasContraryNeighbour(uv, TEXTURE_PIXEL_SIZE, TEXTURE)) {
+ //COLOR.rgb = inside ? mix(COLOR.rgb, color.rgb, color.a) : color.rgb;
+ //COLOR.a += (1.0 - COLOR.a) * color.a;
+
+ if (inside) {
+ float time = TIME * 2.0;
+ if (sin(time) > 0.0) {
+ COLOR.rgb = mix(COLOR.rgb, color.rgb, max(0.5, sin(time)));
+ } else {
+ COLOR.rgb = mix(COLOR.rgb, color2.rgb, max(0.5, -sin(time)));
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/stage/grid_selector/state_cube_placement.gd b/stage/grid_selector/state_cube_placement.gd
new file mode 100644
index 0000000..5280906
--- /dev/null
+++ b/stage/grid_selector/state_cube_placement.gd
@@ -0,0 +1,241 @@
+class_name GridSelectorStateCubePlacement
+extends Node2D
+
+
+signal placed_tiles(grid_positions: Array)
+
+var transform_map = [
+ # #
+ # #
+ # #
+ # !#!
+ # #
+ # #
+ {
+ 0: [Vector2(1, 0), Vector2(2, 0), Vector2(0, -1), Vector2(-1, -1), Vector2(-2, -1)],
+ 90: [Vector2(0, 1), Vector2(0, 2), Vector2(1, 0), Vector2(1, -1), Vector2(1, -2)],
+ 180: [Vector2(-1, 0), Vector2(-2, 0), Vector2(0, 1), Vector2(1, 1), Vector2(2, 1)],
+ 270: [Vector2(0, -1), Vector2(0, -2), Vector2(-1, 0), Vector2(-1, 1), Vector2(-1, 2)],
+ },
+
+ # #
+ # #
+ # #
+ # !#!
+ # #
+ # #
+ {
+ 0: [Vector2(1, 0), Vector2(2, 0), Vector2(0, 1), Vector2(-1, 1), Vector2(-2, 1)],
+ 90: [Vector2(0, 1), Vector2(0, 2), Vector2(-1, 0), Vector2(-1, -1), Vector2(-1, -2)],
+ 180: [Vector2(-1, 0), Vector2(-2, 0), Vector2(0, -1), Vector2(1, -1), Vector2(2, -1)],
+ 270: [Vector2(0, -1), Vector2(0, -2), Vector2(1, 0), Vector2(1, 1), Vector2(1, 2)],
+ },
+
+ # #
+ # #!#!
+ # # #
+ # #
+ {
+ 0: [Vector2(0, 1), Vector2(-1, 1), Vector2(1, 0), Vector2(1, -1), Vector2(2, -1)],
+ 90: [Vector2(-1, 0), Vector2(-1, -1), Vector2(0, 1), Vector2(1, 1), Vector2(1, 2)],
+ 180: [Vector2(0, -1), Vector2(1, -1), Vector2(-1, 0), Vector2(-1, 1), Vector2(-2, 1)],
+ 270: [Vector2(1, 0), Vector2(1, 1), Vector2(0, -1), Vector2(-1, -1), Vector2(-1, -2)],
+ },
+
+ # #
+ # !#!#
+ # # #
+ # #
+ {
+ 0: [Vector2(0, -1), Vector2(-1, -1), Vector2(1, 0), Vector2(1, 1), Vector2(2, 1)],
+ 90: [Vector2(1, 0), Vector2(1, -1), Vector2(0, 1), Vector2(-1, 1), Vector2(-1, 2)],
+ 180: [Vector2(0, 1), Vector2(1, 1), Vector2(-1, 0), Vector2(-1, -1), Vector2(-2, -1)],
+ 270: [Vector2(-1, 0), Vector2(-1, 1), Vector2(0, -1), Vector2(1, -1), Vector2(1, -2)],
+ },
+
+ # # #
+ # !#!
+ # #
+ # # #
+ {
+ 0: [Vector2(-1, 0), Vector2(-1, 1), Vector2(1, 0), Vector2(2, 0), Vector2(2, -1)],
+ 90: [Vector2(0, -1), Vector2(-1, -1), Vector2(0, 1), Vector2(0, 2), Vector2(1, 2)],
+ 180: [Vector2(1, 0), Vector2(1, -1), Vector2(-1, 0), Vector2(-2, 0), Vector2(-2, 1)],
+ 270: [Vector2(0, 1), Vector2(1, 1), Vector2(0, -1), Vector2(0, -2), Vector2(-1, -2)],
+ },
+
+ # # #
+ # !#!
+ # #
+ # # #
+ {
+ 0: [Vector2(-1, 0), Vector2(-1, -1), Vector2(1, 0), Vector2(2, 0), Vector2(2, 1)],
+ 90: [Vector2(0, -1), Vector2(1, -1), Vector2(0, 1), Vector2(0, 2), Vector2(-1, 2)],
+ 180: [Vector2(1, 0), Vector2(1, 1), Vector2(-1, 0), Vector2(-2, 0), Vector2(-2, -1)],
+ 270: [Vector2(0, 1), Vector2(-1, 1), Vector2(0, -1), Vector2(0, -2), Vector2(1, -2)],
+ },
+
+ # #
+ # #!#!
+ # # #
+ # #
+ {
+ 0: [Vector2(0, 1), Vector2(-1, 1), Vector2(1, 0), Vector2(1, -1), Vector2(2, 0)],
+ 90: [Vector2(-1, 0), Vector2(-1, -1), Vector2(0, 1), Vector2(1, 1), Vector2(0, 2)],
+ 180: [Vector2(0, -1), Vector2(1, -1), Vector2(-1, 0), Vector2(-1, 1), Vector2(-2, 0)],
+ 270: [Vector2(1, 0), Vector2(1, 1), Vector2(0, -1), Vector2(-1, -1), Vector2(0, -2)],
+ },
+
+ # #
+ # !#!#
+ # # #
+ # #
+ {
+ 0: [Vector2(0, -1), Vector2(-1, -1), Vector2(1, 0), Vector2(1, 1), Vector2(2, 0)],
+ 90: [Vector2(1, 0), Vector2(1, -1), Vector2(0, 1), Vector2(-1, 1), Vector2(0, 2)],
+ 180: [Vector2(0, 1), Vector2(1, 1), Vector2(-1, 0), Vector2(-1, -1), Vector2(-2, 0)],
+ 270: [Vector2(-1, 0), Vector2(-1, 1), Vector2(0, -1), Vector2(1, -1), Vector2(0, -2)],
+ },
+
+ # # # #
+ # !#!
+ # #
+ # #
+ {
+ 0: [Vector2(-1, 0), Vector2(-1, -1), Vector2(-1, 1), Vector2(1, 0), Vector2(2, 0)],
+ 90: [Vector2(0, 1), Vector2(0, 2), Vector2(0, -1), Vector2(1, -1), Vector2(-1, -1)],
+ 180: [Vector2(1, 0), Vector2(1, 1), Vector2(1, -1), Vector2(-1, 0), Vector2(-2, 0)],
+ 270: [Vector2(0, -1), Vector2(0, -2), Vector2(0, 1), Vector2(-1, 1), Vector2(1, 1)],
+ },
+
+ # #
+ # #!#!#
+ # #
+ # #
+ {
+ 0: [Vector2(1, 0), Vector2(2, 0), Vector2(-1, 0), Vector2(0, 1), Vector2(0, -1)],
+ 90: [Vector2(0, 1), Vector2(0, 2), Vector2(-1, 0), Vector2(1, 0), Vector2(0, -1)],
+ 180: [Vector2(-1, 0), Vector2(-2, 0), Vector2(1, 0), Vector2(0, -1), Vector2(0, 1)],
+ 270: [Vector2(0, -1), Vector2(0, -2), Vector2(1, 0), Vector2(-1, 0), Vector2(0, 1)],
+ },
+]
+
+var current_transform_idx := 0
+var current_rotation := 0
+
+@onready var grid_selector: GridSelector = get_parent()
+@onready var ground_map := grid_selector.ground_map
+@onready var floor_map := grid_selector.floor_map
+
+
+func _process(_delta: float) -> void:
+ if Input.is_action_just_pressed("next_cube_pattern"):
+ current_transform_idx = (current_transform_idx + 1) % transform_map.size()
+ draw(ground_map.local_to_map(grid_selector.global_position))
+ elif Input.is_action_just_pressed("previous_cube_pattern"):
+ current_transform_idx = (current_transform_idx - 1) % transform_map.size()
+ draw(ground_map.local_to_map(grid_selector.global_position))
+ if Input.is_action_just_pressed("next_rotation"):
+ current_rotation = (current_rotation + 90) % 360
+ draw(ground_map.local_to_map(grid_selector.global_position))
+ elif Input.is_action_just_pressed("previous_rotation"):
+ current_rotation = (current_rotation + 270) % 360
+ draw(ground_map.local_to_map(grid_selector.global_position))
+
+ if Input.is_action_just_pressed("left_click"):
+ if can_place():
+ place_tiles()
+
+
+func draw(grid_position: Vector2i) -> void:
+ var node_grid_positions := get_grid_positions(grid_position)
+
+ var all_positions_in_grid := true
+ for p in node_grid_positions:
+ all_positions_in_grid = all_positions_in_grid and (ground_map.get_used_rect() as Rect2i).has_point(p)
+
+ if all_positions_in_grid:
+ grid_selector.global_position = ground_map.map_to_local(grid_position)
+ grid_selector.base_position = grid_selector.global_position
+
+ var selector_tiles: Array = grid_selector.visual.get_children()
+ for idx in selector_tiles.size():
+ var node: Sprite2D = selector_tiles[idx]
+ var node_grid_position := Vector2(grid_position)
+
+ if idx > 0:
+ node_grid_position += transform_map[current_transform_idx][current_rotation][idx - 1]
+
+ node.set_meta("grid_position", node_grid_position)
+ node.global_position = ground_map.map_to_local(node_grid_position)
+
+ grid_selector.adjust_height(node)
+
+
+func place_tiles():
+ if not can_place():
+ return
+
+ var positions = [grid_selector.global_position]
+ for node: Node2D in grid_selector.visual.get_children():
+ var tile: TileData = floor_map.get_cell_tile_data(node.get_meta("grid_position"))
+ if tile == null:
+ positions.append(node.global_position)
+
+ var grid_positions = positions.map(func(p): return ground_map.local_to_map(p))
+ for p in grid_positions:
+ floor_map.set_cell(
+ p,
+ grid_selector.placement_tile_source_id,
+ grid_selector.placement_tile_atlas_coordinates,
+ grid_selector.placement_tile_alternative_tile
+ )
+
+ placed_tiles.emit(grid_positions)
+ draw(ground_map.local_to_map(grid_selector.global_position))
+
+
+func can_place() -> bool:
+ # check if positions overlap with existing floor tiles
+ var grid_positions := get_grid_positions(
+ ground_map.local_to_map(grid_selector.global_position)
+ )
+
+ for p in grid_positions:
+ if p in floor_map.get_used_cells():
+ return false
+
+
+ # check if neighboring is current_team tile
+ for p in grid_positions:
+ var neighbors := floor_map.get_surrounding_cells(p)
+ for n in neighbors:
+ var tile := floor_map.get_cell_tile_data(n)
+ if tile != null:
+ if tile.get_custom_data("team") == grid_selector.current_team:
+ return true
+
+
+ return false
+
+
+func get_grid_positions(grid_position: Vector2i) -> Array:
+ var positions := []
+ for vector: Vector2 in transform_map[current_transform_idx][current_rotation]:
+ var node_grid_position := grid_position + Vector2i(vector)
+ positions.append(node_grid_position)
+
+ positions.append(grid_position)
+
+ return positions
+
+
+func _state_enter() -> void:
+ for node: Node2D in grid_selector.visual.get_children():
+ node.visible = true
+
+ draw(ground_map.local_to_map(grid_selector.global_position))
+
+
+func _state_exit() -> void:
+ pass
diff --git a/stage/grid_selector/state_move_mode.gd b/stage/grid_selector/state_move_mode.gd
new file mode 100644
index 0000000..908f463
--- /dev/null
+++ b/stage/grid_selector/state_move_mode.gd
@@ -0,0 +1,75 @@
+class_name GridSelectorStateMoveMode
+extends Node2D
+
+
+signal confirmed(path: Array)
+signal exited
+
+var target_position: Vector2i
+var current_path: Array
+
+@onready var grid_selector: GridSelector = get_parent()
+@onready var ground_map: TileMapLayer = grid_selector.ground_map
+@onready var floor_map: TileMapLayer = grid_selector.floor_map
+@onready var grid: AStarGrid2D = grid_selector.stage.grid
+@onready var selector_tile: Sprite2D = grid_selector.get_node("Visual").get_child(0).duplicate()
+@onready var path_tile: Sprite2D = grid_selector.get_node("Visual").get_child(1).duplicate()
+
+
+func _input(event: InputEvent) -> void:
+ if event.is_action_pressed("left_click"):
+ if current_path.size() > 1:
+ confirmed.emit(current_path.duplicate())
+
+ elif event.is_action_pressed("right_click"):
+ exited.emit()
+
+
+func draw(grid_position: Vector2i) -> void:
+ if floor_map.get_cell_tile_data(grid_position) == null:
+ return
+
+ target_position = grid_position
+ grid_selector.base_position = ground_map.map_to_local(target_position)
+
+ current_path = grid.get_point_path(
+ ground_map.local_to_map(grid_selector.global_position),
+ target_position
+ )
+
+ # remove starting position
+ var working_path := current_path.slice(1)
+
+ var node_count_difference := working_path.size() - $Visual.get_child_count()
+ if node_count_difference > 0:
+ for _idx in range(0, node_count_difference):
+ $Visual.add_child(path_tile.duplicate())
+ elif node_count_difference < 0:
+ for idx in range(0, abs(node_count_difference)):
+ $Visual.remove_child($Visual.get_child(idx))
+
+ for idx in working_path.size():
+ var path = working_path[idx]
+ var current_path_tile := $Visual.get_child(idx)
+ current_path_tile.global_position = path
+ grid_selector.adjust_height(current_path_tile)
+
+ if idx == working_path.size() - 1:
+ current_path_tile.modulate = selector_tile.modulate
+ else:
+ current_path_tile.modulate = path_tile.modulate
+
+
+func _state_enter() -> void:
+ for node: Node2D in grid_selector.visual.get_children().slice(1):
+ node.visible = false
+
+ $Visual.visible = true
+
+
+func _state_exit() -> void:
+ current_path.clear()
+
+ $Visual.visible = false
+ for node in $Visual.get_children():
+ node.queue_free()
diff --git a/stage/grid_selector/state_select.gd b/stage/grid_selector/state_select.gd
new file mode 100644
index 0000000..986dccc
--- /dev/null
+++ b/stage/grid_selector/state_select.gd
@@ -0,0 +1,43 @@
+class_name GridSelectorStateSelect
+extends Node2D
+
+
+signal selected(node: Node2D)
+
+@onready var grid_selector: GridSelector = get_parent()
+@onready var ground_map: TileMapLayer = grid_selector.ground_map
+@onready var floor_map: TileMapLayer = grid_selector.floor_map
+@onready var selector_tile: Sprite2D = grid_selector.get_node("Visual").get_child(0)
+
+
+func _input(event: InputEvent) -> void:
+ if event.is_action_pressed("left_click"):
+ var query := PhysicsPointQueryParameters2D.new()
+ query.collision_mask = grid_selector.selection_collision_mask
+ query.collide_with_areas = true
+ query.position = selector_tile.global_position
+
+ var collision := get_world_2d().direct_space_state.intersect_point(query, 1)
+
+ if not collision.is_empty():
+ selected.emit(collision[0].collider)
+
+
+func draw(grid_position: Vector2i) -> void:
+ if ground_map.get_used_rect().has_point(grid_position):
+ grid_selector.global_position = ground_map.map_to_local(grid_position)
+ grid_selector.base_position = grid_selector.global_position
+ selector_tile.global_position = grid_selector.global_position
+
+ grid_selector.adjust_height(selector_tile)
+
+
+func _state_enter() -> void:
+ for node: Node2D in grid_selector.visual.get_children().slice(1):
+ node.visible = false
+
+ draw(ground_map.local_to_map(grid_selector.global_position))
+
+
+func _state_exit() -> void:
+ pass
diff --git a/stage/hud.gd b/stage/hud.gd
new file mode 100644
index 0000000..8a0b146
--- /dev/null
+++ b/stage/hud.gd
@@ -0,0 +1,42 @@
+extends CanvasLayer
+
+
+@onready var grid_selector: GridSelector = get_tree().get_first_node_in_group("grid_selector")
+
+
+func _ready() -> void:
+ visible = false
+
+ grid_selector.selected.connect(func(_node: Node2D):
+ grid_selector.process_mode = Node.PROCESS_MODE_DISABLED
+ visible = true
+ $PanelContainer/VBoxContainer/Button.grab_focus()
+ )
+
+ grid_selector.move_mode_exited.connect(func():
+ grid_selector.current_state = grid_selector.get_node("StateSelect")
+ grid_selector.process_mode = Node.PROCESS_MODE_DISABLED
+ visible = true
+ $PanelContainer/VBoxContainer/Button.grab_focus()
+ )
+
+
+func _input(event: InputEvent) -> void:
+ if not visible:
+ return
+
+ if event.is_action_pressed("left_click"):
+ for button: Button in $PanelContainer/VBoxContainer.get_children():
+ if button.has_focus():
+ button.pressed.emit()
+ break
+
+ elif event.is_action_pressed("right_click"):
+ visible = false
+ grid_selector.process_mode = Node.PROCESS_MODE_INHERIT
+
+
+func _on_button_pressed() -> void:
+ grid_selector.process_mode = Node.PROCESS_MODE_INHERIT
+ grid_selector.current_state = grid_selector.get_node("StateMoveMode")
+ visible = false
diff --git a/stage/stage.gd b/stage/stage.gd
new file mode 100644
index 0000000..1f79915
--- /dev/null
+++ b/stage/stage.gd
@@ -0,0 +1,64 @@
+class_name Stage
+extends Node2D
+
+
+var grid := AStarGrid2D.new()
+
+@onready var grid_selector: GridSelector = %GridSelector
+
+
+# Called when the node enters the scene tree for the first time.
+func _ready() -> void:
+ grid.region = $Ground.get_used_rect()
+ grid.cell_size = $Floor.tile_set.tile_size
+ grid.cell_shape = AStarGrid2D.CELL_SHAPE_ISOMETRIC_DOWN
+ grid.diagonal_mode = AStarGrid2D.DIAGONAL_MODE_NEVER
+ grid.update()
+
+ # set whole grid non-walkable initially
+ grid.fill_solid_region(grid.region, true)
+
+ # pre-set floor tiles as walkable
+ for tile in $Floor.get_used_cells():
+ grid.set_point_solid(tile, false)
+
+
+# Called every frame. 'delta' is the elapsed time since the previous frame.
+func _process(_delta: float) -> void:
+ pass
+
+
+func _input(event: InputEvent) -> void:
+ if event.is_action_pressed("test_1"):
+ var unit = preload("res://unit/unit.tscn").instantiate()
+ unit.global_position = %GridSelector.global_position + $Floor.position
+ add_child(unit)
+ # TODO: generate dice throw anim => on end go to dice placement => add unit with tiles => go to select mode
+ if event.is_action_pressed("test_2"):
+ var unit: Node2D = get_node("Unit")
+ var path = grid.get_point_path(
+ $Floor.local_to_map(unit.global_position - $Floor.position),
+ $Floor.local_to_map(get_global_mouse_position() - $Floor.position)
+ )
+ var tween = get_tree().create_tween()
+ for p in path.slice(1): # remove starting position
+ tween.tween_property(unit, "global_position", p + $Floor.position, 0.1)
+
+
+func _on_grid_selector_placed_tiles(grid_positions: Array) -> void:
+ for p in grid_positions:
+ grid.set_point_solid(p, false)
+
+
+func _on_grid_selector_move_mode_confirmed(path: Array) -> void:
+ grid_selector.process_mode = Node.PROCESS_MODE_DISABLED
+
+ var unit: Node2D = get_node("Unit")
+ var tween = get_tree().create_tween()
+ for p in path.slice(1): # remove starting position
+ tween.tween_property(unit, "global_position", p + $Floor.position, 0.1)
+
+ await tween.finished
+ grid_selector.process_mode = Node.PROCESS_MODE_INHERIT
+ grid_selector.current_state = grid_selector.get_node("StateSelect")
+ grid_selector.current_state.draw($Ground.local_to_map(path[path.size() - 1]))
diff --git a/stage/stage.tscn b/stage/stage.tscn
new file mode 100644
index 0000000..adc5173
--- /dev/null
+++ b/stage/stage.tscn
@@ -0,0 +1,62 @@
+[gd_scene load_steps=5 format=4 uid="uid://btphwdkbxijnr"]
+
+[ext_resource type="TileSet" uid="uid://dl0umywqpu3m8" path="res://stage/assets/tilemap.tres" id="1_0isyp"]
+[ext_resource type="Script" path="res://stage/stage.gd" id="1_ccrgc"]
+[ext_resource type="PackedScene" uid="uid://dfhnxccd41wo0" path="res://stage/grid_selector/grid_selector.tscn" id="3_e6w2r"]
+[ext_resource type="Script" path="res://stage/hud.gd" id="4_cu7bb"]
+
+[node name="Stage" type="Node2D"]
+y_sort_enabled = true
+script = ExtResource("1_ccrgc")
+
+[node name="Ground" type="TileMapLayer" parent="."]
+z_index = -1
+texture_filter = 1
+tile_map_data = PackedByteArray("AADw//H/AQAAAAEAAADw//L/AQAAAAEAAADw//P/AQAAAAEAAADw//T/AQAAAAEAAADw//X/AQAAAAEAAADw//b/AQAAAAEAAADw//f/AQAAAAEAAADw//j/AQAAAAEAAADw//n/AQAAAAEAAADw//r/AQAAAAEAAADw//v/AQAAAAEAAADw//z/AQAAAAEAAADw//3/AQAAAAEAAADw//7/AQAAAAEAAADw////AQAAAAEAAADw/wAAAQAAAAEAAADw/wEAAQAAAAEAAADw/wIAAQAAAAEAAADw/wMAAQAAAAEAAADw/wQAAQAAAAEAAADw/wUAAQAAAAEAAADw/wYAAQAAAAEAAADw/wcAAQAAAAEAAADw/wgAAQAAAAEAAADw/wkAAQAAAAEAAADw/woAAQAAAAEAAADw/wsAAQAAAAEAAADw/wwAAQAAAAEAAADw/w0AAQAAAAEAAADw/w4AAQAAAAEAAADw/w8AAQAAAAEAAADx//H/AQAAAAEAAADx//L/AQAAAAEAAADx//P/AQAAAAEAAADx//T/AQAAAAEAAADx//X/AQAAAAEAAADx//b/AQAAAAEAAADx//f/AQAAAAEAAADx//j/AQAAAAEAAADx//n/AQAAAAEAAADx//r/AQAAAAEAAADx//v/AQAAAAEAAADx//z/AQAAAAEAAADx//3/AQAAAAEAAADx//7/AQAAAAEAAADx////AQAAAAEAAADx/wAAAQAAAAEAAADx/wEAAQAAAAEAAADx/wIAAQAAAAEAAADx/wMAAQAAAAEAAADx/wQAAQAAAAEAAADx/wUAAQAAAAEAAADx/wYAAQAAAAEAAADx/wcAAQAAAAEAAADx/wgAAQAAAAEAAADx/wkAAQAAAAEAAADx/woAAQAAAAEAAADx/wsAAQAAAAEAAADx/wwAAQAAAAEAAADx/w0AAQAAAAEAAADx/w4AAQAAAAEAAADx/w8AAQAAAAEAAADy//H/AQAAAAEAAADy//L/AQAAAAEAAADy//P/AQAAAAEAAADy//T/AQAAAAEAAADy//X/AQAAAAEAAADy//b/AQAAAAEAAADy//f/AQAAAAEAAADy//j/AQAAAAEAAADy//n/AQAAAAEAAADy//r/AQAAAAEAAADy//v/AQAAAAEAAADy//z/AQAAAAEAAADy//3/AQAAAAEAAADy//7/AQAAAAEAAADy////AQAAAAEAAADy/wAAAQAAAAEAAADy/wEAAQAAAAEAAADy/wIAAQAAAAEAAADy/wMAAQAAAAEAAADy/wQAAQAAAAEAAADy/wUAAQAAAAEAAADy/wYAAQAAAAEAAADy/wcAAQAAAAEAAADy/wgAAQAAAAEAAADy/wkAAQAAAAEAAADy/woAAQAAAAEAAADy/wsAAQAAAAEAAADy/wwAAQAAAAEAAADy/w0AAQAAAAEAAADy/w4AAQAAAAEAAADy/w8AAQAAAAEAAADz//H/AQAAAAEAAADz//L/AQAAAAEAAADz//P/AQAAAAEAAADz//T/AQAAAAEAAADz//X/AQAAAAEAAADz//b/AQAAAAEAAADz//f/AQAAAAEAAADz//j/AQAAAAEAAADz//n/AQAAAAEAAADz//r/AQAAAAEAAADz//v/AQAAAAEAAADz//z/AQAAAAEAAADz//3/AQAAAAEAAADz//7/AQAAAAEAAADz////AQAAAAEAAADz/wAAAQAAAAEAAADz/wEAAQAAAAEAAADz/wIAAQAAAAEAAADz/wMAAQAAAAEAAADz/wQAAQAAAAEAAADz/wUAAQAAAAEAAADz/wYAAQAAAAEAAADz/wcAAQAAAAEAAADz/wgAAQAAAAEAAADz/wkAAQAAAAEAAADz/woAAQAAAAEAAADz/wsAAQAAAAEAAADz/wwAAQAAAAEAAADz/w0AAQAAAAEAAADz/w4AAQAAAAEAAADz/w8AAQAAAAEAAAD0//H/AQAAAAEAAAD0//L/AQAAAAEAAAD0//P/AQAAAAEAAAD0//T/AQAAAAEAAAD0//X/AQAAAAEAAAD0//b/AQAAAAEAAAD0//f/AQAAAAEAAAD0//j/AQAAAAEAAAD0//n/AQAAAAEAAAD0//r/AQAAAAEAAAD0//v/AQAAAAEAAAD0//z/AQAAAAEAAAD0//3/AQAAAAEAAAD0//7/AQAAAAEAAAD0////AQAAAAEAAAD0/wAAAQAAAAEAAAD0/wEAAQAAAAEAAAD0/wIAAQAAAAEAAAD0/wMAAQAAAAEAAAD0/wQAAQAAAAEAAAD0/wUAAQAAAAEAAAD0/wYAAQAAAAEAAAD0/wcAAQAAAAEAAAD0/wgAAQAAAAEAAAD0/wkAAQAAAAEAAAD0/woAAQAAAAEAAAD0/wsAAQAAAAEAAAD0/wwAAQAAAAEAAAD0/w0AAQAAAAEAAAD0/w4AAQAAAAEAAAD0/w8AAQAAAAEAAAD1//H/AQAAAAEAAAD1//L/AQAAAAEAAAD1//P/AQAAAAEAAAD1//T/AQAAAAEAAAD1//X/AQAAAAEAAAD1//b/AQAAAAEAAAD1//f/AQAAAAEAAAD1//j/AQAAAAEAAAD1//n/AQAAAAEAAAD1//r/AQAAAAEAAAD1//v/AQAAAAEAAAD1//z/AQAAAAEAAAD1//3/AQAAAAEAAAD1//7/AQAAAAEAAAD1////AQAAAAEAAAD1/wAAAQAAAAEAAAD1/wEAAQAAAAEAAAD1/wIAAQAAAAEAAAD1/wMAAQAAAAEAAAD1/wQAAQAAAAEAAAD1/wUAAQAAAAEAAAD1/wYAAQAAAAEAAAD1/wcAAQAAAAEAAAD1/wgAAQAAAAEAAAD1/wkAAQAAAAEAAAD1/woAAQAAAAEAAAD1/wsAAQAAAAEAAAD1/wwAAQAAAAEAAAD1/w0AAQAAAAEAAAD1/w4AAQAAAAEAAAD1/w8AAQAAAAEAAAD2//H/AQAAAAEAAAD2//L/AQAAAAEAAAD2//P/AQAAAAEAAAD2//T/AQAAAAEAAAD2//X/AQAAAAEAAAD2//b/AQAAAAEAAAD2//f/AQAAAAEAAAD2//j/AQAAAAEAAAD2//n/AQAAAAEAAAD2//r/AQAAAAEAAAD2//v/AQAAAAEAAAD2//z/AQAAAAEAAAD2//3/AQAAAAEAAAD2//7/AQAAAAEAAAD2////AQAAAAEAAAD2/wAAAQAAAAEAAAD2/wEAAQAAAAEAAAD2/wIAAQAAAAEAAAD2/wMAAQAAAAEAAAD2/wQAAQAAAAEAAAD2/wUAAQAAAAEAAAD2/wYAAQAAAAEAAAD2/wcAAQAAAAEAAAD2/wgAAQAAAAEAAAD2/wkAAQAAAAEAAAD2/woAAQAAAAEAAAD2/wsAAQAAAAEAAAD2/wwAAQAAAAEAAAD2/w0AAQAAAAEAAAD2/w4AAQAAAAEAAAD2/w8AAQAAAAEAAAD3//H/AQAAAAEAAAD3//L/AQAAAAEAAAD3//P/AQAAAAEAAAD3//T/AQAAAAEAAAD3//X/AQAAAAEAAAD3//b/AQAAAAEAAAD3//f/AQAAAAEAAAD3//j/AQAAAAEAAAD3//n/AQAAAAEAAAD3//r/AQAAAAEAAAD3//v/AQAAAAEAAAD3//z/AQAAAAEAAAD3//3/AQAAAAEAAAD3//7/AQAAAAEAAAD3////AQAAAAEAAAD3/wAAAQAAAAEAAAD3/wEAAQAAAAEAAAD3/wIAAQAAAAEAAAD3/wMAAQAAAAEAAAD3/wQAAQAAAAEAAAD3/wUAAQAAAAEAAAD3/wYAAQAAAAEAAAD3/wcAAQAAAAEAAAD3/wgAAQAAAAEAAAD3/wkAAQAAAAEAAAD3/woAAQAAAAEAAAD3/wsAAQAAAAEAAAD3/wwAAQAAAAEAAAD3/w0AAQAAAAEAAAD3/w4AAQAAAAEAAAD3/w8AAQAAAAEAAAD4//H/AQAAAAEAAAD4//L/AQAAAAEAAAD4//P/AQAAAAEAAAD4//T/AQAAAAEAAAD4//X/AQAAAAEAAAD4//b/AQAAAAEAAAD4//f/AQAAAAEAAAD4//j/AQAAAAEAAAD4//n/AQAAAAEAAAD4//r/AQAAAAEAAAD4//v/AQAAAAEAAAD4//z/AQAAAAEAAAD4//3/AQAAAAEAAAD4//7/AQAAAAEAAAD4////AQAAAAEAAAD4/wAAAQAAAAEAAAD4/wEAAQAAAAEAAAD4/wIAAQAAAAEAAAD4/wMAAQAAAAEAAAD4/wQAAQAAAAEAAAD4/wUAAQAAAAEAAAD4/wYAAQAAAAEAAAD4/wcAAQAAAAEAAAD4/wgAAQAAAAEAAAD4/wkAAQAAAAEAAAD4/woAAQAAAAEAAAD4/wsAAQAAAAEAAAD4/wwAAQAAAAEAAAD4/w0AAQAAAAEAAAD4/w4AAQAAAAEAAAD4/w8AAQAAAAEAAAD5//H/AQAAAAEAAAD5//L/AQAAAAEAAAD5//P/AQAAAAEAAAD5//T/AQAAAAEAAAD5//X/AQAAAAEAAAD5//b/AQAAAAEAAAD5//f/AQAAAAEAAAD5//j/AQAAAAEAAAD5//n/AQAAAAEAAAD5//r/AQAAAAEAAAD5//v/AQAAAAEAAAD5//z/AQAAAAEAAAD5//3/AQAAAAEAAAD5//7/AQAAAAEAAAD5////AQAAAAEAAAD5/wAAAQAAAAEAAAD5/wEAAQAAAAEAAAD5/wIAAQAAAAEAAAD5/wMAAQAAAAEAAAD5/wQAAQAAAAEAAAD5/wUAAQAAAAEAAAD5/wYAAQAAAAEAAAD5/wcAAQAAAAEAAAD5/wgAAQAAAAEAAAD5/wkAAQAAAAEAAAD5/woAAQAAAAEAAAD5/wsAAQAAAAEAAAD5/wwAAQAAAAEAAAD5/w0AAQAAAAEAAAD5/w4AAQAAAAEAAAD5/w8AAQAAAAEAAAD6//H/AQAAAAEAAAD6//L/AQAAAAEAAAD6//P/AQAAAAEAAAD6//T/AQAAAAEAAAD6//X/AQAAAAEAAAD6//b/AQAAAAEAAAD6//f/AQAAAAEAAAD6//j/AQAAAAEAAAD6//n/AQAAAAEAAAD6//r/AQAAAAEAAAD6//v/AQAAAAEAAAD6//z/AQAAAAEAAAD6//3/AQAAAAEAAAD6//7/AQAAAAEAAAD6////AQAAAAEAAAD6/wAAAQAAAAEAAAD6/wEAAQAAAAEAAAD6/wIAAQAAAAEAAAD6/wMAAQAAAAEAAAD6/wQAAQAAAAEAAAD6/wUAAQAAAAEAAAD6/wYAAQAAAAEAAAD6/wcAAQAAAAEAAAD6/wgAAQAAAAEAAAD6/wkAAQAAAAEAAAD6/woAAQAAAAEAAAD6/wsAAQAAAAEAAAD6/wwAAQAAAAEAAAD6/w0AAQAAAAEAAAD6/w4AAQAAAAEAAAD6/w8AAQAAAAEAAAD7//H/AQAAAAEAAAD7//L/AQAAAAEAAAD7//P/AQAAAAEAAAD7//T/AQAAAAEAAAD7//X/AQAAAAEAAAD7//b/AQAAAAEAAAD7//f/AQAAAAEAAAD7//j/AQAAAAEAAAD7//n/AQAAAAEAAAD7//r/AQAAAAEAAAD7//v/AQAAAAEAAAD7//z/AQAAAAEAAAD7//3/AQAAAAEAAAD7//7/AQAAAAEAAAD7////AQAAAAEAAAD7/wAAAQAAAAEAAAD7/wEAAQAAAAEAAAD7/wIAAQAAAAEAAAD7/wMAAQAAAAEAAAD7/wQAAQAAAAEAAAD7/wUAAQAAAAEAAAD7/wYAAQAAAAEAAAD7/wcAAQAAAAEAAAD7/wgAAQAAAAEAAAD7/wkAAQAAAAEAAAD7/woAAQAAAAEAAAD7/wsAAQAAAAEAAAD7/wwAAQAAAAEAAAD7/w0AAQAAAAEAAAD7/w4AAQAAAAEAAAD7/w8AAQAAAAEAAAD8//H/AQAAAAEAAAD8//L/AQAAAAEAAAD8//P/AQAAAAEAAAD8//T/AQAAAAEAAAD8//X/AQAAAAEAAAD8//b/AQAAAAEAAAD8//f/AQAAAAEAAAD8//j/AQAAAAEAAAD8//n/AQAAAAEAAAD8//r/AQAAAAEAAAD8//v/AQAAAAEAAAD8//z/AQAAAAEAAAD8//3/AQAAAAEAAAD8//7/AQAAAAEAAAD8////AQAAAAEAAAD8/wAAAQAAAAEAAAD8/wEAAQAAAAEAAAD8/wIAAQAAAAEAAAD8/wMAAQAAAAEAAAD8/wQAAQAAAAEAAAD8/wUAAQAAAAEAAAD8/wYAAQAAAAEAAAD8/wcAAQAAAAEAAAD8/wgAAQAAAAEAAAD8/wkAAQAAAAEAAAD8/woAAQAAAAEAAAD8/wsAAQAAAAEAAAD8/wwAAQAAAAEAAAD8/w0AAQAAAAEAAAD8/w4AAQAAAAEAAAD8/w8AAQAAAAEAAAD9//H/AQAAAAEAAAD9//L/AQAAAAEAAAD9//P/AQAAAAEAAAD9//T/AQAAAAEAAAD9//X/AQAAAAEAAAD9//b/AQAAAAEAAAD9//f/AQAAAAEAAAD9//j/AQAAAAEAAAD9//n/AQAAAAEAAAD9//r/AQAAAAEAAAD9//v/AQAAAAEAAAD9//z/AQAAAAEAAAD9//3/AQAAAAEAAAD9//7/AQAAAAEAAAD9////AQAAAAEAAAD9/wAAAQAAAAEAAAD9/wEAAQAAAAEAAAD9/wIAAQAAAAEAAAD9/wMAAQAAAAEAAAD9/wQAAQAAAAEAAAD9/wUAAQAAAAEAAAD9/wYAAQAAAAEAAAD9/wcAAQAAAAEAAAD9/wgAAQAAAAEAAAD9/wkAAQAAAAEAAAD9/woAAQAAAAEAAAD9/wsAAQAAAAEAAAD9/wwAAQAAAAEAAAD9/w0AAQAAAAEAAAD9/w4AAQAAAAEAAAD9/w8AAQAAAAEAAAD+//H/AQAAAAEAAAD+//L/AQAAAAEAAAD+//P/AQAAAAEAAAD+//T/AQAAAAEAAAD+//X/AQAAAAEAAAD+//b/AQAAAAEAAAD+//f/AQAAAAEAAAD+//j/AQAAAAEAAAD+//n/AQAAAAEAAAD+//r/AQAAAAEAAAD+//v/AQAAAAEAAAD+//z/AQAAAAEAAAD+//3/AQAAAAEAAAD+//7/AQAAAAEAAAD+////AQAAAAEAAAD+/wAAAQAAAAEAAAD+/wEAAQAAAAEAAAD+/wIAAQAAAAEAAAD+/wMAAQAAAAEAAAD+/wQAAQAAAAEAAAD+/wUAAQAAAAEAAAD+/wYAAQAAAAEAAAD+/wcAAQAAAAEAAAD+/wgAAQAAAAEAAAD+/wkAAQAAAAEAAAD+/woAAQAAAAEAAAD+/wsAAQAAAAEAAAD+/wwAAQAAAAEAAAD+/w0AAQAAAAEAAAD+/w4AAQAAAAEAAAD+/w8AAQAAAAEAAAD///H/AQAAAAEAAAD///L/AQAAAAEAAAD///P/AQAAAAEAAAD///T/AQAAAAEAAAD///X/AQAAAAEAAAD///b/AQAAAAEAAAD///f/AQAAAAEAAAD///j/AQAAAAEAAAD///n/AQAAAAEAAAD///r/AQAAAAEAAAD///v/AQAAAAEAAAD///z/AQAAAAEAAAD///3/AQAAAAEAAAD///7/AQAAAAEAAAD/////AQAAAAEAAAD//wAAAQAAAAEAAAD//wEAAQAAAAEAAAD//wIAAQAAAAEAAAD//wMAAQAAAAEAAAD//wQAAQAAAAEAAAD//wUAAQAAAAEAAAD//wYAAQAAAAEAAAD//wcAAQAAAAEAAAD//wgAAQAAAAEAAAD//wkAAQAAAAEAAAD//woAAQAAAAEAAAD//wsAAQAAAAEAAAD//wwAAQAAAAEAAAD//w0AAQAAAAEAAAD//w4AAQAAAAEAAAD//w8AAQAAAAEAAAAAAPH/AQAAAAEAAAAAAPL/AQAAAAEAAAAAAPP/AQAAAAEAAAAAAPT/AQAAAAEAAAAAAPX/AQAAAAEAAAAAAPb/AQAAAAEAAAAAAPf/AQAAAAEAAAAAAPj/AQAAAAEAAAAAAPn/AQAAAAEAAAAAAPr/AQAAAAEAAAAAAPv/AQAAAAEAAAAAAPz/AQAAAAEAAAAAAP3/AQAAAAEAAAAAAP7/AQAAAAEAAAAAAP//AQAAAAEAAAAAAAAAAQAAAAEAAAAAAAEAAQAAAAEAAAAAAAIAAQAAAAEAAAAAAAMAAQAAAAEAAAAAAAQAAQAAAAEAAAAAAAUAAQAAAAEAAAAAAAYAAQAAAAEAAAAAAAcAAQAAAAEAAAAAAAgAAQAAAAEAAAAAAAkAAQAAAAEAAAAAAAoAAQAAAAEAAAAAAAsAAQAAAAEAAAAAAAwAAQAAAAEAAAAAAA0AAQAAAAEAAAAAAA4AAQAAAAEAAAAAAA8AAQAAAAEAAAABAPH/AQAAAAEAAAABAPL/AQAAAAEAAAABAPP/AQAAAAEAAAABAPT/AQAAAAEAAAABAPX/AQAAAAEAAAABAPb/AQAAAAEAAAABAPf/AQAAAAEAAAABAPj/AQAAAAEAAAABAPn/AQAAAAEAAAABAPr/AQAAAAEAAAABAPv/AQAAAAEAAAABAPz/AQAAAAEAAAABAP3/AQAAAAEAAAABAP7/AQAAAAEAAAABAP//AQAAAAEAAAABAAAAAQAAAAEAAAABAAEAAQAAAAEAAAABAAIAAQAAAAEAAAABAAMAAQAAAAEAAAABAAQAAQAAAAEAAAABAAUAAQAAAAEAAAABAAYAAQAAAAEAAAABAAcAAQAAAAEAAAABAAgAAQAAAAEAAAABAAkAAQAAAAEAAAABAAoAAQAAAAEAAAABAAsAAQAAAAEAAAABAAwAAQAAAAEAAAABAA0AAQAAAAEAAAABAA4AAQAAAAEAAAABAA8AAQAAAAEAAAACAPH/AQAAAAEAAAACAPL/AQAAAAEAAAACAPP/AQAAAAEAAAACAPT/AQAAAAEAAAACAPX/AQAAAAEAAAACAPb/AQAAAAEAAAACAPf/AQAAAAEAAAACAPj/AQAAAAEAAAACAPn/AQAAAAEAAAACAPr/AQAAAAEAAAACAPv/AQAAAAEAAAACAPz/AQAAAAEAAAACAP3/AQAAAAEAAAACAP7/AQAAAAEAAAACAP//AQAAAAEAAAACAAAAAQAAAAEAAAACAAEAAQAAAAEAAAACAAIAAQAAAAEAAAACAAMAAQAAAAEAAAACAAQAAQAAAAEAAAACAAUAAQAAAAEAAAACAAYAAQAAAAEAAAACAAcAAQAAAAEAAAACAAgAAQAAAAEAAAACAAkAAQAAAAEAAAACAAoAAQAAAAEAAAACAAsAAQAAAAEAAAACAAwAAQAAAAEAAAACAA0AAQAAAAEAAAACAA4AAQAAAAEAAAACAA8AAQAAAAEAAAADAPH/AQAAAAEAAAADAPL/AQAAAAEAAAADAPP/AQAAAAEAAAADAPT/AQAAAAEAAAADAPX/AQAAAAEAAAADAPb/AQAAAAEAAAADAPf/AQAAAAEAAAADAPj/AQAAAAEAAAADAPn/AQAAAAEAAAADAPr/AQAAAAEAAAADAPv/AQAAAAEAAAADAPz/AQAAAAEAAAADAP3/AQAAAAEAAAADAP7/AQAAAAEAAAADAP//AQAAAAEAAAADAAAAAQAAAAEAAAADAAEAAQAAAAEAAAADAAIAAQAAAAEAAAADAAMAAQAAAAEAAAADAAQAAQAAAAEAAAADAAUAAQAAAAEAAAADAAYAAQAAAAEAAAADAAcAAQAAAAEAAAADAAgAAQAAAAEAAAADAAkAAQAAAAEAAAADAAoAAQAAAAEAAAADAAsAAQAAAAEAAAADAAwAAQAAAAEAAAADAA0AAQAAAAEAAAADAA4AAQAAAAEAAAADAA8AAQAAAAEAAAAEAPH/AQAAAAEAAAAEAPL/AQAAAAEAAAAEAPP/AQAAAAEAAAAEAPT/AQAAAAEAAAAEAPX/AQAAAAEAAAAEAPb/AQAAAAEAAAAEAPf/AQAAAAEAAAAEAPj/AQAAAAEAAAAEAPn/AQAAAAEAAAAEAPr/AQAAAAEAAAAEAPv/AQAAAAEAAAAEAPz/AQAAAAEAAAAEAP3/AQAAAAEAAAAEAP7/AQAAAAEAAAAEAP//AQAAAAEAAAAEAAAAAQAAAAEAAAAEAAEAAQAAAAEAAAAEAAIAAQAAAAEAAAAEAAMAAQAAAAEAAAAEAAQAAQAAAAEAAAAEAAUAAQAAAAEAAAAEAAYAAQAAAAEAAAAEAAcAAQAAAAEAAAAEAAgAAQAAAAEAAAAEAAkAAQAAAAEAAAAEAAoAAQAAAAEAAAAEAAsAAQAAAAEAAAAEAAwAAQAAAAEAAAAEAA0AAQAAAAEAAAAEAA4AAQAAAAEAAAAEAA8AAQAAAAEAAAAFAPH/AQAAAAEAAAAFAPL/AQAAAAEAAAAFAPP/AQAAAAEAAAAFAPT/AQAAAAEAAAAFAPX/AQAAAAEAAAAFAPb/AQAAAAEAAAAFAPf/AQAAAAEAAAAFAPj/AQAAAAEAAAAFAPn/AQAAAAEAAAAFAPr/AQAAAAEAAAAFAPv/AQAAAAEAAAAFAPz/AQAAAAEAAAAFAP3/AQAAAAEAAAAFAP7/AQAAAAEAAAAFAP//AQAAAAEAAAAFAAAAAQAAAAEAAAAFAAEAAQAAAAEAAAAFAAIAAQAAAAEAAAAFAAMAAQAAAAEAAAAFAAQAAQAAAAEAAAAFAAUAAQAAAAEAAAAFAAYAAQAAAAEAAAAFAAcAAQAAAAEAAAAFAAgAAQAAAAEAAAAFAAkAAQAAAAEAAAAFAAoAAQAAAAEAAAAFAAsAAQAAAAEAAAAFAAwAAQAAAAEAAAAFAA0AAQAAAAEAAAAFAA4AAQAAAAEAAAAFAA8AAQAAAAEAAAAGAPH/AQAAAAEAAAAGAPL/AQAAAAEAAAAGAPP/AQAAAAEAAAAGAPT/AQAAAAEAAAAGAPX/AQAAAAEAAAAGAPb/AQAAAAEAAAAGAPf/AQAAAAEAAAAGAPj/AQAAAAEAAAAGAPn/AQAAAAEAAAAGAPr/AQAAAAEAAAAGAPv/AQAAAAEAAAAGAPz/AQAAAAEAAAAGAP3/AQAAAAEAAAAGAP7/AQAAAAEAAAAGAP//AQAAAAEAAAAGAAAAAQAAAAEAAAAGAAEAAQAAAAEAAAAGAAIAAQAAAAEAAAAGAAMAAQAAAAEAAAAGAAQAAQAAAAEAAAAGAAUAAQAAAAEAAAAGAAYAAQAAAAEAAAAGAAcAAQAAAAEAAAAGAAgAAQAAAAEAAAAGAAkAAQAAAAEAAAAGAAoAAQAAAAEAAAAGAAsAAQAAAAEAAAAGAAwAAQAAAAEAAAAGAA0AAQAAAAEAAAAGAA4AAQAAAAEAAAAGAA8AAQAAAAEAAAAHAPH/AQAAAAEAAAAHAPL/AQAAAAEAAAAHAPP/AQAAAAEAAAAHAPT/AQAAAAEAAAAHAPX/AQAAAAEAAAAHAPb/AQAAAAEAAAAHAPf/AQAAAAEAAAAHAPj/AQAAAAEAAAAHAPn/AQAAAAEAAAAHAPr/AQAAAAEAAAAHAPv/AQAAAAEAAAAHAPz/AQAAAAEAAAAHAP3/AQAAAAEAAAAHAP7/AQAAAAEAAAAHAP//AQAAAAEAAAAHAAAAAQAAAAEAAAAHAAEAAQAAAAEAAAAHAAIAAQAAAAEAAAAHAAMAAQAAAAEAAAAHAAQAAQAAAAEAAAAHAAUAAQAAAAEAAAAHAAYAAQAAAAEAAAAHAAcAAQAAAAEAAAAHAAgAAQAAAAEAAAAHAAkAAQAAAAEAAAAHAAoAAQAAAAEAAAAHAAsAAQAAAAEAAAAHAAwAAQAAAAEAAAAHAA0AAQAAAAEAAAAHAA4AAQAAAAEAAAAHAA8AAQAAAAEAAAAIAPH/AQAAAAEAAAAIAPL/AQAAAAEAAAAIAPP/AQAAAAEAAAAIAPT/AQAAAAEAAAAIAPX/AQAAAAEAAAAIAPb/AQAAAAEAAAAIAPf/AQAAAAEAAAAIAPj/AQAAAAEAAAAIAPn/AQAAAAEAAAAIAPr/AQAAAAEAAAAIAPv/AQAAAAEAAAAIAPz/AQAAAAEAAAAIAP3/AQAAAAEAAAAIAP7/AQAAAAEAAAAIAP//AQAAAAEAAAAIAAAAAQAAAAEAAAAIAAEAAQAAAAEAAAAIAAIAAQAAAAEAAAAIAAMAAQAAAAEAAAAIAAQAAQAAAAEAAAAIAAUAAQAAAAEAAAAIAAYAAQAAAAEAAAAIAAcAAQAAAAEAAAAIAAgAAQAAAAEAAAAIAAkAAQAAAAEAAAAIAAoAAQAAAAEAAAAIAAsAAQAAAAEAAAAIAAwAAQAAAAEAAAAIAA0AAQAAAAEAAAAIAA4AAQAAAAEAAAAIAA8AAQAAAAEAAAAJAPH/AQAAAAEAAAAJAPL/AQAAAAEAAAAJAPP/AQAAAAEAAAAJAPT/AQAAAAEAAAAJAPX/AQAAAAEAAAAJAPb/AQAAAAEAAAAJAPf/AQAAAAEAAAAJAPj/AQAAAAEAAAAJAPn/AQAAAAEAAAAJAPr/AQAAAAEAAAAJAPv/AQAAAAEAAAAJAPz/AQAAAAEAAAAJAP3/AQAAAAEAAAAJAP7/AQAAAAEAAAAJAP//AQAAAAEAAAAJAAAAAQAAAAEAAAAJAAEAAQAAAAEAAAAJAAIAAQAAAAEAAAAJAAMAAQAAAAEAAAAJAAQAAQAAAAEAAAAJAAUAAQAAAAEAAAAJAAYAAQAAAAEAAAAJAAcAAQAAAAEAAAAJAAgAAQAAAAEAAAAJAAkAAQAAAAEAAAAJAAoAAQAAAAEAAAAJAAsAAQAAAAEAAAAJAAwAAQAAAAEAAAAJAA0AAQAAAAEAAAAJAA4AAQAAAAEAAAAJAA8AAQAAAAEAAAAKAPH/AQAAAAEAAAAKAPL/AQAAAAEAAAAKAPP/AQAAAAEAAAAKAPT/AQAAAAEAAAAKAPX/AQAAAAEAAAAKAPb/AQAAAAEAAAAKAPf/AQAAAAEAAAAKAPj/AQAAAAEAAAAKAPn/AQAAAAEAAAAKAPr/AQAAAAEAAAAKAPv/AQAAAAEAAAAKAPz/AQAAAAEAAAAKAP3/AQAAAAEAAAAKAP7/AQAAAAEAAAAKAP//AQAAAAEAAAAKAAAAAQAAAAEAAAAKAAEAAQAAAAEAAAAKAAIAAQAAAAEAAAAKAAMAAQAAAAEAAAAKAAQAAQAAAAEAAAAKAAUAAQAAAAEAAAAKAAYAAQAAAAEAAAAKAAcAAQAAAAEAAAAKAAgAAQAAAAEAAAAKAAkAAQAAAAEAAAAKAAoAAQAAAAEAAAAKAAsAAQAAAAEAAAAKAAwAAQAAAAEAAAAKAA0AAQAAAAEAAAAKAA4AAQAAAAEAAAAKAA8AAQAAAAEAAAALAPH/AQAAAAEAAAALAPL/AQAAAAEAAAALAPP/AQAAAAEAAAALAPT/AQAAAAEAAAALAPX/AQAAAAEAAAALAPb/AQAAAAEAAAALAPf/AQAAAAEAAAALAPj/AQAAAAEAAAALAPn/AQAAAAEAAAALAPr/AQAAAAEAAAALAPv/AQAAAAEAAAALAPz/AQAAAAEAAAALAP3/AQAAAAEAAAALAP7/AQAAAAEAAAALAP//AQAAAAEAAAALAAAAAQAAAAEAAAALAAEAAQAAAAEAAAALAAIAAQAAAAEAAAALAAMAAQAAAAEAAAALAAQAAQAAAAEAAAALAAUAAQAAAAEAAAALAAYAAQAAAAEAAAALAAcAAQAAAAEAAAALAAgAAQAAAAEAAAALAAkAAQAAAAEAAAALAAoAAQAAAAEAAAALAAsAAQAAAAEAAAALAAwAAQAAAAEAAAALAA0AAQAAAAEAAAALAA4AAQAAAAEAAAALAA8AAQAAAAEAAAAMAPH/AQAAAAEAAAAMAPL/AQAAAAEAAAAMAPP/AQAAAAEAAAAMAPT/AQAAAAEAAAAMAPX/AQAAAAEAAAAMAPb/AQAAAAEAAAAMAPf/AQAAAAEAAAAMAPj/AQAAAAEAAAAMAPn/AQAAAAEAAAAMAPr/AQAAAAEAAAAMAPv/AQAAAAEAAAAMAPz/AQAAAAEAAAAMAP3/AQAAAAEAAAAMAP7/AQAAAAEAAAAMAP//AQAAAAEAAAAMAAAAAQAAAAEAAAAMAAEAAQAAAAEAAAAMAAIAAQAAAAEAAAAMAAMAAQAAAAEAAAAMAAQAAQAAAAEAAAAMAAUAAQAAAAEAAAAMAAYAAQAAAAEAAAAMAAcAAQAAAAEAAAAMAAgAAQAAAAEAAAAMAAkAAQAAAAEAAAAMAAoAAQAAAAEAAAAMAAsAAQAAAAEAAAAMAAwAAQAAAAEAAAAMAA0AAQAAAAEAAAAMAA4AAQAAAAEAAAAMAA8AAQAAAAEAAAANAPH/AQAAAAEAAAANAPL/AQAAAAEAAAANAPP/AQAAAAEAAAANAPT/AQAAAAEAAAANAPX/AQAAAAEAAAANAPb/AQAAAAEAAAANAPf/AQAAAAEAAAANAPj/AQAAAAEAAAANAPn/AQAAAAEAAAANAPr/AQAAAAEAAAANAPv/AQAAAAEAAAANAPz/AQAAAAEAAAANAP3/AQAAAAEAAAANAP7/AQAAAAEAAAANAP//AQAAAAEAAAANAAAAAQAAAAEAAAANAAEAAQAAAAEAAAANAAIAAQAAAAEAAAANAAMAAQAAAAEAAAANAAQAAQAAAAEAAAANAAUAAQAAAAEAAAANAAYAAQAAAAEAAAANAAcAAQAAAAEAAAANAAgAAQAAAAEAAAANAAkAAQAAAAEAAAANAAoAAQAAAAEAAAANAAsAAQAAAAEAAAANAAwAAQAAAAEAAAANAA0AAQAAAAEAAAANAA4AAQAAAAEAAAANAA8AAQAAAAEAAAAOAPH/AQAAAAEAAAAOAPL/AQAAAAEAAAAOAPP/AQAAAAEAAAAOAPT/AQAAAAEAAAAOAPX/AQAAAAEAAAAOAPb/AQAAAAEAAAAOAPf/AQAAAAEAAAAOAPj/AQAAAAEAAAAOAPn/AQAAAAEAAAAOAPr/AQAAAAEAAAAOAPv/AQAAAAEAAAAOAPz/AQAAAAEAAAAOAP3/AQAAAAEAAAAOAP7/AQAAAAEAAAAOAP//AQAAAAEAAAAOAAAAAQAAAAEAAAAOAAEAAQAAAAEAAAAOAAIAAQAAAAEAAAAOAAMAAQAAAAEAAAAOAAQAAQAAAAEAAAAOAAUAAQAAAAEAAAAOAAYAAQAAAAEAAAAOAAcAAQAAAAEAAAAOAAgAAQAAAAEAAAAOAAkAAQAAAAEAAAAOAAoAAQAAAAEAAAAOAAsAAQAAAAEAAAAOAAwAAQAAAAEAAAAOAA0AAQAAAAEAAAAOAA4AAQAAAAEAAAAOAA8AAQAAAAEAAAA=")
+tile_set = ExtResource("1_0isyp")
+
+[node name="Floor" type="TileMapLayer" parent="."]
+y_sort_enabled = true
+texture_filter = 1
+position = Vector2(0, -4)
+tile_map_data = PackedByteArray("AAANAP//AQABAAYAAADx////AQADAAYAAAA=")
+tile_set = ExtResource("1_0isyp")
+
+[node name="Camera2D" type="Camera2D" parent="."]
+
+[node name="GridSelector" parent="." node_paths=PackedStringArray("stage", "ground_map", "floor_map") groups=["grid_selector"] instance=ExtResource("3_e6w2r")]
+unique_name_in_owner = true
+stage = NodePath("..")
+ground_map = NodePath("../Ground")
+floor_map = NodePath("../Floor")
+selection_collision_mask = 2
+current_team = "1"
+placement_tile_source_id = 1
+placement_tile_atlas_coordinates = Vector2i(1, 6)
+
+[node name="HUD" type="CanvasLayer" parent="."]
+script = ExtResource("4_cu7bb")
+
+[node name="PanelContainer" type="PanelContainer" parent="HUD"]
+anchors_preset = 1
+anchor_left = 1.0
+anchor_right = 1.0
+offset_left = -40.0
+offset_bottom = 40.0
+grow_horizontal = 0
+
+[node name="VBoxContainer" type="VBoxContainer" parent="HUD/PanelContainer"]
+layout_mode = 2
+theme_override_constants/separation = 0
+
+[node name="Button" type="Button" parent="HUD/PanelContainer/VBoxContainer"]
+layout_mode = 2
+text = "Move"
+
+[node name="Button2" type="Button" parent="HUD/PanelContainer/VBoxContainer"]
+layout_mode = 2
+text = "Status"
+
+[connection signal="move_mode_confirmed" from="GridSelector" to="." method="_on_grid_selector_move_mode_confirmed"]
+[connection signal="placed_tiles" from="GridSelector" to="." method="_on_grid_selector_placed_tiles"]
+[connection signal="pressed" from="HUD/PanelContainer/VBoxContainer/Button" to="HUD" method="_on_button_pressed"]
diff --git a/unit/unit.tscn b/unit/unit.tscn
new file mode 100644
index 0000000..9b152c1
--- /dev/null
+++ b/unit/unit.tscn
@@ -0,0 +1,20 @@
+[gd_scene load_steps=3 format=3 uid="uid://dglv8ajgj4i4c"]
+
+[ext_resource type="Texture2D" uid="uid://blanietpri1be" path="res://icon.svg" id="1_0d47j"]
+
+[sub_resource type="RectangleShape2D" id="RectangleShape2D_4xd6x"]
+size = Vector2(8, 8)
+
+[node name="Unit" type="Node2D"]
+z_index = 2
+
+[node name="Icon" type="Sprite2D" parent="."]
+scale = Vector2(0.063, 0.063)
+texture = ExtResource("1_0d47j")
+
+[node name="Area2D" type="Area2D" parent="."]
+collision_layer = 2
+collision_mask = 0
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Area2D"]
+shape = SubResource("RectangleShape2D_4xd6x")