diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..57db3b0
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,9 @@
+root = true
+
+[*]
+charset = utf-8
+end_of_line = lf
+indent_style = tab
+indent_size = 4
+trim_trailing_whitespace = true
+insert_final_newline = true
diff --git a/.gitignore b/.gitignore
index 57ae9d7..70827b3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,8 +1,5 @@
+/.godot/
/.import/
-/.mono/
-/bin/
-/build/
-/lib/
+/export.cfg
+/export_credentials.cfg
*.translation
-export_presets.cfg
-mono_crash.*
diff --git a/.vscode/launch.json b/.vscode/launch.json
deleted file mode 100644
index 654ff83..0000000
--- a/.vscode/launch.json
+++ /dev/null
@@ -1,30 +0,0 @@
-{
- "version": "0.2.0",
- "configurations": [{
- "name": "Play in Editor",
- "type": "godot-mono",
- "mode": "playInEditor",
- "request": "launch",
- "preLaunchTask": "build"
- },{
- "name": "Launch (Linux)",
- "type": "godot-mono",
- "request": "launch",
- "mode": "executable",
- "executable": "${workspaceRoot}/build/linux/${workspaceFolderBasename}.x86_64",
- "executableArguments": [ "--path", "${workspaceRoot}" ]
- },{
- "name": "Launch (Windows)",
- "type": "godot-mono",
- "request": "launch",
- "mode": "executable",
- "executable": "${workspaceRoot}/build/windows/${workspaceFolderBasename}.exe",
- "executableArguments": [ "--path", "${workspaceRoot}" ]
- },{
- "name": "Attach",
- "type": "godot-mono",
- "request": "attach",
- "address": "localhost",
- "port": 23685
- }]
-}
diff --git a/.vscode/settings.json b/.vscode/settings.json
deleted file mode 100644
index 35690fc..0000000
--- a/.vscode/settings.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "editor.tabSize": 4,
- "editor.insertSpaces": true,
-
- "files.trimTrailingWhitespace": true,
- "files.trimFinalNewlines": true,
- "files.insertFinalNewline": true,
-
- "files.exclude": {
- "**/.git": true,
- "**/*.import": true,
- },
-
- "[markdown]": {
- "files.trimTrailingWhitespace": false,
- }
-}
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
deleted file mode 100644
index 8fc147f..0000000
--- a/.vscode/tasks.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "version": "2.0.0",
- "tasks": [{
- "group": "build",
- "label": "build",
- "type": "shell",
- "command": "msbuild",
- "args": [
- "/property:GenerateFullPaths=true",
- "/consoleloggerparameters:NoSummary",
- "/t:build",
- ],
- "presentation": { "reveal": "silent" },
- "problemMatcher": "$msCompile"
- }]
-}
diff --git a/YourFortV.csproj b/YourFortV.csproj
deleted file mode 100644
index 3b9b28f..0000000
--- a/YourFortV.csproj
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
- net472
-
-
-
-
-
-
-
diff --git a/YourFortV.sln b/YourFortV.sln
deleted file mode 100644
index c39ac98..0000000
--- a/YourFortV.sln
+++ /dev/null
@@ -1,19 +0,0 @@
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 2012
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "YourFortV", "YourFortV.csproj", "{FF89645B-804D-485D-BFAB-AA51330D8862}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Any CPU = Debug|Any CPU
- ExportDebug|Any CPU = ExportDebug|Any CPU
- ExportRelease|Any CPU = ExportRelease|Any CPU
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {FF89645B-804D-485D-BFAB-AA51330D8862}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {FF89645B-804D-485D-BFAB-AA51330D8862}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {FF89645B-804D-485D-BFAB-AA51330D8862}.ExportDebug|Any CPU.ActiveCfg = ExportDebug|Any CPU
- {FF89645B-804D-485D-BFAB-AA51330D8862}.ExportDebug|Any CPU.Build.0 = ExportDebug|Any CPU
- {FF89645B-804D-485D-BFAB-AA51330D8862}.ExportRelease|Any CPU.ActiveCfg = ExportRelease|Any CPU
- {FF89645B-804D-485D-BFAB-AA51330D8862}.ExportRelease|Any CPU.Build.0 = ExportRelease|Any CPU
- EndGlobalSection
-EndGlobal
diff --git a/decal_material.tres b/decal_material.tres
deleted file mode 100644
index f127cdc..0000000
--- a/decal_material.tres
+++ /dev/null
@@ -1,172 +0,0 @@
-[gd_resource type="ShaderMaterial" load_steps=14 format=2]
-
-[sub_resource type="VisualShaderNodeInput" id=1]
-input_name = "modulate_color"
-
-[sub_resource type="VisualShaderNodeInput" id=2]
-input_name = "modulate_alpha"
-
-[sub_resource type="VisualShaderNodeScalarOp" id=3]
-operator = 2
-
-[sub_resource type="VisualShaderNodeExpression" id=4]
-size = Vector2( 512, 260 )
-expression = "vec2 tex_size = vec2(textureSize(mask, 0));
-vec2 pix_loc = uv.xy / TEXTURE_PIXEL_SIZE;
-mask_uv = vec3((pix_loc + offset.xy) / tex_size, 0);
-outside = mask_uv.x >= 0.0 && mask_uv.x <= 1.0 &&
- mask_uv.y >= 0.0 && mask_uv.y <= 1.0;"
-
-[sub_resource type="VisualShaderNodeInput" id=5]
-input_name = "uv"
-
-[sub_resource type="VisualShaderNodeScalarSwitch" id=6]
-
-[sub_resource type="VisualShaderNodeVectorOp" id=7]
-operator = 2
-
-[sub_resource type="VisualShaderNodeTexture" id=8]
-source = 5
-
-[sub_resource type="VisualShaderNodeInput" id=9]
-input_name = "texture"
-
-[sub_resource type="VisualShaderNodeScalarOp" id=10]
-operator = 2
-
-[sub_resource type="VisualShaderNodeVec3Uniform" id=11]
-uniform_name = "offset"
-
-[sub_resource type="VisualShaderNodeTextureUniform" id=12]
-uniform_name = "mask"
-
-[sub_resource type="VisualShader" id=13]
-code = "shader_type canvas_item;
-uniform vec3 offset;
-uniform sampler2D mask;
-
-
-
-void vertex() {
-// Output:0
-
-}
-
-void fragment() {
-// Input:10
- vec3 n_out10p0 = MODULATE.rgb;
-
-// Input:3
-
-// Texture:2
- vec3 n_out2p0;
- float n_out2p1;
- {
- vec4 TEXTURE_tex_read = texture(TEXTURE, UV.xy);
- n_out2p0 = TEXTURE_tex_read.rgb;
- n_out2p1 = TEXTURE_tex_read.a;
- }
-
-// VectorOp:18
- vec3 n_out18p0 = n_out10p0 * n_out2p0;
-
-// Input:13
- float n_out13p0 = MODULATE.a;
-
-// VectorUniform:7
- vec3 n_out7p0 = offset;
-
-// Input:16
- vec3 n_out16p0 = vec3(UV, 0.0);
-
-// Expression:15
- vec3 n_out15p0;
- bool n_out15p1;
- n_out15p0 = vec3(0.0, 0.0, 0.0);
- n_out15p1 = false;
- {
- vec2 tex_size = vec2(textureSize(mask, 0));
- vec2 pix_loc = n_out16p0.xy / TEXTURE_PIXEL_SIZE;
- n_out15p0 = vec3((pix_loc + n_out7p0.xy) / tex_size, 0);
- n_out15p1 = n_out15p0.x >= 0.0 && n_out15p0.x <= 1.0 &&
- n_out15p0.y >= 0.0 && n_out15p0.y <= 1.0;
- }
-
-// TextureUniform:8
- vec3 n_out8p0;
- float n_out8p1;
- {
- vec4 n_tex_read = texture(mask, n_out15p0.xy);
- n_out8p0 = n_tex_read.rgb;
- n_out8p1 = n_tex_read.a;
- }
-
-// ScalarSwitch:17
- float n_in17p2 = 0.00000;
- float n_out17p0;
- if(n_out15p1)
- {
- n_out17p0 = n_out8p1;
- }
- else
- {
- n_out17p0 = n_in17p2;
- }
-
-// ScalarOp:6
- float n_out6p0 = n_out2p1 * n_out17p0;
-
-// ScalarOp:14
- float n_out14p0 = n_out13p0 * n_out6p0;
-
-// Output:0
- COLOR.rgb = n_out18p0;
- COLOR.a = n_out14p0;
-
-}
-
-void light() {
-// Output:0
-
-}
-"
-mode = 1
-flags/light_only = false
-nodes/fragment/0/position = Vector2( 840, -100 )
-nodes/fragment/2/node = SubResource( 8 )
-nodes/fragment/2/position = Vector2( 400, -40 )
-nodes/fragment/3/node = SubResource( 9 )
-nodes/fragment/3/position = Vector2( 220, -40 )
-nodes/fragment/6/node = SubResource( 10 )
-nodes/fragment/6/position = Vector2( 640, 60 )
-nodes/fragment/7/node = SubResource( 11 )
-nodes/fragment/7/position = Vector2( -340, 60 )
-nodes/fragment/8/node = SubResource( 12 )
-nodes/fragment/8/position = Vector2( 400, 100 )
-nodes/fragment/10/node = SubResource( 1 )
-nodes/fragment/10/position = Vector2( 320, -200 )
-nodes/fragment/13/node = SubResource( 2 )
-nodes/fragment/13/position = Vector2( 320, -120 )
-nodes/fragment/14/node = SubResource( 3 )
-nodes/fragment/14/position = Vector2( 640, -60 )
-nodes/fragment/15/node = SubResource( 4 )
-nodes/fragment/15/position = Vector2( -140, 40 )
-nodes/fragment/15/size = Vector2( 512, 260 )
-nodes/fragment/15/input_ports = "0,1,offset;1,1,uv;"
-nodes/fragment/15/output_ports = "0,1,mask_uv;1,2,outside;"
-nodes/fragment/15/expression = "vec2 tex_size = vec2(textureSize(mask, 0));
-vec2 pix_loc = uv.xy / TEXTURE_PIXEL_SIZE;
-mask_uv = vec3((pix_loc + offset.xy) / tex_size, 0);
-outside = mask_uv.x >= 0.0 && mask_uv.x <= 1.0 &&
- mask_uv.y >= 0.0 && mask_uv.y <= 1.0;"
-nodes/fragment/16/node = SubResource( 5 )
-nodes/fragment/16/position = Vector2( -340, 140 )
-nodes/fragment/17/node = SubResource( 6 )
-nodes/fragment/17/position = Vector2( 620, 180 )
-nodes/fragment/18/node = SubResource( 7 )
-nodes/fragment/18/position = Vector2( 640, -180 )
-nodes/fragment/connections = PoolIntArray( 3, 0, 2, 2, 2, 1, 6, 0, 6, 0, 14, 1, 13, 0, 14, 0, 14, 0, 0, 1, 7, 0, 15, 0, 16, 0, 15, 1, 15, 0, 8, 0, 15, 1, 17, 0, 8, 1, 17, 1, 17, 0, 6, 1, 10, 0, 18, 0, 2, 0, 18, 1, 18, 0, 0, 0 )
-
-[resource]
-shader = SubResource( 13 )
-shader_param/offset = Vector3( 0, 0, 0 )
diff --git a/export_presets.cfg b/export_presets.cfg
new file mode 100644
index 0000000..b2265b1
--- /dev/null
+++ b/export_presets.cfg
@@ -0,0 +1,67 @@
+[preset.0]
+
+name="Linux/X11"
+platform="Linux/X11"
+runnable=true
+custom_features=""
+export_filter="all_resources"
+include_filter=""
+exclude_filter=""
+export_path="build/linux/YourFortV.x86_64"
+patch_list=PoolStringArray( )
+script_export_mode=1
+script_encryption_key=""
+
+[preset.0.options]
+
+texture_format/bptc=false
+texture_format/s3tc=true
+texture_format/etc=false
+texture_format/etc2=false
+texture_format/no_bptc_fallbacks=true
+binary_format/64_bits=true
+binary_format/embed_pck=false
+custom_template/release=""
+custom_template/debug=""
+
+[preset.1]
+
+name="Windows Desktop"
+platform="Windows Desktop"
+runnable=true
+custom_features=""
+export_filter="all_resources"
+include_filter=""
+exclude_filter=""
+export_path="build/windows/YourFortV.exe"
+patch_list=PoolStringArray( )
+script_export_mode=1
+script_encryption_key=""
+
+[preset.1.options]
+
+texture_format/bptc=false
+texture_format/s3tc=true
+texture_format/etc=false
+texture_format/etc2=false
+texture_format/no_bptc_fallbacks=true
+binary_format/64_bits=true
+binary_format/embed_pck=false
+custom_template/release=""
+custom_template/debug=""
+codesign/enable=false
+codesign/identity=""
+codesign/password=""
+codesign/timestamp=true
+codesign/timestamp_server_url=""
+codesign/digest_algorithm=1
+codesign/description=""
+codesign/custom_options=PoolStringArray( )
+application/icon=""
+application/file_version=""
+application/product_version=""
+application/company_name=""
+application/product_name=""
+application/file_description=""
+application/copyright=""
+application/trademarks=""
diff --git a/game.gd b/game.gd
new file mode 100644
index 0000000..76e1acf
--- /dev/null
+++ b/game.gd
@@ -0,0 +1,26 @@
+class_name Game
+extends Node
+
+static var INSTANCE : Game
+static var NETWORK : Network
+static var WORLD : World
+static var PLAYERS : Node
+static var LOCAL_PLAYER : Player
+
+func _enter_tree() -> void:
+ INSTANCE = self
+ NETWORK = $Network
+ WORLD = $World
+ PLAYERS = $Players
+ LOCAL_PLAYER = $"Players/1"
+
+func change_world(world: World) -> void:
+ remove_child(WORLD)
+ WORLD.queue_free()
+
+ world.name = "World"
+ add_child(world)
+ WORLD = world
+
+ LOCAL_PLAYER.chunk_loader.tracked_chunks.clear()
+ LOCAL_PLAYER.position = Vector2.ZERO
diff --git a/game.gd.uid b/game.gd.uid
new file mode 100644
index 0000000..bd95097
--- /dev/null
+++ b/game.gd.uid
@@ -0,0 +1 @@
+uid://4rqg0th44b4y
diff --git a/game.tscn b/game.tscn
new file mode 100644
index 0000000..5c7b748
--- /dev/null
+++ b/game.tscn
@@ -0,0 +1,63 @@
+[gd_scene load_steps=13 format=3 uid="uid://bxhfecc34tahh"]
+
+[ext_resource type="Texture2D" uid="uid://17f8yypfxgq8" path="res://hud/background.png" id="1_hve3p"]
+[ext_resource type="Script" uid="uid://4rqg0th44b4y" path="res://game.gd" id="1_mfdv2"]
+[ext_resource type="Script" uid="uid://6cd3jkc185pa" path="res://hud/background.gd" id="2_mfdv2"]
+[ext_resource type="Script" uid="uid://yhfl5jhw8xw1" path="res://world/world.gd" id="3_hve3p"]
+[ext_resource type="Script" uid="uid://cayck3pgtxys6" path="res://network/network.gd" id="4_iotsf"]
+[ext_resource type="PackedScene" uid="uid://dnuy2pdb7p1gy" path="res://player/player.tscn" id="4_lc2xo"]
+[ext_resource type="PackedScene" uid="uid://jv30ao4ppc3h" path="res://hud/escape_menu/escape_menu.tscn" id="5_215e1"]
+[ext_resource type="Script" path="res://scripts/hud/Health.gd" id="6_7sc4i"]
+[ext_resource type="PackedScene" uid="uid://br618d1sbfgie" path="res://hud/radial_menu.tscn" id="7_80cx4"]
+[ext_resource type="Texture2D" uid="uid://cjvxdbr5eplcj" path="res://hud/cursor.png" id="8_e8heu"]
+[ext_resource type="Script" uid="uid://dm2ux2aj8pdpn" path="res://hud/cursor.gd" id="9_rvswv"]
+[ext_resource type="PackedScene" uid="uid://vbqf8dv4enpe" path="res://hud/weapon_info.tscn" id="10_boyg6"]
+
+[node name="Game" type="Node"]
+script = ExtResource("1_mfdv2")
+
+[node name="Background" type="TextureRect" parent="."]
+modulate = Color(0.278431, 0.286275, 0.301961, 1)
+offset_right = 1280.0
+offset_bottom = 720.0
+mouse_filter = 2
+texture = ExtResource("1_hve3p")
+stretch_mode = 1
+script = ExtResource("2_mfdv2")
+
+[node name="Network" type="Node" parent="."]
+script = ExtResource("4_iotsf")
+
+[node name="World" type="Node" parent="."]
+script = ExtResource("3_hve3p")
+
+[node name="Players" type="Node" parent="."]
+
+[node name="1" parent="Players" instance=ExtResource("4_lc2xo")]
+
+[node name="Camera" type="Camera2D" parent="Players/1"]
+
+[node name="HUD" type="CanvasLayer" parent="."]
+
+[node name="EscapeMenu" parent="HUD" instance=ExtResource("5_215e1")]
+visible = false
+z_index = 100
+
+[node name="RadialMenu" parent="HUD" node_paths=PackedStringArray("cursor", "player") instance=ExtResource("7_80cx4")]
+visible = false
+cursor = NodePath("../../CursorLayer/Cursor")
+player = NodePath("../../Players/1")
+
+[node name="Health" type="Node2D" parent="HUD"]
+script = ExtResource("6_7sc4i")
+
+[node name="CursorLayer" type="CanvasLayer" parent="."]
+process_mode = 3
+layer = 2
+follow_viewport_enabled = true
+
+[node name="Cursor" type="Sprite2D" parent="CursorLayer"]
+texture = ExtResource("8_e8heu")
+script = ExtResource("9_rvswv")
+
+[node name="WeaponInfo" parent="CursorLayer/Cursor" instance=ExtResource("10_boyg6")]
diff --git a/gfx/background.png.import b/gfx/background.png.import
deleted file mode 100644
index d42ae6b..0000000
--- a/gfx/background.png.import
+++ /dev/null
@@ -1,34 +0,0 @@
-[remap]
-
-importer="texture"
-type="StreamTexture"
-path="res://.import/background.png-34463f2717b0502091d019b33ae7e4f3.stex"
-metadata={
-"vram_texture": false
-}
-
-[deps]
-
-source_file="res://gfx/background.png"
-dest_files=[ "res://.import/background.png-34463f2717b0502091d019b33ae7e4f3.stex" ]
-
-[params]
-
-compress/mode=0
-compress/lossy_quality=0.7
-compress/hdr_mode=0
-compress/bptc_ldr=0
-compress/normal_map=0
-flags/repeat=1
-flags/filter=false
-flags/mipmaps=false
-flags/anisotropic=false
-flags/srgb=2
-process/fix_alpha_border=true
-process/premult_alpha=false
-process/HDR_as_SRGB=false
-process/invert_color=false
-stream=false
-size_limit=0
-detect_3d=false
-svg/scale=1.0
diff --git a/gfx/block.png.import b/gfx/block.png.import
deleted file mode 100644
index 70bd5a8..0000000
--- a/gfx/block.png.import
+++ /dev/null
@@ -1,34 +0,0 @@
-[remap]
-
-importer="texture"
-type="StreamTexture"
-path="res://.import/block.png-60e5fe55f4421ac5893119a21190be18.stex"
-metadata={
-"vram_texture": false
-}
-
-[deps]
-
-source_file="res://gfx/block.png"
-dest_files=[ "res://.import/block.png-60e5fe55f4421ac5893119a21190be18.stex" ]
-
-[params]
-
-compress/mode=0
-compress/lossy_quality=0.7
-compress/hdr_mode=0
-compress/bptc_ldr=0
-compress/normal_map=0
-flags/repeat=0
-flags/filter=false
-flags/mipmaps=false
-flags/anisotropic=false
-flags/srgb=2
-process/fix_alpha_border=true
-process/premult_alpha=false
-process/HDR_as_SRGB=false
-process/invert_color=false
-stream=false
-size_limit=0
-detect_3d=true
-svg/scale=1.0
diff --git a/gfx/cursor.png.import b/gfx/cursor.png.import
deleted file mode 100644
index 225c81f..0000000
--- a/gfx/cursor.png.import
+++ /dev/null
@@ -1,34 +0,0 @@
-[remap]
-
-importer="texture"
-type="StreamTexture"
-path="res://.import/cursor.png-3b96f8448db3dedf6af5b6b7fc13768f.stex"
-metadata={
-"vram_texture": false
-}
-
-[deps]
-
-source_file="res://gfx/cursor.png"
-dest_files=[ "res://.import/cursor.png-3b96f8448db3dedf6af5b6b7fc13768f.stex" ]
-
-[params]
-
-compress/mode=0
-compress/lossy_quality=0.7
-compress/hdr_mode=0
-compress/bptc_ldr=0
-compress/normal_map=0
-flags/repeat=0
-flags/filter=false
-flags/mipmaps=false
-flags/anisotropic=false
-flags/srgb=2
-process/fix_alpha_border=true
-process/premult_alpha=false
-process/HDR_as_SRGB=false
-process/invert_color=false
-stream=false
-size_limit=0
-detect_3d=true
-svg/scale=1.0
diff --git a/gfx/guns/AK47.png.import b/gfx/guns/AK47.png.import
deleted file mode 100644
index a5ce4a4..0000000
--- a/gfx/guns/AK47.png.import
+++ /dev/null
@@ -1,34 +0,0 @@
-[remap]
-
-importer="texture"
-type="StreamTexture"
-path="res://.import/AK47.png-b3a2177e704ef07670dcc3fbcf5fe2b5.stex"
-metadata={
-"vram_texture": false
-}
-
-[deps]
-
-source_file="res://gfx/guns/AK47.png"
-dest_files=[ "res://.import/AK47.png-b3a2177e704ef07670dcc3fbcf5fe2b5.stex" ]
-
-[params]
-
-compress/mode=0
-compress/lossy_quality=0.7
-compress/hdr_mode=0
-compress/bptc_ldr=0
-compress/normal_map=0
-flags/repeat=0
-flags/filter=true
-flags/mipmaps=false
-flags/anisotropic=false
-flags/srgb=2
-process/fix_alpha_border=true
-process/premult_alpha=false
-process/HDR_as_SRGB=false
-process/invert_color=false
-stream=false
-size_limit=0
-detect_3d=false
-svg/scale=1.0
diff --git a/gfx/guns/Blunderbuss.png.import b/gfx/guns/Blunderbuss.png.import
deleted file mode 100644
index 8970a3f..0000000
--- a/gfx/guns/Blunderbuss.png.import
+++ /dev/null
@@ -1,34 +0,0 @@
-[remap]
-
-importer="texture"
-type="StreamTexture"
-path="res://.import/Blunderbuss.png-f9541a9afbcc7503436ddb33d87600bd.stex"
-metadata={
-"vram_texture": false
-}
-
-[deps]
-
-source_file="res://gfx/guns/Blunderbuss.png"
-dest_files=[ "res://.import/Blunderbuss.png-f9541a9afbcc7503436ddb33d87600bd.stex" ]
-
-[params]
-
-compress/mode=0
-compress/lossy_quality=0.7
-compress/hdr_mode=0
-compress/bptc_ldr=0
-compress/normal_map=0
-flags/repeat=0
-flags/filter=true
-flags/mipmaps=false
-flags/anisotropic=false
-flags/srgb=2
-process/fix_alpha_border=true
-process/premult_alpha=false
-process/HDR_as_SRGB=false
-process/invert_color=false
-stream=false
-size_limit=0
-detect_3d=false
-svg/scale=1.0
diff --git a/gfx/guns/BowArrow.png.import b/gfx/guns/BowArrow.png.import
deleted file mode 100644
index 12f574f..0000000
--- a/gfx/guns/BowArrow.png.import
+++ /dev/null
@@ -1,34 +0,0 @@
-[remap]
-
-importer="texture"
-type="StreamTexture"
-path="res://.import/BowArrow.png-6b5dd8d866365f0485866a478b6a0cd1.stex"
-metadata={
-"vram_texture": false
-}
-
-[deps]
-
-source_file="res://gfx/guns/BowArrow.png"
-dest_files=[ "res://.import/BowArrow.png-6b5dd8d866365f0485866a478b6a0cd1.stex" ]
-
-[params]
-
-compress/mode=0
-compress/lossy_quality=0.7
-compress/hdr_mode=0
-compress/bptc_ldr=0
-compress/normal_map=0
-flags/repeat=0
-flags/filter=true
-flags/mipmaps=false
-flags/anisotropic=false
-flags/srgb=2
-process/fix_alpha_border=true
-process/premult_alpha=false
-process/HDR_as_SRGB=false
-process/invert_color=false
-stream=false
-size_limit=0
-detect_3d=false
-svg/scale=1.0
diff --git a/gfx/guns/ColtSingleActionArmy.png.import b/gfx/guns/ColtSingleActionArmy.png.import
deleted file mode 100644
index b78d113..0000000
--- a/gfx/guns/ColtSingleActionArmy.png.import
+++ /dev/null
@@ -1,34 +0,0 @@
-[remap]
-
-importer="texture"
-type="StreamTexture"
-path="res://.import/ColtSingleActionArmy.png-4ffeb11f8b9db175b4a4529b4533c26c.stex"
-metadata={
-"vram_texture": false
-}
-
-[deps]
-
-source_file="res://gfx/guns/ColtSingleActionArmy.png"
-dest_files=[ "res://.import/ColtSingleActionArmy.png-4ffeb11f8b9db175b4a4529b4533c26c.stex" ]
-
-[params]
-
-compress/mode=0
-compress/lossy_quality=0.7
-compress/hdr_mode=0
-compress/bptc_ldr=0
-compress/normal_map=0
-flags/repeat=0
-flags/filter=true
-flags/mipmaps=false
-flags/anisotropic=false
-flags/srgb=2
-process/fix_alpha_border=true
-process/premult_alpha=false
-process/HDR_as_SRGB=false
-process/invert_color=false
-stream=false
-size_limit=0
-detect_3d=false
-svg/scale=1.0
diff --git a/gfx/guns/Derringer.png.import b/gfx/guns/Derringer.png.import
deleted file mode 100644
index 57f2b2e..0000000
--- a/gfx/guns/Derringer.png.import
+++ /dev/null
@@ -1,34 +0,0 @@
-[remap]
-
-importer="texture"
-type="StreamTexture"
-path="res://.import/Derringer.png-43093e7c64541e63c047f9a45f88d5c6.stex"
-metadata={
-"vram_texture": false
-}
-
-[deps]
-
-source_file="res://gfx/guns/Derringer.png"
-dest_files=[ "res://.import/Derringer.png-43093e7c64541e63c047f9a45f88d5c6.stex" ]
-
-[params]
-
-compress/mode=0
-compress/lossy_quality=0.7
-compress/hdr_mode=0
-compress/bptc_ldr=0
-compress/normal_map=0
-flags/repeat=0
-flags/filter=true
-flags/mipmaps=false
-flags/anisotropic=false
-flags/srgb=2
-process/fix_alpha_border=true
-process/premult_alpha=false
-process/HDR_as_SRGB=false
-process/invert_color=false
-stream=false
-size_limit=0
-detect_3d=false
-svg/scale=1.0
diff --git a/gfx/guns/DoubleBarrel.png.import b/gfx/guns/DoubleBarrel.png.import
deleted file mode 100644
index 78ae5b1..0000000
--- a/gfx/guns/DoubleBarrel.png.import
+++ /dev/null
@@ -1,34 +0,0 @@
-[remap]
-
-importer="texture"
-type="StreamTexture"
-path="res://.import/DoubleBarrel.png-0d2a0a5877ea0832296b59ab69073d32.stex"
-metadata={
-"vram_texture": false
-}
-
-[deps]
-
-source_file="res://gfx/guns/DoubleBarrel.png"
-dest_files=[ "res://.import/DoubleBarrel.png-0d2a0a5877ea0832296b59ab69073d32.stex" ]
-
-[params]
-
-compress/mode=0
-compress/lossy_quality=0.7
-compress/hdr_mode=0
-compress/bptc_ldr=0
-compress/normal_map=0
-flags/repeat=0
-flags/filter=true
-flags/mipmaps=false
-flags/anisotropic=false
-flags/srgb=2
-process/fix_alpha_border=true
-process/premult_alpha=false
-process/HDR_as_SRGB=false
-process/invert_color=false
-stream=false
-size_limit=0
-detect_3d=false
-svg/scale=1.0
diff --git a/gfx/guns/FNScar.png.import b/gfx/guns/FNScar.png.import
deleted file mode 100644
index 80087dd..0000000
--- a/gfx/guns/FNScar.png.import
+++ /dev/null
@@ -1,34 +0,0 @@
-[remap]
-
-importer="texture"
-type="StreamTexture"
-path="res://.import/FNScar.png-6b3a68f387ec6ab89122d03cf241a16f.stex"
-metadata={
-"vram_texture": false
-}
-
-[deps]
-
-source_file="res://gfx/guns/FNScar.png"
-dest_files=[ "res://.import/FNScar.png-6b3a68f387ec6ab89122d03cf241a16f.stex" ]
-
-[params]
-
-compress/mode=0
-compress/lossy_quality=0.7
-compress/hdr_mode=0
-compress/bptc_ldr=0
-compress/normal_map=0
-flags/repeat=0
-flags/filter=true
-flags/mipmaps=false
-flags/anisotropic=false
-flags/srgb=2
-process/fix_alpha_border=true
-process/premult_alpha=false
-process/HDR_as_SRGB=false
-process/invert_color=false
-stream=false
-size_limit=0
-detect_3d=false
-svg/scale=1.0
diff --git a/gfx/guns/LaserPistol.png.import b/gfx/guns/LaserPistol.png.import
deleted file mode 100644
index ab1887f..0000000
--- a/gfx/guns/LaserPistol.png.import
+++ /dev/null
@@ -1,34 +0,0 @@
-[remap]
-
-importer="texture"
-type="StreamTexture"
-path="res://.import/LaserPistol.png-5913c4141046557751080b5a6a4dcbb9.stex"
-metadata={
-"vram_texture": false
-}
-
-[deps]
-
-source_file="res://gfx/guns/LaserPistol.png"
-dest_files=[ "res://.import/LaserPistol.png-5913c4141046557751080b5a6a4dcbb9.stex" ]
-
-[params]
-
-compress/mode=0
-compress/lossy_quality=0.7
-compress/hdr_mode=0
-compress/bptc_ldr=0
-compress/normal_map=0
-flags/repeat=0
-flags/filter=true
-flags/mipmaps=false
-flags/anisotropic=false
-flags/srgb=2
-process/fix_alpha_border=true
-process/premult_alpha=false
-process/HDR_as_SRGB=false
-process/invert_color=false
-stream=false
-size_limit=0
-detect_3d=false
-svg/scale=1.0
diff --git a/gfx/guns/M1911.png.import b/gfx/guns/M1911.png.import
deleted file mode 100644
index d8bbdfd..0000000
--- a/gfx/guns/M1911.png.import
+++ /dev/null
@@ -1,34 +0,0 @@
-[remap]
-
-importer="texture"
-type="StreamTexture"
-path="res://.import/M1911.png-fb90f2bf6081ebaaa4570e1f13d26084.stex"
-metadata={
-"vram_texture": false
-}
-
-[deps]
-
-source_file="res://gfx/guns/M1911.png"
-dest_files=[ "res://.import/M1911.png-fb90f2bf6081ebaaa4570e1f13d26084.stex" ]
-
-[params]
-
-compress/mode=0
-compress/lossy_quality=0.7
-compress/hdr_mode=0
-compress/bptc_ldr=0
-compress/normal_map=0
-flags/repeat=0
-flags/filter=true
-flags/mipmaps=false
-flags/anisotropic=false
-flags/srgb=2
-process/fix_alpha_border=true
-process/premult_alpha=false
-process/HDR_as_SRGB=false
-process/invert_color=false
-stream=false
-size_limit=0
-detect_3d=false
-svg/scale=1.0
diff --git a/gfx/guns/M1Garand.png.import b/gfx/guns/M1Garand.png.import
deleted file mode 100644
index 5c0e27f..0000000
--- a/gfx/guns/M1Garand.png.import
+++ /dev/null
@@ -1,34 +0,0 @@
-[remap]
-
-importer="texture"
-type="StreamTexture"
-path="res://.import/M1Garand.png-8ea72bda0579460c0ab21455199ddf51.stex"
-metadata={
-"vram_texture": false
-}
-
-[deps]
-
-source_file="res://gfx/guns/M1Garand.png"
-dest_files=[ "res://.import/M1Garand.png-8ea72bda0579460c0ab21455199ddf51.stex" ]
-
-[params]
-
-compress/mode=0
-compress/lossy_quality=0.7
-compress/hdr_mode=0
-compress/bptc_ldr=0
-compress/normal_map=0
-flags/repeat=0
-flags/filter=true
-flags/mipmaps=false
-flags/anisotropic=false
-flags/srgb=2
-process/fix_alpha_border=true
-process/premult_alpha=false
-process/HDR_as_SRGB=false
-process/invert_color=false
-stream=false
-size_limit=0
-detect_3d=false
-svg/scale=1.0
diff --git a/gfx/guns/MP40.png.import b/gfx/guns/MP40.png.import
deleted file mode 100644
index e218789..0000000
--- a/gfx/guns/MP40.png.import
+++ /dev/null
@@ -1,34 +0,0 @@
-[remap]
-
-importer="texture"
-type="StreamTexture"
-path="res://.import/MP40.png-541ce9f02220339ddd77f7c18bfb102c.stex"
-metadata={
-"vram_texture": false
-}
-
-[deps]
-
-source_file="res://gfx/guns/MP40.png"
-dest_files=[ "res://.import/MP40.png-541ce9f02220339ddd77f7c18bfb102c.stex" ]
-
-[params]
-
-compress/mode=0
-compress/lossy_quality=0.7
-compress/hdr_mode=0
-compress/bptc_ldr=0
-compress/normal_map=0
-flags/repeat=0
-flags/filter=true
-flags/mipmaps=false
-flags/anisotropic=false
-flags/srgb=2
-process/fix_alpha_border=true
-process/premult_alpha=false
-process/HDR_as_SRGB=false
-process/invert_color=false
-stream=false
-size_limit=0
-detect_3d=false
-svg/scale=1.0
diff --git a/gfx/guns/MauserC96.png.import b/gfx/guns/MauserC96.png.import
deleted file mode 100644
index e2938d8..0000000
--- a/gfx/guns/MauserC96.png.import
+++ /dev/null
@@ -1,34 +0,0 @@
-[remap]
-
-importer="texture"
-type="StreamTexture"
-path="res://.import/MauserC96.png-e3f26ff256559f76cbf4380e8c78de28.stex"
-metadata={
-"vram_texture": false
-}
-
-[deps]
-
-source_file="res://gfx/guns/MauserC96.png"
-dest_files=[ "res://.import/MauserC96.png-e3f26ff256559f76cbf4380e8c78de28.stex" ]
-
-[params]
-
-compress/mode=0
-compress/lossy_quality=0.7
-compress/hdr_mode=0
-compress/bptc_ldr=0
-compress/normal_map=0
-flags/repeat=0
-flags/filter=true
-flags/mipmaps=false
-flags/anisotropic=false
-flags/srgb=2
-process/fix_alpha_border=true
-process/premult_alpha=false
-process/HDR_as_SRGB=false
-process/invert_color=false
-stream=false
-size_limit=0
-detect_3d=false
-svg/scale=1.0
diff --git a/gfx/guns/MoneyLauncher.png.import b/gfx/guns/MoneyLauncher.png.import
deleted file mode 100644
index a6df972..0000000
--- a/gfx/guns/MoneyLauncher.png.import
+++ /dev/null
@@ -1,34 +0,0 @@
-[remap]
-
-importer="texture"
-type="StreamTexture"
-path="res://.import/MoneyLauncher.png-38558cda7f759b8a828a02520ae7fa9d.stex"
-metadata={
-"vram_texture": false
-}
-
-[deps]
-
-source_file="res://gfx/guns/MoneyLauncher.png"
-dest_files=[ "res://.import/MoneyLauncher.png-38558cda7f759b8a828a02520ae7fa9d.stex" ]
-
-[params]
-
-compress/mode=0
-compress/lossy_quality=0.7
-compress/hdr_mode=0
-compress/bptc_ldr=0
-compress/normal_map=0
-flags/repeat=0
-flags/filter=true
-flags/mipmaps=false
-flags/anisotropic=false
-flags/srgb=2
-process/fix_alpha_border=true
-process/premult_alpha=false
-process/HDR_as_SRGB=false
-process/invert_color=false
-stream=false
-size_limit=0
-detect_3d=false
-svg/scale=1.0
diff --git a/gfx/guns/P90.png.import b/gfx/guns/P90.png.import
deleted file mode 100644
index 89ad7ae..0000000
--- a/gfx/guns/P90.png.import
+++ /dev/null
@@ -1,34 +0,0 @@
-[remap]
-
-importer="texture"
-type="StreamTexture"
-path="res://.import/P90.png-b84ced4c3b84daba88bcb46f3f2fb629.stex"
-metadata={
-"vram_texture": false
-}
-
-[deps]
-
-source_file="res://gfx/guns/P90.png"
-dest_files=[ "res://.import/P90.png-b84ced4c3b84daba88bcb46f3f2fb629.stex" ]
-
-[params]
-
-compress/mode=0
-compress/lossy_quality=0.7
-compress/hdr_mode=0
-compress/bptc_ldr=0
-compress/normal_map=0
-flags/repeat=0
-flags/filter=true
-flags/mipmaps=false
-flags/anisotropic=false
-flags/srgb=2
-process/fix_alpha_border=true
-process/premult_alpha=false
-process/HDR_as_SRGB=false
-process/invert_color=false
-stream=false
-size_limit=0
-detect_3d=false
-svg/scale=1.0
diff --git a/gfx/guns/PlasmaBlaster.png.import b/gfx/guns/PlasmaBlaster.png.import
deleted file mode 100644
index f5a71fd..0000000
--- a/gfx/guns/PlasmaBlaster.png.import
+++ /dev/null
@@ -1,34 +0,0 @@
-[remap]
-
-importer="texture"
-type="StreamTexture"
-path="res://.import/PlasmaBlaster.png-662106c2dd5c775f0121fd667460ead0.stex"
-metadata={
-"vram_texture": false
-}
-
-[deps]
-
-source_file="res://gfx/guns/PlasmaBlaster.png"
-dest_files=[ "res://.import/PlasmaBlaster.png-662106c2dd5c775f0121fd667460ead0.stex" ]
-
-[params]
-
-compress/mode=0
-compress/lossy_quality=0.7
-compress/hdr_mode=0
-compress/bptc_ldr=0
-compress/normal_map=0
-flags/repeat=0
-flags/filter=true
-flags/mipmaps=false
-flags/anisotropic=false
-flags/srgb=2
-process/fix_alpha_border=true
-process/premult_alpha=false
-process/HDR_as_SRGB=false
-process/invert_color=false
-stream=false
-size_limit=0
-detect_3d=false
-svg/scale=1.0
diff --git a/gfx/guns/RocketLauncher.png.import b/gfx/guns/RocketLauncher.png.import
deleted file mode 100644
index 12e9505..0000000
--- a/gfx/guns/RocketLauncher.png.import
+++ /dev/null
@@ -1,34 +0,0 @@
-[remap]
-
-importer="texture"
-type="StreamTexture"
-path="res://.import/RocketLauncher.png-fa5fe47507c4a5106da9783313b29ce2.stex"
-metadata={
-"vram_texture": false
-}
-
-[deps]
-
-source_file="res://gfx/guns/RocketLauncher.png"
-dest_files=[ "res://.import/RocketLauncher.png-fa5fe47507c4a5106da9783313b29ce2.stex" ]
-
-[params]
-
-compress/mode=0
-compress/lossy_quality=0.7
-compress/hdr_mode=0
-compress/bptc_ldr=0
-compress/normal_map=0
-flags/repeat=0
-flags/filter=true
-flags/mipmaps=false
-flags/anisotropic=false
-flags/srgb=2
-process/fix_alpha_border=true
-process/premult_alpha=false
-process/HDR_as_SRGB=false
-process/invert_color=false
-stream=false
-size_limit=0
-detect_3d=false
-svg/scale=1.0
diff --git a/gfx/guns/Sawed-OffWinchester1897.png.import b/gfx/guns/Sawed-OffWinchester1897.png.import
deleted file mode 100644
index 7eb6b1a..0000000
--- a/gfx/guns/Sawed-OffWinchester1897.png.import
+++ /dev/null
@@ -1,34 +0,0 @@
-[remap]
-
-importer="texture"
-type="StreamTexture"
-path="res://.import/Sawed-OffWinchester1897.png-1828856c6c85c4c85f9f239d881cc72a.stex"
-metadata={
-"vram_texture": false
-}
-
-[deps]
-
-source_file="res://gfx/guns/Sawed-OffWinchester1897.png"
-dest_files=[ "res://.import/Sawed-OffWinchester1897.png-1828856c6c85c4c85f9f239d881cc72a.stex" ]
-
-[params]
-
-compress/mode=0
-compress/lossy_quality=0.7
-compress/hdr_mode=0
-compress/bptc_ldr=0
-compress/normal_map=0
-flags/repeat=0
-flags/filter=true
-flags/mipmaps=false
-flags/anisotropic=false
-flags/srgb=2
-process/fix_alpha_border=true
-process/premult_alpha=false
-process/HDR_as_SRGB=false
-process/invert_color=false
-stream=false
-size_limit=0
-detect_3d=false
-svg/scale=1.0
diff --git a/gfx/guns/SuperSoaker.png.import b/gfx/guns/SuperSoaker.png.import
deleted file mode 100644
index 4609483..0000000
--- a/gfx/guns/SuperSoaker.png.import
+++ /dev/null
@@ -1,34 +0,0 @@
-[remap]
-
-importer="texture"
-type="StreamTexture"
-path="res://.import/SuperSoaker.png-ad26a5aee73722ca7f641ac2f8616b8a.stex"
-metadata={
-"vram_texture": false
-}
-
-[deps]
-
-source_file="res://gfx/guns/SuperSoaker.png"
-dest_files=[ "res://.import/SuperSoaker.png-ad26a5aee73722ca7f641ac2f8616b8a.stex" ]
-
-[params]
-
-compress/mode=0
-compress/lossy_quality=0.7
-compress/hdr_mode=0
-compress/bptc_ldr=0
-compress/normal_map=0
-flags/repeat=0
-flags/filter=true
-flags/mipmaps=false
-flags/anisotropic=false
-flags/srgb=2
-process/fix_alpha_border=true
-process/premult_alpha=false
-process/HDR_as_SRGB=false
-process/invert_color=false
-stream=false
-size_limit=0
-detect_3d=false
-svg/scale=1.0
diff --git a/gfx/guns/ThombsonSMG.png.import b/gfx/guns/ThombsonSMG.png.import
deleted file mode 100644
index 676862c..0000000
--- a/gfx/guns/ThombsonSMG.png.import
+++ /dev/null
@@ -1,34 +0,0 @@
-[remap]
-
-importer="texture"
-type="StreamTexture"
-path="res://.import/ThombsonSMG.png-3e71e65b4033797b49413ad61792d18e.stex"
-metadata={
-"vram_texture": false
-}
-
-[deps]
-
-source_file="res://gfx/guns/ThombsonSMG.png"
-dest_files=[ "res://.import/ThombsonSMG.png-3e71e65b4033797b49413ad61792d18e.stex" ]
-
-[params]
-
-compress/mode=0
-compress/lossy_quality=0.7
-compress/hdr_mode=0
-compress/bptc_ldr=0
-compress/normal_map=0
-flags/repeat=0
-flags/filter=true
-flags/mipmaps=false
-flags/anisotropic=false
-flags/srgb=2
-process/fix_alpha_border=true
-process/premult_alpha=false
-process/HDR_as_SRGB=false
-process/invert_color=false
-stream=false
-size_limit=0
-detect_3d=false
-svg/scale=1.0
diff --git a/gfx/guns/Uzi.png.import b/gfx/guns/Uzi.png.import
deleted file mode 100644
index 3dc3ab6..0000000
--- a/gfx/guns/Uzi.png.import
+++ /dev/null
@@ -1,34 +0,0 @@
-[remap]
-
-importer="texture"
-type="StreamTexture"
-path="res://.import/Uzi.png-1c37865966347d689e7d0d5728dc5079.stex"
-metadata={
-"vram_texture": false
-}
-
-[deps]
-
-source_file="res://gfx/guns/Uzi.png"
-dest_files=[ "res://.import/Uzi.png-1c37865966347d689e7d0d5728dc5079.stex" ]
-
-[params]
-
-compress/mode=0
-compress/lossy_quality=0.7
-compress/hdr_mode=0
-compress/bptc_ldr=0
-compress/normal_map=0
-flags/repeat=0
-flags/filter=true
-flags/mipmaps=false
-flags/anisotropic=false
-flags/srgb=2
-process/fix_alpha_border=true
-process/premult_alpha=false
-process/HDR_as_SRGB=false
-process/invert_color=false
-stream=false
-size_limit=0
-detect_3d=false
-svg/scale=1.0
diff --git a/gfx/guns/WaltherP38.png.import b/gfx/guns/WaltherP38.png.import
deleted file mode 100644
index 9cd5612..0000000
--- a/gfx/guns/WaltherP38.png.import
+++ /dev/null
@@ -1,34 +0,0 @@
-[remap]
-
-importer="texture"
-type="StreamTexture"
-path="res://.import/WaltherP38.png-c8185be1b2a1769c60b86322c1f29049.stex"
-metadata={
-"vram_texture": false
-}
-
-[deps]
-
-source_file="res://gfx/guns/WaltherP38.png"
-dest_files=[ "res://.import/WaltherP38.png-c8185be1b2a1769c60b86322c1f29049.stex" ]
-
-[params]
-
-compress/mode=0
-compress/lossy_quality=0.7
-compress/hdr_mode=0
-compress/bptc_ldr=0
-compress/normal_map=0
-flags/repeat=0
-flags/filter=true
-flags/mipmaps=false
-flags/anisotropic=false
-flags/srgb=2
-process/fix_alpha_border=true
-process/premult_alpha=false
-process/HDR_as_SRGB=false
-process/invert_color=false
-stream=false
-size_limit=0
-detect_3d=false
-svg/scale=1.0
diff --git a/gfx/guns/Winchester1873.png.import b/gfx/guns/Winchester1873.png.import
deleted file mode 100644
index f7c4231..0000000
--- a/gfx/guns/Winchester1873.png.import
+++ /dev/null
@@ -1,34 +0,0 @@
-[remap]
-
-importer="texture"
-type="StreamTexture"
-path="res://.import/Winchester1873.png-1b4ec1d71f56d7af98fb910a51fa5323.stex"
-metadata={
-"vram_texture": false
-}
-
-[deps]
-
-source_file="res://gfx/guns/Winchester1873.png"
-dest_files=[ "res://.import/Winchester1873.png-1b4ec1d71f56d7af98fb910a51fa5323.stex" ]
-
-[params]
-
-compress/mode=0
-compress/lossy_quality=0.7
-compress/hdr_mode=0
-compress/bptc_ldr=0
-compress/normal_map=0
-flags/repeat=0
-flags/filter=true
-flags/mipmaps=false
-flags/anisotropic=false
-flags/srgb=2
-process/fix_alpha_border=true
-process/premult_alpha=false
-process/HDR_as_SRGB=false
-process/invert_color=false
-stream=false
-size_limit=0
-detect_3d=false
-svg/scale=1.0
diff --git a/gfx/guns/Winchester1897.png.import b/gfx/guns/Winchester1897.png.import
deleted file mode 100644
index f09924c..0000000
--- a/gfx/guns/Winchester1897.png.import
+++ /dev/null
@@ -1,34 +0,0 @@
-[remap]
-
-importer="texture"
-type="StreamTexture"
-path="res://.import/Winchester1897.png-a4adb39ab0537aef28a489a5a9e49483.stex"
-metadata={
-"vram_texture": false
-}
-
-[deps]
-
-source_file="res://gfx/guns/Winchester1897.png"
-dest_files=[ "res://.import/Winchester1897.png-a4adb39ab0537aef28a489a5a9e49483.stex" ]
-
-[params]
-
-compress/mode=0
-compress/lossy_quality=0.7
-compress/hdr_mode=0
-compress/bptc_ldr=0
-compress/normal_map=0
-flags/repeat=0
-flags/filter=true
-flags/mipmaps=false
-flags/anisotropic=false
-flags/srgb=2
-process/fix_alpha_border=true
-process/premult_alpha=false
-process/HDR_as_SRGB=false
-process/invert_color=false
-stream=false
-size_limit=0
-detect_3d=false
-svg/scale=1.0
diff --git a/gfx/hit_decal.png.import b/gfx/hit_decal.png.import
deleted file mode 100644
index 3c49781..0000000
--- a/gfx/hit_decal.png.import
+++ /dev/null
@@ -1,34 +0,0 @@
-[remap]
-
-importer="texture"
-type="StreamTexture"
-path="res://.import/hit_decal.png-774262fc5a2cc970463c1e1e2886a094.stex"
-metadata={
-"vram_texture": false
-}
-
-[deps]
-
-source_file="res://gfx/hit_decal.png"
-dest_files=[ "res://.import/hit_decal.png-774262fc5a2cc970463c1e1e2886a094.stex" ]
-
-[params]
-
-compress/mode=0
-compress/lossy_quality=0.7
-compress/hdr_mode=0
-compress/bptc_ldr=0
-compress/normal_map=0
-flags/repeat=0
-flags/filter=false
-flags/mipmaps=false
-flags/anisotropic=false
-flags/srgb=2
-process/fix_alpha_border=true
-process/premult_alpha=false
-process/HDR_as_SRGB=false
-process/invert_color=false
-stream=false
-size_limit=0
-detect_3d=false
-svg/scale=1.0
diff --git a/gfx/icon.png.import b/gfx/icon.png.import
deleted file mode 100644
index 9e6ed24..0000000
--- a/gfx/icon.png.import
+++ /dev/null
@@ -1,34 +0,0 @@
-[remap]
-
-importer="texture"
-type="StreamTexture"
-path="res://.import/icon.png-3866f89624e56ede0f5895d50d47f7c1.stex"
-metadata={
-"vram_texture": false
-}
-
-[deps]
-
-source_file="res://gfx/icon.png"
-dest_files=[ "res://.import/icon.png-3866f89624e56ede0f5895d50d47f7c1.stex" ]
-
-[params]
-
-compress/mode=0
-compress/lossy_quality=0.7
-compress/hdr_mode=0
-compress/bptc_ldr=0
-compress/normal_map=0
-flags/repeat=0
-flags/filter=true
-flags/mipmaps=false
-flags/anisotropic=false
-flags/srgb=2
-process/fix_alpha_border=true
-process/premult_alpha=false
-process/HDR_as_SRGB=false
-process/invert_color=false
-stream=false
-size_limit=0
-detect_3d=true
-svg/scale=1.0
diff --git a/gfx/icon.xcf b/gfx/icon.xcf
deleted file mode 100644
index f9ada09..0000000
Binary files a/gfx/icon.xcf and /dev/null differ
diff --git a/gfx/player.png.import b/gfx/player.png.import
deleted file mode 100644
index c48e6c3..0000000
--- a/gfx/player.png.import
+++ /dev/null
@@ -1,34 +0,0 @@
-[remap]
-
-importer="texture"
-type="StreamTexture"
-path="res://.import/player.png-3013952efb05378239c0b5ec08f70756.stex"
-metadata={
-"vram_texture": false
-}
-
-[deps]
-
-source_file="res://gfx/player.png"
-dest_files=[ "res://.import/player.png-3013952efb05378239c0b5ec08f70756.stex" ]
-
-[params]
-
-compress/mode=0
-compress/lossy_quality=0.7
-compress/hdr_mode=0
-compress/bptc_ldr=0
-compress/normal_map=0
-flags/repeat=0
-flags/filter=false
-flags/mipmaps=false
-flags/anisotropic=false
-flags/srgb=2
-process/fix_alpha_border=true
-process/premult_alpha=false
-process/HDR_as_SRGB=false
-process/invert_color=false
-stream=false
-size_limit=0
-detect_3d=true
-svg/scale=1.0
diff --git a/globals/physics_layer.gd b/globals/physics_layer.gd
new file mode 100644
index 0000000..c366f54
--- /dev/null
+++ b/globals/physics_layer.gd
@@ -0,0 +1,4 @@
+class_name PhysicsLayer
+
+const WORLD := 0b00000001
+const PLAYERS := 0b00000010
diff --git a/globals/physics_layer.gd.uid b/globals/physics_layer.gd.uid
new file mode 100644
index 0000000..8acb09b
--- /dev/null
+++ b/globals/physics_layer.gd.uid
@@ -0,0 +1 @@
+uid://bix4ydqnn8tyf
diff --git a/hud/background.gd b/hud/background.gd
new file mode 100644
index 0000000..e59ead3
--- /dev/null
+++ b/hud/background.gd
@@ -0,0 +1,10 @@
+class_name Background
+extends TextureRect
+
+func _process(delta: float) -> void:
+ var offset := Vector2(8.0, 8.0)
+ var tile_size := texture.get_size()
+ var viewport_origin := -get_viewport().canvas_transform.origin
+ var viewport_size := get_viewport_rect().size
+ position = (viewport_origin / tile_size).floor() * tile_size - offset
+ size = ((viewport_size + offset) / tile_size + Vector2.ONE).ceil() * tile_size
diff --git a/hud/background.gd.uid b/hud/background.gd.uid
new file mode 100644
index 0000000..193cb18
--- /dev/null
+++ b/hud/background.gd.uid
@@ -0,0 +1 @@
+uid://6cd3jkc185pa
diff --git a/gfx/background.png b/hud/background.png
similarity index 100%
rename from gfx/background.png
rename to hud/background.png
diff --git a/hud/background.png.import b/hud/background.png.import
new file mode 100644
index 0000000..13839a5
--- /dev/null
+++ b/hud/background.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://17f8yypfxgq8"
+path="res://.godot/imported/background.png-5a6727418e72aaf1aa4ee59c6ce8f6b2.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://hud/background.png"
+dest_files=["res://.godot/imported/background.png-5a6727418e72aaf1aa4ee59c6ce8f6b2.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/hud/cursor.gd b/hud/cursor.gd
new file mode 100644
index 0000000..9e67935
--- /dev/null
+++ b/hud/cursor.gd
@@ -0,0 +1,20 @@
+class_name Cursor
+extends Node2D
+
+## Position of the cursor in HUD coordinates.
+var hud_position: Vector2
+
+func _ready() -> void:
+ Input.mouse_mode = Input.MOUSE_MODE_HIDDEN
+
+func _notification(what: int) -> void:
+ # TODO: Keep mouse visible when it was pressed down in the game window.
+ # Meaning the game will continue to receive mouse move updates.
+ match what:
+ NOTIFICATION_WM_MOUSE_ENTER: visible = true
+ NOTIFICATION_WM_MOUSE_EXIT: visible = false
+
+func _process(delta: float) -> void:
+ # FIXME: Fix flickering mouse position when player moves.
+ position = get_global_mouse_position()
+ hud_position = get_viewport().get_mouse_position()
diff --git a/hud/cursor.gd.uid b/hud/cursor.gd.uid
new file mode 100644
index 0000000..ae6f5cc
--- /dev/null
+++ b/hud/cursor.gd.uid
@@ -0,0 +1 @@
+uid://dm2ux2aj8pdpn
diff --git a/gfx/cursor.png b/hud/cursor.png
similarity index 100%
rename from gfx/cursor.png
rename to hud/cursor.png
diff --git a/hud/cursor.png.import b/hud/cursor.png.import
new file mode 100644
index 0000000..25752d5
--- /dev/null
+++ b/hud/cursor.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cjvxdbr5eplcj"
+path="res://.godot/imported/cursor.png-f5d5b937f215ed4ffd5a25acc5a94b3a.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://hud/cursor.png"
+dest_files=["res://.godot/imported/cursor.png-f5d5b937f215ed4ffd5a25acc5a94b3a.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/hud/escape_menu/escape_menu.gd b/hud/escape_menu/escape_menu.gd
new file mode 100644
index 0000000..d60d007
--- /dev/null
+++ b/hud/escape_menu/escape_menu.gd
@@ -0,0 +1,26 @@
+class_name EscapeMenu
+extends Control
+
+@export var return_button : Button
+
+func _unhandled_input(event: InputEvent) -> void:
+ if event.is_action_pressed("ui_cancel"):
+ toggle()
+
+func toggle() -> void:
+ if visible: close()
+ else: open()
+func open() -> void:
+ if visible: return
+ # get_tree().paused = true
+ return_button.grab_focus()
+ visible = true
+func close() -> void:
+ if not visible: return
+ # get_tree().paused = false
+ visible = false
+
+func _on_quit_pressed() -> void:
+ get_tree().quit()
+func _on_return_pressed() -> void:
+ close()
diff --git a/hud/escape_menu/escape_menu.gd.uid b/hud/escape_menu/escape_menu.gd.uid
new file mode 100644
index 0000000..f197043
--- /dev/null
+++ b/hud/escape_menu/escape_menu.gd.uid
@@ -0,0 +1 @@
+uid://bmeafg5lumxiy
diff --git a/hud/escape_menu/escape_menu.tscn b/hud/escape_menu/escape_menu.tscn
new file mode 100644
index 0000000..41ed0e0
--- /dev/null
+++ b/hud/escape_menu/escape_menu.tscn
@@ -0,0 +1,128 @@
+[gd_scene load_steps=6 format=3 uid="uid://jv30ao4ppc3h"]
+
+[ext_resource type="Theme" uid="uid://4tevy1my8joc" path="res://hud/theme/ui_theme.tres" id="1"]
+[ext_resource type="Script" uid="uid://bmeafg5lumxiy" path="res://hud/escape_menu/escape_menu.gd" id="2_d0mme"]
+[ext_resource type="PackedScene" uid="uid://bqvs0e08m6hug" path="res://hud/escape_menu/escape_menu_appearance.tscn" id="3_hj3go"]
+[ext_resource type="PackedScene" uid="uid://7jb7w5ef8aw2" path="res://hud/escape_menu/escape_menu_multiplayer.tscn" id="4_1g7ww"]
+[ext_resource type="PackedScene" uid="uid://uu2v0w84blem" path="res://hud/escape_menu/escape_menu_world.tscn" id="4_f42q7"]
+
+[node name="EscapeMenu" type="Control" node_paths=PackedStringArray("return_button")]
+process_mode = 3
+layout_mode = 3
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+theme = ExtResource("1")
+script = ExtResource("2_d0mme")
+return_button = NodePath("CenterContainer/PanelContainer/MarginContainer/VBoxContainer/Return")
+
+[node name="Background" type="ColorRect" parent="."]
+layout_mode = 0
+anchor_right = 1.0
+anchor_bottom = 1.0
+color = Color(0, 0, 0, 0.501961)
+
+[node name="CenterContainer" type="CenterContainer" 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="CenterContainer"]
+layout_mode = 2
+
+[node name="MarginContainer" type="MarginContainer" parent="CenterContainer/PanelContainer"]
+layout_mode = 2
+theme_override_constants/margin_left = 4
+theme_override_constants/margin_top = 4
+theme_override_constants/margin_right = 4
+theme_override_constants/margin_bottom = 4
+
+[node name="VBoxContainer" type="VBoxContainer" parent="CenterContainer/PanelContainer/MarginContainer"]
+layout_mode = 2
+
+[node name="Label" type="Label" parent="CenterContainer/PanelContainer/MarginContainer/VBoxContainer"]
+custom_minimum_size = Vector2(0, 13)
+layout_mode = 2
+text = "Escape Menu"
+horizontal_alignment = 1
+vertical_alignment = 1
+
+[node name="HSeparator" type="HSeparator" parent="CenterContainer/PanelContainer/MarginContainer/VBoxContainer"]
+layout_mode = 2
+
+[node name="TabContainer" type="TabContainer" parent="CenterContainer/PanelContainer/MarginContainer/VBoxContainer"]
+layout_mode = 2
+size_flags_vertical = 3
+theme_override_constants/side_margin = 0
+current_tab = 1
+use_hidden_tabs_for_min_size = true
+
+[node name="Appearance" parent="CenterContainer/PanelContainer/MarginContainer/VBoxContainer/TabContainer" instance=ExtResource("3_hj3go")]
+visible = false
+layout_mode = 2
+
+[node name="Multiplayer" parent="CenterContainer/PanelContainer/MarginContainer/VBoxContainer/TabContainer" instance=ExtResource("4_1g7ww")]
+layout_mode = 2
+
+[node name="World" parent="CenterContainer/PanelContainer/MarginContainer/VBoxContainer/TabContainer" instance=ExtResource("4_f42q7")]
+visible = false
+layout_mode = 2
+
+[node name="HSeparator2" type="HSeparator" parent="CenterContainer/PanelContainer/MarginContainer/VBoxContainer"]
+layout_mode = 2
+
+[node name="Quit" type="Button" parent="CenterContainer/PanelContainer/MarginContainer/VBoxContainer"]
+layout_mode = 2
+text = " "
+
+[node name="RichTextLabel" type="RichTextLabel" parent="CenterContainer/PanelContainer/MarginContainer/VBoxContainer/Quit"]
+layout_mode = 1
+anchors_preset = 8
+anchor_left = 0.5
+anchor_top = 0.5
+anchor_right = 0.5
+anchor_bottom = 0.5
+offset_left = -44.0
+offset_top = -4.5
+offset_right = 44.0
+offset_bottom = 4.5
+grow_horizontal = 2
+grow_vertical = 2
+mouse_filter = 1
+bbcode_enabled = true
+text = "Quit Game [color=#999999](Alt+F4)[/color]"
+fit_content = true
+scroll_active = false
+autowrap_mode = 0
+
+[node name="Return" type="Button" parent="CenterContainer/PanelContainer/MarginContainer/VBoxContainer"]
+layout_mode = 2
+text = " "
+
+[node name="RichTextLabel" type="RichTextLabel" parent="CenterContainer/PanelContainer/MarginContainer/VBoxContainer/Return"]
+layout_mode = 1
+anchors_preset = 8
+anchor_left = 0.5
+anchor_top = 0.5
+anchor_right = 0.5
+anchor_bottom = 0.5
+offset_left = -49.5
+offset_top = -4.5
+offset_right = 49.5
+offset_bottom = 4.5
+grow_horizontal = 2
+grow_vertical = 2
+mouse_filter = 1
+bbcode_enabled = true
+text = "Return to Game [color=#999999](Esc)[/color]"
+fit_content = true
+scroll_active = false
+autowrap_mode = 0
+
+[connection signal="pressed" from="CenterContainer/PanelContainer/MarginContainer/VBoxContainer/Quit" to="." method="_on_quit_pressed"]
+[connection signal="pressed" from="CenterContainer/PanelContainer/MarginContainer/VBoxContainer/Return" to="." method="_on_return_pressed"]
diff --git a/hud/escape_menu/escape_menu_appearance.gd b/hud/escape_menu/escape_menu_appearance.gd
new file mode 100644
index 0000000..e4b4d89
--- /dev/null
+++ b/hud/escape_menu/escape_menu_appearance.gd
@@ -0,0 +1,27 @@
+class_name EscapeMenuAppearance
+extends CenterContainer
+
+@export var display_name : LineEdit
+@export var color_preview : TextureRect
+@export var color_slider : Slider
+
+var INVALID_CHARS := RegEx.create_from_string("\\s")
+
+func _ready() -> void:
+ color_slider.value = randf()
+ color_preview.modulate = Color.from_hsv(color_slider.value, 1.0, 1.0)
+
+func _on_display_name_text_changed(new_text: String) -> void:
+ var valid_text := INVALID_CHARS.sub(new_text, "", true)
+ if valid_text == new_text: return
+
+ var previous_caret_column = display_name.caret_column
+ display_name.text = valid_text
+ display_name.caret_column = previous_caret_column - (new_text.length() - valid_text.length())
+
+func _on_hue_value_changed(value: float) -> void:
+ color_preview.modulate = Color.from_hsv(color_slider.value, 1.0, 1.0)
+
+func _on_visibility_changed() -> void:
+ if is_visible_in_tree(): return # only run when hiding
+ # TODO: Apply name and color to local player.
diff --git a/hud/escape_menu/escape_menu_appearance.gd.uid b/hud/escape_menu/escape_menu_appearance.gd.uid
new file mode 100644
index 0000000..95cc0fc
--- /dev/null
+++ b/hud/escape_menu/escape_menu_appearance.gd.uid
@@ -0,0 +1 @@
+uid://cn2xq3f6mtmd2
diff --git a/hud/escape_menu/escape_menu_appearance.tscn b/hud/escape_menu/escape_menu_appearance.tscn
new file mode 100644
index 0000000..afd5228
--- /dev/null
+++ b/hud/escape_menu/escape_menu_appearance.tscn
@@ -0,0 +1,65 @@
+[gd_scene load_steps=3 format=3 uid="uid://bqvs0e08m6hug"]
+
+[ext_resource type="Script" uid="uid://cn2xq3f6mtmd2" path="res://hud/escape_menu/escape_menu_appearance.gd" id="1_w5wcg"]
+[ext_resource type="Texture2D" uid="uid://bghhc7sjlstuv" path="res://player/player.png" id="2_57ibk"]
+
+[node name="Appearance" type="CenterContainer" node_paths=PackedStringArray("display_name", "color_preview", "color_slider")]
+script = ExtResource("1_w5wcg")
+display_name = NodePath("MarginContainer/VBoxContainer/ContainerName/DisplayName")
+color_preview = NodePath("MarginContainer/VBoxContainer/ContainerColor/Preview")
+color_slider = NodePath("MarginContainer/VBoxContainer/ContainerColor/Hue")
+metadata/_tab_index = 0
+
+[node name="MarginContainer" type="MarginContainer" parent="."]
+layout_mode = 2
+theme_override_constants/margin_left = 6
+theme_override_constants/margin_top = 6
+theme_override_constants/margin_right = 6
+theme_override_constants/margin_bottom = 4
+
+[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer"]
+layout_mode = 2
+
+[node name="ContainerName" type="HBoxContainer" parent="MarginContainer/VBoxContainer"]
+layout_mode = 2
+
+[node name="Label" type="Label" parent="MarginContainer/VBoxContainer/ContainerName"]
+custom_minimum_size = Vector2(36, 0)
+layout_mode = 2
+text = "Name:"
+
+[node name="DisplayName" type="LineEdit" parent="MarginContainer/VBoxContainer/ContainerName"]
+custom_minimum_size = Vector2(142, 0)
+layout_mode = 2
+size_flags_horizontal = 3
+max_length = 20
+caret_blink = true
+
+[node name="ContainerColor" type="HBoxContainer" parent="MarginContainer/VBoxContainer"]
+layout_mode = 2
+
+[node name="Label" type="Label" parent="MarginContainer/VBoxContainer/ContainerColor"]
+custom_minimum_size = Vector2(36, 0)
+layout_mode = 2
+text = "Color:"
+
+[node name="Preview" type="TextureRect" parent="MarginContainer/VBoxContainer/ContainerColor"]
+layout_mode = 2
+texture = ExtResource("2_57ibk")
+
+[node name="Hue" type="HSlider" parent="MarginContainer/VBoxContainer/ContainerColor"]
+layout_mode = 2
+size_flags_horizontal = 3
+max_value = 1.0
+step = 0.0
+scrollable = false
+
+[node name="Label" type="Label" parent="MarginContainer/VBoxContainer"]
+custom_minimum_size = Vector2(0, 12)
+layout_mode = 2
+theme_override_colors/font_color = Color(0.6, 0.6, 0.6, 1)
+text = "(Close Menu to apply changes.)"
+
+[connection signal="visibility_changed" from="." to="." method="_on_visibility_changed"]
+[connection signal="text_changed" from="MarginContainer/VBoxContainer/ContainerName/DisplayName" to="." method="_on_display_name_text_changed"]
+[connection signal="value_changed" from="MarginContainer/VBoxContainer/ContainerColor/Hue" to="." method="_on_hue_value_changed"]
diff --git a/hud/escape_menu/escape_menu_multiplayer.gd b/hud/escape_menu/escape_menu_multiplayer.gd
new file mode 100644
index 0000000..78bff02
--- /dev/null
+++ b/hud/escape_menu/escape_menu_multiplayer.gd
@@ -0,0 +1,77 @@
+class_name EscapeMenuMultiplayer
+extends CenterContainer
+
+# TODO: Display and update player count.
+const STATUS_DEFAULT := [ "No connection" , Color.ORANGE ]
+
+const STATUS_CLIENT_CONNECTING := [ "Connecting ..." , Color.YELLOW ]
+const STATUS_CLIENT_CONNECTED := [ "Connected (%d player%s)" , Color.GREEN ]
+const STATUS_CLIENT_FAILED_TO_CONNECT := [ "Failed to connect" , Color.RED ]
+const STATUS_CLIENT_DISCONNECTED := [ "Disconnected" , Color.ORANGE ]
+const STATUS_SERVER_DISCONNECTED := [ "Server disconnected" , Color.ORANGE ]
+
+const STATUS_SERVER_RUNNING := [ "Server running (%d player%s)" , Color.GREEN ]
+const STATUS_SERVER_STOPPED := [ "Server stopped" , Color.ORANGE ]
+
+const STATUS_ERROR_ALREADY_IN_USE := [ "Already in use" , Color.RED ]
+const STATUS_ERROR_CANT_CREATE := [ "Cant create" , Color.RED ]
+
+@onready var status_label : Label = %Status
+@onready var port_box : SpinBox = %Port
+@onready var address_edit : LineEdit = %Address
+
+@onready var open_close_button : Button = %OpenClose
+@onready var dis_connect_button : Button = %DisConnect
+
+func _ready() -> void:
+ _update_status(STATUS_DEFAULT)
+ Game.NETWORK.status_changed.connect(_on_status_changed)
+
+func _on_hide_address_toggled(toggled_on: bool) -> void:
+ address_edit.secret = toggled_on
+
+func _on_status_changed(new_status: Network.Status, old_status: Network.Status) -> void:
+ match new_status:
+ Network.Status.SINGLEPLAYER:
+ match old_status:
+ Network.Status.CLIENT_CONNECTING: _update_status(STATUS_CLIENT_FAILED_TO_CONNECT)
+ Network.Status.CLIENT_CONNECTED : _update_status(STATUS_SERVER_DISCONNECTED)
+ Network.Status.SERVER_RUNNING : _update_status(STATUS_SERVER_STOPPED)
+ open_close_button.text = "Open Server"
+ dis_connect_button.disabled = false
+ dis_connect_button.text = "Connect"
+ open_close_button.disabled = false
+
+ Network.Status.CLIENT_CONNECTING:
+ _update_status(STATUS_CLIENT_CONNECTING)
+ dis_connect_button.text = "Disconnect"
+ open_close_button.disabled = true
+
+ Network.Status.CLIENT_CONNECTED:
+ _update_status(STATUS_CLIENT_CONNECTED)
+
+ Network.Status.SERVER_RUNNING:
+ _update_status(STATUS_SERVER_RUNNING)
+ open_close_button.text = "Close Server"
+ dis_connect_button.disabled = true
+
+func _on_open_close_pressed() -> void:
+ if open_close_button.text == "Open Server":
+ match Game.NETWORK.start_server(int(port_box.value)):
+ ERR_ALREADY_IN_USE: _update_status(STATUS_ERROR_ALREADY_IN_USE)
+ ERR_CANT_CREATE : _update_status(STATUS_ERROR_CANT_CREATE)
+ else:
+ Game.NETWORK.stop_server()
+
+func _on_dis_connect_pressed() -> void:
+ if dis_connect_button.text == "Connect":
+ var address := address_edit.text if address_edit.text else "localhost"
+ if Game.NETWORK.connect_to_server(address): _update_status(STATUS_ERROR_CANT_CREATE)
+ else:
+ Game.NETWORK.disconnect_from_server()
+ # Without this it would (incorrectly?) display "failed to connect".
+ _update_status(STATUS_CLIENT_DISCONNECTED)
+
+func _update_status(status: Array) -> void:
+ status_label.text = status[0]
+ status_label.modulate = status[1]
diff --git a/hud/escape_menu/escape_menu_multiplayer.gd.uid b/hud/escape_menu/escape_menu_multiplayer.gd.uid
new file mode 100644
index 0000000..41ce839
--- /dev/null
+++ b/hud/escape_menu/escape_menu_multiplayer.gd.uid
@@ -0,0 +1 @@
+uid://bu37wh6sy6bdl
diff --git a/hud/escape_menu/escape_menu_multiplayer.tscn b/hud/escape_menu/escape_menu_multiplayer.tscn
new file mode 100644
index 0000000..1f077a0
--- /dev/null
+++ b/hud/escape_menu/escape_menu_multiplayer.tscn
@@ -0,0 +1,92 @@
+[gd_scene load_steps=2 format=3 uid="uid://7jb7w5ef8aw2"]
+
+[ext_resource type="Script" uid="uid://bu37wh6sy6bdl" path="res://hud/escape_menu/escape_menu_multiplayer.gd" id="1_0u4gd"]
+
+[node name="Multiplayer" type="CenterContainer"]
+script = ExtResource("1_0u4gd")
+metadata/_tab_index = 1
+
+[node name="MarginContainer" type="MarginContainer" parent="."]
+layout_mode = 2
+theme_override_constants/margin_left = 6
+theme_override_constants/margin_top = 6
+theme_override_constants/margin_right = 6
+theme_override_constants/margin_bottom = 4
+
+[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer"]
+layout_mode = 2
+
+[node name="ContainerStatus" type="HBoxContainer" parent="MarginContainer/VBoxContainer"]
+layout_mode = 2
+
+[node name="Label" type="Label" parent="MarginContainer/VBoxContainer/ContainerStatus"]
+custom_minimum_size = Vector2(36, 0)
+layout_mode = 2
+text = "Status:"
+
+[node name="Status" type="Label" parent="MarginContainer/VBoxContainer/ContainerStatus"]
+unique_name_in_owner = true
+layout_mode = 2
+size_flags_horizontal = 3
+size_flags_vertical = 5
+
+[node name="ContainerServer" type="HBoxContainer" parent="MarginContainer/VBoxContainer"]
+layout_mode = 2
+
+[node name="Label" type="Label" parent="MarginContainer/VBoxContainer/ContainerServer"]
+custom_minimum_size = Vector2(36, 0)
+layout_mode = 2
+text = "Port:"
+
+[node name="Port" type="SpinBox" parent="MarginContainer/VBoxContainer/ContainerServer"]
+unique_name_in_owner = true
+layout_mode = 2
+min_value = 1024.0
+max_value = 65535.0
+value = 42005.0
+alignment = 2
+
+[node name="OpenClose" type="Button" parent="MarginContainer/VBoxContainer/ContainerServer"]
+unique_name_in_owner = true
+layout_mode = 2
+size_flags_horizontal = 3
+text = "Open Server"
+
+[node name="ContainerClient" type="HBoxContainer" parent="MarginContainer/VBoxContainer"]
+layout_mode = 2
+
+[node name="Label" type="Label" parent="MarginContainer/VBoxContainer/ContainerClient"]
+custom_minimum_size = Vector2(36, 0)
+layout_mode = 2
+text = "Address:"
+
+[node name="Address" type="LineEdit" parent="MarginContainer/VBoxContainer/ContainerClient"]
+unique_name_in_owner = true
+custom_minimum_size = Vector2(120, 0)
+layout_mode = 2
+placeholder_text = "localhost"
+caret_blink = true
+
+[node name="DisConnect" type="Button" parent="MarginContainer/VBoxContainer/ContainerClient"]
+unique_name_in_owner = true
+custom_minimum_size = Vector2(57, 0)
+layout_mode = 2
+size_flags_horizontal = 3
+text = "Connect"
+
+[node name="ContainerHideAddress" type="HBoxContainer" parent="MarginContainer/VBoxContainer"]
+layout_mode = 2
+
+[node name="HideAddress" type="CheckBox" parent="MarginContainer/VBoxContainer/ContainerHideAddress"]
+layout_mode = 2
+button_pressed = true
+text = "Hide Address"
+
+[node name="Label" type="Label" parent="MarginContainer/VBoxContainer/ContainerHideAddress"]
+layout_mode = 2
+theme_override_colors/font_color = Color(0.6, 0.6, 0.6, 1)
+text = "(for streamers etc.)"
+
+[connection signal="pressed" from="MarginContainer/VBoxContainer/ContainerServer/OpenClose" to="." method="_on_open_close_pressed"]
+[connection signal="pressed" from="MarginContainer/VBoxContainer/ContainerClient/DisConnect" to="." method="_on_dis_connect_pressed"]
+[connection signal="toggled" from="MarginContainer/VBoxContainer/ContainerHideAddress/HideAddress" to="." method="_on_hide_address_toggled"]
diff --git a/hud/escape_menu/escape_menu_world.gd b/hud/escape_menu/escape_menu_world.gd
new file mode 100644
index 0000000..bae5e58
--- /dev/null
+++ b/hud/escape_menu/escape_menu_world.gd
@@ -0,0 +1,72 @@
+class_name EscapeMenuWorld
+extends CenterContainer
+
+@onready var save_file_dialog : FileDialog = %SaveFileDialog
+@onready var load_file_dialog : FileDialog = %LoadFileDialog
+
+@onready var filename_label : Label = %Filename
+@onready var playtime_label : Label = %Playtime
+@onready var last_saved_label : Label = %LastSaved
+
+@onready var quick_save_button : Button = %QuickSave
+@onready var save_as_button : Button = %SaveAs
+@onready var load_from_button : Button = %LoadFrom
+
+var current_world : String
+
+func _ready() -> void:
+ # Hide "Quick Save" button until world is loaded/saved, and `current_world` is set.
+ quick_save_button.visible = false
+ save_as_button.text = "Save World As..."
+
+ DirAccess.make_dir_recursive_absolute(World.WORLDS_DIR)
+ var global_path := ProjectSettings.globalize_path(World.WORLDS_DIR)
+ save_file_dialog.current_path = global_path
+ load_file_dialog.current_path = global_path
+
+ # this.GetClient().StatusChanged += OnStatusChanged;
+
+func _process(delta: float) -> void:
+ var playtime := Game.WORLD.playtime
+ var seconds := floori(playtime ) % 60
+ var minutes := floori(playtime / 60 ) % 60
+ var hours := floori(playtime / (60 * 60) ) % 24
+ var days := floori(playtime / (60 * 60 * 24))
+
+ var str = ""
+ if days > 0: str += "%dd " % days
+ str += "%02dh %02dm %02ds" % [ hours, minutes, seconds ]
+ playtime_label.text = str
+
+
+func _on_quick_save_pressed() -> void:
+ _on_save_file_dialog_file_selected(current_world)
+
+func _on_save_as_pressed() -> void:
+ save_file_dialog.invalidate()
+ save_file_dialog.popup_centered()
+func _on_save_file_dialog_file_selected(path: String) -> void:
+ Game.WORLD.save(path)
+ current_world = path
+ filename_label.text = path.get_file()
+ last_saved_label.text = _unix_time_to_string(Game.WORLD.last_saved)
+ quick_save_button.visible = true
+ save_as_button.text = "Save As..."
+
+func _on_load_from_pressed() -> void:
+ load_file_dialog.invalidate()
+ load_file_dialog.popup_centered()
+func _on_load_file_dialog_file_selected(path: String) -> void:
+ var world := World.load(path)
+ if not world: return
+ Game.INSTANCE.change_world(world)
+
+ current_world = path
+ filename_label.text = path.get_file()
+ last_saved_label.text = _unix_time_to_string(world.last_saved)
+ quick_save_button.visible = true
+ save_as_button.text = "Save As..."
+
+func _unix_time_to_string(time: int) -> String:
+ var d := Time.get_datetime_dict_from_unix_time(time)
+ return "%04d-%02d-%02d %02d:%02d" % [ d.year, d.month, d.day, d.hour, d.minute ]
diff --git a/hud/escape_menu/escape_menu_world.gd.uid b/hud/escape_menu/escape_menu_world.gd.uid
new file mode 100644
index 0000000..fd79737
--- /dev/null
+++ b/hud/escape_menu/escape_menu_world.gd.uid
@@ -0,0 +1 @@
+uid://q1o7rlr8roy1
diff --git a/hud/escape_menu/escape_menu_world.tscn b/hud/escape_menu/escape_menu_world.tscn
new file mode 100644
index 0000000..5acdd1d
--- /dev/null
+++ b/hud/escape_menu/escape_menu_world.tscn
@@ -0,0 +1,121 @@
+[gd_scene load_steps=2 format=3 uid="uid://uu2v0w84blem"]
+
+[ext_resource type="Script" uid="uid://q1o7rlr8roy1" path="res://hud/escape_menu/escape_menu_world.gd" id="1_ayi2r"]
+
+[node name="World" type="CenterContainer"]
+script = ExtResource("1_ayi2r")
+metadata/_tab_index = 2
+
+[node name="SaveFileDialog" type="FileDialog" parent="."]
+unique_name_in_owner = true
+auto_translate_mode = 1
+title = "Save World"
+size = Vector2i(781, 320)
+mode_overrides_title = false
+access = 2
+filters = PackedStringArray("*.yf5 ; YourFortV")
+use_native_dialog = true
+
+[node name="LoadFileDialog" type="FileDialog" parent="."]
+unique_name_in_owner = true
+auto_translate_mode = 1
+title = "Load World"
+size = Vector2i(781, 320)
+ok_button_text = "Load"
+mode_overrides_title = false
+file_mode = 0
+access = 2
+filters = PackedStringArray("*.yf5 ; YourFortV")
+use_native_dialog = true
+
+[node name="MarginContainer" type="MarginContainer" parent="."]
+layout_mode = 2
+theme_override_constants/margin_left = 6
+theme_override_constants/margin_top = 6
+theme_override_constants/margin_right = 6
+theme_override_constants/margin_bottom = 4
+
+[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer"]
+custom_minimum_size = Vector2(180, 0)
+layout_mode = 2
+
+[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/VBoxContainer"]
+layout_mode = 2
+
+[node name="Label" type="Label" parent="MarginContainer/VBoxContainer/HBoxContainer"]
+custom_minimum_size = Vector2(58, 0)
+layout_mode = 2
+text = "Filename:"
+
+[node name="Filename" type="Label" parent="MarginContainer/VBoxContainer/HBoxContainer"]
+unique_name_in_owner = true
+layout_mode = 2
+size_flags_horizontal = 3
+theme_override_colors/font_color = Color(0.6, 0.6, 0.6, 1)
+text = "-not saved yet-"
+
+[node name="HBoxContainer2" type="HBoxContainer" parent="MarginContainer/VBoxContainer"]
+layout_mode = 2
+
+[node name="Label" type="Label" parent="MarginContainer/VBoxContainer/HBoxContainer2"]
+custom_minimum_size = Vector2(58, 0)
+layout_mode = 2
+text = "Playtime:"
+
+[node name="Playtime" type="Label" parent="MarginContainer/VBoxContainer/HBoxContainer2"]
+unique_name_in_owner = true
+layout_mode = 2
+size_flags_horizontal = 3
+theme_override_colors/font_color = Color(0.6, 0.6, 0.6, 1)
+text = "000d 00h 00m 00s"
+
+[node name="HBoxContainer3" type="HBoxContainer" parent="MarginContainer/VBoxContainer"]
+layout_mode = 2
+
+[node name="Label" type="Label" parent="MarginContainer/VBoxContainer/HBoxContainer3"]
+custom_minimum_size = Vector2(58, 0)
+layout_mode = 2
+text = "Last Saved:"
+
+[node name="LastSaved" type="Label" parent="MarginContainer/VBoxContainer/HBoxContainer3"]
+unique_name_in_owner = true
+layout_mode = 2
+size_flags_horizontal = 3
+theme_override_colors/font_color = Color(0.6, 0.6, 0.6, 1)
+text = "0000-00-00 00:00"
+
+[node name="HSeparator" type="HSeparator" parent="MarginContainer/VBoxContainer"]
+layout_mode = 2
+
+[node name="HBoxContainer4" type="HBoxContainer" parent="MarginContainer/VBoxContainer"]
+layout_mode = 2
+
+[node name="QuickSave" type="Button" parent="MarginContainer/VBoxContainer/HBoxContainer4"]
+unique_name_in_owner = true
+custom_minimum_size = Vector2(112, 17)
+layout_mode = 2
+size_flags_horizontal = 3
+text = "Quick Save"
+
+[node name="SaveAs" type="Button" parent="MarginContainer/VBoxContainer/HBoxContainer4"]
+unique_name_in_owner = true
+custom_minimum_size = Vector2(0, 17)
+layout_mode = 2
+size_flags_horizontal = 3
+text = "Save As..."
+
+[node name="HBoxContainer5" type="HBoxContainer" parent="MarginContainer/VBoxContainer"]
+layout_mode = 2
+
+[node name="LoadFrom" type="Button" parent="MarginContainer/VBoxContainer/HBoxContainer5"]
+unique_name_in_owner = true
+custom_minimum_size = Vector2(80, 17)
+layout_mode = 2
+size_flags_horizontal = 3
+text = "Load World From..."
+
+[connection signal="file_selected" from="SaveFileDialog" to="." method="_on_save_file_dialog_file_selected"]
+[connection signal="file_selected" from="LoadFileDialog" to="." method="_on_load_file_dialog_file_selected"]
+[connection signal="pressed" from="MarginContainer/VBoxContainer/HBoxContainer4/QuickSave" to="." method="_on_quick_save_pressed"]
+[connection signal="pressed" from="MarginContainer/VBoxContainer/HBoxContainer4/SaveAs" to="." method="_on_save_as_pressed"]
+[connection signal="pressed" from="MarginContainer/VBoxContainer/HBoxContainer5/LoadFrom" to="." method="_on_load_from_pressed"]
diff --git a/hud/health.gd b/hud/health.gd
new file mode 100644
index 0000000..309fbf6
--- /dev/null
+++ b/hud/health.gd
@@ -0,0 +1,87 @@
+# TODO: Make this work again.
+class_name Health
+extends Node2D
+
+const TIME_VISIBLE := 1.0
+const TIME_FADE := 1.5
+
+@export var player : Player
+
+@export var segments := 6
+@export var inner_radius := 14
+@export var outer_radius := 24
+@export var separation := 2.0
+
+@onready var start_angle := (TAU / 4) - (TAU / segments / 2)
+
+var health : float
+var visibility_timer : float
+
+
+func _ready() -> void:
+ visible = false
+
+
+func _process(delta: float) -> void:
+ if not player:
+ visible = false
+ return
+
+ if player.health.current >= 1.0:
+ if !visible: return
+ if visibility_timer > TIME_VISIBLE + TIME_FADE:
+ visible = false
+ return
+ if visibility_timer > TIME_VISIBLE:
+ modulate = Color(Color.WHITE, 1.0 - (visibility_timer - TIME_VISIBLE) / TIME_FADE)
+ visibility_timer += delta
+
+ else:
+ visible = true
+ modulate = Color.WHITE
+ visibility_timer = 0.0
+
+ position = player.get_global_transform_with_canvas().origin;
+ health = player.health.current;
+
+
+func _draw() -> void:
+ for i in segments:
+ var angle_1 := start_angle + TAU * ( i / float(segments))
+ var angle_3 := start_angle + TAU * ((i + 1) / float(segments))
+ var angle_2 := (angle_1 + angle_3) / 2
+
+ var sep_1 := separation * Vector2.from_angle(angle_1 + TAU / 4)
+ var sep_2 := separation * Vector2.from_angle(angle_3 - TAU / 4)
+
+ draw_colored_polygon([
+ inner_radius * Vector2.from_angle(angle_2) ,
+ inner_radius * Vector2.from_angle(angle_1) + sep_1,
+ outer_radius * Vector2.from_angle(angle_1) + sep_1,
+ outer_radius * Vector2.from_angle(angle_2) ,
+ outer_radius * Vector2.from_angle(angle_3) + sep_2,
+ inner_radius * Vector2.from_angle(angle_3) + sep_2,
+ ], Color(Color.BLACK, 0.4)) # antialiased = true
+
+ for i in segments:
+ var fullness := clampf((health * segments) - i, 0.0, 1.0)
+ if fullness <= 0.1: return
+
+ var angle_1 := start_angle + TAU * ( i / float(segments))
+ var angle_3 := start_angle + TAU * ((i + 1) / float(segments))
+ var angle_2 := (angle_1 + angle_3) / 2
+
+ var sep_1 := separation * Vector2.from_angle(angle_1 + TAU / 4)
+ var sep_2 := separation * Vector2.from_angle(angle_3 - TAU / 4)
+
+ var _inner_radius_2 = inner_radius + 1
+ var _outer_radius_2 = lerpf(inner_radius, outer_radius, fullness) - 1
+
+ draw_colored_polygon([
+ inner_radius * Vector2.from_angle(angle_2) ,
+ inner_radius * Vector2.from_angle(angle_1) + sep_1,
+ outer_radius * Vector2.from_angle(angle_1) + sep_1,
+ outer_radius * Vector2.from_angle(angle_2) ,
+ outer_radius * Vector2.from_angle(angle_3) + sep_2,
+ inner_radius * Vector2.from_angle(angle_3) + sep_2,
+ ], Color(Color.RED, 0.5)) # antialiased = true
diff --git a/hud/health.gd.uid b/hud/health.gd.uid
new file mode 100644
index 0000000..94baa9c
--- /dev/null
+++ b/hud/health.gd.uid
@@ -0,0 +1 @@
+uid://b12ppoaf6wls4
diff --git a/hud/radial_menu.gd b/hud/radial_menu.gd
new file mode 100644
index 0000000..00dfcef
--- /dev/null
+++ b/hud/radial_menu.gd
@@ -0,0 +1,114 @@
+class_name RadialMenu
+extends Node2D
+
+const TIME_FADE := 0.6
+const TIME_VISIBLE := 0.4
+
+@export var cursor : Cursor
+@export var player : Player
+
+@export var min_segments := 8
+@export var inner_radius := 32.0
+@export var outer_radius := 64.0
+@export var separation := 2.0
+
+@onready var label := $Label as Label
+@onready var start_angle := (TAU / 4) - (TAU / min_segments / 2)
+
+var visibility_timer: float
+
+var hovered: Item:
+ get: return hovered
+ set(value): hovered = value; label.text = str(value.name) if value else ""
+
+func _unhandled_input(event: InputEvent) -> void:
+ if not player or not player.health.is_alive: return
+
+ if event.is_action_pressed("interact_select"):
+ position = cursor.hud_position.round()
+ visible = true
+ modulate = Color.WHITE
+
+ hovered = player.inventory.equipped
+ player.inventory.equipped = null
+
+ visibility_timer = INF
+
+ var select_dec := event.is_action_pressed("interact_select_dec")
+ var select_inc := event.is_action_pressed("interact_select_inc")
+ if select_dec != select_inc: # xor would be more fitting here
+ if visible and visibility_timer == INF:
+ var cursor_offset := to_local(cursor.hud_position)
+ if cursor_offset.length() > inner_radius: return
+ else:
+ position = player.get_global_transform_with_canvas().origin
+ hovered = player.inventory.equipped
+
+ visible = true
+ modulate = Color.WHITE
+ visibility_timer = TIME_FADE + TIME_VISIBLE
+
+ var items := player.inventory.get_items()
+ if items.is_empty(): return
+
+ var new_index := 0
+ if hovered:
+ var index := hovered.get_index()
+ var diff := 1 if select_inc else -1
+ new_index = posmod(index + diff, items.size())
+ hovered = items[new_index]
+ player.inventory.equipped = hovered
+ queue_redraw()
+
+func _process(delta: float) -> void:
+ if not player or not player.health.is_alive: visible = false
+ if not visible: return
+
+ visibility_timer -= delta
+ if visibility_timer <= 0.0: visible = false
+ if visibility_timer < TIME_FADE: modulate = Color(Color.WHITE, visibility_timer / TIME_FADE)
+ if visibility_timer < INF: return
+
+ var cursor_offset := to_local(cursor.hud_position)
+ var angle := cursor_offset.angle() - start_angle
+ var index := floori(fmod((angle / TAU + 1), 1) * min_segments)
+
+ var items := player.inventory.get_items()
+ if cursor_offset.length() > inner_radius and index < items.size() and items[index] != hovered:
+ hovered = items[index]
+
+ if not Input.is_action_pressed("interact_select"):
+ player.inventory.equipped = hovered
+ visibility_timer = TIME_FADE
+
+ queue_redraw()
+
+func _draw() -> void:
+ var items := player.inventory.get_items()
+ var segments := maxi(min_segments, items.size())
+ for i in segments:
+ var angle_1 := start_angle + TAU * ( i / float(segments))
+ var angle_3 := start_angle + TAU * ((i + 1) / float(segments))
+ var angle_2 := (angle_1 + angle_3) / 2
+
+ var sep_1 := separation * Vector2.from_angle(angle_1 + TAU / 4)
+ var sep_2 := separation * Vector2.from_angle(angle_3 - TAU / 4)
+
+ var is_hovered := i < items.size() and items[i] == hovered
+ var inner_radius_2 := inner_radius + (5.0 if is_hovered else 0.0)
+ var outer_radius_2 := outer_radius + (5.0 if is_hovered else 0.0)
+
+ var color := Color(0.1, 0.1, 0.1, 0.7 if is_hovered else 0.4)
+ draw_colored_polygon([
+ inner_radius_2 * Vector2.from_angle(angle_1) + sep_1,
+ outer_radius_2 * Vector2.from_angle(angle_1) + sep_1,
+ (outer_radius_2 + separation) * Vector2.from_angle(angle_2) ,
+ outer_radius_2 * Vector2.from_angle(angle_3) + sep_2,
+ inner_radius_2 * Vector2.from_angle(angle_3) + sep_2,
+ ], color)
+
+ if i < items.size():
+ var sprite := items[i]
+ var pos := (inner_radius_2 + outer_radius_2) / 2 * Vector2.from_angle(angle_2)
+ if sprite.centered: pos -= sprite.texture.get_size() / 2
+ draw_texture(sprite.texture, pos, sprite.modulate)
diff --git a/hud/radial_menu.gd.uid b/hud/radial_menu.gd.uid
new file mode 100644
index 0000000..15a348c
--- /dev/null
+++ b/hud/radial_menu.gd.uid
@@ -0,0 +1 @@
+uid://doey28skdr0ty
diff --git a/hud/radial_menu.tscn b/hud/radial_menu.tscn
new file mode 100644
index 0000000..62f1bb9
--- /dev/null
+++ b/hud/radial_menu.tscn
@@ -0,0 +1,24 @@
+[gd_scene load_steps=3 format=3 uid="uid://br618d1sbfgie"]
+
+[ext_resource type="Script" uid="uid://doey28skdr0ty" path="res://hud/radial_menu.gd" id="1_pmlck"]
+[ext_resource type="Theme" uid="uid://4tevy1my8joc" path="res://hud/theme/ui_theme.tres" id="2_ahx0k"]
+
+[node name="RadialMenu" type="Node2D"]
+script = ExtResource("1_pmlck")
+
+[node name="Label" type="Label" parent="."]
+anchors_preset = 8
+anchor_left = 0.5
+anchor_top = 0.5
+anchor_right = 0.5
+anchor_bottom = 0.5
+offset_left = -29.0
+offset_top = -16.0
+offset_right = 29.0
+offset_bottom = 16.0
+grow_horizontal = 2
+grow_vertical = 2
+theme = ExtResource("2_ahx0k")
+horizontal_alignment = 1
+vertical_alignment = 1
+autowrap_mode = 2
diff --git a/HeartbitXX.ttf b/hud/theme/HeartbitXX.ttf
similarity index 100%
rename from HeartbitXX.ttf
rename to hud/theme/HeartbitXX.ttf
diff --git a/hud/theme/HeartbitXX.ttf.import b/hud/theme/HeartbitXX.ttf.import
new file mode 100644
index 0000000..77c7bb6
--- /dev/null
+++ b/hud/theme/HeartbitXX.ttf.import
@@ -0,0 +1,40 @@
+[remap]
+
+importer="font_data_dynamic"
+type="FontFile"
+uid="uid://swxa7umqpfwu"
+path="res://.godot/imported/HeartbitXX.ttf-0f40fa5f8905572711540edfa78ad592.fontdata"
+
+[deps]
+
+source_file="res://hud/theme/HeartbitXX.ttf"
+dest_files=["res://.godot/imported/HeartbitXX.ttf-0f40fa5f8905572711540edfa78ad592.fontdata"]
+
+[params]
+
+Rendering=null
+antialiasing=0
+generate_mipmaps=false
+disable_embedded_bitmaps=true
+multichannel_signed_distance_field=false
+msdf_pixel_range=8
+msdf_size=48
+allow_system_fallback=true
+force_autohinter=false
+hinting=0
+subpixel_positioning=0
+keep_rounding_remainders=true
+oversampling=0.0
+Fallbacks=null
+fallbacks=[]
+Compress=null
+compress=true
+preload=[{
+"chars": [],
+"glyphs": [],
+"name": "New Configuration",
+"size": Vector2i(16, 0)
+}]
+language_support={}
+script_support={}
+opentype_features={}
diff --git a/hud/theme/checkbox_check.png b/hud/theme/checkbox_check.png
new file mode 100644
index 0000000..e11d853
Binary files /dev/null and b/hud/theme/checkbox_check.png differ
diff --git a/hud/theme/checkbox_check.png.import b/hud/theme/checkbox_check.png.import
new file mode 100644
index 0000000..519d47d
--- /dev/null
+++ b/hud/theme/checkbox_check.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://c7rhuvmdwfkk"
+path="res://.godot/imported/checkbox_check.png-bbe69d46e6b7f8266782ba329dde8bcf.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://hud/theme/checkbox_check.png"
+dest_files=["res://.godot/imported/checkbox_check.png-bbe69d46e6b7f8266782ba329dde8bcf.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/hud/theme/checkbox_uncheck.png b/hud/theme/checkbox_uncheck.png
new file mode 100644
index 0000000..780d5ec
Binary files /dev/null and b/hud/theme/checkbox_uncheck.png differ
diff --git a/hud/theme/checkbox_uncheck.png.import b/hud/theme/checkbox_uncheck.png.import
new file mode 100644
index 0000000..fab0052
--- /dev/null
+++ b/hud/theme/checkbox_uncheck.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cxk2noaybwgrv"
+path="res://.godot/imported/checkbox_uncheck.png-644d262213e0aa5438792b360402e2f7.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://hud/theme/checkbox_uncheck.png"
+dest_files=["res://.godot/imported/checkbox_uncheck.png-644d262213e0aa5438792b360402e2f7.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/hud/theme/ui_theme.tres b/hud/theme/ui_theme.tres
new file mode 100644
index 0000000..6af4e46
--- /dev/null
+++ b/hud/theme/ui_theme.tres
@@ -0,0 +1,38 @@
+[gd_resource type="Theme" load_steps=5 format=3 uid="uid://4tevy1my8joc"]
+
+[ext_resource type="FontFile" uid="uid://swxa7umqpfwu" path="res://hud/theme/HeartbitXX.ttf" id="1"]
+[ext_resource type="Texture2D" uid="uid://c7rhuvmdwfkk" path="res://hud/theme/checkbox_check.png" id="1_tbeor"]
+[ext_resource type="Texture2D" uid="uid://cxk2noaybwgrv" path="res://hud/theme/checkbox_uncheck.png" id="2_mk0s6"]
+
+[sub_resource type="FontVariation" id="FontVariation_touxu"]
+base_font = ExtResource("1")
+spacing_top = -3
+spacing_bottom = -1
+
+[resource]
+default_font = SubResource("FontVariation_touxu")
+Button/colors/font_color = Color(0.88, 0.88, 0.88, 1)
+Button/colors/font_color_disabled = Color(0.9, 0.9, 0.9, 0.2)
+Button/colors/font_color_hover = Color(0.94, 0.94, 0.94, 1)
+Button/colors/font_color_pressed = Color(1, 1, 1, 1)
+Button/constants/hseparation = 2
+Button/constants/outline_size = 4
+Button/styles/disabled = null
+Button/styles/focus = null
+Button/styles/hover = null
+Button/styles/normal = null
+Button/styles/pressed = null
+CheckBox/constants/icon_max_width = 11
+CheckBox/constants/outline_size = 4
+CheckBox/icons/checked = ExtResource("1_tbeor")
+CheckBox/icons/checked_disabled = null
+CheckBox/icons/radio_checked = null
+CheckBox/icons/radio_checked_disabled = null
+CheckBox/icons/radio_unchecked = null
+CheckBox/icons/radio_unchecked_disabled = null
+CheckBox/icons/unchecked = ExtResource("2_mk0s6")
+CheckBox/icons/unchecked_disabled = null
+HSeparator/constants/separation = 3
+Label/constants/outline_size = 4
+RichTextLabel/constants/outline_size = 4
+VBoxContainer/constants/separation = 3
diff --git a/hud/weapon_info.gd b/hud/weapon_info.gd
new file mode 100644
index 0000000..c57447f
--- /dev/null
+++ b/hud/weapon_info.gd
@@ -0,0 +1,36 @@
+class_name WeaponInfo
+extends Node2D
+
+# TODO: Render rounds as sprites?
+
+const VISIBLE_DURATION := 0.8
+
+@onready var rounds := $Rounds as Label
+@onready var reloading := $Reloading as ProgressBar
+
+var _visible_delay : float
+var _previous_weapon : Weapon
+var _previous_rounds : int
+
+func _process(delta: float) -> void:
+ var player := Game.LOCAL_PLAYER
+ var weapon := player.inventory.equipped as Weapon if player else null
+ if not weapon: visible = false; _previous_weapon = null; return
+
+ visible = true
+ _visible_delay -= delta
+ if _visible_delay <= 0:
+ modulate = Color(modulate, modulate.a - delta)
+ if modulate.a <= 0: visible = false
+
+ if weapon != _previous_weapon or weapon.rounds != _previous_rounds or weapon.is_reloading:
+ _visible_delay = VISIBLE_DURATION
+ modulate = Color.WHITE
+
+ rounds.visible = weapon.capacity > 1
+ rounds.text = "%d/%d" % [ weapon.rounds, weapon.capacity ]
+ reloading.value = weapon.reload_progress
+ reloading.visible = weapon.is_reloading
+
+ _previous_weapon = weapon
+ _previous_rounds = weapon.rounds
diff --git a/hud/weapon_info.gd.uid b/hud/weapon_info.gd.uid
new file mode 100644
index 0000000..3bee1d4
--- /dev/null
+++ b/hud/weapon_info.gd.uid
@@ -0,0 +1 @@
+uid://b8mob2xa2uq51
diff --git a/hud/weapon_info.tscn b/hud/weapon_info.tscn
new file mode 100644
index 0000000..19a0c0b
--- /dev/null
+++ b/hud/weapon_info.tscn
@@ -0,0 +1,53 @@
+[gd_scene load_steps=6 format=3 uid="uid://vbqf8dv4enpe"]
+
+[ext_resource type="Theme" uid="uid://4tevy1my8joc" path="res://hud/theme/ui_theme.tres" id="1_q5pwl"]
+[ext_resource type="Script" uid="uid://b8mob2xa2uq51" path="res://hud/weapon_info.gd" id="1_qxd8k"]
+
+[sub_resource type="StyleBoxFlat" id="1"]
+bg_color = Color(0, 0, 0, 0.752941)
+border_width_left = 1
+border_width_top = 1
+border_width_right = 1
+border_width_bottom = 1
+border_color = Color(0, 0, 0, 0.501961)
+corner_detail = 1
+expand_margin_left = 1.0
+expand_margin_top = 1.0
+expand_margin_right = 1.0
+expand_margin_bottom = 1.0
+
+[sub_resource type="StyleBoxFlat" id="2"]
+bg_color = Color(0, 0.752941, 0, 0.752941)
+corner_detail = 1
+
+[sub_resource type="Theme" id="3"]
+ProgressBar/colors/font_color = Color(0.94, 0.94, 0.94, 1)
+ProgressBar/colors/font_color_shadow = Color(0, 0, 0, 1)
+ProgressBar/fonts/font = null
+ProgressBar/styles/bg = SubResource("1")
+ProgressBar/styles/fg = SubResource("2")
+
+[node name="WeaponInfo" type="Node2D"]
+script = ExtResource("1_qxd8k")
+
+[node name="Rounds" type="Label" parent="."]
+anchors_preset = 5
+anchor_left = 0.5
+anchor_right = 0.5
+offset_left = -40.0
+offset_top = 7.0
+offset_right = 40.0
+offset_bottom = 16.0
+theme = ExtResource("1_q5pwl")
+text = "12/12"
+horizontal_alignment = 1
+
+[node name="Reloading" type="ProgressBar" parent="."]
+offset_left = -16.0
+offset_top = 22.0
+offset_right = 16.0
+offset_bottom = 26.0
+theme = SubResource("3")
+max_value = 1.0
+value = 0.5
+show_percentage = false
diff --git a/gfx/icon.png b/icon.png
similarity index 100%
rename from gfx/icon.png
rename to icon.png
diff --git a/icon.png.import b/icon.png.import
new file mode 100644
index 0000000..2463c6c
--- /dev/null
+++ b/icon.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dupictrmg4l3v"
+path="res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://icon.png"
+dest_files=["res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.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/item/bullet.gd b/item/bullet.gd
new file mode 100644
index 0000000..7364ade
--- /dev/null
+++ b/item/bullet.gd
@@ -0,0 +1,102 @@
+class_name Bullet
+extends Node2D
+
+const LIFE_TIME := 0.6
+const FADE_TIME := 0.6
+
+var direction : Vector2
+var effective_range : float
+var maximum_range : float
+var velocity : float
+var damage : float
+var color : Color
+
+var _start_position : Vector2
+var _age := 0.0
+var _distance := 0.0
+
+func _init(
+ position : Vector2,
+ direction : Vector2,
+ effective_range : float,
+ maximum_range : float,
+ velocity : float,
+ damage : float,
+ color : Color,
+) -> void:
+ _start_position = position
+ self.position = position
+ self.direction = direction
+ self.effective_range = effective_range
+ self.maximum_range = maximum_range
+ self.velocity = velocity
+ self.damage = damage
+ self.color = color
+
+func _on_collide(obj: CollisionObject2D, hit_position: Vector2) -> void:
+ # TODO: Add a global game setting to specify whether shooter or server announces successful hit.
+ # For now, server is the most straight-forward. Eventually, support client predictive movement?
+ pass
+
+# protected virtual void OnCollide(CollisionObject2D obj, Vector2 hitPosition)
+# {
+# // TODO: Add a global game setting to specify whether shooter or server announces successful hit.
+# // For now, server is the most straight-forward. Eventually, support client predictive movement?
+# if (!(this.GetGame() is Server) || !(obj.GetNodeOrNull("Sprite2D") is Sprite2D sprite)) return;
+# var world = this.GetWorld3d();
+# var path = world.GetPathTo(sprite);
+# var color = new Color(Color, (1 + Color.a) / 2);
+# RPC.Reliable(world.GetPlayersTracking(BlockPos.FromVector(obj.GlobalPosition).ToChunkPos()),
+# world.SpawnHit, path, hitPosition, color);
+# if (obj is Player player) {
+# var rangeFactor = Math.Min(1.0F, (MaximumRange - _distance) / (MaximumRange - EffectiveRange));
+# player.Health -= Damage * rangeFactor;
+# }
+# // TODO: Also spawn a ghost of the player who was hit so they can see where they got shot?
+# }
+
+func _process(delta: float) -> void:
+ if _age > LIFE_TIME:
+ modulate = Color(modulate, modulate.a - delta / FADE_TIME)
+ if modulate.a <= 0: queue_free()
+ _age += delta
+
+func _physics_process(delta: float) -> void:
+ var previous_position := position
+ _distance = min(maximum_range, velocity * _age)
+ position = _start_position + direction * _distance
+
+ var mask := PhysicsLayer.WORLD | PhysicsLayer.PLAYERS
+ var ray := PhysicsRayQueryParameters2D.create(previous_position, position, mask)
+ var result := get_world_2d().direct_space_state.intersect_ray(ray)
+ if !result.is_empty():
+ position = result.position as Vector2
+ _distance = _start_position.distance_to(position)
+ var obj := result.collider as CollisionObject2D
+ if obj: _on_collide(obj, position - obj.global_position)
+ set_physics_process(false)
+
+ if _distance > maximum_range:
+ set_physics_process(false)
+
+ queue_redraw()
+
+func _draw() -> void:
+ var points: Array[Vector2]
+ var colors: Array[Color]
+
+ if _distance > 16:
+ points.append(Vector2.ZERO)
+ colors.append(Color(color, color.a * minf(1, 1 - (_distance - effective_range) / (maximum_range - effective_range))))
+
+ if _distance > effective_range:
+ points.append(direction * -(_distance - effective_range))
+ colors.append(color)
+
+ points.append(direction * -maxf(0.0, _distance - 16))
+ colors.append(color)
+
+ points.append(direction * -_distance)
+ colors.append(Color(color, 0.0))
+
+ draw_polyline_colors(points, colors, 1.5, true)
diff --git a/item/bullet.gd.uid b/item/bullet.gd.uid
new file mode 100644
index 0000000..ec17dae
--- /dev/null
+++ b/item/bullet.gd.uid
@@ -0,0 +1 @@
+uid://dtxrt2lq1vuhh
diff --git a/item/creative_building.gd b/item/creative_building.gd
new file mode 100644
index 0000000..f54cc44
--- /dev/null
+++ b/item/creative_building.gd
@@ -0,0 +1,37 @@
+class_name CreativeBuilding
+extends Item
+
+func _process(_delta: float) -> void:
+ if not player.network.is_local: return
+ if not is_equipped: return
+
+ var mouse_pos := get_global_mouse_position()
+ var block_pos := Block.pos_from_vec(mouse_pos)
+ var block := Game.WORLD.get_block(block_pos)
+
+ rotation = player.position.angle_to_point(mouse_pos)
+
+ if Input.is_action_pressed("interact_primary"):
+ if block.matter == Matter.NONE:
+ set_block(block, Matter.PLASTIC, Shape.FULL)
+
+ if Input.is_action_pressed("interact_secondary"):
+ set_block(block, Matter.NONE, Shape.EMPTY)
+
+
+func set_block(block: Block, matter: Matter, shape: Shape) -> void:
+ block.matter = matter
+ block.shape = shape
+ if not multiplayer.is_server():
+ # Inform the server about the requested change.
+ _on_set_block.rpc_id(1, block.pos, matter.id, shape.id)
+
+@rpc("reliable")
+func _on_set_block(block_pos: Vector2i, matter_id: int, shape_id: int) -> void:
+ if not multiplayer.is_server(): return # Can only be processed by server.
+ var block := Game.WORLD.get_block(block_pos)
+ # TODO: Standerdize on one of these registry methods?
+ block.matter = Matter.REGISTRY.lookup_by_id(matter_id)
+ block.shape = Shape.lookup(shape_id)
+ # TODO: This will cause the player who sent the message to receive
+ # a block change even though they already changed said block.
diff --git a/item/creative_building.gd.uid b/item/creative_building.gd.uid
new file mode 100644
index 0000000..1ab3059
--- /dev/null
+++ b/item/creative_building.gd.uid
@@ -0,0 +1 @@
+uid://dv62vpu4lkr87
diff --git a/gfx/guns/AK47.png b/item/guns/AK47.png
similarity index 100%
rename from gfx/guns/AK47.png
rename to item/guns/AK47.png
diff --git a/item/guns/AK47.png.import b/item/guns/AK47.png.import
new file mode 100644
index 0000000..1fb5e75
--- /dev/null
+++ b/item/guns/AK47.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cvwd84agvfpmh"
+path="res://.godot/imported/AK47.png-9e0de10706fa2125046af78c6951bba1.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://item/guns/AK47.png"
+dest_files=["res://.godot/imported/AK47.png-9e0de10706fa2125046af78c6951bba1.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/gfx/guns/Blunderbuss.png b/item/guns/Blunderbuss.png
similarity index 100%
rename from gfx/guns/Blunderbuss.png
rename to item/guns/Blunderbuss.png
diff --git a/item/guns/Blunderbuss.png.import b/item/guns/Blunderbuss.png.import
new file mode 100644
index 0000000..55ca065
--- /dev/null
+++ b/item/guns/Blunderbuss.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dkrp5gulnscj6"
+path="res://.godot/imported/Blunderbuss.png-ea4df78a817b1c20f211b870aa1bd0c2.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://item/guns/Blunderbuss.png"
+dest_files=["res://.godot/imported/Blunderbuss.png-ea4df78a817b1c20f211b870aa1bd0c2.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/gfx/guns/BowArrow.png b/item/guns/BowArrow.png
similarity index 100%
rename from gfx/guns/BowArrow.png
rename to item/guns/BowArrow.png
diff --git a/item/guns/BowArrow.png.import b/item/guns/BowArrow.png.import
new file mode 100644
index 0000000..a9b4b6b
--- /dev/null
+++ b/item/guns/BowArrow.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bgxqkxshjqt7m"
+path="res://.godot/imported/BowArrow.png-b88568c99a9a6cb163a082a5424495d7.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://item/guns/BowArrow.png"
+dest_files=["res://.godot/imported/BowArrow.png-b88568c99a9a6cb163a082a5424495d7.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/gfx/guns/ColtSingleActionArmy.png b/item/guns/ColtSingleActionArmy.png
similarity index 100%
rename from gfx/guns/ColtSingleActionArmy.png
rename to item/guns/ColtSingleActionArmy.png
diff --git a/item/guns/ColtSingleActionArmy.png.import b/item/guns/ColtSingleActionArmy.png.import
new file mode 100644
index 0000000..fbb4065
--- /dev/null
+++ b/item/guns/ColtSingleActionArmy.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dkbjlb3ie6eo7"
+path="res://.godot/imported/ColtSingleActionArmy.png-53f5d63d5c6f6c53d1718f1b3495fa5b.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://item/guns/ColtSingleActionArmy.png"
+dest_files=["res://.godot/imported/ColtSingleActionArmy.png-53f5d63d5c6f6c53d1718f1b3495fa5b.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/gfx/guns/Derringer.png b/item/guns/Derringer.png
similarity index 100%
rename from gfx/guns/Derringer.png
rename to item/guns/Derringer.png
diff --git a/item/guns/Derringer.png.import b/item/guns/Derringer.png.import
new file mode 100644
index 0000000..7f8426e
--- /dev/null
+++ b/item/guns/Derringer.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dp5ndpw6wo20p"
+path="res://.godot/imported/Derringer.png-edcaf811e99acb87033922d6561f5c13.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://item/guns/Derringer.png"
+dest_files=["res://.godot/imported/Derringer.png-edcaf811e99acb87033922d6561f5c13.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/gfx/guns/DoubleBarrel.png b/item/guns/DoubleBarrel.png
similarity index 100%
rename from gfx/guns/DoubleBarrel.png
rename to item/guns/DoubleBarrel.png
diff --git a/item/guns/DoubleBarrel.png.import b/item/guns/DoubleBarrel.png.import
new file mode 100644
index 0000000..e598ff8
--- /dev/null
+++ b/item/guns/DoubleBarrel.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bwk4k706icgq"
+path="res://.godot/imported/DoubleBarrel.png-54aa633aff2593c0bf4cf861dc8dd82b.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://item/guns/DoubleBarrel.png"
+dest_files=["res://.godot/imported/DoubleBarrel.png-54aa633aff2593c0bf4cf861dc8dd82b.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/gfx/guns/FNScar.png b/item/guns/FNScar.png
similarity index 100%
rename from gfx/guns/FNScar.png
rename to item/guns/FNScar.png
diff --git a/item/guns/FNScar.png.import b/item/guns/FNScar.png.import
new file mode 100644
index 0000000..b402588
--- /dev/null
+++ b/item/guns/FNScar.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dddw8o4powkib"
+path="res://.godot/imported/FNScar.png-b105fd117f81dc1354218f6b6955b43d.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://item/guns/FNScar.png"
+dest_files=["res://.godot/imported/FNScar.png-b105fd117f81dc1354218f6b6955b43d.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/gfx/guns/LaserPistol.png b/item/guns/LaserPistol.png
similarity index 100%
rename from gfx/guns/LaserPistol.png
rename to item/guns/LaserPistol.png
diff --git a/item/guns/LaserPistol.png.import b/item/guns/LaserPistol.png.import
new file mode 100644
index 0000000..98891bb
--- /dev/null
+++ b/item/guns/LaserPistol.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://3g6me8fpg35s"
+path="res://.godot/imported/LaserPistol.png-9394305269d8d63186368029700440c6.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://item/guns/LaserPistol.png"
+dest_files=["res://.godot/imported/LaserPistol.png-9394305269d8d63186368029700440c6.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/gfx/guns/M1911.png b/item/guns/M1911.png
similarity index 100%
rename from gfx/guns/M1911.png
rename to item/guns/M1911.png
diff --git a/item/guns/M1911.png.import b/item/guns/M1911.png.import
new file mode 100644
index 0000000..a93d8dd
--- /dev/null
+++ b/item/guns/M1911.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://tv06ly70vsao"
+path="res://.godot/imported/M1911.png-7d4e5f7b4f1553130c761b64dd29262a.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://item/guns/M1911.png"
+dest_files=["res://.godot/imported/M1911.png-7d4e5f7b4f1553130c761b64dd29262a.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/gfx/guns/M1Garand.png b/item/guns/M1Garand.png
similarity index 100%
rename from gfx/guns/M1Garand.png
rename to item/guns/M1Garand.png
diff --git a/item/guns/M1Garand.png.import b/item/guns/M1Garand.png.import
new file mode 100644
index 0000000..acabd4a
--- /dev/null
+++ b/item/guns/M1Garand.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cvkgeg6x8yxtw"
+path="res://.godot/imported/M1Garand.png-12ee5c732a974903fbb09b48ad2c79e7.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://item/guns/M1Garand.png"
+dest_files=["res://.godot/imported/M1Garand.png-12ee5c732a974903fbb09b48ad2c79e7.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/gfx/guns/MP40.png b/item/guns/MP40.png
similarity index 100%
rename from gfx/guns/MP40.png
rename to item/guns/MP40.png
diff --git a/item/guns/MP40.png.import b/item/guns/MP40.png.import
new file mode 100644
index 0000000..49d066c
--- /dev/null
+++ b/item/guns/MP40.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://b4dhv1ixku4da"
+path="res://.godot/imported/MP40.png-ffcf812b823e262dc75501c0686d5313.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://item/guns/MP40.png"
+dest_files=["res://.godot/imported/MP40.png-ffcf812b823e262dc75501c0686d5313.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/gfx/guns/MauserC96.png b/item/guns/MauserC96.png
similarity index 100%
rename from gfx/guns/MauserC96.png
rename to item/guns/MauserC96.png
diff --git a/item/guns/MauserC96.png.import b/item/guns/MauserC96.png.import
new file mode 100644
index 0000000..8bbcaed
--- /dev/null
+++ b/item/guns/MauserC96.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://os0rj18vcn22"
+path="res://.godot/imported/MauserC96.png-15ce284f3a5f5e5be66284ffdbb1d604.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://item/guns/MauserC96.png"
+dest_files=["res://.godot/imported/MauserC96.png-15ce284f3a5f5e5be66284ffdbb1d604.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/gfx/guns/MoneyLauncher.png b/item/guns/MoneyLauncher.png
similarity index 100%
rename from gfx/guns/MoneyLauncher.png
rename to item/guns/MoneyLauncher.png
diff --git a/item/guns/MoneyLauncher.png.import b/item/guns/MoneyLauncher.png.import
new file mode 100644
index 0000000..30d1f45
--- /dev/null
+++ b/item/guns/MoneyLauncher.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bkqhl81jsdgmi"
+path="res://.godot/imported/MoneyLauncher.png-e41399c2fe71a24ae15ef8d3c7188b17.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://item/guns/MoneyLauncher.png"
+dest_files=["res://.godot/imported/MoneyLauncher.png-e41399c2fe71a24ae15ef8d3c7188b17.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/gfx/guns/P90.png b/item/guns/P90.png
similarity index 100%
rename from gfx/guns/P90.png
rename to item/guns/P90.png
diff --git a/item/guns/P90.png.import b/item/guns/P90.png.import
new file mode 100644
index 0000000..127b0c4
--- /dev/null
+++ b/item/guns/P90.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dwvmok3x0o3hl"
+path="res://.godot/imported/P90.png-c6225c70707d095b22c5c67b040ae854.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://item/guns/P90.png"
+dest_files=["res://.godot/imported/P90.png-c6225c70707d095b22c5c67b040ae854.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/gfx/guns/PlasmaBlaster.png b/item/guns/PlasmaBlaster.png
similarity index 100%
rename from gfx/guns/PlasmaBlaster.png
rename to item/guns/PlasmaBlaster.png
diff --git a/item/guns/PlasmaBlaster.png.import b/item/guns/PlasmaBlaster.png.import
new file mode 100644
index 0000000..e09c59c
--- /dev/null
+++ b/item/guns/PlasmaBlaster.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://kbly6jhjj24a"
+path="res://.godot/imported/PlasmaBlaster.png-e3d2037a87aa4e0f3938947eab7038fb.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://item/guns/PlasmaBlaster.png"
+dest_files=["res://.godot/imported/PlasmaBlaster.png-e3d2037a87aa4e0f3938947eab7038fb.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/gfx/guns/RocketLauncher.png b/item/guns/RocketLauncher.png
similarity index 100%
rename from gfx/guns/RocketLauncher.png
rename to item/guns/RocketLauncher.png
diff --git a/item/guns/RocketLauncher.png.import b/item/guns/RocketLauncher.png.import
new file mode 100644
index 0000000..032f7b6
--- /dev/null
+++ b/item/guns/RocketLauncher.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://nbw5sjg53bcg"
+path="res://.godot/imported/RocketLauncher.png-558d1cc513eafec458dd2117e8ab2c6a.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://item/guns/RocketLauncher.png"
+dest_files=["res://.godot/imported/RocketLauncher.png-558d1cc513eafec458dd2117e8ab2c6a.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/gfx/guns/Sawed-OffWinchester1897.png b/item/guns/Sawed-OffWinchester1897.png
similarity index 100%
rename from gfx/guns/Sawed-OffWinchester1897.png
rename to item/guns/Sawed-OffWinchester1897.png
diff --git a/item/guns/Sawed-OffWinchester1897.png.import b/item/guns/Sawed-OffWinchester1897.png.import
new file mode 100644
index 0000000..ab293e0
--- /dev/null
+++ b/item/guns/Sawed-OffWinchester1897.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dwnbdufhi3h61"
+path="res://.godot/imported/Sawed-OffWinchester1897.png-2be9b019aef1a7f77c34f11beabf0a07.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://item/guns/Sawed-OffWinchester1897.png"
+dest_files=["res://.godot/imported/Sawed-OffWinchester1897.png-2be9b019aef1a7f77c34f11beabf0a07.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/gfx/guns/SuperSoaker.png b/item/guns/SuperSoaker.png
similarity index 100%
rename from gfx/guns/SuperSoaker.png
rename to item/guns/SuperSoaker.png
diff --git a/item/guns/SuperSoaker.png.import b/item/guns/SuperSoaker.png.import
new file mode 100644
index 0000000..8b566b3
--- /dev/null
+++ b/item/guns/SuperSoaker.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://boka3vpba0msa"
+path="res://.godot/imported/SuperSoaker.png-72fcd83d139ea04de48fc318d7ec74d6.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://item/guns/SuperSoaker.png"
+dest_files=["res://.godot/imported/SuperSoaker.png-72fcd83d139ea04de48fc318d7ec74d6.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/gfx/guns/ThombsonSMG.png b/item/guns/ThombsonSMG.png
similarity index 100%
rename from gfx/guns/ThombsonSMG.png
rename to item/guns/ThombsonSMG.png
diff --git a/item/guns/ThombsonSMG.png.import b/item/guns/ThombsonSMG.png.import
new file mode 100644
index 0000000..ea41d1f
--- /dev/null
+++ b/item/guns/ThombsonSMG.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bmoqub28nbmot"
+path="res://.godot/imported/ThombsonSMG.png-797946c31b36813fc4e6c1295eb35cfe.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://item/guns/ThombsonSMG.png"
+dest_files=["res://.godot/imported/ThombsonSMG.png-797946c31b36813fc4e6c1295eb35cfe.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/gfx/guns/Uzi.png b/item/guns/Uzi.png
similarity index 100%
rename from gfx/guns/Uzi.png
rename to item/guns/Uzi.png
diff --git a/item/guns/Uzi.png.import b/item/guns/Uzi.png.import
new file mode 100644
index 0000000..7d67dad
--- /dev/null
+++ b/item/guns/Uzi.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dl75yes1afnqw"
+path="res://.godot/imported/Uzi.png-09b13d76224b3bdd7822138e701ce19a.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://item/guns/Uzi.png"
+dest_files=["res://.godot/imported/Uzi.png-09b13d76224b3bdd7822138e701ce19a.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/gfx/guns/WaltherP38.png b/item/guns/WaltherP38.png
similarity index 100%
rename from gfx/guns/WaltherP38.png
rename to item/guns/WaltherP38.png
diff --git a/item/guns/WaltherP38.png.import b/item/guns/WaltherP38.png.import
new file mode 100644
index 0000000..7eb0679
--- /dev/null
+++ b/item/guns/WaltherP38.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bkk3od4m50xdn"
+path="res://.godot/imported/WaltherP38.png-cf5b11e2961e28e3d2a8077afb1d4b41.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://item/guns/WaltherP38.png"
+dest_files=["res://.godot/imported/WaltherP38.png-cf5b11e2961e28e3d2a8077afb1d4b41.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/gfx/guns/Winchester1873.png b/item/guns/Winchester1873.png
similarity index 100%
rename from gfx/guns/Winchester1873.png
rename to item/guns/Winchester1873.png
diff --git a/item/guns/Winchester1873.png.import b/item/guns/Winchester1873.png.import
new file mode 100644
index 0000000..f9944c7
--- /dev/null
+++ b/item/guns/Winchester1873.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cwsmo6o4byr6m"
+path="res://.godot/imported/Winchester1873.png-2b0d854ba721301cbb9b8d315588406a.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://item/guns/Winchester1873.png"
+dest_files=["res://.godot/imported/Winchester1873.png-2b0d854ba721301cbb9b8d315588406a.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/gfx/guns/Winchester1897.png b/item/guns/Winchester1897.png
similarity index 100%
rename from gfx/guns/Winchester1897.png
rename to item/guns/Winchester1897.png
diff --git a/item/guns/Winchester1897.png.import b/item/guns/Winchester1897.png.import
new file mode 100644
index 0000000..5b5bc3f
--- /dev/null
+++ b/item/guns/Winchester1897.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://c8g5rchaxfje4"
+path="res://.godot/imported/Winchester1897.png-3e8918ff4798ab088aef027539ebc5c9.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://item/guns/Winchester1897.png"
+dest_files=["res://.godot/imported/Winchester1897.png-3e8918ff4798ab088aef027539ebc5c9.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/gfx/hit_decal.png b/item/hit_decal.png
similarity index 100%
rename from gfx/hit_decal.png
rename to item/hit_decal.png
diff --git a/item/hit_decal.png.import b/item/hit_decal.png.import
new file mode 100644
index 0000000..1fcd3c5
--- /dev/null
+++ b/item/hit_decal.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://28onsnq1ko6c"
+path="res://.godot/imported/hit_decal.png-fef13e463b8ce9e27e702b1946db025d.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://item/hit_decal.png"
+dest_files=["res://.godot/imported/hit_decal.png-fef13e463b8ce9e27e702b1946db025d.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/item/item.gd b/item/item.gd
new file mode 100644
index 0000000..b92a103
--- /dev/null
+++ b/item/item.gd
@@ -0,0 +1,19 @@
+class_name Item
+extends Sprite2D
+
+signal equipped
+signal unequipped
+
+var is_equipped := false
+
+var cursor: Cursor: # TODO: Do this in a better way.
+ get: return get_node("/root/Game/CursorLayer/Cursor")
+var player: Player:
+ get: return get_node_or_null("../..")
+
+func set_equipped(value: bool) -> void:
+ if value == is_equipped: return
+ visible = value
+ is_equipped = value
+ if value: equipped.emit()
+ else: unequipped.emit()
diff --git a/item/item.gd.uid b/item/item.gd.uid
new file mode 100644
index 0000000..64f28c8
--- /dev/null
+++ b/item/item.gd.uid
@@ -0,0 +1 @@
+uid://3sfr80frhvsd
diff --git a/sfx/assault_rifle.rfx b/item/sounds/assault_rifle.rfx
similarity index 100%
rename from sfx/assault_rifle.rfx
rename to item/sounds/assault_rifle.rfx
diff --git a/sfx/assault_rifle.wav b/item/sounds/assault_rifle.wav
similarity index 100%
rename from sfx/assault_rifle.wav
rename to item/sounds/assault_rifle.wav
diff --git a/item/sounds/assault_rifle.wav.import b/item/sounds/assault_rifle.wav.import
new file mode 100644
index 0000000..8684f3d
--- /dev/null
+++ b/item/sounds/assault_rifle.wav.import
@@ -0,0 +1,24 @@
+[remap]
+
+importer="wav"
+type="AudioStreamWAV"
+uid="uid://clj0jr2p5n2fm"
+path="res://.godot/imported/assault_rifle.wav-8f0eecdbe43424b2d5081d5b741592e0.sample"
+
+[deps]
+
+source_file="res://item/sounds/assault_rifle.wav"
+dest_files=["res://.godot/imported/assault_rifle.wav-8f0eecdbe43424b2d5081d5b741592e0.sample"]
+
+[params]
+
+force/8_bit=false
+force/mono=false
+force/max_rate=false
+force/max_rate_hz=44100
+edit/trim=false
+edit/normalize=false
+edit/loop_mode=0
+edit/loop_begin=0
+edit/loop_end=-1
+compress/mode=0
diff --git a/sfx/revolver.rfx b/item/sounds/revolver.rfx
similarity index 100%
rename from sfx/revolver.rfx
rename to item/sounds/revolver.rfx
diff --git a/sfx/revolver.wav b/item/sounds/revolver.wav
similarity index 100%
rename from sfx/revolver.wav
rename to item/sounds/revolver.wav
diff --git a/item/sounds/revolver.wav.import b/item/sounds/revolver.wav.import
new file mode 100644
index 0000000..a88c612
--- /dev/null
+++ b/item/sounds/revolver.wav.import
@@ -0,0 +1,24 @@
+[remap]
+
+importer="wav"
+type="AudioStreamWAV"
+uid="uid://bdsgcbe6my0t3"
+path="res://.godot/imported/revolver.wav-ea966a6a1d65267caa2744339f9d7c57.sample"
+
+[deps]
+
+source_file="res://item/sounds/revolver.wav"
+dest_files=["res://.godot/imported/revolver.wav-ea966a6a1d65267caa2744339f9d7c57.sample"]
+
+[params]
+
+force/8_bit=false
+force/mono=false
+force/max_rate=false
+force/max_rate_hz=44100
+edit/trim=false
+edit/normalize=false
+edit/loop_mode=0
+edit/loop_begin=0
+edit/loop_end=-1
+compress/mode=0
diff --git a/sfx/rifle.rfx b/item/sounds/rifle.rfx
similarity index 100%
rename from sfx/rifle.rfx
rename to item/sounds/rifle.rfx
diff --git a/sfx/rifle.wav b/item/sounds/rifle.wav
similarity index 100%
rename from sfx/rifle.wav
rename to item/sounds/rifle.wav
diff --git a/item/sounds/rifle.wav.import b/item/sounds/rifle.wav.import
new file mode 100644
index 0000000..847867d
--- /dev/null
+++ b/item/sounds/rifle.wav.import
@@ -0,0 +1,24 @@
+[remap]
+
+importer="wav"
+type="AudioStreamWAV"
+uid="uid://dtdtur6706acx"
+path="res://.godot/imported/rifle.wav-44fd29b7200c3294033844b76e89b140.sample"
+
+[deps]
+
+source_file="res://item/sounds/rifle.wav"
+dest_files=["res://.godot/imported/rifle.wav-44fd29b7200c3294033844b76e89b140.sample"]
+
+[params]
+
+force/8_bit=false
+force/mono=false
+force/max_rate=false
+force/max_rate_hz=44100
+edit/trim=false
+edit/normalize=false
+edit/loop_mode=0
+edit/loop_begin=0
+edit/loop_end=-1
+compress/mode=0
diff --git a/sfx/shotgun.rfx b/item/sounds/shotgun.rfx
similarity index 100%
rename from sfx/shotgun.rfx
rename to item/sounds/shotgun.rfx
diff --git a/sfx/shotgun.wav b/item/sounds/shotgun.wav
similarity index 100%
rename from sfx/shotgun.wav
rename to item/sounds/shotgun.wav
diff --git a/item/sounds/shotgun.wav.import b/item/sounds/shotgun.wav.import
new file mode 100644
index 0000000..17ecec9
--- /dev/null
+++ b/item/sounds/shotgun.wav.import
@@ -0,0 +1,24 @@
+[remap]
+
+importer="wav"
+type="AudioStreamWAV"
+uid="uid://dinsrxi61427g"
+path="res://.godot/imported/shotgun.wav-f78a1958faebd3710a56a1c9e37fb9f6.sample"
+
+[deps]
+
+source_file="res://item/sounds/shotgun.wav"
+dest_files=["res://.godot/imported/shotgun.wav-f78a1958faebd3710a56a1c9e37fb9f6.sample"]
+
+[params]
+
+force/8_bit=false
+force/mono=false
+force/max_rate=false
+force/max_rate_hz=44100
+edit/trim=false
+edit/normalize=false
+edit/loop_mode=0
+edit/loop_begin=0
+edit/loop_end=-1
+compress/mode=0
diff --git a/item/weapon.gd b/item/weapon.gd
new file mode 100644
index 0000000..2b6f92d
--- /dev/null
+++ b/item/weapon.gd
@@ -0,0 +1,272 @@
+# TODO: "Click" sound when attempting to fire when not ready, or empty.
+# TODO: "Single reload" for revolver & shotgun.
+# TODO: Add outline around weapon sprites.
+
+class_name Weapon
+extends Item
+
+const NETWORK_EPSILON := 0.05
+
+@export var automatic := false
+@export var fire_rate := 100 # rounds/minute
+@export var capacity := 12
+@export var reload_time := 1.0
+
+@export var knockback := 0.0
+@export var spread := 0.0
+@export var spread_increase := 0.0
+@export var recoil_min := 0.0
+@export var recoil_max := 0.0
+
+@export var effective_range := 320
+@export var maximum_range := 640
+@export var bullet_velocity := 2000
+@export var bullets_per_shot := 1
+@export var damage := 0.0
+@export var bullet_opacity := 0.2
+
+@onready var rounds := capacity
+@onready var tip_offset := $Tip.position as Vector2
+
+var is_reloading: bool:
+ get: return _reload_delay > 0.0
+var reload_progress: float:
+ get: return clampf(1 - _reload_delay / reload_time, 0.0, 1.0)
+
+var lowered := false
+var aim_direction: float
+# TODO: Tell the server when we're pressing/releasing the trigger.
+
+var _trigger_held := -INF
+var _fire_delay := 0.0
+var _reload_delay := 0.0
+
+var _current_spread_inc := 0.0
+var _current_recoil := 0.0
+
+# Needs to be kept alive for `draw_mesh` to work.
+var _mesh: ArrayMesh
+
+func _unhandled_input(event: InputEvent) -> void:
+ if not player.network.is_local: return
+ if not is_equipped: return
+
+ if event.is_action_pressed("interact_primary"):
+ _trigger_held = 0.0
+ _on_trigger_pressed()
+
+ if event.is_action_pressed("interact_reload"):
+ reload()
+
+func _on_trigger_pressed() -> void:
+ fire()
+
+func _on_trigger_released() -> void:
+ pass
+
+func _process(delta: float) -> void:
+ var speed_decrease := maxf(TAU / 200, _current_spread_inc * 1.5)
+ var recoil_decrease := maxf(TAU / 600, _current_recoil * 1.5)
+ _current_spread_inc = maxf(0.0, _current_spread_inc - speed_decrease * delta)
+ _current_recoil = maxf(0.0, _current_recoil - recoil_decrease * delta)
+
+ if not player.health.is_alive:
+ # TODO: Do this once when player respawns.
+ rounds = capacity
+ _trigger_held = -INF
+ _fire_delay = 0.0
+ _reload_delay = 0.0
+ if player.network.is_local: queue_redraw()
+
+ elif not is_equipped:
+ # When switching away from the weapon while reloading, reset reload time.
+ if is_reloading: _reload_delay = reload_time
+
+ else:
+ if _trigger_held >= 0.0:
+ _trigger_held += delta
+
+ if is_reloading:
+ _reload_delay -= delta
+ if _reload_delay <= 0.0:
+ _reload_delay = 0.0
+ rounds = capacity
+
+ if _fire_delay > 0.0:
+ _fire_delay -= delta
+ # We allow _fireDelay to go into negatives to allow
+ # for more accurate rate of fire for automatic weapons.
+ # Though, if the trigger isn't held down, reset it to 0.
+ if _fire_delay < 0.0 and (!automatic || _trigger_held < 0.0):
+ _fire_delay = 0.0
+
+ if player.network.is_local:
+ # Automatically reload when out of rounds.
+ if rounds <= 0: reload()
+
+ if _trigger_held >= 0.0:
+ if !Input.is_action_pressed("interact_primary"):
+ _trigger_held = -INF
+ _on_trigger_released()
+ elif automatic:
+ fire()
+
+ # Gun tip_offset C = Cursor
+ # v v b v
+ # x---###########x------------------------------x
+ # | ##==# _____-----
+ # a | ## _____-----
+ # | _____----- c
+ # x_____-----
+ # ^
+ # B = Player
+
+ # The length of `a` and `c` as well as the angle of `c` are known.
+ # `a` is the y component of the weapon's TipOffset.
+ # `c` is the line connecting the player and cursor.
+ # Find out the angle `C` to subtract from the already known angle of `c`.
+ # CREDIT to lizzie for helping me figure out this trigonometry problem.
+
+ var a := tip_offset.y * (1 if (scale.y > 0) else -1)
+ var c := player.position.distance_to(cursor.position)
+ # If the cursor is too close to the player, put the
+ # weapon in a "lowered" state, where it can't be shot.
+ lowered = c < tip_offset.x
+ if lowered: aim_direction = deg_to_rad(30 if cursor.position.x > player.position.x else 150)
+ else: aim_direction = player.position.angle_to_point(cursor.position) - asin(a / c)
+
+ # TODO: Send aim angle
+ queue_redraw()
+ else:
+ _reload_delay = 0.0
+
+ var angle = absf(rad_to_deg(fposmod(aim_direction + PI, TAU) - PI))
+ if scale.y > 0 and angle > 100: scale.y = -1
+ if scale.y < 0 and angle < 80: scale.y = 1
+ rotation = aim_direction - _current_recoil * (1 if scale.y > 0 else -1)
+
+ # [RPC(MultiplayerAPI.RPCMode.AnyPeer)]
+ # private void SendAimAngle(float value)
+ # {
+ # if (this.GetGame() is Server) {
+ # if ((Player.NetworkID != GetTree().GetRemoteSenderId()) || !Player.IsAlive) return;
+ # if (float.IsNaN(value = Mathf.PosMod(value, Mathf.Tau))) return;
+
+ # RPC.Unreliable(SendAimAngle, value);
+ # } else if (!Player.IsLocal)
+ # AimDirection = value;
+ # }
+
+func fire() -> void:
+ var _seed := randi()
+ if !_fire_internal(aim_direction, scale.y > 0, _seed): return
+ # RPC.Reliable(1, SendFire, AimDirection, Scale.y > 0, _seed);
+ player.velocity -= knockback * Vector2.from_angle(rotation)
+
+func _fire_internal(aim: float, to_right: bool, _seed: int) -> bool:
+ var is_server := false
+ var epsilon := 0.0 if is_server else NETWORK_EPSILON
+ if !player.health.is_alive: return false
+ if !is_equipped or lowered or rounds <= 0: return false
+ if _reload_delay > epsilon or _fire_delay > epsilon: return false
+
+ if !is_server:
+ var stream: AudioStreamPlayer2D = get_node_or_null("Fire")
+ if stream: stream.play()
+
+ var random := RandomNumberGenerator.new()
+ random.seed = _seed
+
+ var angle := aim - _current_recoil * (1 if to_right else -1)
+ var tip := (tip_offset if to_right else tip_offset * Vector2(1, -1)).rotated(angle)
+
+ for i in bullets_per_shot:
+ var spr := (deg_to_rad(spread) + _current_spread_inc) * clampf(random.randfn(0.4), -1, 1)
+ var dir := Vector2.from_angle(angle + spr)
+ var color := Color(player.appearance.color, bullet_opacity)
+ var bullet := Bullet.new(
+ player.global_position + tip, dir, effective_range, maximum_range,
+ bullet_velocity, damage / bullets_per_shot, color)
+ Game.WORLD.add_child(bullet)
+
+ _current_spread_inc += deg_to_rad(spread_increase)
+ _current_recoil += deg_to_rad(random.randf_range(recoil_min, recoil_max))
+
+ if is_server or player.network.is_local:
+ # Do not keep track of fire rate or ammo for other players.
+ _fire_delay += 60.0 / fire_rate
+ rounds -= 1
+
+ return true
+
+ # [RPC(MultiplayerAPI.RPCMode.AnyPeer)]
+ # private void SendFire(float aimDirection, bool toRight, int seed)
+ # {
+ # if (this.GetGame() is Server) {
+ # if (Player.NetworkID != GetTree().GetRemoteSenderId()) return;
+ # if (float.IsNaN(aimDirection = Mathf.PosMod(aimDirection, Mathf.Tau))) return;
+
+ # // TODO: Only send to players who can see the full path of the bullet.
+ # if (FireInternal(aimDirection, toRight, seed))
+ # RPC.Reliable(SendFire, aimDirection, toRight, seed);
+ # } else if (!Player.IsLocal)
+ # FireInternal(aimDirection, toRight, seed);
+ # }
+
+func reload() -> void:
+ if _reload_internal():
+ pass # send_reload
+
+func _reload_internal() -> bool:
+ if !is_equipped or !player.health.is_alive or rounds >= capacity or is_reloading: return false
+ # TODO: Play reload sound.
+ _reload_delay += reload_time
+ return true
+
+ # [RPC(MultiplayerAPI.RPCMode.AnyPeer)]
+ # private void SendReload()
+ # {
+ # if (this.GetGame() is Server) {
+ # if (Player.NetworkID != GetTree().GetRemoteSenderId()) return;
+ # if (ReloadInternal()) RPC.Reliable(SendReload);
+ # } else if (!Player.IsLocal)
+ # ReloadInternal();
+ # }
+
+func _draw() -> void:
+ if !player.network.is_local or !player.health.is_alive or lowered: return
+ # Draws an "aiming cone" to show where bullets might travel.
+
+ var tip := tip_offset + Vector2(4, 0)
+ var angle := sin((deg_to_rad(spread) + _current_spread_inc) / 2)
+ var color := Color.BLACK
+
+ var points: Array[Vector2]
+ var colors: Array[Color]
+ var append := func(opacity: float, dist: float) -> void:
+ points.push_front(tip + Vector2(1, angle) * dist)
+ points.push_back (tip + Vector2(1, -angle) * dist)
+ colors.push_front(Color(color, opacity))
+ colors.push_back (Color(color, opacity))
+ append.call(0.00, maximum_range)
+ append.call(0.15, effective_range)
+ append.call(0.15, 64)
+ append.call(0.00, 0)
+
+ var st := SurfaceTool.new()
+ st.begin(Mesh.PRIMITIVE_TRIANGLE_STRIP)
+ st.set_color(colors[0])
+ st.add_vertex(Vector3(points[0].x, points[0].y, 0))
+ st.set_color(colors[1])
+ st.add_vertex(Vector3(points[1].x, points[1].y, 0))
+ st.add_vertex(Vector3(points[6].x, points[6].y, 0))
+ st.set_color(colors[2])
+ st.add_vertex(Vector3(points[2].x, points[2].y, 0))
+ st.add_vertex(Vector3(points[5].x, points[5].y, 0))
+ st.set_color(colors[3])
+ st.add_vertex(Vector3(points[3].x, points[3].y, 0))
+ st.add_vertex(Vector3(points[4].x, points[5].y, 0))
+
+ _mesh = st.commit()
+ draw_mesh(_mesh, null)
+ draw_polyline_colors(points, colors, 1.0, true)
diff --git a/item/weapon.gd.uid b/item/weapon.gd.uid
new file mode 100644
index 0000000..e8b3882
--- /dev/null
+++ b/item/weapon.gd.uid
@@ -0,0 +1 @@
+uid://vvivkvsnr34j
diff --git a/network/network.gd b/network/network.gd
new file mode 100644
index 0000000..2a77847
--- /dev/null
+++ b/network/network.gd
@@ -0,0 +1,118 @@
+class_name Network
+extends Node
+
+const DEFAULT_PORT := 42005
+
+signal status_changed(new_status: Status, old_status: Status)
+enum Status { SINGLEPLAYER, CLIENT_CONNECTING, CLIENT_CONNECTED, SERVER_RUNNING }
+var status := Status.SINGLEPLAYER
+
+## Connects to the server at the given address, which can be a IPv4 address or
+## hostname, or an IPv6 address wrapped in square brackets, optionally followed
+## by a colon and valid port number (defaults to `42005`).
+##
+## Returns `OK` if successful or `ERR_CANT_CREATE` if the client could
+## not be created, such as if an invalid address is given.
+func connect_to_server(address_and_port: String) -> int: # Error
+ assert(status == Status.SINGLEPLAYER)
+
+ # For IPv6 addresses, check if the address contains a square bracket,
+ # then search for the colon that separates address and port from there.
+ var bracket_index := address_and_port.find("]")
+ var colon_index := address_and_port.find(":", maxi(0, bracket_index))
+
+ var address := address_and_port
+ var port := DEFAULT_PORT
+ # If a colon is found, split the string into separate address and port.
+ if colon_index >= 0:
+ address = address_and_port.substr(0, colon_index)
+ port = int(address_and_port.substr(colon_index + 1))
+ # If address is surrounded in square brackets (such as IPv6), strip them.
+ if (address.substr(0, 1) == "[") and (address.substr(address.length() - 1) == "]"):
+ address = address.substr(1, address.length() - 2)
+
+ var peer := ENetMultiplayerPeer.new()
+ var error := peer.create_client(address, port)
+ if error: return error
+
+ multiplayer.multiplayer_peer = peer
+ _set_status(Status.CLIENT_CONNECTING)
+ return OK
+
+func disconnect_from_server() -> void:
+ assert((status == Status.CLIENT_CONNECTING) or (status == Status.CLIENT_CONNECTED))
+ _on_server_disconnected()
+ _set_status(Status.SINGLEPLAYER)
+
+
+func start_server(port := DEFAULT_PORT) -> int: # Error
+ assert(status == Status.SINGLEPLAYER)
+
+ var peer := ENetMultiplayerPeer.new()
+ var error := peer.create_server(port)
+ if error: return error
+
+ multiplayer.multiplayer_peer = peer
+ _set_status(Status.SERVER_RUNNING)
+ return OK
+
+func stop_server() -> void:
+ assert(status == Status.SERVER_RUNNING)
+ _on_server_stopped()
+ _set_status(Status.SINGLEPLAYER)
+
+
+func _ready() -> void:
+ multiplayer.connected_to_server.connect(_on_connected_to_server)
+ multiplayer.server_disconnected.connect(_on_server_disconnected)
+ multiplayer.peer_connected .connect(_on_peer_connected)
+ multiplayer.peer_disconnected .connect(_on_peer_disconnected)
+
+ multiplayer.connected_to_server.connect(_set_status.bind(Status.CLIENT_CONNECTED))
+ multiplayer.server_disconnected.connect(_set_status.bind(Status.SINGLEPLAYER))
+ multiplayer.connection_failed .connect(_set_status.bind(Status.SINGLEPLAYER))
+
+
+func _on_connected_to_server() -> void:
+ # Set our own peer id to the one the server assigned to us. (Also renames the player node.)
+ Game.LOCAL_PLAYER.network.peer_id = multiplayer.get_unique_id()
+ Game.INSTANCE.change_world(World.new())
+
+func _on_server_disconnected() -> void:
+ # If not properly connected (`_on_connected_to_server` wasn't called), return.
+ if status != Status.CLIENT_CONNECTED: return
+ # Reset the peer id of the player since we're back to singleplayer, where `1` is the server.
+ Game.LOCAL_PLAYER.network.peer_id = 1
+ Game.INSTANCE.change_world(World.new())
+ _clear_other_players()
+
+func _on_server_stopped() -> void:
+ _clear_other_players()
+
+func _on_peer_connected(id: int) -> void:
+ var player: Player = preload("res://player/player.tscn").instantiate()
+ player.get_node("Network").peer_id = id
+ Game.PLAYERS.add_child(player)
+
+func _on_peer_disconnected(id: int) -> void:
+ var player: Player = Game.PLAYERS.get_node(str(id))
+ Game.PLAYERS.remove_child(player)
+ player.queue_free()
+
+
+func _clear_other_players() -> void:
+ for player in Game.PLAYERS.get_children():
+ if player != Game.LOCAL_PLAYER:
+ player.queue_free()
+
+func _set_status(new_status: Status) -> void:
+ if new_status == status: return
+
+ if new_status == Status.SINGLEPLAYER:
+ # Reset the peer to work as a singleplayer server again.
+ multiplayer.multiplayer_peer.close()
+ multiplayer.multiplayer_peer = OfflineMultiplayerPeer.new()
+
+ var old_status := status
+ status = new_status
+ status_changed.emit(new_status, old_status)
diff --git a/network/network.gd.uid b/network/network.gd.uid
new file mode 100644
index 0000000..3252625
--- /dev/null
+++ b/network/network.gd.uid
@@ -0,0 +1 @@
+uid://cayck3pgtxys6
diff --git a/player/appearance.gd b/player/appearance.gd
new file mode 100644
index 0000000..5529a4e
--- /dev/null
+++ b/player/appearance.gd
@@ -0,0 +1,13 @@
+class_name PlayerAppearance
+extends Node
+
+@onready var label := $DisplayName as Label
+@onready var sprite := $Sprite as Sprite2D
+
+var display_name: String:
+ get: return label.text
+ set(value): label.text = value
+
+var color: Color:
+ get: return sprite.self_modulate
+ set(value): sprite.self_modulate = value
diff --git a/player/appearance.gd.uid b/player/appearance.gd.uid
new file mode 100644
index 0000000..acafa02
--- /dev/null
+++ b/player/appearance.gd.uid
@@ -0,0 +1 @@
+uid://cm1l4kpund5dp
diff --git a/player/chunk_loader.gd b/player/chunk_loader.gd
new file mode 100644
index 0000000..a1fc928
--- /dev/null
+++ b/player/chunk_loader.gd
@@ -0,0 +1,58 @@
+class_name ChunkLoader
+extends Node2D
+
+@export var load_distance := 3
+@export var unload_distance := 4
+
+signal start_tracking(chunk: Chunk)
+signal stop_tracking (chunk: Chunk)
+
+var tracked_chunks: Dictionary[Vector2i, Variant] # value is unused
+
+# TODO: This is a pretty naive implementation, calling this every
+# update regardless of whether or how far the players moved.
+func _process(delta: float) -> void:
+ if not multiplayer.is_server(): return
+ var loader_chunk_pos := Chunk.pos_from_vec(global_position)
+
+ # All currently tracked chunks start out in this dictionary.
+ # Ones outside of `unload_distance` are removed in the loop.
+ var out_of_range: Dictionary[Vector2i, Variant] = tracked_chunks.duplicate()
+
+ var chunk_range := range(-unload_distance, unload_distance + 1)
+ for x in chunk_range:
+ for y in chunk_range:
+ var chunk_pos := loader_chunk_pos + Vector2i(x, y)
+ out_of_range.erase(chunk_pos)
+ if tracked_chunks.has(chunk_pos): continue
+
+ # Check to see is chunk is in `load_distance`.
+ var in_load_range := (absi(x) <= load_distance) and ((absi(y) <= load_distance))
+ if not in_load_range: continue # it's not
+
+ var chunk := Game.WORLD.get_or_create_chunk(chunk_pos)
+ tracked_chunks[chunk_pos] = null
+ chunk.tracked_by[self] = null
+ start_tracking.emit(chunk)
+
+ # Untrack any chunks outside of `unload_distance`.
+ for chunk_pos in out_of_range: _forget(chunk_pos, true)
+
+func _exit_tree() -> void:
+ for chunk_pos in tracked_chunks: _forget(chunk_pos, false)
+ tracked_chunks.clear()
+
+func _forget(chunk_pos: Vector2i, emit_signal: bool) -> void:
+ var chunk := Game.WORLD.get_chunk_or_null(chunk_pos)
+ tracked_chunks.erase(chunk_pos)
+ chunk.tracked_by.erase(self)
+
+ if emit_signal:
+ stop_tracking.emit(chunk)
+
+ # FIXME: This is currently the only way a chunk gets removed:
+ # When a player tracks it and stops tracking it. However,
+ # there's other ways a chunk may be created. Consider this!
+ if chunk.tracked_by.is_empty():
+ chunk.get_parent().remove_child(chunk)
+ chunk.queue_free()
diff --git a/player/chunk_loader.gd.uid b/player/chunk_loader.gd.uid
new file mode 100644
index 0000000..82c84c8
--- /dev/null
+++ b/player/chunk_loader.gd.uid
@@ -0,0 +1 @@
+uid://disk1asctm3lb
diff --git a/player/health.gd b/player/health.gd
new file mode 100644
index 0000000..cac40d8
--- /dev/null
+++ b/player/health.gd
@@ -0,0 +1,47 @@
+class_name PlayerHealth
+extends Node
+
+const TIME_BEFORE_REGEN := 1.0
+const REGENERATION_TIMER := 1.0 / 3
+const REGENERATION_AMOUNT := 0.025
+const RESPAWN_TIMER := 5.0
+
+var current := 1.0
+var previous := 1.0
+var regeneration_delay := 0.0
+var respawn_delay := 0.0
+
+var is_alive: bool:
+ get: return current > 0.0
+
+@onready var player: Player = get_parent()
+
+func _process(delta: float) -> void:
+ # Damage player when falling into "the void", so they can respawn.
+ if player.position.y > 9000: current -= 0.01
+
+ if is_alive and current < 1.0:
+ regeneration_delay += delta
+ if regeneration_delay >= (TIME_BEFORE_REGEN + REGENERATION_TIMER):
+ regeneration_delay -= REGENERATION_TIMER
+ current = minf(1.0, current + REGENERATION_AMOUNT)
+ else:
+ regeneration_delay = 0.0
+
+ if not is_alive:
+ respawn_delay += delta
+ if respawn_delay >= RESPAWN_TIMER:
+ player.position = Vector2.ZERO
+ player.velocity = Vector2.ZERO
+ player.modulate = Color.WHITE
+ current = 1.0
+ respawn_delay = 0.0
+ # TODO: Add invulnerability timer? Or some other way to prevent "void" damage
+ # after server considers player respawned, but it hasn't teleported yet.
+
+ if previous != current:
+ if not is_alive and previous > 0:
+ player.modulate = Color(0.35, 0.35, 0.35, 0.8)
+ if current < previous:
+ regeneration_delay = 0.0
+ previous = current
diff --git a/player/health.gd.uid b/player/health.gd.uid
new file mode 100644
index 0000000..0b9a5d4
--- /dev/null
+++ b/player/health.gd.uid
@@ -0,0 +1 @@
+uid://lavpkfgmvc82
diff --git a/player/inventory.gd b/player/inventory.gd
new file mode 100644
index 0000000..605d77f
--- /dev/null
+++ b/player/inventory.gd
@@ -0,0 +1,21 @@
+class_name PlayerInventory
+extends Node2D
+
+@export var default_equipped: Node2D
+
+@onready var player: Player = get_parent()
+
+var equipped: Item:
+ get: return equipped
+ set(value):
+ if value == equipped: return
+ if value: assert(value.get_parent() == self, "item is not a child")
+ if equipped: equipped.set_equipped(false)
+ if value: value .set_equipped(true)
+ equipped = value
+
+func _ready() -> void:
+ equipped = default_equipped
+
+func get_items() -> Array[Item]:
+ return Array(get_children(), TYPE_OBJECT, "Sprite2D", Item)
diff --git a/player/inventory.gd.uid b/player/inventory.gd.uid
new file mode 100644
index 0000000..1812067
--- /dev/null
+++ b/player/inventory.gd.uid
@@ -0,0 +1 @@
+uid://cx5bh024nq4ot
diff --git a/player/movement.gd b/player/movement.gd
new file mode 100644
index 0000000..6785fdb
--- /dev/null
+++ b/player/movement.gd
@@ -0,0 +1,57 @@
+class_name PlayerMovement
+extends Node
+
+# TODO: Implement "low jumps" activated by releasing the jump button early.
+@export var jump_early_time := 0.2
+@export var jump_coyote_time := 0.2
+
+@export var movement_speed := 160.0
+@export var jump_velocity := 240.0
+@export var gravity := 480.0
+
+@export var acceleration := 0.25
+@export var friction_ground := 0.2
+@export var friction_air := 0.05
+
+@onready var player: Player = get_parent()
+
+var time_since_jump_pressed := INF
+var time_since_on_floor := INF
+
+func _physics_process(delta: float) -> void:
+ _apply_movement(delta)
+
+ player.velocity.y += gravity * delta # Apply gravity.
+ player.move_and_slide() # Actually move the player.
+
+func _apply_movement(delta: float) -> void:
+ if not player.network.is_local: return
+
+ var move_dir := 0.0
+ var jump_pressed := false
+
+ # TODO: Check if escape menu is open?
+ if player.health.is_alive:
+ move_dir = Input.get_axis("move_left", "move_right")
+ jump_pressed = Input.is_action_just_pressed("move_jump")
+
+ # Handle jumping.
+ if jump_pressed: time_since_jump_pressed = 0
+ if player.is_on_floor(): time_since_on_floor = 0
+
+ if time_since_jump_pressed <= jump_early_time and time_since_on_floor <= jump_coyote_time:
+ player.velocity.y -= jump_velocity
+ time_since_jump_pressed = INF
+ time_since_on_floor = INF
+
+ time_since_jump_pressed += delta
+ time_since_on_floor += delta
+
+
+ if move_dir:
+ # If player is trying to move, accelerate them.
+ player.velocity.x = lerpf(player.velocity.x, move_dir * movement_speed, acceleration)
+ else:
+ # If player is not moving, apply friction.
+ var friction := friction_ground if player.is_on_floor() else friction_air
+ player.velocity.x = lerpf(player.velocity.x, 0, friction)
diff --git a/player/movement.gd.uid b/player/movement.gd.uid
new file mode 100644
index 0000000..26df166
--- /dev/null
+++ b/player/movement.gd.uid
@@ -0,0 +1 @@
+uid://bwlbh0k6pm7hw
diff --git a/player/network.gd b/player/network.gd
new file mode 100644
index 0000000..a6084f3
--- /dev/null
+++ b/player/network.gd
@@ -0,0 +1,18 @@
+class_name PlayerNetwork
+extends Node
+
+var is_local: bool:
+ get: return is_multiplayer_authority()
+
+var peer_id: int:
+ get: return get_multiplayer_authority()
+ set(value):
+ get_parent().set_multiplayer_authority(value)
+ get_parent().name = str(value)
+
+@onready var player: Player = get_parent()
+
+func _ready() -> void:
+ if not is_local and multiplayer.is_server():
+ player.chunk_loader.start_tracking.connect(Game.WORLD.spawn_chunk.bind(peer_id))
+ player.chunk_loader.stop_tracking.connect(Game.WORLD.despawn_chunk.bind(peer_id))
diff --git a/player/network.gd.uid b/player/network.gd.uid
new file mode 100644
index 0000000..d413427
--- /dev/null
+++ b/player/network.gd.uid
@@ -0,0 +1 @@
+uid://c3ly8e6oigxab
diff --git a/player/player.gd b/player/player.gd
new file mode 100644
index 0000000..2329cb5
--- /dev/null
+++ b/player/player.gd
@@ -0,0 +1,23 @@
+class_name Player
+extends CharacterBody2D
+
+var _appearance : PlayerAppearance
+var _inventory : PlayerInventory
+var _movement : PlayerMovement
+var _health : PlayerHealth
+var _network : PlayerNetwork
+var _chunk_loader : ChunkLoader
+
+# Lazily initialized properties that are available as soon as called, rather than `@onready`.
+var appearance : PlayerAppearance:
+ get: _appearance = _appearance if _appearance else $Appearance ; return _appearance
+var inventory : PlayerInventory:
+ get: _inventory = _inventory if _inventory else $Inventory ; return _inventory
+var movement : PlayerMovement:
+ get: _movement = _movement if _movement else $Movement ; return _movement
+var health : PlayerHealth:
+ get: _health = _health if _health else $Health ; return _health
+var network : PlayerNetwork:
+ get: _network = _network if _network else $Network ; return _network
+var chunk_loader : ChunkLoader:
+ get: _chunk_loader = _chunk_loader if _chunk_loader else $ChunkLoader; return _chunk_loader
diff --git a/player/player.gd.uid b/player/player.gd.uid
new file mode 100644
index 0000000..148df34
--- /dev/null
+++ b/player/player.gd.uid
@@ -0,0 +1 @@
+uid://c1llv3kpm51m2
diff --git a/gfx/player.png b/player/player.png
similarity index 100%
rename from gfx/player.png
rename to player/player.png
diff --git a/player/player.png.import b/player/player.png.import
new file mode 100644
index 0000000..6ac2ad3
--- /dev/null
+++ b/player/player.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bghhc7sjlstuv"
+path="res://.godot/imported/player.png-1ad27fc2a62fa126eae918723933dd6f.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://player/player.png"
+dest_files=["res://.godot/imported/player.png-1ad27fc2a62fa126eae918723933dd6f.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/player/player.tscn b/player/player.tscn
new file mode 100644
index 0000000..599b761
--- /dev/null
+++ b/player/player.tscn
@@ -0,0 +1,196 @@
+[gd_scene load_steps=24 format=3 uid="uid://dnuy2pdb7p1gy"]
+
+[ext_resource type="Theme" uid="uid://4tevy1my8joc" path="res://hud/theme/ui_theme.tres" id="1"]
+[ext_resource type="Script" uid="uid://bwlbh0k6pm7hw" path="res://player/movement.gd" id="1_1nsan"]
+[ext_resource type="Script" uid="uid://c1llv3kpm51m2" path="res://player/player.gd" id="1_vycj2"]
+[ext_resource type="Texture2D" uid="uid://bghhc7sjlstuv" path="res://player/player.png" id="2"]
+[ext_resource type="Script" uid="uid://cm1l4kpund5dp" path="res://player/appearance.gd" id="2_uewl2"]
+[ext_resource type="Script" uid="uid://lavpkfgmvc82" path="res://player/health.gd" id="3_t8epa"]
+[ext_resource type="Script" uid="uid://c3ly8e6oigxab" path="res://player/network.gd" id="4_w24id"]
+[ext_resource type="Script" uid="uid://cx5bh024nq4ot" path="res://player/inventory.gd" id="5_0sdk6"]
+[ext_resource type="Texture2D" uid="uid://3m3yv5gi6t35" path="res://world/blocks/simple.png" id="6"]
+[ext_resource type="Texture2D" uid="uid://dkbjlb3ie6eo7" path="res://item/guns/ColtSingleActionArmy.png" id="7"]
+[ext_resource type="Script" uid="uid://dv62vpu4lkr87" path="res://item/creative_building.gd" id="7_x7c3f"]
+[ext_resource type="Texture2D" uid="uid://bwk4k706icgq" path="res://item/guns/DoubleBarrel.png" id="9"]
+[ext_resource type="Script" uid="uid://vvivkvsnr34j" path="res://item/weapon.gd" id="9_yu5hk"]
+[ext_resource type="Texture2D" uid="uid://boka3vpba0msa" path="res://item/guns/SuperSoaker.png" id="10"]
+[ext_resource type="Texture2D" uid="uid://cvkgeg6x8yxtw" path="res://item/guns/M1Garand.png" id="11"]
+[ext_resource type="Texture2D" uid="uid://dddw8o4powkib" path="res://item/guns/FNScar.png" id="12"]
+[ext_resource type="AudioStream" uid="uid://dinsrxi61427g" path="res://item/sounds/shotgun.wav" id="13"]
+[ext_resource type="AudioStream" uid="uid://bdsgcbe6my0t3" path="res://item/sounds/revolver.wav" id="14"]
+[ext_resource type="AudioStream" uid="uid://dtdtur6706acx" path="res://item/sounds/rifle.wav" id="15"]
+[ext_resource type="AudioStream" uid="uid://clj0jr2p5n2fm" path="res://item/sounds/assault_rifle.wav" id="16"]
+[ext_resource type="Script" uid="uid://disk1asctm3lb" path="res://player/chunk_loader.gd" id="21_x7c3f"]
+
+[sub_resource type="CircleShape2D" id="1"]
+radius = 7.9
+
+[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_65viv"]
+properties/0/path = NodePath(".:position")
+properties/0/spawn = true
+properties/0/replication_mode = 1
+properties/1/path = NodePath(".:velocity")
+properties/1/spawn = true
+properties/1/replication_mode = 1
+
+[node name="Player" type="CharacterBody2D"]
+z_index = 10
+collision_layer = 2
+script = ExtResource("1_vycj2")
+
+[node name="Shape" type="CollisionShape2D" parent="."]
+shape = SubResource("1")
+
+[node name="Appearance" type="Node2D" parent="."]
+script = ExtResource("2_uewl2")
+
+[node name="DisplayName" type="Label" parent="Appearance"]
+modulate = Color(1, 1, 1, 0.501961)
+custom_minimum_size = Vector2(160, 15)
+anchors_preset = 5
+anchor_left = 0.5
+anchor_right = 0.5
+offset_left = -720.0
+offset_top = -24.0
+offset_right = -560.0
+offset_bottom = -9.0
+theme = ExtResource("1")
+
+[node name="Sprite" type="Sprite2D" parent="Appearance"]
+z_index = -5
+texture = ExtResource("2")
+
+[node name="Inventory" type="Node2D" parent="."]
+script = ExtResource("5_0sdk6")
+
+[node name="Creative Building" type="Sprite2D" parent="Inventory"]
+visible = false
+scale = Vector2(0.5, 0.5)
+texture = ExtResource("6")
+offset = Vector2(12, 0)
+script = ExtResource("7_x7c3f")
+
+[node name="Revolver" type="Sprite2D" parent="Inventory"]
+visible = false
+texture = ExtResource("7")
+offset = Vector2(8, 0)
+script = ExtResource("9_yu5hk")
+fire_rate = 400
+capacity = 6
+reload_time = 1.4
+knockback = 50.0
+spread = 1.5
+spread_increase = 1.0
+recoil_min = 3.0
+recoil_max = 5.0
+bullet_velocity = 1200
+damage = 0.22
+
+[node name="Tip" type="Node2D" parent="Inventory/Revolver"]
+position = Vector2(15, -2.5)
+
+[node name="Fire" type="AudioStreamPlayer2D" parent="Inventory/Revolver"]
+stream = ExtResource("14")
+
+[node name="Shotgun" type="Sprite2D" parent="Inventory"]
+visible = false
+texture = ExtResource("9")
+offset = Vector2(8, 0)
+script = ExtResource("9_yu5hk")
+capacity = 2
+reload_time = 2.0
+knockback = 135.0
+spread = 8.0
+spread_increase = 10.0
+recoil_min = 6.0
+recoil_max = 12.0
+effective_range = 240
+maximum_range = 360
+bullet_velocity = 1000
+bullets_per_shot = 6
+damage = 0.6
+bullet_opacity = 0.1
+
+[node name="Tip" type="Node2D" parent="Inventory/Shotgun"]
+position = Vector2(22, -1.5)
+
+[node name="Fire" type="AudioStreamPlayer2D" parent="Inventory/Shotgun"]
+stream = ExtResource("13")
+
+[node name="Rifle" type="Sprite2D" parent="Inventory"]
+visible = false
+texture = ExtResource("11")
+offset = Vector2(8, 0)
+script = ExtResource("9_yu5hk")
+capacity = 1
+reload_time = 1.6
+knockback = 100.0
+spread_increase = 2.0
+recoil_min = 8.0
+recoil_max = 8.0
+effective_range = 480
+maximum_range = 920
+bullet_velocity = 4000
+damage = 0.8
+bullet_opacity = 0.4
+
+[node name="Tip" type="Node2D" parent="Inventory/Rifle"]
+position = Vector2(24, -1.5)
+
+[node name="Fire" type="AudioStreamPlayer2D" parent="Inventory/Rifle"]
+stream = ExtResource("15")
+
+[node name="Assault Rifle" type="Sprite2D" parent="Inventory"]
+visible = false
+texture = ExtResource("12")
+offset = Vector2(8, 0)
+script = ExtResource("9_yu5hk")
+automatic = true
+fire_rate = 600
+capacity = 30
+reload_time = 2.4
+knockback = 30.0
+spread = 0.6
+spread_increase = 0.8
+recoil_min = 1.0
+recoil_max = 2.5
+damage = 0.12
+bullet_opacity = 0.15
+
+[node name="Tip" type="Node2D" parent="Inventory/Assault Rifle"]
+position = Vector2(22, -1.5)
+
+[node name="Fire" type="AudioStreamPlayer2D" parent="Inventory/Assault Rifle"]
+stream = ExtResource("16")
+
+[node name="Super Soaker" type="Sprite2D" parent="Inventory"]
+visible = false
+texture = ExtResource("10")
+offset = Vector2(8, 0)
+script = ExtResource("9_yu5hk")
+automatic = true
+fire_rate = 120
+capacity = 4
+reload_time = 2.0
+knockback = 60.0
+spread = 3.0
+spread_increase = 10.0
+bullet_velocity = 640
+bullets_per_shot = 16
+bullet_opacity = 0.05
+
+[node name="Tip" type="Node2D" parent="Inventory/Super Soaker"]
+position = Vector2(17, 0.5)
+
+[node name="Movement" type="Node" parent="."]
+script = ExtResource("1_1nsan")
+
+[node name="Health" type="Node" parent="."]
+script = ExtResource("3_t8epa")
+
+[node name="Network" type="MultiplayerSynchronizer" parent="."]
+replication_config = SubResource("SceneReplicationConfig_65viv")
+script = ExtResource("4_w24id")
+
+[node name="ChunkLoader" type="Node2D" parent="."]
+script = ExtResource("21_x7c3f")
diff --git a/project.godot b/project.godot
index 718acf8..f743822 100644
--- a/project.godot
+++ b/project.godot
@@ -6,27 +6,36 @@
; [section] ; section goes between []
; param=value ; assign values to parameters
-config_version=4
-
-_global_script_classes=[ ]
-_global_script_class_icons={
-}
+config_version=5
[application]
config/name="YourFortV"
-run/main_scene="res://scene/ClientScene.tscn"
+run/main_scene="uid://bxhfecc34tahh"
config/use_custom_user_dir=true
config/custom_user_dir_name="YourFortV"
-boot_splash/image="res://gfx/icon.png"
+config/features=PackedStringArray("4.4")
boot_splash/use_filter=false
-config/icon="res://gfx/icon.png"
+boot_splash/image="res://icon.png"
+config/icon="res://icon.png"
+
+[debug]
+
+gdscript/warnings/unused_parameter=0
+gdscript/warnings/shadowed_variable=0
+gdscript/warnings/shadowed_variable_base_class=0
+gdscript/warnings/shadowed_global_identifier=0
[display]
-window/size/width=1280
-window/size/height=720
+window/size/viewport_width=1280
+window/size/viewport_height=720
window/stretch/mode="viewport"
+window/stretch/scale=3.0
+
+[dotnet]
+
+project/assembly_name="YourFortV"
[global]
@@ -60,67 +69,63 @@ texture={
move_left={
"deadzone": 0.5,
-"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":65,"unicode":0,"echo":false,"script":null)
+"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":65,"key_label":0,"unicode":97,"location":0,"echo":false,"script":null)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":0,"axis_value":-1.0,"script":null)
- ]
+]
}
move_right={
"deadzone": 0.5,
-"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":68,"unicode":0,"echo":false,"script":null)
+"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":68,"key_label":0,"unicode":100,"location":0,"echo":false,"script":null)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":0,"axis_value":1.0,"script":null)
- ]
+]
}
move_jump={
"deadzone": 0.5,
-"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":32,"unicode":0,"echo":false,"script":null)
-, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":87,"unicode":0,"echo":false,"script":null)
+"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":87,"key_label":0,"unicode":119,"location":0,"echo":false,"script":null)
+, 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":32,"key_label":0,"unicode":32,"location":0,"echo":false,"script":null)
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":1,"pressure":0.0,"pressed":false,"script":null)
- ]
+]
}
interact_primary={
"deadzone": 0.5,
-"events": [ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":1,"pressed":false,"doubleclick":false,"script":null)
- ]
+"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":1,"canceled":false,"pressed":false,"double_click":false,"script":null)
+]
}
interact_secondary={
"deadzone": 0.5,
-"events": [ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":2,"pressed":false,"doubleclick":false,"script":null)
- ]
+"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":2,"canceled":false,"pressed":false,"double_click":false,"script":null)
+]
}
interact_reload={
"deadzone": 0.5,
-"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":82,"unicode":0,"echo":false,"script":null)
- ]
+"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":82,"key_label":0,"unicode":114,"location":0,"echo":false,"script":null)
+]
}
interact_select={
"deadzone": 0.5,
-"events": [ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":3,"pressed":false,"doubleclick":false,"script":null)
- ]
+"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":3,"canceled":false,"pressed":false,"double_click":false,"script":null)
+]
}
interact_select_dec={
"deadzone": 0.5,
-"events": [ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":4,"pressed":false,"doubleclick":false,"script":null)
- ]
+"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":4,"canceled":false,"pressed":false,"double_click":false,"script":null)
+]
}
interact_select_inc={
"deadzone": 0.5,
-"events": [ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":5,"pressed":false,"doubleclick":false,"script":null)
- ]
-}
-ui_menu={
-"deadzone": 0.5,
-"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777217,"unicode":0,"echo":false,"script":null)
-, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":11,"pressure":0.0,"pressed":false,"script":null)
- ]
+"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":5,"canceled":false,"pressed":false,"double_click":false,"script":null)
+]
}
[layer_names]
-2d_physics/layer_1="players"
-2d_physics/layer_2="blocks"
+2d_physics/layer_1="World"
+2d_physics/layer_2="Players"
[rendering]
+textures/canvas_textures/default_texture_filter=0
+2d/snap/snap_2d_transforms_to_pixel=true
2d/snapping/use_gpu_pixel_snap=true
quality/filters/use_nearest_mipmap_filter=true
quality/dynamic_fonts/use_oversampling=false
diff --git a/scene/ClientScene.tscn b/scene/ClientScene.tscn
deleted file mode 100644
index 9ec383a..0000000
--- a/scene/ClientScene.tscn
+++ /dev/null
@@ -1,132 +0,0 @@
-[gd_scene load_steps=17 format=2]
-
-[ext_resource path="res://scene/GameScene.tscn" type="PackedScene" id=1]
-[ext_resource path="res://src/HUD/Cursor.cs" type="Script" id=2]
-[ext_resource path="res://gfx/cursor.png" type="Texture" id=3]
-[ext_resource path="res://gfx/background.png" type="Texture" id=4]
-[ext_resource path="res://src/Background.cs" type="Script" id=5]
-[ext_resource path="res://src/Viewport.cs" type="Script" id=6]
-[ext_resource path="res://scene/EscapeMenu.tscn" type="PackedScene" id=7]
-[ext_resource path="res://src/Scenes/Client.cs" type="Script" id=8]
-[ext_resource path="res://src/Network/IntegratedServer.cs" type="Script" id=9]
-[ext_resource path="res://ui_theme.tres" type="Theme" id=10]
-[ext_resource path="res://src/HUD/RadialMenu.cs" type="Script" id=11]
-[ext_resource path="res://src/HUD/WeaponInfo.cs" type="Script" id=12]
-[ext_resource path="res://src/HUD/Health.cs" type="Script" id=13]
-
-[sub_resource type="StyleBoxFlat" id=1]
-bg_color = Color( 0, 0, 0, 0.752941 )
-border_width_left = 1
-border_width_top = 1
-border_width_right = 1
-border_width_bottom = 1
-border_color = Color( 0, 0, 0, 0.501961 )
-corner_detail = 1
-expand_margin_left = 1.0
-expand_margin_right = 1.0
-expand_margin_top = 1.0
-expand_margin_bottom = 1.0
-
-[sub_resource type="StyleBoxFlat" id=2]
-bg_color = Color( 0, 0.752941, 0, 0.752941 )
-corner_detail = 1
-
-[sub_resource type="Theme" id=3]
-ProgressBar/colors/font_color = Color( 0.94, 0.94, 0.94, 1 )
-ProgressBar/colors/font_color_shadow = Color( 0, 0, 0, 1 )
-ProgressBar/fonts/font = null
-ProgressBar/styles/bg = SubResource( 1 )
-ProgressBar/styles/fg = SubResource( 2 )
-
-[node name="Client" instance=ExtResource( 1 )]
-script = ExtResource( 8 )
-IntegratedServerPath = NodePath("IntegratedServer")
-CursorPath = NodePath("CursorLayer/Cursor")
-
-[node name="IntegratedServer" type="Node" parent="." index="0"]
-script = ExtResource( 9 )
-
-[node name="Viewport" type="Node" parent="." index="1"]
-script = ExtResource( 6 )
-
-[node name="Background" type="TextureRect" parent="." index="2"]
-modulate = Color( 0.278431, 0.286275, 0.301961, 1 )
-margin_right = 1280.0
-margin_bottom = 720.0
-mouse_filter = 2
-texture = ExtResource( 4 )
-stretch_mode = 2
-script = ExtResource( 5 )
-__meta__ = {
-"_edit_lock_": true,
-"_edit_use_anchors_": false
-}
-
-[node name="HUD" type="CanvasLayer" parent="." index="4"]
-
-[node name="Health" type="Node2D" parent="HUD" index="0"]
-script = ExtResource( 13 )
-
-[node name="RadialMenu" type="Node2D" parent="HUD" index="1"]
-visible = false
-script = ExtResource( 11 )
-
-[node name="ActiveName" type="Label" parent="HUD/RadialMenu" index="0"]
-anchor_left = 0.5
-anchor_top = 0.5
-anchor_right = 0.5
-anchor_bottom = 0.5
-margin_left = -29.0
-margin_top = -16.0
-margin_right = 29.0
-margin_bottom = 16.0
-theme = ExtResource( 10 )
-align = 1
-valign = 1
-autowrap = true
-__meta__ = {
-"_edit_use_anchors_": false
-}
-
-[node name="EscapeMenu" parent="HUD" index="2" instance=ExtResource( 7 )]
-visible = false
-
-[node name="CursorLayer" type="CanvasLayer" parent="." index="5"]
-layer = 2
-follow_viewport_enable = true
-
-[node name="Cursor" type="Sprite" parent="CursorLayer" index="0"]
-z_index = 1000
-texture = ExtResource( 3 )
-script = ExtResource( 2 )
-
-[node name="WeaponInfo" type="Node2D" parent="CursorLayer/Cursor" index="0"]
-script = ExtResource( 12 )
-
-[node name="Rounds" type="Label" parent="CursorLayer/Cursor/WeaponInfo" index="0"]
-anchor_left = 0.5
-anchor_right = 0.5
-margin_left = -40.0
-margin_top = 7.0
-margin_right = 40.0
-margin_bottom = 16.0
-theme = ExtResource( 10 )
-text = "12/12"
-align = 1
-valign = 1
-__meta__ = {
-"_edit_use_anchors_": false
-}
-
-[node name="Reloading" type="ProgressBar" parent="CursorLayer/Cursor/WeaponInfo" index="1"]
-margin_left = -16.0
-margin_top = 10.0
-margin_right = 16.0
-margin_bottom = 13.0
-theme = SubResource( 3 )
-max_value = 1.0
-value = 0.5
-percent_visible = false
-__meta__ = {
-"_edit_use_anchors_": false
-}
diff --git a/scene/EscapeMenu.tscn b/scene/EscapeMenu.tscn
deleted file mode 100644
index dbd21a2..0000000
--- a/scene/EscapeMenu.tscn
+++ /dev/null
@@ -1,517 +0,0 @@
-[gd_scene load_steps=7 format=2]
-
-[ext_resource path="res://ui_theme.tres" type="Theme" id=1]
-[ext_resource path="res://src/EscapeMenu.cs" type="Script" id=2]
-[ext_resource path="res://gfx/player.png" type="Texture" id=3]
-[ext_resource path="res://src/EscapeMenuMultiplayer.cs" type="Script" id=4]
-[ext_resource path="res://src/EscapeMenuAppearance.cs" type="Script" id=5]
-[ext_resource path="res://src/EscapeMenuWorld.cs" type="Script" id=6]
-
-[node name="EscapeMenu" type="Control"]
-anchor_right = 1.0
-anchor_bottom = 1.0
-theme = ExtResource( 1 )
-script = ExtResource( 2 )
-__meta__ = {
-"_edit_lock_": true,
-"_edit_use_anchors_": false
-}
-ReturnPath = NodePath("CenterContainer/PanelContainer/VBoxContainer/Return")
-
-[node name="ColorRect" type="ColorRect" parent="."]
-anchor_right = 1.0
-anchor_bottom = 1.0
-color = Color( 0, 0, 0, 0.501961 )
-__meta__ = {
-"_edit_lock_": true
-}
-
-[node name="SaveFileDialog" type="FileDialog" parent="."]
-anchor_left = 0.5
-anchor_top = 0.5
-anchor_right = 0.5
-anchor_bottom = 0.5
-margin_left = -240.0
-margin_top = -160.0
-margin_right = 240.0
-margin_bottom = 160.0
-rect_min_size = Vector2( 0, 0 )
-window_title = "Save World As..."
-mode_overrides_title = false
-access = 2
-filters = PoolStringArray( "*.yf5 ; YourFortV Save" )
-current_dir = "/"
-current_path = "/"
-__meta__ = {
-"_edit_use_anchors_": false
-}
-
-[node name="LoadFileDialog" type="FileDialog" parent="."]
-anchor_left = 0.5
-anchor_top = 0.5
-anchor_right = 0.5
-anchor_bottom = 0.5
-margin_left = -240.0
-margin_top = -160.0
-margin_right = 240.0
-margin_bottom = 160.0
-rect_min_size = Vector2( 0, 0 )
-window_title = "Load World From..."
-mode_overrides_title = false
-mode = 0
-access = 2
-filters = PoolStringArray( "*.yf5 ; YourFortV Save" )
-current_dir = "/"
-current_path = "/"
-__meta__ = {
-"_edit_use_anchors_": false
-}
-
-[node name="CenterContainer" type="CenterContainer" parent="."]
-anchor_right = 1.0
-anchor_bottom = 1.0
-__meta__ = {
-"_edit_lock_": true,
-"_edit_use_anchors_": false
-}
-
-[node name="PanelContainer" type="PanelContainer" parent="CenterContainer"]
-margin_left = 518.0
-margin_top = 258.0
-margin_right = 761.0
-margin_bottom = 461.0
-
-[node name="VBoxContainer" type="VBoxContainer" parent="CenterContainer/PanelContainer"]
-margin_left = 7.0
-margin_top = 7.0
-margin_right = 236.0
-margin_bottom = 196.0
-__meta__ = {
-"_edit_use_anchors_": false
-}
-
-[node name="Label" type="Label" parent="CenterContainer/PanelContainer/VBoxContainer"]
-margin_right = 229.0
-margin_bottom = 9.0
-text = "Escape Menu"
-align = 1
-__meta__ = {
-"_edit_use_anchors_": false
-}
-
-[node name="HSeparator" type="HSeparator" parent="CenterContainer/PanelContainer/VBoxContainer"]
-margin_top = 13.0
-margin_right = 229.0
-margin_bottom = 17.0
-
-[node name="TabContainer" type="TabContainer" parent="CenterContainer/PanelContainer/VBoxContainer"]
-margin_top = 21.0
-margin_right = 229.0
-margin_bottom = 139.0
-custom_constants/side_margin = 0
-use_hidden_tabs_for_min_size = true
-
-[node name="Appearance" type="CenterContainer" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer"]
-anchor_right = 1.0
-anchor_bottom = 1.0
-margin_left = 4.0
-margin_top = 27.0
-margin_right = -4.0
-margin_bottom = -4.0
-script = ExtResource( 5 )
-DisplayNamePath = NodePath("VBoxContainer/ContainerName/DisplayName")
-ColorPreviewPath = NodePath("VBoxContainer/ContainerColor/Preview")
-ColorSliderPath = NodePath("VBoxContainer/ContainerColor/Hue")
-
-[node name="VBoxContainer" type="VBoxContainer" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Appearance"]
-margin_left = 19.0
-margin_top = 16.0
-margin_right = 201.0
-margin_bottom = 71.0
-
-[node name="ContainerName" type="HBoxContainer" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Appearance/VBoxContainer"]
-margin_right = 182.0
-margin_bottom = 19.0
-
-[node name="Label" type="Label" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Appearance/VBoxContainer/ContainerName"]
-margin_top = 5.0
-margin_right = 36.0
-margin_bottom = 14.0
-rect_min_size = Vector2( 36, 0 )
-text = "Name:"
-align = 2
-
-[node name="DisplayName" type="LineEdit" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Appearance/VBoxContainer/ContainerName"]
-margin_left = 40.0
-margin_right = 182.0
-margin_bottom = 19.0
-rect_min_size = Vector2( 142, 0 )
-size_flags_horizontal = 3
-align = 1
-max_length = 20
-caret_blink = true
-
-[node name="ContainerColor" type="HBoxContainer" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Appearance/VBoxContainer"]
-margin_top = 23.0
-margin_right = 182.0
-margin_bottom = 39.0
-
-[node name="Label" type="Label" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Appearance/VBoxContainer/ContainerColor"]
-margin_top = 3.0
-margin_right = 36.0
-margin_bottom = 12.0
-rect_min_size = Vector2( 36, 0 )
-text = "Color:"
-align = 2
-
-[node name="Preview" type="TextureRect" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Appearance/VBoxContainer/ContainerColor"]
-margin_left = 40.0
-margin_right = 56.0
-margin_bottom = 16.0
-texture = ExtResource( 3 )
-
-[node name="Hue" type="HSlider" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Appearance/VBoxContainer/ContainerColor"]
-margin_left = 60.0
-margin_right = 182.0
-margin_bottom = 16.0
-size_flags_horizontal = 3
-max_value = 1.0
-step = 0.0
-scrollable = false
-
-[node name="Label" type="Label" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Appearance/VBoxContainer"]
-margin_top = 43.0
-margin_right = 182.0
-margin_bottom = 55.0
-rect_min_size = Vector2( 0, 12 )
-custom_colors/font_color = Color( 0.6, 0.6, 0.6, 1 )
-text = "(Close Menu to apply changes.)"
-align = 1
-valign = 2
-
-[node name="Multiplayer" type="CenterContainer" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer"]
-visible = false
-anchor_right = 1.0
-anchor_bottom = 1.0
-margin_left = 4.0
-margin_top = 27.0
-margin_right = -4.0
-margin_bottom = -4.0
-script = ExtResource( 4 )
-StatusPath = NodePath("VBoxContainer/ContainerStatus/Status")
-ServerOpenClosePath = NodePath("VBoxContainer/ContainerServer/ServerOpenClose")
-ServerPortPath = NodePath("VBoxContainer/ContainerServer/ServerPort")
-ClientDisConnectPath = NodePath("VBoxContainer/ContainerClient/ClientDisConnect")
-ClientAddressPath = NodePath("VBoxContainer/ContainerClient/ClientAddress")
-
-[node name="VBoxContainer" type="VBoxContainer" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Multiplayer"]
-margin_right = 221.0
-margin_bottom = 87.0
-
-[node name="ContainerStatus" type="HBoxContainer" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Multiplayer/VBoxContainer"]
-margin_right = 221.0
-margin_bottom = 13.0
-__meta__ = {
-"_edit_use_anchors_": false
-}
-
-[node name="Label" type="Label" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Multiplayer/VBoxContainer/ContainerStatus"]
-margin_top = 2.0
-margin_right = 36.0
-margin_bottom = 11.0
-rect_min_size = Vector2( 36, 0 )
-text = "Status:"
-align = 2
-
-[node name="Status" type="Label" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Multiplayer/VBoxContainer/ContainerStatus"]
-modulate = Color( 1, 0, 0, 1 )
-margin_left = 40.0
-margin_right = 221.0
-margin_bottom = 13.0
-rect_min_size = Vector2( 0, 13 )
-size_flags_horizontal = 3
-size_flags_vertical = 5
-text = "No Connection"
-align = 1
-valign = 1
-__meta__ = {
-"_edit_use_anchors_": false
-}
-
-[node name="ContainerServer" type="HBoxContainer" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Multiplayer/VBoxContainer"]
-margin_top = 17.0
-margin_right = 221.0
-margin_bottom = 36.0
-
-[node name="Label" type="Label" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Multiplayer/VBoxContainer/ContainerServer"]
-margin_top = 5.0
-margin_right = 36.0
-margin_bottom = 14.0
-rect_min_size = Vector2( 36, 0 )
-text = "Port:"
-align = 2
-
-[node name="ServerPort" type="LineEdit" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Multiplayer/VBoxContainer/ContainerServer"]
-margin_left = 40.0
-margin_right = 90.0
-margin_bottom = 19.0
-custom_constants/minimum_spaces = 8
-align = 1
-max_length = 6
-caret_blink = true
-__meta__ = {
-"_edit_use_anchors_": false
-}
-
-[node name="ServerOpenClose" type="Button" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Multiplayer/VBoxContainer/ContainerServer"]
-margin_left = 94.0
-margin_right = 221.0
-margin_bottom = 19.0
-size_flags_horizontal = 3
-text = "Open Server"
-__meta__ = {
-"_edit_use_anchors_": false
-}
-
-[node name="ContainerClient" type="HBoxContainer" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Multiplayer/VBoxContainer"]
-margin_top = 40.0
-margin_right = 221.0
-margin_bottom = 59.0
-
-[node name="Label" type="Label" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Multiplayer/VBoxContainer/ContainerClient"]
-margin_top = 5.0
-margin_right = 36.0
-margin_bottom = 14.0
-rect_min_size = Vector2( 36, 0 )
-text = "Address:"
-align = 2
-
-[node name="ClientAddress" type="LineEdit" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Multiplayer/VBoxContainer/ContainerClient"]
-margin_left = 40.0
-margin_right = 160.0
-margin_bottom = 19.0
-rect_min_size = Vector2( 120, 0 )
-align = 1
-caret_blink = true
-
-[node name="ClientDisConnect" type="Button" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Multiplayer/VBoxContainer/ContainerClient"]
-margin_left = 164.0
-margin_right = 221.0
-margin_bottom = 19.0
-rect_min_size = Vector2( 57, 0 )
-size_flags_horizontal = 3
-text = "Connect"
-
-[node name="ContainerHideAddress" type="HBoxContainer" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Multiplayer/VBoxContainer"]
-margin_top = 63.0
-margin_right = 221.0
-margin_bottom = 87.0
-
-[node name="HideAddress" type="CheckBox" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Multiplayer/VBoxContainer/ContainerHideAddress"]
-margin_right = 82.0
-margin_bottom = 24.0
-text = "Hide Address"
-
-[node name="Label" type="Label" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Multiplayer/VBoxContainer/ContainerHideAddress"]
-margin_left = 86.0
-margin_top = 7.0
-margin_right = 173.0
-margin_bottom = 16.0
-custom_colors/font_color = Color( 0.6, 0.6, 0.6, 1 )
-text = "(for streamers etc.)"
-
-[node name="World" type="CenterContainer" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer"]
-visible = false
-anchor_right = 1.0
-anchor_bottom = 1.0
-margin_left = 4.0
-margin_top = 27.0
-margin_right = -4.0
-margin_bottom = -4.0
-script = ExtResource( 6 )
-FilenamePath = NodePath("VBoxContainer/HBoxContainer/Filename")
-LastSavedPath = NodePath("VBoxContainer/HBoxContainer3/LastSaved")
-PlaytimePath = NodePath("VBoxContainer/HBoxContainer2/Playtime")
-QuickSavePath = NodePath("VBoxContainer/HBoxContainer4/QuickSave")
-SaveAsPath = NodePath("VBoxContainer/HBoxContainer4/SaveAs")
-SaveFileDialogPath = NodePath("../../../../../SaveFileDialog")
-LoadFileDialogPath = NodePath("../../../../../LoadFileDialog")
-
-[node name="VBoxContainer" type="VBoxContainer" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/World"]
-margin_left = 20.0
-margin_top = 1.0
-margin_right = 200.0
-margin_bottom = 86.0
-rect_min_size = Vector2( 180, 0 )
-
-[node name="HBoxContainer" type="HBoxContainer" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/World/VBoxContainer"]
-margin_right = 180.0
-margin_bottom = 9.0
-
-[node name="Label" type="Label" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/World/VBoxContainer/HBoxContainer"]
-margin_right = 58.0
-margin_bottom = 9.0
-rect_min_size = Vector2( 58, 0 )
-text = "Filename:"
-align = 2
-
-[node name="Filename" type="Label" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/World/VBoxContainer/HBoxContainer"]
-margin_left = 62.0
-margin_right = 180.0
-margin_bottom = 9.0
-size_flags_horizontal = 3
-custom_colors/font_color = Color( 0.6, 0.6, 0.6, 1 )
-text = "-not saved yet-"
-align = 1
-
-[node name="HBoxContainer2" type="HBoxContainer" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/World/VBoxContainer"]
-margin_top = 13.0
-margin_right = 180.0
-margin_bottom = 22.0
-
-[node name="Label" type="Label" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/World/VBoxContainer/HBoxContainer2"]
-margin_right = 58.0
-margin_bottom = 9.0
-rect_min_size = Vector2( 58, 0 )
-text = "Playtime:"
-align = 2
-
-[node name="Playtime" type="Label" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/World/VBoxContainer/HBoxContainer2"]
-margin_left = 62.0
-margin_right = 180.0
-margin_bottom = 9.0
-size_flags_horizontal = 3
-custom_colors/font_color = Color( 0.6, 0.6, 0.6, 1 )
-text = "000d 00h 00m 00s"
-align = 1
-
-[node name="HBoxContainer3" type="HBoxContainer" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/World/VBoxContainer"]
-margin_top = 26.0
-margin_right = 180.0
-margin_bottom = 35.0
-
-[node name="Label" type="Label" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/World/VBoxContainer/HBoxContainer3"]
-margin_right = 58.0
-margin_bottom = 9.0
-rect_min_size = Vector2( 58, 0 )
-text = "Last Saved:"
-align = 2
-
-[node name="LastSaved" type="Label" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/World/VBoxContainer/HBoxContainer3"]
-margin_left = 62.0
-margin_right = 180.0
-margin_bottom = 9.0
-size_flags_horizontal = 3
-custom_colors/font_color = Color( 0.6, 0.6, 0.6, 1 )
-text = "0000-00-00 00:00"
-align = 1
-
-[node name="HSeparator" type="HSeparator" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/World/VBoxContainer"]
-margin_top = 39.0
-margin_right = 180.0
-margin_bottom = 43.0
-
-[node name="HBoxContainer4" type="HBoxContainer" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/World/VBoxContainer"]
-margin_top = 47.0
-margin_right = 180.0
-margin_bottom = 64.0
-
-[node name="QuickSave" type="Button" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/World/VBoxContainer/HBoxContainer4"]
-margin_right = 112.0
-margin_bottom = 17.0
-rect_min_size = Vector2( 112, 17 )
-size_flags_horizontal = 3
-text = "Quick Save"
-
-[node name="SaveAs" type="Button" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/World/VBoxContainer/HBoxContainer4"]
-margin_left = 116.0
-margin_right = 180.0
-margin_bottom = 17.0
-rect_min_size = Vector2( 0, 17 )
-size_flags_horizontal = 3
-text = "Save As..."
-
-[node name="HBoxContainer5" type="HBoxContainer" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/World/VBoxContainer"]
-margin_top = 68.0
-margin_right = 180.0
-margin_bottom = 85.0
-
-[node name="LoadFrom" type="Button" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/World/VBoxContainer/HBoxContainer5"]
-margin_right = 180.0
-margin_bottom = 17.0
-rect_min_size = Vector2( 80, 17 )
-size_flags_horizontal = 3
-text = "Load World From..."
-
-[node name="HSeparator2" type="HSeparator" parent="CenterContainer/PanelContainer/VBoxContainer"]
-margin_top = 143.0
-margin_right = 229.0
-margin_bottom = 147.0
-
-[node name="Quit" type="Button" parent="CenterContainer/PanelContainer/VBoxContainer"]
-margin_top = 151.0
-margin_right = 229.0
-margin_bottom = 168.0
-rect_min_size = Vector2( 0, 17 )
-
-[node name="RichTextLabel" type="RichTextLabel" parent="CenterContainer/PanelContainer/VBoxContainer/Quit"]
-anchor_left = 0.5
-anchor_top = 0.5
-anchor_right = 0.5
-anchor_bottom = 0.5
-margin_left = -105.5
-margin_top = -5.0
-margin_right = 105.5
-margin_bottom = 5.0
-mouse_filter = 1
-bbcode_enabled = true
-bbcode_text = "[center]Quit Game [color=#999](Alt+F4)[/color][/center]"
-text = "Quit Game (Alt+F4)"
-fit_content_height = true
-scroll_active = false
-__meta__ = {
-"_edit_use_anchors_": false
-}
-
-[node name="Return" type="Button" parent="CenterContainer/PanelContainer/VBoxContainer"]
-margin_top = 172.0
-margin_right = 229.0
-margin_bottom = 189.0
-rect_min_size = Vector2( 0, 17 )
-__meta__ = {
-"_edit_use_anchors_": false
-}
-
-[node name="RichTextLabel" type="RichTextLabel" parent="CenterContainer/PanelContainer/VBoxContainer/Return"]
-anchor_left = 0.5
-anchor_top = 0.5
-anchor_right = 0.5
-anchor_bottom = 0.5
-margin_left = -105.5
-margin_top = -5.0
-margin_right = 105.5
-margin_bottom = 5.0
-mouse_filter = 1
-bbcode_enabled = true
-bbcode_text = "[center]Return to Game [color=#999](Esc)[/color][/center]"
-text = "Return to Game (Esc)"
-fit_content_height = true
-scroll_active = false
-__meta__ = {
-"_edit_use_anchors_": false
-}
-
-[connection signal="file_selected" from="SaveFileDialog" to="CenterContainer/PanelContainer/VBoxContainer/TabContainer/World" method="_on_SaveFileDialog_file_selected"]
-[connection signal="file_selected" from="LoadFileDialog" to="CenterContainer/PanelContainer/VBoxContainer/TabContainer/World" method="_on_LoadFileDialog_file_selected"]
-[connection signal="visibility_changed" from="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Appearance" to="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Appearance" method="_on_Appearance_visibility_changed"]
-[connection signal="text_changed" from="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Appearance/VBoxContainer/ContainerName/DisplayName" to="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Appearance" method="_on_DisplayName_text_changed"]
-[connection signal="value_changed" from="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Appearance/VBoxContainer/ContainerColor/Hue" to="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Appearance" method="_on_Hue_value_changed"]
-[connection signal="text_changed" from="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Multiplayer/VBoxContainer/ContainerServer/ServerPort" to="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Multiplayer" method="_on_ServerPort_text_changed"]
-[connection signal="pressed" from="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Multiplayer/VBoxContainer/ContainerServer/ServerOpenClose" to="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Multiplayer" method="_on_ServerOpenClose_pressed"]
-[connection signal="pressed" from="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Multiplayer/VBoxContainer/ContainerClient/ClientDisConnect" to="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Multiplayer" method="_on_ClientDisConnect_pressed"]
-[connection signal="toggled" from="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Multiplayer/VBoxContainer/ContainerHideAddress/HideAddress" to="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Multiplayer" method="_on_HideAddress_toggled"]
-[connection signal="pressed" from="CenterContainer/PanelContainer/VBoxContainer/TabContainer/World/VBoxContainer/HBoxContainer4/QuickSave" to="CenterContainer/PanelContainer/VBoxContainer/TabContainer/World" method="_on_QuickSave_pressed"]
-[connection signal="pressed" from="CenterContainer/PanelContainer/VBoxContainer/TabContainer/World/VBoxContainer/HBoxContainer4/SaveAs" to="CenterContainer/PanelContainer/VBoxContainer/TabContainer/World" method="_on_SaveAs_pressed"]
-[connection signal="pressed" from="CenterContainer/PanelContainer/VBoxContainer/TabContainer/World/VBoxContainer/HBoxContainer5/LoadFrom" to="CenterContainer/PanelContainer/VBoxContainer/TabContainer/World" method="_on_LoadFrom_pressed"]
-[connection signal="pressed" from="CenterContainer/PanelContainer/VBoxContainer/Quit" to="." method="_on_Quit_pressed"]
-[connection signal="pressed" from="CenterContainer/PanelContainer/VBoxContainer/Return" to="." method="_on_Return_pressed"]
diff --git a/scene/GameScene.tscn b/scene/GameScene.tscn
deleted file mode 100644
index 50c0780..0000000
--- a/scene/GameScene.tscn
+++ /dev/null
@@ -1,13 +0,0 @@
-[gd_scene load_steps=3 format=2]
-
-[ext_resource path="res://src/World/World.cs" type="Script" id=1]
-[ext_resource path="res://src/Scenes/Game.cs" type="Script" id=3]
-
-[node name="Game" type="Node"]
-pause_mode = 2
-script = ExtResource( 3 )
-
-[node name="World" type="Node" parent="."]
-script = ExtResource( 1 )
-PlayerContainerPath = NodePath("")
-BlockContainerPath = NodePath("")
diff --git a/scene/Player.tscn b/scene/Player.tscn
deleted file mode 100644
index e70697a..0000000
--- a/scene/Player.tscn
+++ /dev/null
@@ -1,175 +0,0 @@
-[gd_scene load_steps=18 format=2]
-
-[ext_resource path="res://ui_theme.tres" type="Theme" id=1]
-[ext_resource path="res://gfx/player.png" type="Texture" id=2]
-[ext_resource path="res://src/Objects/Player.cs" type="Script" id=3]
-[ext_resource path="res://src/Items/CreativeBuilding.cs" type="Script" id=4]
-[ext_resource path="res://src/Items/Items.cs" type="Script" id=5]
-[ext_resource path="res://gfx/block.png" type="Texture" id=6]
-[ext_resource path="res://gfx/guns/ColtSingleActionArmy.png" type="Texture" id=7]
-[ext_resource path="res://src/Items/Weapon.cs" type="Script" id=8]
-[ext_resource path="res://gfx/guns/DoubleBarrel.png" type="Texture" id=9]
-[ext_resource path="res://gfx/guns/SuperSoaker.png" type="Texture" id=10]
-[ext_resource path="res://gfx/guns/M1Garand.png" type="Texture" id=11]
-[ext_resource path="res://gfx/guns/FNScar.png" type="Texture" id=12]
-[ext_resource path="res://sfx/shotgun.wav" type="AudioStream" id=13]
-[ext_resource path="res://sfx/revolver.wav" type="AudioStream" id=14]
-[ext_resource path="res://sfx/rifle.wav" type="AudioStream" id=15]
-[ext_resource path="res://sfx/assault_rifle.wav" type="AudioStream" id=16]
-
-[sub_resource type="CircleShape2D" id=1]
-radius = 8.0
-
-[node name="Player" type="KinematicBody2D"]
-z_index = 10
-collision_mask = 2
-script = ExtResource( 3 )
-DisplayNamePath = NodePath("DisplayName")
-SpritePath = NodePath("Sprite")
-
-[node name="CircleShape" type="CollisionShape2D" parent="."]
-shape = SubResource( 1 )
-
-[node name="DisplayName" type="Label" parent="."]
-modulate = Color( 1, 1, 1, 0.501961 )
-anchor_left = 0.5
-anchor_right = 0.5
-margin_left = -80.0
-margin_top = -24.0
-margin_right = 80.0
-margin_bottom = -9.0
-rect_min_size = Vector2( 160, 15 )
-theme = ExtResource( 1 )
-align = 1
-valign = 1
-__meta__ = {
-"_edit_use_anchors_": false
-}
-
-[node name="Sprite" type="Sprite" parent="."]
-z_index = -5
-texture = ExtResource( 2 )
-
-[node name="Items" type="Node2D" parent="."]
-script = ExtResource( 5 )
-DefaultItemPath = NodePath("Creative Building")
-
-[node name="Creative Building" type="Node2D" parent="Items"]
-visible = false
-script = ExtResource( 4 )
-
-[node name="Icon" type="Sprite" parent="Items/Creative Building"]
-visible = false
-texture = ExtResource( 6 )
-
-[node name="Revolver" type="Sprite" parent="Items"]
-visible = false
-texture = ExtResource( 7 )
-offset = Vector2( 8, 0 )
-script = ExtResource( 8 )
-RateOfFire = 400
-Capacity = 6
-ReloadTime = 1.4
-Knockback = 50.0
-Spread = 1.5
-SpreadIncrease = 1.0
-RecoilMin = 3.0
-RecoilMax = 5.0
-BulletVelocity = 1200
-Damage = 0.22
-
-[node name="Tip" type="Node2D" parent="Items/Revolver"]
-position = Vector2( 15, -2.5 )
-
-[node name="Fire" type="AudioStreamPlayer2D" parent="Items/Revolver"]
-stream = ExtResource( 14 )
-
-[node name="Shotgun" type="Sprite" parent="Items"]
-visible = false
-texture = ExtResource( 9 )
-offset = Vector2( 8, 0 )
-script = ExtResource( 8 )
-Capacity = 2
-ReloadTime = 2.0
-Knockback = 135.0
-Spread = 8.0
-SpreadIncrease = 10.0
-RecoilMin = 6.0
-RecoilMax = 12.0
-EffectiveRange = 240
-MaximumRange = 360
-BulletVelocity = 1000
-BulletsPerShot = 6
-Damage = 0.6
-BulletOpacity = 0.1
-
-[node name="Tip" type="Node2D" parent="Items/Shotgun"]
-position = Vector2( 22, -1.5 )
-
-[node name="Fire" type="AudioStreamPlayer2D" parent="Items/Shotgun"]
-stream = ExtResource( 13 )
-
-[node name="Rifle" type="Sprite" parent="Items"]
-visible = false
-texture = ExtResource( 11 )
-offset = Vector2( 8, 0 )
-script = ExtResource( 8 )
-Capacity = 1
-ReloadTime = 1.6
-Knockback = 100.0
-SpreadIncrease = 2.0
-RecoilMin = 8.0
-RecoilMax = 8.0
-EffectiveRange = 480
-MaximumRange = 920
-BulletVelocity = 4000
-Damage = 0.8
-BulletOpacity = 0.4
-
-[node name="Tip" type="Node2D" parent="Items/Rifle"]
-position = Vector2( 24, -1.5 )
-
-[node name="Fire" type="AudioStreamPlayer2D" parent="Items/Rifle"]
-stream = ExtResource( 15 )
-
-[node name="Assault Rifle" type="Sprite" parent="Items"]
-visible = false
-texture = ExtResource( 12 )
-offset = Vector2( 8, 0 )
-script = ExtResource( 8 )
-Automatic = true
-RateOfFire = 600
-Capacity = 30
-ReloadTime = 2.4
-Knockback = 30.0
-Spread = 0.6
-SpreadIncrease = 0.8
-RecoilMin = 1.0
-RecoilMax = 2.5
-Damage = 0.12
-BulletOpacity = 0.15
-
-[node name="Tip" type="Node2D" parent="Items/Assault Rifle"]
-position = Vector2( 22, -1.5 )
-
-[node name="Fire" type="AudioStreamPlayer2D" parent="Items/Assault Rifle"]
-stream = ExtResource( 16 )
-
-[node name="Super Soaker" type="Sprite" parent="Items"]
-visible = false
-texture = ExtResource( 10 )
-offset = Vector2( 8, 0 )
-script = ExtResource( 8 )
-Automatic = true
-RateOfFire = 120
-Capacity = 4
-ReloadTime = 2.0
-Knockback = 60.0
-Spread = 3.0
-SpreadIncrease = 10.0
-BulletVelocity = 640
-BulletsPerShot = 16
-BulletOpacity = 0.06
-
-[node name="Tip" type="Node2D" parent="Items/Super Soaker"]
-position = Vector2( 17, 0.5 )
diff --git a/scene/ServerScene.tscn b/scene/ServerScene.tscn
deleted file mode 100644
index 95958dc..0000000
--- a/scene/ServerScene.tscn
+++ /dev/null
@@ -1,7 +0,0 @@
-[gd_scene load_steps=3 format=2]
-
-[ext_resource path="res://scene/GameScene.tscn" type="PackedScene" id=1]
-[ext_resource path="res://src/Scenes/Server.cs" type="Script" id=2]
-
-[node name="Server" instance=ExtResource( 1 )]
-script = ExtResource( 2 )
diff --git a/scenes/ServerScene.tscn b/scenes/ServerScene.tscn
new file mode 100644
index 0000000..7d4195d
--- /dev/null
+++ b/scenes/ServerScene.tscn
@@ -0,0 +1,10 @@
+[gd_scene load_steps=3 format=3 uid="uid://s2sp2ex03fep"]
+
+[sub_resource type="Resource" id="Resource_an8jd"]
+metadata/__load_path__ = "res://scenes/GameScene.tscn"
+
+[sub_resource type="Resource" id="Resource_gedws"]
+metadata/__load_path__ = "res://src/Scenes/Server.cs"
+
+[node name="Server"]
+script = SubResource("Resource_gedws")
diff --git a/scenes/camera.gd.uid b/scenes/camera.gd.uid
new file mode 100644
index 0000000..29a3883
--- /dev/null
+++ b/scenes/camera.gd.uid
@@ -0,0 +1 @@
+uid://m2elqkdmqcyc
diff --git a/sfx/assault_rifle.wav.import b/sfx/assault_rifle.wav.import
deleted file mode 100644
index 666bcdb..0000000
--- a/sfx/assault_rifle.wav.import
+++ /dev/null
@@ -1,21 +0,0 @@
-[remap]
-
-importer="wav"
-type="AudioStreamSample"
-path="res://.import/assault_rifle.wav-be55643f0ef4eee454a1d69851e40bdb.sample"
-
-[deps]
-
-source_file="res://sfx/assault_rifle.wav"
-dest_files=[ "res://.import/assault_rifle.wav-be55643f0ef4eee454a1d69851e40bdb.sample" ]
-
-[params]
-
-force/8_bit=false
-force/mono=false
-force/max_rate=false
-force/max_rate_hz=44100
-edit/trim=false
-edit/normalize=false
-edit/loop=false
-compress/mode=0
diff --git a/sfx/revolver.wav.import b/sfx/revolver.wav.import
deleted file mode 100644
index 9e11d82..0000000
--- a/sfx/revolver.wav.import
+++ /dev/null
@@ -1,21 +0,0 @@
-[remap]
-
-importer="wav"
-type="AudioStreamSample"
-path="res://.import/revolver.wav-a193edf66acf3d5ba572c83152b952b7.sample"
-
-[deps]
-
-source_file="res://sfx/revolver.wav"
-dest_files=[ "res://.import/revolver.wav-a193edf66acf3d5ba572c83152b952b7.sample" ]
-
-[params]
-
-force/8_bit=false
-force/mono=false
-force/max_rate=false
-force/max_rate_hz=44100
-edit/trim=false
-edit/normalize=false
-edit/loop=false
-compress/mode=0
diff --git a/sfx/rifle.wav.import b/sfx/rifle.wav.import
deleted file mode 100644
index db63f3f..0000000
--- a/sfx/rifle.wav.import
+++ /dev/null
@@ -1,21 +0,0 @@
-[remap]
-
-importer="wav"
-type="AudioStreamSample"
-path="res://.import/rifle.wav-4d8a68001c8b651b3f0f41b64fa095a8.sample"
-
-[deps]
-
-source_file="res://sfx/rifle.wav"
-dest_files=[ "res://.import/rifle.wav-4d8a68001c8b651b3f0f41b64fa095a8.sample" ]
-
-[params]
-
-force/8_bit=false
-force/mono=false
-force/max_rate=false
-force/max_rate_hz=44100
-edit/trim=false
-edit/normalize=false
-edit/loop=false
-compress/mode=0
diff --git a/sfx/shotgun.wav.import b/sfx/shotgun.wav.import
deleted file mode 100644
index 97c3a4f..0000000
--- a/sfx/shotgun.wav.import
+++ /dev/null
@@ -1,21 +0,0 @@
-[remap]
-
-importer="wav"
-type="AudioStreamSample"
-path="res://.import/shotgun.wav-29870054b4a67834b920542f9f1e5152.sample"
-
-[deps]
-
-source_file="res://sfx/shotgun.wav"
-dest_files=[ "res://.import/shotgun.wav-29870054b4a67834b920542f9f1e5152.sample" ]
-
-[params]
-
-force/8_bit=false
-force/mono=false
-force/max_rate=false
-force/max_rate_hz=44100
-edit/trim=false
-edit/normalize=false
-edit/loop=false
-compress/mode=0
diff --git a/src/Background.cs b/src/Background.cs
deleted file mode 100644
index bf2d65b..0000000
--- a/src/Background.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-using Godot;
-
-public class Background : TextureRect
-{
- public override void _Process(float delta)
- {
- var offset = new Vector2(8, 8);
- var tileSize = Texture.GetSize();
- RectPosition = (-GetViewportTransform().origin / tileSize).Floor() * tileSize - offset;
- RectSize = ((GetViewport().Size + offset) / tileSize + Vector2.One).Ceil() * tileSize;
- }
-}
diff --git a/src/EscapeMenu.cs b/src/EscapeMenu.cs
deleted file mode 100644
index 9176d41..0000000
--- a/src/EscapeMenu.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-using Godot;
-
-public class EscapeMenu : Control
-{
- public static EscapeMenu Instance { get; private set; }
-
- [Export] public NodePath ReturnPath { get; set; }
- public Button Return { get; private set; }
-
- public EscapeMenu() => Instance = this;
-
- public override void _Ready()
- {
- Return = GetNode