diff --git a/Assets/Animations/stun.res b/Assets/Animations/stun.res
new file mode 100644
index 0000000..24458f6
Binary files /dev/null and b/Assets/Animations/stun.res differ
diff --git a/Assets/Fonts/alagard-spaced.tres b/Assets/Fonts/alagard-spaced.tres
new file mode 100644
index 0000000..432e03f
--- /dev/null
+++ b/Assets/Fonts/alagard-spaced.tres
@@ -0,0 +1,7 @@
+[gd_resource type="FontVariation" load_steps=2 format=3 uid="uid://ndkrorerbxft"]
+
+[ext_resource type="FontFile" uid="uid://cgwa8bjiyv534" path="res://Assets/Fonts/alagard.ttf" id="1_krbnd"]
+
+[resource]
+base_font = ExtResource("1_krbnd")
+spacing_glyph = 4
diff --git a/Assets/Fonts/compass-pro-spaced.tres b/Assets/Fonts/compass-pro-spaced.tres
new file mode 100644
index 0000000..335a2f0
--- /dev/null
+++ b/Assets/Fonts/compass-pro-spaced.tres
@@ -0,0 +1,7 @@
+[gd_resource type="FontVariation" load_steps=2 format=3 uid="uid://bjnmfgt5yqle7"]
+
+[ext_resource type="FontFile" uid="uid://bo3obq6sos7lu" path="res://Assets/Fonts/compass-pro.ttf" id="1_brr65"]
+
+[resource]
+base_font = ExtResource("1_brr65")
+spacing_glyph = 4
diff --git a/Assets/Fonts/compass-pro.ttf b/Assets/Fonts/compass-pro.ttf
new file mode 100644
index 0000000..5432d65
Binary files /dev/null and b/Assets/Fonts/compass-pro.ttf differ
diff --git a/Assets/Fonts/compass-pro.ttf.import b/Assets/Fonts/compass-pro.ttf.import
new file mode 100644
index 0000000..89ed156
--- /dev/null
+++ b/Assets/Fonts/compass-pro.ttf.import
@@ -0,0 +1,33 @@
+[remap]
+
+importer="font_data_dynamic"
+type="FontFile"
+uid="uid://bo3obq6sos7lu"
+path="res://.godot/imported/compass-pro.ttf-5e813dda823d14f9501edd94273a527c.fontdata"
+
+[deps]
+
+source_file="res://Assets/Fonts/compass-pro.ttf"
+dest_files=["res://.godot/imported/compass-pro.ttf-5e813dda823d14f9501edd94273a527c.fontdata"]
+
+[params]
+
+Rendering=null
+antialiasing=1
+generate_mipmaps=false
+multichannel_signed_distance_field=false
+msdf_pixel_range=8
+msdf_size=48
+allow_system_fallback=true
+force_autohinter=false
+hinting=1
+subpixel_positioning=1
+oversampling=0.0
+Fallbacks=null
+fallbacks=[]
+Compress=null
+compress=true
+preload=[]
+language_support={}
+script_support={}
+opentype_features={}
diff --git a/Assets/Music/gillette.mp3 b/Assets/Music/gillette.mp3
new file mode 100644
index 0000000..bdf52b0
Binary files /dev/null and b/Assets/Music/gillette.mp3 differ
diff --git a/Assets/Music/gillette.mp3.import b/Assets/Music/gillette.mp3.import
new file mode 100644
index 0000000..35c9a70
--- /dev/null
+++ b/Assets/Music/gillette.mp3.import
@@ -0,0 +1,19 @@
+[remap]
+
+importer="mp3"
+type="AudioStreamMP3"
+uid="uid://ipss4y2gkk3y"
+path="res://.godot/imported/gillette.mp3-5dd6f93f1f9df01778f80e3dd2caeb1e.mp3str"
+
+[deps]
+
+source_file="res://Assets/Music/gillette.mp3"
+dest_files=["res://.godot/imported/gillette.mp3-5dd6f93f1f9df01778f80e3dd2caeb1e.mp3str"]
+
+[params]
+
+loop=false
+loop_offset=0
+bpm=0
+beat_count=0
+bar_beats=4
diff --git a/Assets/Sounds/parry.wav b/Assets/Sounds/parry.wav
index 7ed32bf..9558d8b 100644
Binary files a/Assets/Sounds/parry.wav and b/Assets/Sounds/parry.wav differ
diff --git a/Assets/Sounds/rauuul.wav b/Assets/Sounds/rauuul.wav
new file mode 100644
index 0000000..5d8bfea
Binary files /dev/null and b/Assets/Sounds/rauuul.wav differ
diff --git a/Assets/Sounds/rauuul.wav.import b/Assets/Sounds/rauuul.wav.import
new file mode 100644
index 0000000..1d8d538
--- /dev/null
+++ b/Assets/Sounds/rauuul.wav.import
@@ -0,0 +1,24 @@
+[remap]
+
+importer="wav"
+type="AudioStreamWAV"
+uid="uid://cqj44je3mvk60"
+path="res://.godot/imported/rauuul.wav-9eb73999b440b60f20c6cb1832d4cb17.sample"
+
+[deps]
+
+source_file="res://Assets/Sounds/rauuul.wav"
+dest_files=["res://.godot/imported/rauuul.wav-9eb73999b440b60f20c6cb1832d4cb17.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/Assets/Sounds/rock-smash.wav b/Assets/Sounds/rock-smash.wav
new file mode 100644
index 0000000..8cda6ef
Binary files /dev/null and b/Assets/Sounds/rock-smash.wav differ
diff --git a/Assets/Sounds/rock-smash.wav.import b/Assets/Sounds/rock-smash.wav.import
new file mode 100644
index 0000000..3025169
--- /dev/null
+++ b/Assets/Sounds/rock-smash.wav.import
@@ -0,0 +1,24 @@
+[remap]
+
+importer="wav"
+type="AudioStreamWAV"
+uid="uid://jsnjoyaj6p5a"
+path="res://.godot/imported/rock-smash.wav-5412810912e8fdbd3060f5accd900f03.sample"
+
+[deps]
+
+source_file="res://Assets/Sounds/rock-smash.wav"
+dest_files=["res://.godot/imported/rock-smash.wav-5412810912e8fdbd3060f5accd900f03.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/Assets/Sounds/unsheathe.wav b/Assets/Sounds/unsheathe.wav
new file mode 100644
index 0000000..b2a4170
Binary files /dev/null and b/Assets/Sounds/unsheathe.wav differ
diff --git a/Assets/Sounds/unsheathe.wav.import b/Assets/Sounds/unsheathe.wav.import
new file mode 100644
index 0000000..4debf52
--- /dev/null
+++ b/Assets/Sounds/unsheathe.wav.import
@@ -0,0 +1,24 @@
+[remap]
+
+importer="wav"
+type="AudioStreamWAV"
+uid="uid://cceld51anbm1m"
+path="res://.godot/imported/unsheathe.wav-44389853e33f8a5eeb838ecbc38c9e52.sample"
+
+[deps]
+
+source_file="res://Assets/Sounds/unsheathe.wav"
+dest_files=["res://.godot/imported/unsheathe.wav-44389853e33f8a5eeb838ecbc38c9e52.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/Assets/Sounds/whoosh.wav b/Assets/Sounds/whoosh.wav
new file mode 100644
index 0000000..7d4d197
Binary files /dev/null and b/Assets/Sounds/whoosh.wav differ
diff --git a/Assets/Sounds/whoosh.wav.import b/Assets/Sounds/whoosh.wav.import
new file mode 100644
index 0000000..f336874
--- /dev/null
+++ b/Assets/Sounds/whoosh.wav.import
@@ -0,0 +1,24 @@
+[remap]
+
+importer="wav"
+type="AudioStreamWAV"
+uid="uid://qvthq6tppp63"
+path="res://.godot/imported/whoosh.wav-ed2d61376c9fa3c90f1bcd8d0d47a04b.sample"
+
+[deps]
+
+source_file="res://Assets/Sounds/whoosh.wav"
+dest_files=["res://.godot/imported/whoosh.wav-ed2d61376c9fa3c90f1bcd8d0d47a04b.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/Assets/Sprites/Characters/doc.ase b/Assets/Sprites/Characters/doc.ase
index edb9f18..14a189e 100644
Binary files a/Assets/Sprites/Characters/doc.ase and b/Assets/Sprites/Characters/doc.ase differ
diff --git a/Assets/Sprites/Characters/doc.png b/Assets/Sprites/Characters/doc.png
index cd4c281..2141d27 100644
Binary files a/Assets/Sprites/Characters/doc.png and b/Assets/Sprites/Characters/doc.png differ
diff --git a/Assets/Sprites/Characters/forsen-hand.ase b/Assets/Sprites/Characters/forsen-hand.ase
new file mode 100644
index 0000000..ddccb85
Binary files /dev/null and b/Assets/Sprites/Characters/forsen-hand.ase differ
diff --git a/Assets/Sprites/Characters/forsen-hand.png b/Assets/Sprites/Characters/forsen-hand.png
new file mode 100644
index 0000000..8deb621
Binary files /dev/null and b/Assets/Sprites/Characters/forsen-hand.png differ
diff --git a/Assets/Sprites/Characters/forsen-hand.png.import b/Assets/Sprites/Characters/forsen-hand.png.import
new file mode 100644
index 0000000..c7966e6
--- /dev/null
+++ b/Assets/Sprites/Characters/forsen-hand.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dpepm54hjuyga"
+path="res://.godot/imported/forsen-hand.png-d22d8449d49935bb2be976828e8a6ea2.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://Assets/Sprites/Characters/forsen-hand.png"
+dest_files=["res://.godot/imported/forsen-hand.png-d22d8449d49935bb2be976828e8a6ea2.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/Assets/Sprites/Characters/forsen2-portrait.png b/Assets/Sprites/Characters/forsen2-portrait.png
new file mode 100644
index 0000000..d2e13c8
Binary files /dev/null and b/Assets/Sprites/Characters/forsen2-portrait.png differ
diff --git a/Assets/Sprites/Characters/forsen2-portrait.png.import b/Assets/Sprites/Characters/forsen2-portrait.png.import
new file mode 100644
index 0000000..d43f62c
--- /dev/null
+++ b/Assets/Sprites/Characters/forsen2-portrait.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bwlk47lcbhlds"
+path="res://.godot/imported/forsen2-portrait.png-ca8f11b7ad39ec3d34d5a24ad210303a.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://Assets/Sprites/Characters/forsen2-portrait.png"
+dest_files=["res://.godot/imported/forsen2-portrait.png-ca8f11b7ad39ec3d34d5a24ad210303a.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/Assets/Sprites/Characters/forsen2.ase b/Assets/Sprites/Characters/forsen2.ase
index 614a72c..561ec0f 100644
Binary files a/Assets/Sprites/Characters/forsen2.ase and b/Assets/Sprites/Characters/forsen2.ase differ
diff --git a/Assets/Sprites/Characters/forsen2.png b/Assets/Sprites/Characters/forsen2.png
index cf9d00c..15d9adc 100644
Binary files a/Assets/Sprites/Characters/forsen2.png and b/Assets/Sprites/Characters/forsen2.png differ
diff --git a/Assets/Sprites/Characters/lost-soul.ase b/Assets/Sprites/Characters/lost-soul.ase
new file mode 100644
index 0000000..7666210
Binary files /dev/null and b/Assets/Sprites/Characters/lost-soul.ase differ
diff --git a/Assets/Sprites/Misc/compact-disc.ase b/Assets/Sprites/Misc/compact-disc.ase
new file mode 100644
index 0000000..2b4f5eb
Binary files /dev/null and b/Assets/Sprites/Misc/compact-disc.ase differ
diff --git a/Assets/Sprites/Misc/compact-disc.png b/Assets/Sprites/Misc/compact-disc.png
new file mode 100644
index 0000000..05cfc7f
Binary files /dev/null and b/Assets/Sprites/Misc/compact-disc.png differ
diff --git a/Assets/Sprites/Misc/compact-disc.png.import b/Assets/Sprites/Misc/compact-disc.png.import
new file mode 100644
index 0000000..9c834db
--- /dev/null
+++ b/Assets/Sprites/Misc/compact-disc.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://qc6agawkad5k"
+path="res://.godot/imported/compact-disc.png-5b17d460d1330809bc650ebf5321160e.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://Assets/Sprites/Misc/compact-disc.png"
+dest_files=["res://.godot/imported/compact-disc.png-5b17d460d1330809bc650ebf5321160e.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/Assets/Sprites/Particles/DocIntroParticles.tres b/Assets/Sprites/Particles/DocIntroParticles.tres
new file mode 100644
index 0000000..ab58291
--- /dev/null
+++ b/Assets/Sprites/Particles/DocIntroParticles.tres
@@ -0,0 +1,22 @@
+[gd_resource type="ParticleProcessMaterial" load_steps=3 format=3 uid="uid://rcjujd5dv7lm"]
+
+[sub_resource type="Gradient" id="Gradient_v7xci"]
+offsets = PackedFloat32Array(0.525926, 0.6)
+colors = PackedColorArray(0, 0, 0, 1, 1, 0, 0, 1)
+
+[sub_resource type="GradientTexture1D" id="GradientTexture1D_pntll"]
+gradient = SubResource("Gradient_v7xci")
+
+[resource]
+particle_flag_disable_z = true
+spread = 180.0
+gravity = Vector3(0, 0, 0)
+initial_velocity_min = 64.0
+initial_velocity_max = 96.0
+orbit_velocity_min = 0.0
+orbit_velocity_max = 0.0
+linear_accel_min = -128.0
+linear_accel_max = -96.0
+scale_min = 0.1
+scale_max = 0.2
+color_initial_ramp = SubResource("GradientTexture1D_pntll")
diff --git a/Assets/Sprites/Particles/NPCDamageProcessMaterial.tres b/Assets/Sprites/Particles/NPCDamageProcessMaterial.tres
new file mode 100644
index 0000000..7789477
--- /dev/null
+++ b/Assets/Sprites/Particles/NPCDamageProcessMaterial.tres
@@ -0,0 +1,25 @@
+[gd_resource type="ParticleProcessMaterial" load_steps=3 format=3 uid="uid://bat28samf7ukd"]
+
+[sub_resource type="Curve" id="Curve_jqr7v"]
+_data = [Vector2(0, 0), 0.0, 2.0, 0, 1, Vector2(0.5, 1), 0.0, 0.0, 0, 0, Vector2(1, 0), -2.0, 0.0, 1, 0]
+point_count = 3
+
+[sub_resource type="CurveTexture" id="CurveTexture_s2csc"]
+curve = SubResource("Curve_jqr7v")
+
+[resource]
+emission_shape = 1
+emission_sphere_radius = 8.0
+particle_flag_disable_z = true
+direction = Vector3(0, -1, 0)
+gravity = Vector3(0, 0, 0)
+initial_velocity_min = 64.0
+initial_velocity_max = 128.0
+orbit_velocity_min = 0.0
+orbit_velocity_max = 0.0
+linear_accel_min = -256.0
+linear_accel_max = -128.0
+scale_min = 0.01
+scale_max = 0.02
+scale_curve = SubResource("CurveTexture_s2csc")
+attractor_interaction_enabled = false
diff --git a/Assets/Sprites/Particles/ParryParticles.tres b/Assets/Sprites/Particles/ParryParticles.tres
new file mode 100644
index 0000000..7b255aa
--- /dev/null
+++ b/Assets/Sprites/Particles/ParryParticles.tres
@@ -0,0 +1,32 @@
+[gd_resource type="ParticleProcessMaterial" load_steps=5 format=3 uid="uid://cbfaqolx1ydvv"]
+
+[sub_resource type="Gradient" id="Gradient_44upg"]
+offsets = PackedFloat32Array(0, 0.5)
+colors = PackedColorArray(1, 1, 1, 1, 1, 1, 1, 0)
+
+[sub_resource type="GradientTexture1D" id="GradientTexture1D_droiy"]
+gradient = SubResource("Gradient_44upg")
+
+[sub_resource type="Curve" id="Curve_4kf4j"]
+_data = [Vector2(0, 0.5), 0.0, 0.0, 0, 0, Vector2(0.1, 1), 0.0, 0.0, 0, 0, Vector2(1, 0.5), 0.0, 0.0, 0, 0]
+point_count = 3
+
+[sub_resource type="CurveTexture" id="CurveTexture_qqrjb"]
+curve = SubResource("Curve_4kf4j")
+
+[resource]
+emission_shape = 1
+emission_sphere_radius = 4.0
+particle_flag_disable_z = true
+spread = 180.0
+gravity = Vector3(0, 0, 0)
+initial_velocity_min = 256.0
+initial_velocity_max = 256.0
+orbit_velocity_min = 0.0
+orbit_velocity_max = 0.0
+linear_accel_min = -512.0
+linear_accel_max = -512.0
+scale_min = 2.0
+scale_max = 2.0
+scale_curve = SubResource("CurveTexture_qqrjb")
+color_ramp = SubResource("GradientTexture1D_droiy")
diff --git a/Assets/Sprites/Particles/PlayerDamageProcessMaterial.tres b/Assets/Sprites/Particles/PlayerDamageProcessMaterial.tres
new file mode 100644
index 0000000..1436696
--- /dev/null
+++ b/Assets/Sprites/Particles/PlayerDamageProcessMaterial.tres
@@ -0,0 +1,42 @@
+[gd_resource type="ParticleProcessMaterial" load_steps=7 format=3 uid="uid://x5qcq5muvc3g"]
+
+[sub_resource type="Gradient" id="Gradient_6k7fi"]
+offsets = PackedFloat32Array(0, 0.540741, 0.592593, 1)
+colors = PackedColorArray(0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1)
+
+[sub_resource type="GradientTexture1D" id="GradientTexture1D_1phkb"]
+gradient = SubResource("Gradient_6k7fi")
+
+[sub_resource type="Gradient" id="Gradient_3tax5"]
+offsets = PackedFloat32Array(0, 0.533333, 1)
+colors = PackedColorArray(1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0)
+
+[sub_resource type="GradientTexture1D" id="GradientTexture1D_13jjx"]
+gradient = SubResource("Gradient_3tax5")
+
+[sub_resource type="Curve" id="Curve_0565g"]
+_data = [Vector2(0, 0.5), 0.0, 5.0, 0, 1, Vector2(0.1, 1), 0.0, 0.0, 0, 0, Vector2(1, 0), -1.11111, 0.0, 1, 0]
+point_count = 3
+
+[sub_resource type="CurveTexture" id="CurveTexture_k4txv"]
+curve = SubResource("Curve_0565g")
+
+[resource]
+emission_shape = 2
+emission_sphere_radius = 32.0
+particle_flag_disable_z = true
+direction = Vector3(0, -1, 0)
+gravity = Vector3(0, 0, 0)
+initial_velocity_min = 128.0
+initial_velocity_max = 256.0
+orbit_velocity_min = 0.0
+orbit_velocity_max = 0.0
+tangential_accel_min = -16.0
+tangential_accel_max = 16.0
+scale_min = 0.25
+scale_max = 0.25
+scale_curve = SubResource("CurveTexture_k4txv")
+color_ramp = SubResource("GradientTexture1D_13jjx")
+color_initial_ramp = SubResource("GradientTexture1D_1phkb")
+turbulence_enabled = true
+turbulence_noise_scale = 4.0
diff --git a/Assets/Sprites/Particles/circle-16.png b/Assets/Sprites/Particles/circle-16.png
new file mode 100644
index 0000000..4d99d1b
Binary files /dev/null and b/Assets/Sprites/Particles/circle-16.png differ
diff --git a/Assets/Sprites/Particles/circle-16.png.import b/Assets/Sprites/Particles/circle-16.png.import
new file mode 100644
index 0000000..539b139
--- /dev/null
+++ b/Assets/Sprites/Particles/circle-16.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://c1a7lvb4uuwfy"
+path="res://.godot/imported/circle-16.png-2c9910635b94cf262d735877f73c9d54.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://Assets/Sprites/Particles/circle-16.png"
+dest_files=["res://.godot/imported/circle-16.png-2c9910635b94cf262d735877f73c9d54.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/Assets/Sprites/Particles/circle-64.png b/Assets/Sprites/Particles/circle-64.png
new file mode 100644
index 0000000..6318d34
Binary files /dev/null and b/Assets/Sprites/Particles/circle-64.png differ
diff --git a/Assets/Sprites/Particles/circle-64.png.import b/Assets/Sprites/Particles/circle-64.png.import
new file mode 100644
index 0000000..86930a0
--- /dev/null
+++ b/Assets/Sprites/Particles/circle-64.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://d75jkoev5v3w"
+path="res://.godot/imported/circle-64.png-14e0a440e19bf6b7889c28107bfd3189.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://Assets/Sprites/Particles/circle-64.png"
+dest_files=["res://.godot/imported/circle-64.png-14e0a440e19bf6b7889c28107bfd3189.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/Assets/Sprites/Particles/circle.png b/Assets/Sprites/Particles/circle.png
new file mode 100644
index 0000000..35051c4
Binary files /dev/null and b/Assets/Sprites/Particles/circle.png differ
diff --git a/Assets/Sprites/Particles/circle.png.import b/Assets/Sprites/Particles/circle.png.import
new file mode 100644
index 0000000..e013f1e
--- /dev/null
+++ b/Assets/Sprites/Particles/circle.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bd8l8kafb42dt"
+path="res://.godot/imported/circle.png-e947f0f855ee4b3d0717c4cb325e029e.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://Assets/Sprites/Particles/circle.png"
+dest_files=["res://.godot/imported/circle.png-e947f0f855ee4b3d0717c4cb325e029e.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/Assets/Sprites/Particles/player-light.ase b/Assets/Sprites/Particles/player-light.ase
new file mode 100644
index 0000000..4566692
Binary files /dev/null and b/Assets/Sprites/Particles/player-light.ase differ
diff --git a/Assets/Sprites/Particles/player-light.png b/Assets/Sprites/Particles/player-light.png
new file mode 100644
index 0000000..c161968
Binary files /dev/null and b/Assets/Sprites/Particles/player-light.png differ
diff --git a/Assets/Sprites/Particles/player-light.png.import b/Assets/Sprites/Particles/player-light.png.import
new file mode 100644
index 0000000..22671be
--- /dev/null
+++ b/Assets/Sprites/Particles/player-light.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://d1ukste16yq6v"
+path="res://.godot/imported/player-light.png-261881914c11364b14e2af7628defbb7.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://Assets/Sprites/Particles/player-light.png"
+dest_files=["res://.godot/imported/player-light.png-261881914c11364b14e2af7628defbb7.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/Assets/Sprites/UI/boss-bar.png b/Assets/Sprites/UI/boss-bar.png
new file mode 100644
index 0000000..d6d935c
Binary files /dev/null and b/Assets/Sprites/UI/boss-bar.png differ
diff --git a/Assets/Sprites/UI/boss-bar.png.import b/Assets/Sprites/UI/boss-bar.png.import
new file mode 100644
index 0000000..cde30dd
--- /dev/null
+++ b/Assets/Sprites/UI/boss-bar.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://b07x1uedfexfi"
+path="res://.godot/imported/boss-bar.png-14402f9e8d9c8a30b766d18572a90e44.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://Assets/Sprites/UI/boss-bar.png"
+dest_files=["res://.godot/imported/boss-bar.png-14402f9e8d9c8a30b766d18572a90e44.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/Assets/Sprites/UI/over-under-bar.png b/Assets/Sprites/UI/over-under-bar.png
new file mode 100644
index 0000000..9308bff
Binary files /dev/null and b/Assets/Sprites/UI/over-under-bar.png differ
diff --git a/Assets/Sprites/UI/over-under-bar.png.import b/Assets/Sprites/UI/over-under-bar.png.import
new file mode 100644
index 0000000..d13d8ef
--- /dev/null
+++ b/Assets/Sprites/UI/over-under-bar.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://b75oak1nd2q6x"
+path="res://.godot/imported/over-under-bar.png-2dd8e0831ce7b8d0ab833d2ac7ca543b.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://Assets/Sprites/UI/over-under-bar.png"
+dest_files=["res://.godot/imported/over-under-bar.png-2dd8e0831ce7b8d0ab833d2ac7ca543b.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/Assets/Sprites/UI/progress-bar.ase b/Assets/Sprites/UI/progress-bar.ase
new file mode 100644
index 0000000..1cc8c77
Binary files /dev/null and b/Assets/Sprites/UI/progress-bar.ase differ
diff --git a/Assets/Sprites/UI/progress-bar.png b/Assets/Sprites/UI/progress-bar.png
new file mode 100644
index 0000000..50a7897
Binary files /dev/null and b/Assets/Sprites/UI/progress-bar.png differ
diff --git a/Assets/Sprites/UI/progress-bar.png.import b/Assets/Sprites/UI/progress-bar.png.import
new file mode 100644
index 0000000..1663caa
--- /dev/null
+++ b/Assets/Sprites/UI/progress-bar.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://co7xm7i5f6n51"
+path="res://.godot/imported/progress-bar.png-0e003ec68d4d1aedbb2c4345d3d47107.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://Assets/Sprites/UI/progress-bar.png"
+dest_files=["res://.godot/imported/progress-bar.png-0e003ec68d4d1aedbb2c4345d3d47107.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/Assets/Sprites/arena-tileset-normal.png b/Assets/Sprites/arena-tileset-normal.png
index 2082f9e..16bb549 100644
Binary files a/Assets/Sprites/arena-tileset-normal.png and b/Assets/Sprites/arena-tileset-normal.png differ
diff --git a/Assets/Sprites/arena-tileset.ase b/Assets/Sprites/arena-tileset.ase
index 3fefc84..0c50590 100644
Binary files a/Assets/Sprites/arena-tileset.ase and b/Assets/Sprites/arena-tileset.ase differ
diff --git a/Assets/Sprites/doc-lance.ase b/Assets/Sprites/doc-lance.ase
new file mode 100644
index 0000000..747007b
Binary files /dev/null and b/Assets/Sprites/doc-lance.ase differ
diff --git a/Assets/Sprites/doc-lance.png b/Assets/Sprites/doc-lance.png
new file mode 100644
index 0000000..9ba2ebb
Binary files /dev/null and b/Assets/Sprites/doc-lance.png differ
diff --git a/Assets/Sprites/doc-lance.png.import b/Assets/Sprites/doc-lance.png.import
new file mode 100644
index 0000000..8ece2eb
--- /dev/null
+++ b/Assets/Sprites/doc-lance.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://o7enu13gvji5"
+path="res://.godot/imported/doc-lance.png-2fd1894aa4282b30b176bb21b10e8c6f.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://Assets/Sprites/doc-lance.png"
+dest_files=["res://.godot/imported/doc-lance.png-2fd1894aa4282b30b176bb21b10e8c6f.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/Assets/Sprites/night-grass-side.ase b/Assets/Sprites/night-grass-side.ase
new file mode 100644
index 0000000..2e5e978
Binary files /dev/null and b/Assets/Sprites/night-grass-side.ase differ
diff --git a/Assets/Sprites/sword-swing-large.ase b/Assets/Sprites/sword-swing-large.ase
new file mode 100644
index 0000000..561f0cd
Binary files /dev/null and b/Assets/Sprites/sword-swing-large.ase differ
diff --git a/Assets/Sprites/sword-swing-large.png b/Assets/Sprites/sword-swing-large.png
new file mode 100644
index 0000000..5a9daf0
Binary files /dev/null and b/Assets/Sprites/sword-swing-large.png differ
diff --git a/Assets/Sprites/sword-swing-large.png.import b/Assets/Sprites/sword-swing-large.png.import
new file mode 100644
index 0000000..e400a73
--- /dev/null
+++ b/Assets/Sprites/sword-swing-large.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cmvh6pc71ir1m"
+path="res://.godot/imported/sword-swing-large.png-d24bea57b216aba22c9a1cccd93085d2.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://Assets/Sprites/sword-swing-large.png"
+dest_files=["res://.godot/imported/sword-swing-large.png-d24bea57b216aba22c9a1cccd93085d2.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/Assets/Sprites/sword.ase b/Assets/Sprites/sword.ase
index 1826a21..4c3fa58 100644
Binary files a/Assets/Sprites/sword.ase and b/Assets/Sprites/sword.ase differ
diff --git a/Assets/Sprites/sword.png b/Assets/Sprites/sword.png
index 546593d..ec42116 100644
Binary files a/Assets/Sprites/sword.png and b/Assets/Sprites/sword.png differ
diff --git a/BoundingBoxes/CameraBounds.cs b/BoundingBoxes/CameraBounds.cs
new file mode 100644
index 0000000..10cdb94
--- /dev/null
+++ b/BoundingBoxes/CameraBounds.cs
@@ -0,0 +1,21 @@
+using Godot;
+
+namespace SupaLidlGame.BoundingBoxes;
+
+public partial class CameraBounds : Area2D
+{
+ public override void _Ready()
+ {
+ BodyEntered += OnBodyEntered;
+ base._Ready();
+ }
+
+ private void OnBodyEntered(Node2D body)
+ {
+ if (body is Characters.Player player)
+ {
+ var camera = player.Camera;
+ //camera.LimitLeft =
+ }
+ }
+}
diff --git a/BoundingBoxes/Hurtbox.cs b/BoundingBoxes/Hurtbox.cs
index ca36c51..0d661d5 100644
--- a/BoundingBoxes/Hurtbox.cs
+++ b/BoundingBoxes/Hurtbox.cs
@@ -11,8 +11,13 @@ public partial class Hurtbox : BoundingBox, IFaction
float damage,
Character inflictor,
float knockback,
- Vector2 knockbackOrigin = default,
- Vector2 knockbackVector = default);
+ Vector2 knockbackDir = default);
+
+ ///
+ /// The timer to use for invincibility frames
+ ///
+ [Export]
+ public Timer InvincibilityTimer { get; set; }
public override void _Ready()
{
@@ -20,6 +25,15 @@ public partial class Hurtbox : BoundingBox, IFaction
{
Faction = factionEntity.Faction;
}
+
+ if (InvincibilityTimer is not null)
+ {
+ InvincibilityTimer.Timeout += () =>
+ {
+ GD.Print("invincibility off");
+ Monitorable = true;
+ };
+ }
}
public void InflictDamage(
@@ -29,11 +43,48 @@ public partial class Hurtbox : BoundingBox, IFaction
Vector2 knockbackOrigin = default,
Vector2 knockbackVector = default)
{
+ if (!IsInstanceValid(this))
+ {
+ // this should fix the error of the object being invalid
+ return;
+ }
+
+ Vector2 knockbackDir = knockbackVector;
+ if (knockbackDir == default)
+ {
+ if (knockbackOrigin == default)
+ {
+ if (inflictor is null)
+ {
+ knockbackOrigin = GlobalPosition + Vector2.Down;
+ }
+ else
+ {
+ knockbackOrigin = inflictor.GlobalPosition;
+ }
+ }
+
+ knockbackDir = knockbackOrigin.DirectionTo(GlobalPosition);
+ }
+
+ if (InvincibilityTimer is not null)
+ {
+ if (!InvincibilityTimer.IsStopped())
+ {
+ return;
+ }
+
+ InvincibilityTimer.Start();
+ //Monitorable = false;
+ SetDeferred("monitorable", false);
+ GD.Print("invincible");
+ }
+
EmitSignal(
SignalName.ReceivedDamage,
damage,
inflictor,
knockback,
- knockbackOrigin, knockbackVector);
+ knockbackDir);
}
}
diff --git a/Characters/Boss.cs b/Characters/Boss.cs
new file mode 100644
index 0000000..a04cdef
--- /dev/null
+++ b/Characters/Boss.cs
@@ -0,0 +1,34 @@
+using Godot;
+using GodotUtilities;
+
+namespace SupaLidlGame.Characters;
+
+public abstract partial class Boss : Enemy
+{
+ [Export]
+ public State.NPC.NPCStateMachine BossStateMachine { get; set; }
+
+ [Export]
+ public string BossName { get; set; }
+
+ [Export]
+ public AudioStream Music { get; set; }
+
+ public abstract int Intensity { get; }
+
+ private bool _isActive;
+
+ [Export]
+ public bool IsActive
+ {
+ get => _isActive;
+ set
+ {
+ _isActive = value;
+
+ // register or deregister ourselves when we are active/inactive
+ this.GetAncestor()
+ .RegisterBoss(_isActive ? this : null);
+ }
+ }
+}
diff --git a/Characters/Character.cs b/Characters/Character.cs
index e986353..8986137 100644
--- a/Characters/Character.cs
+++ b/Characters/Character.cs
@@ -13,7 +13,7 @@ public partial class Character : CharacterBody2D, IFaction
public float Speed { get; protected set; } = 32.0f;
[Export]
- public float Friction { get; protected set; } = 4.0f;
+ public float Friction { get; set; } = 4.0f;
[Export]
public float Mass
@@ -39,9 +39,12 @@ public partial class Character : CharacterBody2D, IFaction
public Vector2 Direction { get; set; } = Vector2.Zero;
public Vector2 Target { get; set; } = Vector2.Zero;
+
+ [Export]
+ public Texture2D HandTexture { get; set; }
[Export]
- public float Health
+ public virtual float Health
{
get => _health;
set
@@ -66,7 +69,7 @@ public partial class Character : CharacterBody2D, IFaction
public double StunTime { get; set; }
[Export]
- public AnimatedSprite2D Sprite { get; set; }
+ public Sprite2D Sprite { get; set; }
[Export]
public Inventory Inventory { get; set; }
@@ -80,8 +83,19 @@ public partial class Character : CharacterBody2D, IFaction
[Export]
public ushort Faction { get; set; }
+ public AnimationPlayer MovementAnimation { get; set; }
+
+ public AnimationPlayer HurtAnimation { get; set; }
+
+ public AnimationPlayer StunAnimation { get; set; }
+
public override void _Ready()
{
+ // TODO: 80+ char line
+ MovementAnimation = GetNode("Animations/Movement");
+ HurtAnimation = GetNode("Animations/Hurt");
+ StunAnimation = GetNode("Animations/Stun");
+ GD.Print(Name + " " + MovementAnimation.CurrentAnimation);
Hurtbox.ReceivedDamage += OnReceivedDamage;
}
@@ -92,6 +106,15 @@ public partial class Character : CharacterBody2D, IFaction
StateMachine.Process(delta);
}
+ if (StunTime > 0 && !StunAnimation.IsPlaying())
+ {
+ StunAnimation.Play("stun");
+ }
+ else if (StunTime < 0 && StunAnimation.IsPlaying())
+ {
+ StunAnimation.Stop();
+ }
+
Sprite.FlipH = Target.X < 0;
DrawTarget();
}
@@ -113,6 +136,18 @@ public partial class Character : CharacterBody2D, IFaction
{
Velocity *= 0.25f;
}
+
+ var state = StateMachine.CurrentState;
+ if (state is State.Character.CharacterDashState dashState)
+ {
+ Velocity *= dashState.VelocityModifier;
+ }
+ // TODO: make PlayerRollState a CharacterRollState instead
+ else if (state is State.Character.PlayerRollState rollState)
+ {
+ Velocity *= 2;
+ //Velocity *= rollState.VelocityModifier;
+ }
}
public virtual void Die()
@@ -131,7 +166,7 @@ public partial class Character : CharacterBody2D, IFaction
public virtual void Stun(float time)
{
- StunTime += time;
+ StunTime = Mathf.Max(time, StunTime);
}
protected virtual void DrawTarget()
@@ -156,13 +191,25 @@ public partial class Character : CharacterBody2D, IFaction
{
if (StunTime > 0)
{
- GD.Print("tried to use weapon but stunned");
return;
}
if (Inventory.SelectedItem is Weapon weapon)
{
weapon.Use();
+ if (weapon.IsUsing)
+ {
+ Inventory.EmitSignal(Inventory.SignalName.UsedItem, weapon);
+ }
+ }
+ }
+
+ public void DeuseCurrentItem()
+ {
+ if (Inventory.SelectedItem is Weapon weapon)
+ {
+ weapon.Deuse();
+ // TODO: DeusedItem signal, implement when needed
}
}
@@ -174,12 +221,18 @@ public partial class Character : CharacterBody2D, IFaction
}
}
+ protected virtual float ReceiveDamage(
+ float damage,
+ Character inflictor,
+ float knockback,
+ Vector2 knockbackDir = default) => damage;
+
+
public virtual void OnReceivedDamage(
float damage,
Character inflictor,
float knockback,
- Vector2 knockbackOrigin = default,
- Vector2 knockbackVector = default)
+ Vector2 knockbackDir = default)
{
if (Health <= 0)
{
@@ -187,7 +240,7 @@ public partial class Character : CharacterBody2D, IFaction
}
float oldHealth = Health;
- Health -= damage;
+ Health -= ReceiveDamage(damage, inflictor, knockback, knockbackDir);
// create damage text
var textScene = GD.Load("res://UI/FloatingText.tscn");
@@ -197,41 +250,25 @@ public partial class Character : CharacterBody2D, IFaction
this.GetAncestor().AddChild(instance);
// apply knockback
- Vector2 knockbackDir = knockbackVector;
- if (knockbackDir == default)
- {
- if (knockbackOrigin == default)
- {
- if (inflictor is null)
- {
- knockbackOrigin = GlobalPosition + Vector2.Down;
- }
- else
- {
- knockbackOrigin = inflictor.GlobalPosition;
- }
- }
-
- knockbackDir = knockbackOrigin.DirectionTo(GlobalPosition);
- }
ApplyImpulse(knockbackDir.Normalized() * knockback);
GD.Print("lol");
// play damage animation
- var anim = GetNode("FlashAnimation");
+ var anim = GetNode("Animations/Hurt");
if (anim != null)
{
anim.Stop();
- anim.Play("Hurt");
+ anim.Play("hurt");
+ anim.Queue("hurt_flash");
}
// if anyone involved is a player, shake their screen
Player plr = inflictor as Player ?? this as Player;
if (plr is not null)
{
- plr.Camera.Shake(1, 0.4f);
+ //plr.Camera.Shake(1, 0.4f);
}
if (this.GetNode("HurtSound") is AudioStreamPlayer2D sound)
diff --git a/Characters/Doc.cs b/Characters/Doc.cs
index 67d9a2b..b54c7a5 100644
--- a/Characters/Doc.cs
+++ b/Characters/Doc.cs
@@ -1,21 +1,45 @@
using Godot;
+using GodotUtilities;
+using SupaLidlGame.State.Character;
namespace SupaLidlGame.Characters;
-public partial class Doc : Enemy
+public partial class Doc : Boss
{
- [Export]
- public State.NPC.NPCStateMachine BossStateMachine { get; set; }
+ public AnimationPlayer TelegraphAnimation { get; set; }
- public int Intensity
+ [Export]
+ public Items.Weapons.Sword Lance { get; set; }
+
+ protected bool _dashedAway = false;
+
+ public override float Health
+ {
+ get => base.Health;
+ set
+ {
+ if (IsActive)
+ {
+ base.Health = value;
+ }
+ else
+ {
+ // play opening animation
+ // then become active when it finishes
+ base.Health = value;
+ }
+ }
+ }
+
+ public override int Intensity
{
get
{
switch (Health)
{
- case < 250:
+ case < 200:
return 3;
- case < 500:
+ case < 400:
return 2;
default:
return 1;
@@ -23,15 +47,115 @@ public partial class Doc : Enemy
}
}
+ public Doc()
+ {
+ ShouldMove = false;
+ }
+
public override void _Ready()
{
- GD.Print(Health);
+ TelegraphAnimation = GetNode("Animations/Telegraph");
base._Ready();
+
+ // when we are hurt, start the boss fight
+ Hurt += (Events.HealthChangedArgs args) =>
+ {
+ if (!IsActive)
+ {
+ IsActive = true;
+ Inventory.SelectedItem = Lance;
+ }
+ };
}
public override void _Process(double delta)
{
- BossStateMachine.Process(delta);
+ if (IsActive)
+ {
+ BossStateMachine.Process(delta);
+ }
base._Process(delta);
}
+
+ protected override float ReceiveDamage(
+ float damage,
+ Character inflictor,
+ float knockback,
+ Vector2 knockbackDir = default)
+ {
+ if (IsActive)
+ {
+ return base.ReceiveDamage(
+ damage, inflictor, knockback, knockbackDir);
+ }
+
+ return 1;
+ }
+
+ public override void OnReceivedDamage(
+ float damage,
+ Character inflictor,
+ float knockback,
+ Vector2 knockbackDir = default)
+ {
+ GetNode("Effects/HurtParticles")
+ .SetDirection(knockbackDir);
+
+ base.OnReceivedDamage(damage, inflictor, knockback, knockbackDir);
+ }
+
+ protected override void Think()
+ {
+ if (BossStateMachine.CurrentState is State.NPC.Doc.DocLanceState)
+ {
+ ThirdPhaseThink();
+ }
+ else
+ {
+ base.Think();
+ }
+ }
+
+ protected void ThirdPhaseThink()
+ {
+ Character bestTarget = FindBestTarget();
+ if (bestTarget is not null)
+ {
+ Vector2 pos = bestTarget.GlobalPosition;
+ Target = pos - GlobalPosition;
+ Vector2 dir = GlobalPosition.DirectionTo(pos);
+ float dist = GlobalPosition.DistanceSquaredTo(pos);
+ UpdateWeights(pos);
+
+ if (CanAttack && StunTime <= 0)
+ {
+ bool isTargetStunned = bestTarget.StunTime > 0;
+ if (!isTargetStunned && dist < 2500)
+ {
+ if (Inventory.SelectedItem is Items.Weapon weapon)
+ {
+ // dash away if too close
+ DashTo(-dir);
+ UseCurrentItem();
+ _dashedAway = true;
+ }
+ }
+ else if (isTargetStunned || (dist < 3600 && _dashedAway))
+ {
+ if (!Inventory.SelectedItem.IsUsing)
+ {
+ DashTo(dir);
+ UseCurrentItem();
+ _dashedAway = false;
+ }
+ }
+ }
+ }
+ }
+
+ private void DashTo(Vector2 direction)
+ {
+ StateMachine.ChangeState(out var state);
+ state.DashDirection = direction;
+ }
}
diff --git a/Characters/Doc.tscn b/Characters/Doc.tscn
index 5593f81..7b71310 100644
--- a/Characters/Doc.tscn
+++ b/Characters/Doc.tscn
@@ -1,30 +1,155 @@
-[gd_scene load_steps=38 format=3 uid="uid://d2skjvvx6fal0"]
+[gd_scene load_steps=61 format=3 uid="uid://d2skjvvx6fal0"]
[ext_resource type="Script" path="res://Characters/Doc.cs" id="2_3elet"]
[ext_resource type="Shader" path="res://Shaders/Flash.gdshader" id="2_5jxom"]
+[ext_resource type="AudioStream" uid="uid://ipss4y2gkk3y" path="res://Assets/Music/gillette.mp3" id="3_eo4lg"]
[ext_resource type="Texture2D" uid="uid://baiuqgrqipppt" path="res://Assets/Sprites/Characters/doc.png" id="3_rs44f"]
[ext_resource type="Script" path="res://State/Character/CharacterStateMachine.cs" id="3_t5jjc"]
+[ext_resource type="Texture2D" uid="uid://dpepm54hjuyga" path="res://Assets/Sprites/Characters/forsen-hand.png" id="4_8lqj6"]
[ext_resource type="Script" path="res://State/Character/NPCIdleState.cs" id="4_b35px"]
[ext_resource type="Script" path="res://State/Character/NPCMoveState.cs" id="5_pejsd"]
[ext_resource type="Script" path="res://State/NPC/NPCStateMachine.cs" id="6_kjpug"]
+[ext_resource type="Script" path="res://State/Character/CharacterDashState.cs" id="7_0ks57"]
[ext_resource type="Script" path="res://State/NPC/Doc/DocTelegraphState.cs" id="7_tfwbh"]
[ext_resource type="PackedScene" uid="uid://cjgxyhgcyvsv7" path="res://BoundingBoxes/Hurtbox.tscn" id="7_tnve0"]
[ext_resource type="Script" path="res://State/NPC/Doc/DocShungiteDartState.cs" id="8_1hoax"]
[ext_resource type="Script" path="res://Items/Inventory.cs" id="8_r8ejq"]
[ext_resource type="Script" path="res://State/NPC/Doc/DocExitState.cs" id="9_6com1"]
[ext_resource type="PackedScene" uid="uid://1tiswf3gtyvv" path="res://Entities/ShungiteSpike.tscn" id="9_7kavk"]
-[ext_resource type="PackedScene" uid="uid://djaljmco3xo4g" path="res://Entities/ShungiteDart.tscn" id="9_kthpr"]
[ext_resource type="AudioStream" uid="uid://k6kpdj1kv0jg" path="res://Assets/Sounds/splat.ogg" id="9_stm0e"]
[ext_resource type="Script" path="res://State/NPC/Doc/DocShungiteSpikeState.cs" id="10_bgs6o"]
+[ext_resource type="PackedScene" uid="uid://cqx56u46g2c16" path="res://Entities/CompactDisc.tscn" id="11_23p3o"]
[ext_resource type="Script" path="res://State/NPC/Doc/DocChooseAttackState.cs" id="12_45x13"]
[ext_resource type="Script" path="res://State/NPC/Doc/DocUnwantedFrequencyState.cs" id="12_d51jv"]
[ext_resource type="PackedScene" uid="uid://1y5r6sklwgrp" path="res://Entities/UnwantedFrequency.tscn" id="13_lpj21"]
+[ext_resource type="Script" path="res://State/NPC/Doc/DocLanceState.cs" id="15_dmd05"]
+[ext_resource type="Script" path="res://Utils/AnimationManager.cs" id="16_bsvls"]
+[ext_resource type="Texture2D" uid="uid://bd8l8kafb42dt" path="res://Assets/Sprites/Particles/circle.png" id="16_x277j"]
+[ext_resource type="Material" uid="uid://bat28samf7ukd" path="res://Assets/Sprites/Particles/NPCDamageProcessMaterial.tres" id="17_iomdx"]
+[ext_resource type="Texture2D" uid="uid://c1a7lvb4uuwfy" path="res://Assets/Sprites/Particles/circle-16.png" id="19_p0p6c"]
+[ext_resource type="Material" uid="uid://rcjujd5dv7lm" path="res://Assets/Sprites/Particles/DocIntroParticles.tres" id="19_q4rt1"]
+[ext_resource type="Animation" uid="uid://8e8r3y1imvsx" path="res://Assets/Animations/stun.res" id="21_ixn4k"]
+[ext_resource type="PackedScene" uid="uid://p7oijq6dbvvk" path="res://Items/Weapons/DocLance.tscn" id="24_2es2r"]
+[ext_resource type="PackedScene" uid="uid://bauucuqvjwbxp" path="res://Items/Weapons/DocLanceHold.tscn" id="26_0tntj"]
[sub_resource type="ShaderMaterial" id="ShaderMaterial_7n7iy"]
resource_local_to_scene = true
shader = ExtResource("2_5jxom")
shader_parameter/color = Quaternion(1, 1, 1, 1)
shader_parameter/intensity = 0.0
+shader_parameter/alpha_modulate = 1.0
+
+[sub_resource type="Animation" id="Animation_7ay6e"]
+length = 0.001
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath("../Sprite:frame")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 1,
+"values": [0]
+}
+
+[sub_resource type="Animation" id="Animation_px7yx"]
+resource_name = "idle"
+length = 0.5
+loop_mode = 1
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath("../Sprite:frame")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0, 0.3),
+"transitions": PackedFloat32Array(1, 1),
+"update": 1,
+"values": [0, 1]
+}
+
+[sub_resource type="Animation" id="Animation_a7sk6"]
+resource_name = "move"
+length = 0.6
+loop_mode = 1
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath("../Sprite:frame")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0, 0.1, 0.2, 0.3, 0.4, 0.5),
+"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1),
+"update": 1,
+"values": [2, 3, 4, 5, 6, 7]
+}
+
+[sub_resource type="Animation" id="Animation_j0d8o"]
+resource_name = "dash"
+length = 0.1
+
+[sub_resource type="AnimationLibrary" id="AnimationLibrary_1xv7m"]
+_data = {
+"RESET": SubResource("Animation_7ay6e"),
+"dash": SubResource("Animation_j0d8o"),
+"idle": SubResource("Animation_px7yx"),
+"move": SubResource("Animation_a7sk6")
+}
+
+[sub_resource type="Animation" id="Animation_dbist"]
+length = 0.001
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath("../Effects/UnwantedFrequenciesParticles:emitting")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 1,
+"values": [false]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath("../Sprite:frame")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 1,
+"values": [0]
+}
+tracks/2/type = "value"
+tracks/2/imported = false
+tracks/2/enabled = true
+tracks/2/path = NodePath("../Sprite:scale")
+tracks/2/interp = 1
+tracks/2/loop_wrap = true
+tracks/2/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [Vector2(1, 1)]
+}
+tracks/3/type = "value"
+tracks/3/imported = false
+tracks/3/enabled = true
+tracks/3/path = NodePath("..:material:shader_parameter/alpha_modulate")
+tracks/3/interp = 1
+tracks/3/loop_wrap = true
+tracks/3/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [1.0]
+}
[sub_resource type="Animation" id="Animation_7oukw"]
resource_name = "enter_in"
@@ -44,14 +169,38 @@ tracks/0/keys = {
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
-tracks/1/path = NodePath("../Sprite:modulate")
+tracks/1/path = NodePath("../Sprite:frame")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 1,
+"values": [0]
+}
+tracks/2/type = "value"
+tracks/2/imported = false
+tracks/2/enabled = true
+tracks/2/path = NodePath("../Effects/UnwantedFrequenciesParticles:emitting")
+tracks/2/interp = 1
+tracks/2/loop_wrap = true
+tracks/2/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 1,
+"values": [false]
+}
+tracks/3/type = "value"
+tracks/3/imported = false
+tracks/3/enabled = true
+tracks/3/path = NodePath("..:material:shader_parameter/alpha_modulate")
+tracks/3/interp = 1
+tracks/3/loop_wrap = true
+tracks/3/keys = {
"times": PackedFloat32Array(0, 0.5),
-"transitions": PackedFloat32Array(2, 1),
+"transitions": PackedFloat32Array(1, 1),
"update": 0,
-"values": [Color(1, 1, 1, 0), Color(1, 1, 1, 0.5)]
+"values": [0.0, 1.0]
}
[sub_resource type="Animation" id="Animation_j3s0y"]
@@ -72,112 +221,113 @@ tracks/0/keys = {
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
-tracks/1/path = NodePath("../Sprite:modulate")
+tracks/1/path = NodePath("../Sprite:frame")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 1,
+"values": [0]
+}
+tracks/2/type = "value"
+tracks/2/imported = false
+tracks/2/enabled = true
+tracks/2/path = NodePath("../Effects/UnwantedFrequenciesParticles:emitting")
+tracks/2/interp = 1
+tracks/2/loop_wrap = true
+tracks/2/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 1,
+"values": [false]
+}
+tracks/3/type = "value"
+tracks/3/imported = false
+tracks/3/enabled = true
+tracks/3/path = NodePath("..:material:shader_parameter/alpha_modulate")
+tracks/3/interp = 1
+tracks/3/loop_wrap = true
+tracks/3/keys = {
"times": PackedFloat32Array(0, 0.5),
-"transitions": PackedFloat32Array(1, 2),
+"transitions": PackedFloat32Array(1, 1),
"update": 0,
-"values": [Color(1, 1, 1, 0.5), Color(1, 1, 1, 0)]
+"values": [1.0, 0.0]
+}
+
+[sub_resource type="Animation" id="Animation_8dhub"]
+resource_name = "shungite_spike"
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath("../Sprite:frame")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 1,
+"values": [15]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath("../Sprite:scale")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0, 0.1, 0.2, 0.3),
+"transitions": PackedFloat32Array(2, 5, 5, 5),
+"update": 0,
+"values": [Vector2(1.5, 0.75), Vector2(1, 1), Vector2(0.75, 1.5), Vector2(1, 1)]
+}
+
+[sub_resource type="Animation" id="Animation_qggcf"]
+resource_name = "unwanted_frequencies"
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath("../Effects/UnwantedFrequenciesParticles:emitting")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0, 1),
+"transitions": PackedFloat32Array(1, 1),
+"update": 1,
+"values": [true, false]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath("../Sprite:frame")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8),
+"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1),
+"update": 1,
+"values": [8, 9, 10, 11, 12, 13, 14, 8, 9]
+}
+tracks/2/type = "value"
+tracks/2/imported = false
+tracks/2/enabled = true
+tracks/2/path = NodePath("../Sprite:scale")
+tracks/2/interp = 1
+tracks/2/loop_wrap = true
+tracks/2/keys = {
+"times": PackedFloat32Array(0, 0.1),
+"transitions": PackedFloat32Array(1, 1),
+"update": 0,
+"values": [Vector2(1.5, 0.75), Vector2(1, 1)]
}
[sub_resource type="AnimationLibrary" id="AnimationLibrary_rpply"]
_data = {
+"RESET": SubResource("Animation_dbist"),
"enter_in": SubResource("Animation_7oukw"),
-"exit_out": SubResource("Animation_j3s0y")
-}
-
-[sub_resource type="AtlasTexture" id="AtlasTexture_dib6t"]
-atlas = ExtResource("3_rs44f")
-region = Rect2(0, 0, 12, 16)
-
-[sub_resource type="AtlasTexture" id="AtlasTexture_cwqre"]
-atlas = ExtResource("3_rs44f")
-region = Rect2(12, 0, 12, 16)
-
-[sub_resource type="AtlasTexture" id="AtlasTexture_r8xjl"]
-atlas = ExtResource("3_rs44f")
-region = Rect2(24, 0, 12, 16)
-
-[sub_resource type="AtlasTexture" id="AtlasTexture_7hkj4"]
-atlas = ExtResource("3_rs44f")
-region = Rect2(36, 0, 12, 16)
-
-[sub_resource type="AtlasTexture" id="AtlasTexture_w04w0"]
-atlas = ExtResource("3_rs44f")
-region = Rect2(48, 0, 12, 16)
-
-[sub_resource type="AtlasTexture" id="AtlasTexture_ym6tg"]
-atlas = ExtResource("3_rs44f")
-region = Rect2(60, 0, 12, 16)
-
-[sub_resource type="AtlasTexture" id="AtlasTexture_3rbas"]
-atlas = ExtResource("3_rs44f")
-region = Rect2(72, 0, 12, 16)
-
-[sub_resource type="AtlasTexture" id="AtlasTexture_63wkp"]
-atlas = ExtResource("3_rs44f")
-region = Rect2(84, 0, 12, 16)
-
-[sub_resource type="SpriteFrames" id="SpriteFrames_kb0pl"]
-resource_local_to_scene = true
-animations = [{
-"frames": [{
-"duration": 1.0,
-"texture": SubResource("AtlasTexture_dib6t")
-}, {
-"duration": 1.0,
-"texture": SubResource("AtlasTexture_cwqre")
-}],
-"loop": true,
-"name": &"idle",
-"speed": 5.0
-}, {
-"frames": [{
-"duration": 1.0,
-"texture": SubResource("AtlasTexture_r8xjl")
-}, {
-"duration": 1.0,
-"texture": SubResource("AtlasTexture_7hkj4")
-}, {
-"duration": 1.0,
-"texture": SubResource("AtlasTexture_w04w0")
-}, {
-"duration": 1.0,
-"texture": SubResource("AtlasTexture_ym6tg")
-}, {
-"duration": 1.0,
-"texture": SubResource("AtlasTexture_3rbas")
-}, {
-"duration": 1.0,
-"texture": SubResource("AtlasTexture_63wkp")
-}],
-"loop": true,
-"name": &"move",
-"speed": 12.0
-}]
-
-[sub_resource type="RectangleShape2D" id="RectangleShape2D_uict5"]
-size = Vector2(16, 8)
-
-[sub_resource type="RectangleShape2D" id="RectangleShape2D_8lxmf"]
-size = Vector2(16, 18)
-
-[sub_resource type="Animation" id="Animation_dxevc"]
-resource_name = "Hurt"
-length = 0.6
-tracks/0/type = "value"
-tracks/0/imported = false
-tracks/0/enabled = true
-tracks/0/path = NodePath(".:material:shader_parameter/intensity")
-tracks/0/interp = 2
-tracks/0/loop_wrap = true
-tracks/0/keys = {
-"times": PackedFloat32Array(0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6),
-"transitions": PackedFloat32Array(4, 4, 4, 4, 4, 4, 4),
-"update": 0,
-"values": [0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0]
+"exit_out": SubResource("Animation_j3s0y"),
+"shungite_spike": SubResource("Animation_8dhub"),
+"unwanted_frequencies": SubResource("Animation_qggcf")
}
[sub_resource type="Animation" id="Animation_k6l16"]
@@ -194,27 +344,134 @@ tracks/0/keys = {
"update": 0,
"values": [0.0]
}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath("Effects/HurtParticles:emitting")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 1,
+"values": [false]
+}
+
+[sub_resource type="Animation" id="Animation_dxevc"]
+resource_name = "hurt"
+length = 0.6
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:material:shader_parameter/intensity")
+tracks/0/interp = 2
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6),
+"transitions": PackedFloat32Array(4, 4, 4, 4, 4, 4, 4),
+"update": 0,
+"values": [0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath("Effects/HurtParticles:emitting")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0, 0.1),
+"transitions": PackedFloat32Array(1, 1),
+"update": 1,
+"values": [true, false]
+}
[sub_resource type="AnimationLibrary" id="AnimationLibrary_xe5eq"]
_data = {
-"Hurt": SubResource("Animation_dxevc"),
-"RESET": SubResource("Animation_k6l16")
+"RESET": SubResource("Animation_k6l16"),
+"hurt": SubResource("Animation_dxevc")
}
-[node name="Doc" type="CharacterBody2D" node_paths=PackedStringArray("BossStateMachine", "Sprite", "Inventory", "StateMachine", "Hurtbox")]
+[sub_resource type="AnimationLibrary" id="AnimationLibrary_kks2p"]
+_data = {
+"stun": ExtResource("21_ixn4k")
+}
+
+[sub_resource type="Animation" id="Animation_uemm6"]
+resource_name = "intro"
+
+[sub_resource type="AnimationLibrary" id="AnimationLibrary_kjxam"]
+_data = {
+"intro": SubResource("Animation_uemm6")
+}
+
+[sub_resource type="Gradient" id="Gradient_lcoxi"]
+offsets = PackedFloat32Array(0.37037, 0.651852)
+colors = PackedColorArray(0.367549, 0.894801, 1, 1, 0.992095, 0.364069, 1, 1)
+
+[sub_resource type="GradientTexture1D" id="GradientTexture1D_5606i"]
+gradient = SubResource("Gradient_lcoxi")
+
+[sub_resource type="Gradient" id="Gradient_pikjh"]
+offsets = PackedFloat32Array(0.533333, 1)
+colors = PackedColorArray(1, 1, 1, 1, 1, 1, 1, 0)
+
+[sub_resource type="GradientTexture1D" id="GradientTexture1D_pjeh8"]
+gradient = SubResource("Gradient_pikjh")
+
+[sub_resource type="Curve" id="Curve_x3x4q"]
+_data = [Vector2(0, 0.463636), 0.0, 0.0, 0, 0, Vector2(0.325301, 1), 0.0, 0.0, 0, 0, Vector2(1, 0), 0.0, 0.0, 0, 0]
+point_count = 3
+
+[sub_resource type="CurveTexture" id="CurveTexture_ssoms"]
+curve = SubResource("Curve_x3x4q")
+
+[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_s1tqp"]
+emission_shape = 3
+emission_box_extents = Vector3(8, 1, 1)
+particle_flag_disable_z = true
+direction = Vector3(0, -1, 0)
+spread = 0.0
+gravity = Vector3(0, 0, 0)
+initial_velocity_min = 32.0
+initial_velocity_max = 64.0
+orbit_velocity_min = 0.0
+orbit_velocity_max = 0.0
+scale_max = 1.5
+scale_curve = SubResource("CurveTexture_ssoms")
+color_ramp = SubResource("GradientTexture1D_pjeh8")
+color_initial_ramp = SubResource("GradientTexture1D_5606i")
+
+[sub_resource type="CanvasTexture" id="CanvasTexture_hs7xn"]
+
+[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_j1srf"]
+particle_flag_disable_z = true
+gravity = Vector3(0, 98, 0)
+orbit_velocity_min = 0.0
+orbit_velocity_max = 0.0
+
+[sub_resource type="RectangleShape2D" id="RectangleShape2D_uict5"]
+size = Vector2(11, 5)
+
+[sub_resource type="RectangleShape2D" id="RectangleShape2D_8lxmf"]
+size = Vector2(16, 19)
+
+[node name="Doc" type="CharacterBody2D" node_paths=PackedStringArray("Lance", "BossStateMachine", "Sprite", "Inventory", "StateMachine", "Hurtbox")]
y_sort_enabled = true
texture_filter = 3
material = SubResource("ShaderMaterial_7n7iy")
collision_layer = 10
collision_mask = 17
script = ExtResource("2_3elet")
+Lance = NodePath("Inventory/DocLance")
BossStateMachine = NodePath("BossStateMachine")
-Health = 1000.0
+BossName = "Doc, The Two-Time"
+Music = ExtResource("3_eo4lg")
+HandTexture = ExtResource("4_8lqj6")
+Health = 800.0
Sprite = NodePath("Sprite")
Inventory = NodePath("Inventory")
StateMachine = NodePath("StateMachine")
Hurtbox = NodePath("Hurtbox")
-Faction = 2
[node name="StateMachine" type="Node" parent="." node_paths=PackedStringArray("InitialState", "Character")]
script = ExtResource("3_t5jjc")
@@ -231,6 +488,13 @@ script = ExtResource("5_pejsd")
IdleState = NodePath("../Idle")
Character = NodePath("../..")
+[node name="Dash" type="Node" parent="StateMachine" node_paths=PackedStringArray("IdleState", "Character")]
+script = ExtResource("7_0ks57")
+IdleState = NodePath("../Idle")
+TimeToDash = 0.1
+VelocityModifier = 10.0
+Character = NodePath("../..")
+
[node name="BossStateMachine" type="Node" parent="." node_paths=PackedStringArray("InitialState")]
script = ExtResource("6_kjpug")
InitialState = NodePath("Telegraph")
@@ -245,14 +509,14 @@ NPC = NodePath("../..")
script = ExtResource("8_1hoax")
Duration = 8.0
AttackDuration = 1.0
-Projectile = ExtResource("9_kthpr")
+Projectile = ExtResource("11_23p3o")
ChooseAttackState = NodePath("../ChooseAttack")
Doc = NodePath("../..")
NPC = NodePath("../..")
[node name="Spike" type="Node" parent="BossStateMachine" node_paths=PackedStringArray("ChooseAttackState", "Doc", "NPC")]
script = ExtResource("10_bgs6o")
-Duration = 8.0
+Duration = 4.0
AttackDuration = 1.0
Projectile = ExtResource("9_7kavk")
ChooseAttackState = NodePath("../ChooseAttack")
@@ -268,11 +532,17 @@ ChooseAttackState = NodePath("../ChooseAttack")
Doc = NodePath("../..")
NPC = NodePath("../..")
-[node name="ChooseAttack" type="Node" parent="BossStateMachine" node_paths=PackedStringArray("DartState", "SpikeState", "UnwantedFrequencyState", "ExitState", "NPC")]
+[node name="Lance" type="Node" parent="BossStateMachine" node_paths=PackedStringArray("ExitState", "NPC")]
+script = ExtResource("15_dmd05")
+ExitState = NodePath("../Exit")
+NPC = NodePath("../..")
+
+[node name="ChooseAttack" type="Node" parent="BossStateMachine" node_paths=PackedStringArray("DartState", "SpikeState", "UnwantedFrequencyState", "LanceState", "ExitState", "NPC")]
script = ExtResource("12_45x13")
DartState = NodePath("../Dart")
SpikeState = NodePath("../Spike")
UnwantedFrequencyState = NodePath("../UnwantedFrequency")
+LanceState = NodePath("../Lance")
ExitState = NodePath("../Exit")
NPC = NodePath("../..")
@@ -283,33 +553,85 @@ TelegraphState = NodePath("../Telegraph")
NPC = NodePath("../..")
[node name="Animations" type="Node" parent="."]
+script = ExtResource("16_bsvls")
+
+[node name="Movement" type="AnimationPlayer" parent="Animations"]
+libraries = {
+"": SubResource("AnimationLibrary_1xv7m")
+}
[node name="Telegraph" type="AnimationPlayer" parent="Animations"]
libraries = {
"": SubResource("AnimationLibrary_rpply")
}
-[node name="Sprite" type="AnimatedSprite2D" parent="."]
+[node name="Hurt" type="AnimationPlayer" parent="Animations"]
+root_node = NodePath("../..")
+libraries = {
+"": SubResource("AnimationLibrary_xe5eq")
+}
+
+[node name="Stun" type="AnimationPlayer" parent="Animations"]
+libraries = {
+"": SubResource("AnimationLibrary_kks2p")
+}
+
+[node name="Misc" type="AnimationPlayer" parent="Animations"]
+libraries = {
+"": SubResource("AnimationLibrary_kjxam")
+}
+
+[node name="Effects" type="Node2D" parent="."]
+
+[node name="UnwantedFrequenciesParticles" type="GPUParticles2D" parent="Effects"]
+emitting = false
+process_material = SubResource("ParticleProcessMaterial_s1tqp")
+texture = SubResource("CanvasTexture_hs7xn")
+lifetime = 0.5
+trail_enabled = true
+trail_sections = 4
+
+[node name="HurtParticles" type="GPUParticles2D" parent="Effects"]
+position = Vector2(0, -8)
+emitting = false
+process_material = ExtResource("17_iomdx")
+texture = ExtResource("16_x277j")
+lifetime = 0.4
+one_shot = true
+explosiveness = 1.0
+
+[node name="IntroParticles" type="GPUParticles2D" parent="Effects"]
+position = Vector2(0, -8)
+emitting = false
+amount = 32
+process_material = ExtResource("19_q4rt1")
+texture = ExtResource("19_p0p6c")
+
+[node name="Dash" type="GPUParticles2D" parent="Effects"]
+position = Vector2(0, -8)
+emitting = false
+amount = 32
+process_material = SubResource("ParticleProcessMaterial_j1srf")
+
+[node name="Sprite" type="Sprite2D" parent="."]
modulate = Color(1, 1, 1, 0.5)
+y_sort_enabled = true
use_parent_material = true
-position = Vector2(0, -4)
-sprite_frames = SubResource("SpriteFrames_kb0pl")
-animation = &"move"
-frame_progress = 0.563144
-offset = Vector2(0, 4)
+position = Vector2(-0.5, 0)
+texture = ExtResource("3_rs44f")
+offset = Vector2(0, -8)
+hframes = 16
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
-visible = false
-position = Vector2(0, 4)
+position = Vector2(-0.5, -1.5)
shape = SubResource("RectangleShape2D_uict5")
[node name="Hurtbox" parent="." instance=ExtResource("7_tnve0")]
-visible = false
position = Vector2(0, -4)
Faction = 2
[node name="CollisionShape2D" parent="Hurtbox" index="0"]
-position = Vector2(0, 4)
+position = Vector2(0, -3.5)
shape = SubResource("RectangleShape2D_8lxmf")
[node name="Inventory" type="Node2D" parent="."]
@@ -317,10 +639,9 @@ y_sort_enabled = true
script = ExtResource("8_r8ejq")
Items = Array[Node2D]([])
-[node name="FlashAnimation" type="AnimationPlayer" parent="."]
-libraries = {
-"": SubResource("AnimationLibrary_xe5eq")
-}
+[node name="DocLance" parent="Inventory" instance=ExtResource("24_2es2r")]
+
+[node name="DocLanceHold" parent="Inventory" instance=ExtResource("26_0tntj")]
[node name="HurtSound" type="AudioStreamPlayer2D" parent="."]
stream = ExtResource("9_stm0e")
diff --git a/Characters/NPC.cs b/Characters/NPC.cs
index 96ecb65..f903d7e 100644
--- a/Characters/NPC.cs
+++ b/Characters/NPC.cs
@@ -1,3 +1,5 @@
+#undef DEBUG_NPC
+
using Godot;
using SupaLidlGame.Extensions;
using SupaLidlGame.Items;
@@ -41,6 +43,10 @@ public partial class NPC : Character
}
}
+ public bool ShouldMove { get; set; } = true;
+
+ public bool CanAttack { get; set; } = true;
+
protected float[] _weights = new float[16];
protected int _bestWeightIdx;
protected double _thinkTimeElapsed = 0;
@@ -65,7 +71,7 @@ public partial class NPC : Character
public override void _Draw()
{
-#if DEBUG
+#if DEBUG_NPC
for (int i = 0; i < 16; i++)
{
Vector2 vec = _weightDirs[i] * _weights[i] * 32;
@@ -116,12 +122,19 @@ public partial class NPC : Character
{
_thinkTimeElapsed = 0;
Think();
-#if DEBUG
+#if DEBUG_NPC
QueueRedraw();
#endif
}
- Direction = _weightDirs[_bestWeightIdx];
+ if (ShouldMove)
+ {
+ Direction = _weightDirs[_bestWeightIdx];
+ }
+ else
+ {
+ Direction = Vector2.Zero;
+ }
}
public void UpdateWeights(Vector2 pos)
@@ -221,7 +234,7 @@ public partial class NPC : Character
float dist = GlobalPosition.DistanceSquaredTo(pos);
UpdateWeights(pos);
- if (dist < 1024)
+ if (dist < 1600 && CanAttack)
{
if (Inventory.SelectedItem is Weapon weapon)
{
diff --git a/Characters/Player.cs b/Characters/Player.cs
index 04e2171..0bbdb59 100644
--- a/Characters/Player.cs
+++ b/Characters/Player.cs
@@ -8,7 +8,6 @@ namespace SupaLidlGame.Characters;
[Scene]
public sealed partial class Player : Character
{
- private AnimatedSprite2D _sprite;
private string _spriteAnim;
[Export]
@@ -17,40 +16,32 @@ public sealed partial class Player : Character
[Export]
public Marker2D DirectionMarker { get; private set; }
+ [Export]
+ public AnimationTree AnimationTree { get; private set; }
+
public InteractionRay InteractionRay { get; private set; }
- public string Animation
- {
- get => _sprite.Animation;
- set
- {
- // the Player.Animation property might be set before this node is
- // even ready, so if _sprite is null, then we just hold the new
- // animation in a temp value, which will be assigned once this node
- // is ready
- if (_sprite is null)
- {
- _spriteAnim = value;
- return;
- }
-
- _sprite.Play(value);
- }
- }
+ public AnimationPlayer AttackAnimation { get; set; }
public override void _Ready()
{
InteractionRay = GetNode("Direction2D/InteractionRay");
- _sprite = GetNode("Sprite");
- if (_spriteAnim != default)
- {
- _sprite.Animation = _spriteAnim;
- }
- base._Ready();
Death += (Events.HealthChangedArgs args) =>
{
Visible = false;
};
+
+ AttackAnimation = GetNode("Animations/Attack");
+
+ base._Ready();
+
+ Inventory.UsedItem += (Items.Item item) =>
+ {
+ if (item is Items.Weapons.Sword)
+ {
+ AttackAnimation.Play("sword");
+ }
+ };
}
public override void _Input(InputEvent @event)
@@ -69,11 +60,6 @@ public sealed partial class Player : Character
public override void ModifyVelocity()
{
- if (StateMachine.CurrentState is SupaLidlGame.State.Character.PlayerRollState)
- {
- Velocity *= 2;
- }
-
base.ModifyVelocity();
}
@@ -88,19 +74,17 @@ public sealed partial class Player : Character
float damage,
Character inflictor,
float knockback,
- Vector2 knockbackOrigin = default,
- Vector2 knockbackVector = default)
+ Vector2 knockbackDir = default)
{
if (damage >= 10 && IsAlive)
{
Camera.Shake(2, 0.5f);
}
- base.OnReceivedDamage(
- damage,
- inflictor,
- knockback,
- knockbackOrigin,
- knockbackVector);
+
+ GetNode("Effects/HurtParticles")
+ .SetDirection(knockbackDir);
+
+ base.OnReceivedDamage(damage, inflictor, knockback, knockbackDir);
}
public override void Die()
diff --git a/Characters/Player.tscn b/Characters/Player.tscn
index b3a2f7e..e06ff3a 100644
--- a/Characters/Player.tscn
+++ b/Characters/Player.tscn
@@ -1,4 +1,4 @@
-[gd_scene load_steps=39 format=3 uid="uid://b2254pup8k161"]
+[gd_scene load_steps=55 format=3 uid="uid://b2254pup8k161"]
[ext_resource type="Script" path="res://Characters/Player.cs" id="1_flygr"]
[ext_resource type="Shader" path="res://Shaders/Flash.gdshader" id="2_ngsgt"]
@@ -8,111 +8,163 @@
[ext_resource type="Script" path="res://State/Character/PlayerIdleState.cs" id="6_wkfdm"]
[ext_resource type="PackedScene" uid="uid://dvqap2uhcah63" path="res://Items/Weapons/Sword.tscn" id="7_4rxuv"]
[ext_resource type="Script" path="res://State/Character/PlayerMoveState.cs" id="7_dfqd8"]
+[ext_resource type="Script" path="res://Utils/AnimationManager.cs" id="7_sdgvb"]
[ext_resource type="Script" path="res://Items/Inventory.cs" id="7_xyenu"]
[ext_resource type="Script" path="res://State/Character/PlayerRollState.cs" id="8_fy0v5"]
+[ext_resource type="Animation" uid="uid://8e8r3y1imvsx" path="res://Assets/Animations/stun.res" id="8_m08fh"]
+[ext_resource type="Material" uid="uid://x5qcq5muvc3g" path="res://Assets/Sprites/Particles/PlayerDamageProcessMaterial.tres" id="8_yf112"]
+[ext_resource type="Texture2D" uid="uid://c1a7lvb4uuwfy" path="res://Assets/Sprites/Particles/circle-16.png" id="9_7gumm"]
[ext_resource type="PackedScene" uid="uid://cjgxyhgcyvsv7" path="res://BoundingBoxes/Hurtbox.tscn" id="9_avyu4"]
[ext_resource type="AudioStream" uid="uid://bkeyg8weaqnuu" path="res://Assets/Sounds/splat-player.ogg" id="12_vvem5"]
[ext_resource type="Script" path="res://BoundingBoxes/InteractionRay.cs" id="13_hs3u1"]
-[ext_resource type="Texture2D" uid="uid://coarr28adgo1u" path="res://Assets/Sprites/Particles/point-light.png" id="14_l4ekh"]
+[ext_resource type="PackedScene" uid="uid://p7oijq6dbvvk" path="res://Items/Weapons/DocLance.tscn" id="14_bj0lo"]
+[ext_resource type="Texture2D" uid="uid://d1ukste16yq6v" path="res://Assets/Sprites/Particles/player-light.png" id="15_3hahh"]
[ext_resource type="Script" path="res://Utils/DamageTime.cs" id="15_4xl06"]
[sub_resource type="ShaderMaterial" id="ShaderMaterial_h78y7"]
shader = ExtResource("2_ngsgt")
-shader_parameter/color = Quaternion(1, 1, 1, 1)
+shader_parameter/color = Vector4(1, 1, 1, 1)
shader_parameter/intensity = 0.0
+shader_parameter/alpha_modulate = 1.0
-[sub_resource type="AtlasTexture" id="AtlasTexture_55yt4"]
-atlas = ExtResource("4_5vird")
-region = Rect2(0, 0, 24, 24)
-
-[sub_resource type="AtlasTexture" id="AtlasTexture_xa1bi"]
-atlas = ExtResource("4_5vird")
-region = Rect2(24, 0, 24, 24)
-
-[sub_resource type="AtlasTexture" id="AtlasTexture_hiodl"]
-atlas = ExtResource("4_5vird")
-region = Rect2(48, 0, 24, 24)
-
-[sub_resource type="AtlasTexture" id="AtlasTexture_tok7d"]
-atlas = ExtResource("4_5vird")
-region = Rect2(72, 0, 24, 24)
-
-[sub_resource type="AtlasTexture" id="AtlasTexture_dp8x6"]
-atlas = ExtResource("4_5vird")
-region = Rect2(96, 0, 24, 24)
-
-[sub_resource type="AtlasTexture" id="AtlasTexture_sglor"]
-atlas = ExtResource("4_5vird")
-region = Rect2(120, 0, 24, 24)
-
-[sub_resource type="AtlasTexture" id="AtlasTexture_gb41o"]
-atlas = ExtResource("4_5vird")
-region = Rect2(144, 0, 24, 24)
-
-[sub_resource type="AtlasTexture" id="AtlasTexture_bx6qq"]
-atlas = ExtResource("4_5vird")
-region = Rect2(168, 0, 24, 24)
-
-[sub_resource type="SpriteFrames" id="SpriteFrames_2h7cf"]
-animations = [{
-"frames": [{
-"duration": 1.0,
-"texture": SubResource("AtlasTexture_55yt4")
-}, {
-"duration": 1.0,
-"texture": SubResource("AtlasTexture_xa1bi")
-}],
-"loop": true,
-"name": &"idle",
-"speed": 2.0
-}, {
-"frames": [{
-"duration": 1.0,
-"texture": SubResource("AtlasTexture_hiodl")
-}, {
-"duration": 1.0,
-"texture": SubResource("AtlasTexture_tok7d")
-}, {
-"duration": 1.0,
-"texture": SubResource("AtlasTexture_dp8x6")
-}, {
-"duration": 1.0,
-"texture": SubResource("AtlasTexture_sglor")
-}, {
-"duration": 1.0,
-"texture": SubResource("AtlasTexture_gb41o")
-}, {
-"duration": 1.0,
-"texture": SubResource("AtlasTexture_bx6qq")
-}],
-"loop": true,
-"name": &"move",
-"speed": 10.0
-}]
-
-[sub_resource type="RectangleShape2D" id="RectangleShape2D_bfqew"]
-size = Vector2(12, 8)
-
-[sub_resource type="LabelSettings" id="LabelSettings_q5h1n"]
-font_size = 24
-
-[sub_resource type="RectangleShape2D" id="RectangleShape2D_cjk6b"]
-size = Vector2(8, 8)
-
-[sub_resource type="Animation" id="Animation_dxevc"]
-resource_name = "Hurt"
-length = 0.6
+[sub_resource type="Animation" id="Animation_imqdv"]
+length = 0.001
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
-tracks/0/path = NodePath(".:material:shader_parameter/intensity")
-tracks/0/interp = 2
+tracks/0/path = NodePath("../Sprites/Node2D/Character:frame")
+tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
-"times": PackedFloat32Array(0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6),
-"transitions": PackedFloat32Array(4, 4, 4, 4, 4, 4, 4),
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 1,
+"values": [0]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath("../Sprites/Node2D/Character:rotation")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
"update": 0,
-"values": [0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0]
+"values": [0.0]
+}
+
+[sub_resource type="Animation" id="Animation_mg66i"]
+resource_name = "idle"
+length = 0.5
+loop_mode = 1
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath("../Sprites/Node2D/Character:frame")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0, 0.3),
+"transitions": PackedFloat32Array(1, 1),
+"update": 1,
+"values": [0, 1]
+}
+
+[sub_resource type="Animation" id="Animation_iyr4r"]
+resource_name = "move"
+length = 0.6
+loop_mode = 1
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath("../Sprites/Node2D/Character:frame")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0, 0.1, 0.2, 0.3, 0.4, 0.5),
+"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1),
+"update": 1,
+"values": [2, 3, 4, 5, 6, 7]
+}
+
+[sub_resource type="Animation" id="Animation_vobpw"]
+resource_name = "roll"
+length = 0.5
+step = 0.05
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath("../Sprites/Node2D/Character:rotation")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0, 0.5),
+"transitions": PackedFloat32Array(1, 1),
+"update": 0,
+"values": [0.0, 6.28319]
+}
+
+[sub_resource type="Animation" id="Animation_tpnyg"]
+resource_name = "stop"
+length = 0.2
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath("../Sprites/Node2D/Character:frame")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0, 0.2),
+"transitions": PackedFloat32Array(1, 1),
+"update": 1,
+"values": [10, 0]
+}
+
+[sub_resource type="AnimationLibrary" id="AnimationLibrary_0tohi"]
+_data = {
+"RESET": SubResource("Animation_imqdv"),
+"idle": SubResource("Animation_mg66i"),
+"move": SubResource("Animation_iyr4r"),
+"roll": SubResource("Animation_vobpw"),
+"stop": SubResource("Animation_tpnyg")
+}
+
+[sub_resource type="Animation" id="Animation_adxyh"]
+length = 0.001
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath("../Sprites/Node2D/Character:frame")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 1,
+"values": [0]
+}
+
+[sub_resource type="Animation" id="Animation_3w3u1"]
+resource_name = "sword"
+length = 0.3
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath("../Sprites/Node2D/Character:frame")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0, 0.1, 0.2),
+"transitions": PackedFloat32Array(1, 1, 1),
+"update": 1,
+"values": [12, 13, 14]
+}
+
+[sub_resource type="AnimationLibrary" id="AnimationLibrary_73mj7"]
+_data = {
+"RESET": SubResource("Animation_adxyh"),
+"sword": SubResource("Animation_3w3u1")
}
[sub_resource type="Animation" id="Animation_k6l16"]
@@ -129,87 +181,205 @@ tracks/0/keys = {
"update": 0,
"values": [0.0]
}
-
-[sub_resource type="AnimationLibrary" id="AnimationLibrary_xe5eq"]
-_data = {
-"Hurt": SubResource("Animation_dxevc"),
-"RESET": SubResource("Animation_k6l16")
-}
-
-[sub_resource type="Animation" id="Animation_yejx2"]
-length = 0.001
-tracks/0/type = "value"
-tracks/0/imported = false
-tracks/0/enabled = true
-tracks/0/path = NodePath("Sprite:rotation")
-tracks/0/interp = 1
-tracks/0/loop_wrap = true
-tracks/0/keys = {
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath("Sprites/Node2D/Character:frame")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
-"update": 0,
-"values": [0.0]
+"update": 1,
+"values": [0]
+}
+tracks/2/type = "value"
+tracks/2/imported = false
+tracks/2/enabled = true
+tracks/2/path = NodePath("Effects/HurtParticles:emitting")
+tracks/2/interp = 1
+tracks/2/loop_wrap = true
+tracks/2/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 1,
+"values": [false]
}
-[sub_resource type="Animation" id="Animation_rx2pj"]
-resource_name = "roll"
-length = 0.5
+[sub_resource type="Animation" id="Animation_dxevc"]
+resource_name = "hurt"
+length = 0.2
step = 0.05
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
-tracks/0/path = NodePath("Sprite:rotation")
-tracks/0/interp = 1
+tracks/0/path = NodePath(".:material:shader_parameter/intensity")
+tracks/0/interp = 2
tracks/0/loop_wrap = true
tracks/0/keys = {
-"times": PackedFloat32Array(0, 0.25, 0.5),
-"transitions": PackedFloat32Array(1, 1, 1),
+"times": PackedFloat32Array(0, 0.05, 0.1, 0.2),
+"transitions": PackedFloat32Array(4, 4, 4, 4),
"update": 0,
-"values": [0.0, 3.14159, 6.28319]
+"values": [1.0, 0.0, 1.0, 0.0]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath("Sprites/Node2D/Character:frame")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 1,
+"values": [11]
+}
+tracks/2/type = "value"
+tracks/2/imported = false
+tracks/2/enabled = true
+tracks/2/path = NodePath("Effects/HurtParticles:emitting")
+tracks/2/interp = 1
+tracks/2/loop_wrap = true
+tracks/2/keys = {
+"times": PackedFloat32Array(0, 0.1),
+"transitions": PackedFloat32Array(1, 1),
+"update": 1,
+"values": [true, false]
+}
+tracks/3/type = "method"
+tracks/3/imported = false
+tracks/3/enabled = true
+tracks/3/path = NodePath("Effects/HurtParticles")
+tracks/3/interp = 1
+tracks/3/loop_wrap = true
+tracks/3/keys = {
+"times": PackedFloat32Array(0.2),
+"transitions": PackedFloat32Array(1),
+"values": [{
+"args": [],
+"method": &"restart"
+}]
}
-[sub_resource type="AnimationLibrary" id="AnimationLibrary_jai06"]
+[sub_resource type="Animation" id="Animation_pjey7"]
+resource_name = "hurt_flash"
+length = 0.4
+step = 0.05
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath(".:material:shader_parameter/intensity")
+tracks/0/interp = 2
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0, 0.2, 0.4),
+"transitions": PackedFloat32Array(4, 4, 4),
+"update": 0,
+"values": [0.0, 1.0, 0.0]
+}
+
+[sub_resource type="AnimationLibrary" id="AnimationLibrary_xe5eq"]
_data = {
-"RESET": SubResource("Animation_yejx2"),
-"roll": SubResource("Animation_rx2pj")
+"RESET": SubResource("Animation_k6l16"),
+"hurt": SubResource("Animation_dxevc"),
+"hurt_flash": SubResource("Animation_pjey7")
}
-[sub_resource type="Gradient" id="Gradient_3tax5"]
-offsets = PackedFloat32Array(0.533333, 1)
-colors = PackedColorArray(1, 1, 1, 1, 1, 1, 1, 0)
+[sub_resource type="AnimationLibrary" id="AnimationLibrary_kks2p"]
+_data = {
+"stun": ExtResource("8_m08fh")
+}
-[sub_resource type="GradientTexture1D" id="GradientTexture1D_pjeh8"]
-gradient = SubResource("Gradient_3tax5")
+[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_kwett"]
+animation = &"idle"
-[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_humq0"]
-emission_shape = 1
-emission_sphere_radius = 1.0
+[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_vqdng"]
+animation = &"move"
+
+[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_4np0m"]
+animation = &"roll"
+
+[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_suhx1"]
+animation = &"stop"
+
+[sub_resource type="AnimationNodeStateMachineTransition" id="AnimationNodeStateMachineTransition_sorqc"]
+advance_mode = 2
+
+[sub_resource type="AnimationNodeStateMachineTransition" id="AnimationNodeStateMachineTransition_ujrp0"]
+advance_condition = &"move"
+
+[sub_resource type="AnimationNodeStateMachineTransition" id="AnimationNodeStateMachineTransition_kjkm8"]
+advance_condition = &"idle"
+
+[sub_resource type="AnimationNodeStateMachineTransition" id="AnimationNodeStateMachineTransition_1ywlq"]
+switch_mode = 2
+advance_mode = 2
+advance_condition = &"idle"
+
+[sub_resource type="AnimationNodeStateMachineTransition" id="AnimationNodeStateMachineTransition_abs7t"]
+advance_condition = &"roll"
+
+[sub_resource type="AnimationNodeStateMachineTransition" id="AnimationNodeStateMachineTransition_qlka8"]
+advance_condition = &"idle"
+
+[sub_resource type="AnimationNodeStateMachineTransition" id="AnimationNodeStateMachineTransition_ql2f3"]
+advance_condition = &"move"
+
+[sub_resource type="AnimationNodeStateMachineTransition" id="AnimationNodeStateMachineTransition_g1yba"]
+advance_condition = &"roll"
+
+[sub_resource type="AnimationNodeStateMachine" id="AnimationNodeStateMachine_0ukul"]
+states/End/position = Vector2(613, 100)
+states/Start/position = Vector2(89, 100)
+states/idle/node = SubResource("AnimationNodeAnimation_kwett")
+states/idle/position = Vector2(259, 100)
+states/move/node = SubResource("AnimationNodeAnimation_vqdng")
+states/move/position = Vector2(259, 18)
+states/roll/node = SubResource("AnimationNodeAnimation_4np0m")
+states/roll/position = Vector2(89, 18)
+states/stop/node = SubResource("AnimationNodeAnimation_suhx1")
+states/stop/position = Vector2(438, 100)
+transitions = ["Start", "idle", SubResource("AnimationNodeStateMachineTransition_sorqc"), "idle", "move", SubResource("AnimationNodeStateMachineTransition_ujrp0"), "move", "stop", SubResource("AnimationNodeStateMachineTransition_kjkm8"), "stop", "idle", SubResource("AnimationNodeStateMachineTransition_1ywlq"), "idle", "roll", SubResource("AnimationNodeStateMachineTransition_abs7t"), "roll", "idle", SubResource("AnimationNodeStateMachineTransition_qlka8"), "roll", "move", SubResource("AnimationNodeStateMachineTransition_ql2f3"), "move", "roll", SubResource("AnimationNodeStateMachineTransition_g1yba")]
+graph_offset = Vector2(-335.315, -63.5708)
+
+[sub_resource type="AnimationNodeStateMachinePlayback" id="AnimationNodeStateMachinePlayback_jln87"]
+
+[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_852jj"]
particle_flag_disable_z = true
-direction = Vector3(0, 0, 0)
spread = 180.0
gravity = Vector3(0, 0, 0)
-initial_velocity_min = 32.0
-initial_velocity_max = 32.0
+initial_velocity_min = 8.0
+initial_velocity_max = 16.0
orbit_velocity_min = 0.0
-orbit_velocity_max = 0.1
-tangential_accel_min = 64.0
-tangential_accel_max = 64.0
-color_ramp = SubResource("GradientTexture1D_pjeh8")
+orbit_velocity_max = 0.0
+linear_accel_min = -32.0
+linear_accel_max = -16.0
+scale_min = 0.1
+scale_max = 0.1
[sub_resource type="CanvasTexture" id="CanvasTexture_pited"]
+diffuse_texture = ExtResource("9_7gumm")
+
+[sub_resource type="RectangleShape2D" id="RectangleShape2D_bfqew"]
+size = Vector2(12, 8)
+
+[sub_resource type="LabelSettings" id="LabelSettings_q5h1n"]
+font_size = 24
+
+[sub_resource type="RectangleShape2D" id="RectangleShape2D_cjk6b"]
+size = Vector2(8, 8)
[node name="Player" type="CharacterBody2D" node_paths=PackedStringArray("Camera", "DirectionMarker", "Sprite", "Inventory", "StateMachine", "Hurtbox")]
y_sort_enabled = true
texture_filter = 3
material = SubResource("ShaderMaterial_h78y7")
-position = Vector2(1, -12)
collision_layer = 6
collision_mask = 17
script = ExtResource("1_flygr")
Camera = NodePath("Camera2D")
DirectionMarker = NodePath("Direction2D")
-Speed = 64.0
-Sprite = NodePath("Sprite")
+Speed = 80.0
+Sprite = NodePath("Sprites/Node2D/Character")
Inventory = NodePath("Inventory")
StateMachine = NodePath("StateMachine")
Hurtbox = NodePath("Hurtbox")
@@ -237,18 +407,89 @@ script = ExtResource("8_fy0v5")
IdleState = NodePath("../Idle")
Character = NodePath("../..")
+[node name="Animations" type="Node" parent="."]
+script = ExtResource("7_sdgvb")
+
+[node name="Movement" type="AnimationPlayer" parent="Animations"]
+libraries = {
+"": SubResource("AnimationLibrary_0tohi")
+}
+
+[node name="Attack" type="AnimationPlayer" parent="Animations"]
+libraries = {
+"": SubResource("AnimationLibrary_73mj7")
+}
+
+[node name="Hurt" type="AnimationPlayer" parent="Animations"]
+root_node = NodePath("../..")
+libraries = {
+"": SubResource("AnimationLibrary_xe5eq")
+}
+
+[node name="Stun" type="AnimationPlayer" parent="Animations"]
+libraries = {
+"": SubResource("AnimationLibrary_kks2p")
+}
+
+[node name="AnimationTree" type="AnimationTree" parent="Animations"]
+tree_root = SubResource("AnimationNodeStateMachine_0ukul")
+anim_player = NodePath("../Movement")
+parameters/playback = SubResource("AnimationNodeStateMachinePlayback_jln87")
+parameters/conditions/idle = false
+parameters/conditions/move = false
+parameters/conditions/roll = false
+
+[node name="Effects" type="Node2D" parent="."]
+
+[node name="RollParticles" type="GPUParticles2D" parent="Effects"]
+emitting = false
+amount = 16
+process_material = SubResource("ParticleProcessMaterial_852jj")
+texture = ExtResource("9_7gumm")
+lifetime = 0.8
+
+[node name="DeathParticles" type="GPUParticles2D" parent="Effects"]
+emitting = false
+amount = 32
+process_material = ExtResource("8_yf112")
+texture = SubResource("CanvasTexture_pited")
+lifetime = 2.0
+preprocess = 0.1
+explosiveness = 0.9
+
+[node name="HurtParticles" type="GPUParticles2D" parent="Effects"]
+emitting = false
+amount = 32
+process_material = ExtResource("8_yf112")
+texture = ExtResource("9_7gumm")
+lifetime = 1.5
+one_shot = true
+preprocess = 0.1
+explosiveness = 0.9
+
[node name="Camera2D" parent="." instance=ExtResource("4_ym125")]
+limit_left = -256
+limit_top = -256
+limit_right = 256
+limit_bottom = 256
position_smoothing_speed = 8.0
-[node name="Sprite" type="AnimatedSprite2D" parent="."]
+[node name="Sprites" type="Node2D" parent="."]
+y_sort_enabled = true
use_parent_material = true
-position = Vector2(0, 4)
-sprite_frames = SubResource("SpriteFrames_2h7cf")
-animation = &"idle"
+rotation = 6.28319
+
+[node name="Node2D" type="Node2D" parent="Sprites"]
+
+[node name="Character" type="Sprite2D" parent="Sprites/Node2D"]
+use_parent_material = true
+position = Vector2(-1, -8)
+texture = ExtResource("4_5vird")
offset = Vector2(0, -4)
+hframes = 24
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
-position = Vector2(0, 8)
+position = Vector2(0, -4)
shape = SubResource("RectangleShape2D_bfqew")
[node name="Debug" type="Control" parent="."]
@@ -266,10 +507,8 @@ text = "lol"
label_settings = SubResource("LabelSettings_q5h1n")
horizontal_alignment = 1
-[node name="Node" type="Node" parent="."]
-
[node name="Inventory" type="Node2D" parent="."]
-position = Vector2(0, 4)
+position = Vector2(0, -4)
script = ExtResource("7_xyenu")
InventoryMap = {
"equip_1": 0,
@@ -278,56 +517,50 @@ InventoryMap = {
[node name="Node2D" parent="Inventory" instance=ExtResource("7_4rxuv")]
visible = false
-ShouldHideIdle = false
-[node name="Hurtbox" parent="." instance=ExtResource("9_avyu4")]
+[node name="DocLance" parent="Inventory" instance=ExtResource("14_bj0lo")]
+
+[node name="Hurtbox" parent="." node_paths=PackedStringArray("InvincibilityTimer") instance=ExtResource("9_avyu4")]
+visible = false
+InvincibilityTimer = NodePath("Timer")
Faction = 1
[node name="CollisionShape2D" parent="Hurtbox" index="0"]
-position = Vector2(0, 6)
+visible = false
+position = Vector2(0, 4)
shape = SubResource("RectangleShape2D_cjk6b")
-[node name="FlashAnimation" type="AnimationPlayer" parent="."]
-libraries = {
-"": SubResource("AnimationLibrary_xe5eq")
-}
-
-[node name="RollAnimation" type="AnimationPlayer" parent="."]
-libraries = {
-"": SubResource("AnimationLibrary_jai06")
-}
+[node name="Timer" type="Timer" parent="Hurtbox"]
+one_shot = true
[node name="HurtSound" type="AudioStreamPlayer2D" parent="."]
+visible = false
stream = ExtResource("12_vvem5")
max_distance = 64.0
[node name="AudioListener2D" type="AudioListener2D" parent="."]
+visible = false
current = true
[node name="Direction2D" type="Marker2D" parent="."]
+visible = false
position = Vector2(0, 6)
[node name="InteractionRay" type="RayCast2D" parent="Direction2D"]
+visible = false
target_position = Vector2(16, 0)
collision_mask = 64
collide_with_areas = true
script = ExtResource("13_hs3u1")
-[node name="DeathParticles" type="GPUParticles2D" parent="."]
-emitting = false
-amount = 16
-process_material = SubResource("ParticleProcessMaterial_humq0")
-texture = SubResource("CanvasTexture_pited")
-one_shot = true
-explosiveness = 0.9
-
[node name="PointLight2D" type="PointLight2D" parent="."]
+visible = false
blend_mode = 2
shadow_enabled = true
shadow_filter = 2
shadow_filter_smooth = 3.0
-texture = ExtResource("14_l4ekh")
-texture_scale = 0.5
+texture = ExtResource("15_3hahh")
+height = 10.0
[node name="DamageTime" type="Node" parent="."]
script = ExtResource("15_4xl06")
diff --git a/Entities/CompactDisc.tscn b/Entities/CompactDisc.tscn
new file mode 100644
index 0000000..192ee99
--- /dev/null
+++ b/Entities/CompactDisc.tscn
@@ -0,0 +1,41 @@
+[gd_scene load_steps=7 format=3 uid="uid://cqx56u46g2c16"]
+
+[ext_resource type="PackedScene" uid="uid://djaljmco3xo4g" path="res://Entities/ShungiteDart.tscn" id="1_md2qh"]
+[ext_resource type="Texture2D" uid="uid://qc6agawkad5k" path="res://Assets/Sprites/Misc/compact-disc.png" id="3_8r6gc"]
+
+[sub_resource type="AtlasTexture" id="AtlasTexture_wvy7p"]
+atlas = ExtResource("3_8r6gc")
+region = Rect2(0, 0, 12, 12)
+
+[sub_resource type="AtlasTexture" id="AtlasTexture_0ibsw"]
+atlas = ExtResource("3_8r6gc")
+region = Rect2(12, 0, 12, 12)
+
+[sub_resource type="SpriteFrames" id="SpriteFrames_80dw6"]
+animations = [{
+"frames": [{
+"duration": 1.0,
+"texture": SubResource("AtlasTexture_wvy7p")
+}, {
+"duration": 1.0,
+"texture": SubResource("AtlasTexture_0ibsw")
+}],
+"loop": true,
+"name": &"default",
+"speed": 5.0
+}]
+
+[sub_resource type="CircleShape2D" id="CircleShape2D_v6kob"]
+radius = 4.0
+
+[node name="ShungiteDart" instance=ExtResource("1_md2qh")]
+
+[node name="Sprite2D" parent="." index="0"]
+sprite_frames = SubResource("SpriteFrames_80dw6")
+frame_progress = 0.70222
+speed_scale = 2.0
+
+[node name="CollisionShape2D" parent="Hitbox" index="0"]
+shape = SubResource("CircleShape2D_v6kob")
+
+[editable path="Hitbox"]
diff --git a/Entities/Projectile.cs b/Entities/Projectile.cs
index 31718a9..b617181 100644
--- a/Entities/Projectile.cs
+++ b/Entities/Projectile.cs
@@ -6,7 +6,15 @@ namespace SupaLidlGame.Entities;
public partial class Projectile : RigidBody2D
{
- public Vector2 Velocity => Direction * Speed;
+ //public virtual Vector2 Velocity => Direction * Speed;
+ public virtual Vector2 Velocity
+ {
+ get => Direction * Speed;
+ set
+ {
+ throw new System.NotImplementedException();
+ }
+ }
[Export]
public string ProjectileName { get; set; }
@@ -14,6 +22,12 @@ public partial class Projectile : RigidBody2D
[Export]
public float Speed { get; set; }
+ [Export]
+ public Vector2 AccelerationDirection { get; set; }
+
+ [Export]
+ public float AccelerationMagnitude { get; set; }
+
[Export]
public Vector2 Direction { get; set; }
diff --git a/Entities/ShungiteSpike.cs b/Entities/ShungiteSpike.cs
index c88eb64..26fc2a2 100644
--- a/Entities/ShungiteSpike.cs
+++ b/Entities/ShungiteSpike.cs
@@ -63,8 +63,7 @@ public partial class ShungiteSpike : Projectile
float damage,
Characters.Character inflictor,
float knockback,
- Vector2 knockbackOrigin = default,
- Vector2 knockbackVector = default)
+ Vector2 knockbackDir)
{
// if we were hit by the player before the spike freezes,
// spawn a dart towards where the player is aiming
diff --git a/Entities/ShungiteSpike.tscn b/Entities/ShungiteSpike.tscn
index f3dec6c..37ae25d 100644
--- a/Entities/ShungiteSpike.tscn
+++ b/Entities/ShungiteSpike.tscn
@@ -5,10 +5,10 @@
[ext_resource type="Texture2D" uid="uid://dvx2b0y6dup53" path="res://Assets/Sprites/Misc/shungite-spike.png" id="2_klp8v"]
[ext_resource type="PackedScene" uid="uid://du5vhccg75nrq" path="res://BoundingBoxes/Hitbox.tscn" id="3_kojrj"]
[ext_resource type="PackedScene" uid="uid://cjgxyhgcyvsv7" path="res://BoundingBoxes/Hurtbox.tscn" id="4_d8dl4"]
-[ext_resource type="AudioStream" uid="uid://c4n7ioxpukdwi" path="res://Assets/Sounds/parry.wav" id="6_fepye"]
+[ext_resource type="AudioStream" uid="uid://jsnjoyaj6p5a" path="res://Assets/Sounds/rock-smash.wav" id="6_vr2ui"]
[sub_resource type="CircleShape2D" id="CircleShape2D_hrev2"]
-radius = 8.0
+radius = 6.0
[sub_resource type="CircleShape2D" id="CircleShape2D_kumrg"]
radius = 12.0
@@ -144,7 +144,7 @@ shape = SubResource("CircleShape2D_hrev2")
shape = SubResource("CircleShape2D_kumrg")
[node name="AudioStreamPlayer2D" type="AudioStreamPlayer2D" parent="."]
-stream = ExtResource("6_fepye")
+stream = ExtResource("6_vr2ui")
[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
libraries = {
diff --git a/Entities/Torch.tscn b/Entities/Torch.tscn
index 3d13af6..6aee75c 100644
--- a/Entities/Torch.tscn
+++ b/Entities/Torch.tscn
@@ -57,7 +57,7 @@ animations = [{
}],
"loop": true,
"name": &"default",
-"speed": 5.0
+"speed": 10.0
}]
[node name="Torch" type="Node2D"]
@@ -67,8 +67,7 @@ texture_filter = 1
position = Vector2(0, -12)
sprite_frames = SubResource("SpriteFrames_gf7ku")
autoplay = "default"
-frame = 5
-frame_progress = 0.743234
+frame_progress = 0.337799
[node name="PointLight2D" type="PointLight2D" parent="."]
color = Color(1, 0.898039, 0.686275, 1)
diff --git a/Entities/TorchLamp.tscn b/Entities/TorchLamp.tscn
index ba5c3fa..973648d 100644
--- a/Entities/TorchLamp.tscn
+++ b/Entities/TorchLamp.tscn
@@ -1,7 +1,7 @@
[gd_scene load_steps=16 format=3 uid="uid://ceadk7pam7vab"]
[ext_resource type="Texture2D" uid="uid://cyldr0ck3yfrp" path="res://Assets/Sprites/Misc/torch-lamp.png" id="1_dlkl0"]
-[ext_resource type="Texture2D" uid="uid://b8ann6yb8qox4" path="res://Assets/Sprites/Particles/light-pixel.png" id="2_yuj6j"]
+[ext_resource type="Texture2D" uid="uid://coarr28adgo1u" path="res://Assets/Sprites/Particles/point-light.png" id="2_0xpf8"]
[sub_resource type="AtlasTexture" id="AtlasTexture_ikvnd"]
atlas = ExtResource("1_dlkl0")
@@ -98,17 +98,18 @@ animations = [{
[node name="TorchLamp" type="Node2D"]
[node name="AnimatedSprite2D" type="AnimatedSprite2D" parent="."]
+y_sort_enabled = true
texture_filter = 1
-position = Vector2(0, -12)
sprite_frames = SubResource("SpriteFrames_gf7ku")
autoplay = "default"
frame = 6
frame_progress = 0.743234
+offset = Vector2(0, -12)
[node name="PointLight2D" type="PointLight2D" parent="."]
-color = Color(1, 0.827451, 0.619608, 1)
+color = Color(1, 0.803922, 0.698039, 1)
+energy = 1.2
blend_mode = 2
-shadow_enabled = true
shadow_filter_smooth = 3.0
-texture = ExtResource("2_yuj6j")
-offset = Vector2(0, 2)
+texture = ExtResource("2_0xpf8")
+texture_scale = 0.25
diff --git a/Entities/UnwantedFrequency.cs b/Entities/UnwantedFrequency.cs
index e2c9932..5a1f8a4 100644
--- a/Entities/UnwantedFrequency.cs
+++ b/Entities/UnwantedFrequency.cs
@@ -15,6 +15,7 @@ public partial class UnwantedFrequency : Projectile
public Node2D TrailRotation { get; set; }
public Node2D TrailPosition { get; set; }
public GpuParticles2D DeathParticles { get; set; }
+ public GpuParticles2D SpawnParticles { get; set; }
public Timer DeferDeathTimer { get; set; }
private double _currentLifetime = 0;
@@ -26,6 +27,8 @@ public partial class UnwantedFrequency : Projectile
Trail = TrailPosition.GetNode("Trail");
DeferDeathTimer = GetNode("DeferDeath");
DeathParticles = GetNode("DeathParticles");
+ SpawnParticles = GetNode("SpawnParticles");
+ SpawnParticles.Emitting = true;
Hitbox.Hit += (BoundingBoxes.BoundingBox box) =>
{
if (box is BoundingBoxes.Hurtbox && box.Faction != Hitbox.Faction)
@@ -62,7 +65,8 @@ public partial class UnwantedFrequency : Projectile
public override void Die()
{
- IsDead = Trail.IsDead = Hitbox.IsDisabled = true;
+ IsDead = Trail.IsDead = true;
+ Hitbox.SetDeferred("monitoring", false);
DeferDeathTimer.Timeout += () =>
{
QueueFree();
diff --git a/Entities/UnwantedFrequency.tscn b/Entities/UnwantedFrequency.tscn
index 8087070..0a21254 100644
--- a/Entities/UnwantedFrequency.tscn
+++ b/Entities/UnwantedFrequency.tscn
@@ -1,4 +1,4 @@
-[gd_scene load_steps=14 format=3 uid="uid://1y5r6sklwgrp"]
+[gd_scene load_steps=19 format=3 uid="uid://1y5r6sklwgrp"]
[ext_resource type="Script" path="res://Entities/UnwantedFrequency.cs" id="1_6sbe0"]
[ext_resource type="PackedScene" uid="uid://du5vhccg75nrq" path="res://BoundingBoxes/Hitbox.tscn" id="2_gxtvd"]
@@ -34,6 +34,36 @@ orbit_velocity_min = 0.0
orbit_velocity_max = 2.0
color_ramp = SubResource("GradientTexture1D_yfhnr")
+[sub_resource type="Gradient" id="Gradient_5hy7c"]
+colors = PackedColorArray(1, 1, 1, 1, 1, 1, 1, 0)
+
+[sub_resource type="GradientTexture1D" id="GradientTexture1D_iyaih"]
+gradient = SubResource("Gradient_5hy7c")
+
+[sub_resource type="Curve" id="Curve_wt1cb"]
+_data = [Vector2(0, 0), 0.0, 0.0, 0, 0, Vector2(0.2, 1), 0.0, 0.0, 0, 0, Vector2(1, 0.5), 0.0, 0.0, 0, 0]
+point_count = 3
+
+[sub_resource type="CurveTexture" id="CurveTexture_5uulw"]
+curve = SubResource("Curve_wt1cb")
+
+[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_olfm2"]
+particle_flag_disable_z = true
+spread = 180.0
+gravity = Vector3(0, 0, 0)
+initial_velocity_min = 32.0
+initial_velocity_max = 32.0
+angular_velocity_min = 90.0
+angular_velocity_max = 90.0
+orbit_velocity_min = 0.0
+orbit_velocity_max = 0.0
+tangential_accel_min = 8.0
+tangential_accel_max = 8.0
+scale_max = 2.0
+scale_curve = SubResource("CurveTexture_5uulw")
+color = Color(1, 0, 0, 1)
+color_ramp = SubResource("GradientTexture1D_iyaih")
+
[sub_resource type="Animation" id="Animation_w1abs"]
length = 0.001
tracks/0/type = "value"
@@ -73,12 +103,12 @@ _data = {
[node name="UnwantedFrequency" type="RigidBody2D" node_paths=PackedStringArray("Hitbox")]
script = ExtResource("1_6sbe0")
-HomingVelocity = 1.4
+HomingVelocity = 1.2
ProjectileName = "Unwanted Frequency"
-Speed = 140.0
+Speed = 124.0
Direction = Vector2(1, 1)
Hitbox = NodePath("Hitbox")
-Lifetime = 8.0
+Lifetime = 7.0
[node name="Hitbox" parent="." instance=ExtResource("2_gxtvd")]
collision_layer = 0
@@ -122,6 +152,14 @@ lifetime = 2.0
one_shot = true
explosiveness = 0.8
+[node name="SpawnParticles" type="GPUParticles2D" parent="."]
+emitting = false
+amount = 12
+process_material = SubResource("ParticleProcessMaterial_olfm2")
+lifetime = 2.0
+one_shot = true
+explosiveness = 1.0
+
[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
libraries = {
"": SubResource("AnimationLibrary_v8fdt")
diff --git a/Extensions/Node.cs b/Extensions/Node.cs
index cf7191c..d29dd43 100644
--- a/Extensions/Node.cs
+++ b/Extensions/Node.cs
@@ -38,4 +38,17 @@ public static class NodeExtensions
{
return node.GetNode(name) as T;
}
+
+ public static T FindChildOfType(this Node node) where T : Node
+ {
+ foreach (Node child in node.GetChildren())
+ {
+ if (child is T t)
+ {
+ return t;
+ }
+ }
+
+ return null;
+ }
}
diff --git a/Extensions/Node2DExtensions.cs b/Extensions/Node2DExtensions.cs
index ab70549..c62366e 100644
--- a/Extensions/Node2DExtensions.cs
+++ b/Extensions/Node2DExtensions.cs
@@ -30,6 +30,7 @@ public static class Node2DExtensions
var clone = node.Duplicate() as T;
world.AddChild(clone);
clone.GlobalPosition = node.GlobalPosition;
+ GD.Print("clone on world: " + clone.GlobalPosition);
return clone;
}
diff --git a/Extensions/Particles2D.cs b/Extensions/Particles2D.cs
index fb76d57..9fdee78 100644
--- a/Extensions/Particles2D.cs
+++ b/Extensions/Particles2D.cs
@@ -10,5 +10,6 @@ public static class Particles2D
{
particles.QueueFree();
};
+ particles.Emitting = true;
}
}
diff --git a/Items/Inventory.cs b/Items/Inventory.cs
index fe50d2f..18190fb 100644
--- a/Items/Inventory.cs
+++ b/Items/Inventory.cs
@@ -14,6 +14,9 @@ public partial class Inventory : Node2D
[Export]
public Dictionary InventoryMap { get; set; }
+ [Signal]
+ public delegate void UsedItemEventHandler(Item item);
+
public const int MaxCapacity = 32;
private Item _selectedItem;
diff --git a/Items/Weapon.cs b/Items/Weapon.cs
index 2d6a497..26d74eb 100644
--- a/Items/Weapon.cs
+++ b/Items/Weapon.cs
@@ -53,6 +53,9 @@ public abstract partial class Weapon : Item
[Export]
public float MaxDistanceHint { get; set; }
+ [Export]
+ public Sprite2D HandAnchor { get; set; }
+
public virtual bool IsParryable { get; protected set; } = false;
public bool IsParried { get; set; }
@@ -70,6 +73,12 @@ public abstract partial class Weapon : Item
Visible = true;
}
Character = character;
+
+ // set the hand textures to the character's
+ if (HandAnchor is not null && character.HandTexture is not null)
+ {
+ HandAnchor.Texture = character.HandTexture;
+ }
}
public override void Unequip(Character character)
@@ -99,7 +108,7 @@ public abstract partial class Weapon : Item
}
}
- public virtual void _on_hitbox_hit(BoundingBox box)
+ public virtual void OnHitboxHit(BoundingBox box)
{
if (box is Hurtbox hurtbox)
{
diff --git a/Items/Weapons/DocLance.tscn b/Items/Weapons/DocLance.tscn
new file mode 100644
index 0000000..6db849d
--- /dev/null
+++ b/Items/Weapons/DocLance.tscn
@@ -0,0 +1,293 @@
+[gd_scene load_steps=21 format=3 uid="uid://p7oijq6dbvvk"]
+
+[ext_resource type="Script" path="res://Items/Weapons/Sword.cs" id="1_1oyma"]
+[ext_resource type="Script" path="res://State/Weapon/WeaponStateMachine.cs" id="2_c41ov"]
+[ext_resource type="Script" path="res://State/Weapon/SwordIdleState.cs" id="3_sxffm"]
+[ext_resource type="Script" path="res://State/Weapon/SwordAnticipateState.cs" id="4_t7af2"]
+[ext_resource type="Script" path="res://State/Weapon/SwordAttackState.cs" id="5_i5v42"]
+[ext_resource type="Texture2D" uid="uid://o7enu13gvji5" path="res://Assets/Sprites/doc-lance.png" id="6_7t87o"]
+[ext_resource type="Material" uid="uid://cbfaqolx1ydvv" path="res://Assets/Sprites/Particles/ParryParticles.tres" id="8_y2qyn"]
+[ext_resource type="PackedScene" uid="uid://du5vhccg75nrq" path="res://BoundingBoxes/Hitbox.tscn" id="9_buajm"]
+[ext_resource type="Texture2D" uid="uid://cmvh6pc71ir1m" path="res://Assets/Sprites/sword-swing-large.png" id="11_46l1i"]
+[ext_resource type="AudioStream" uid="uid://qvthq6tppp63" path="res://Assets/Sounds/whoosh.wav" id="12_85vwu"]
+[ext_resource type="AudioStream" uid="uid://cceld51anbm1m" path="res://Assets/Sounds/unsheathe.wav" id="12_khh4e"]
+[ext_resource type="AudioStream" uid="uid://c4n7ioxpukdwi" path="res://Assets/Sounds/parry.wav" id="13_p4djk"]
+
+[sub_resource type="Curve" id="Curve_36q15"]
+_data = [Vector2(0, 1), 0.0, 0.0, 0, 0, Vector2(0.5, 1), 0.0, 0.0, 0, 0, Vector2(1, 0.5), 0.0, 0.0, 0, 0]
+point_count = 3
+
+[sub_resource type="CurveTexture" id="CurveTexture_383y7"]
+curve = SubResource("Curve_36q15")
+
+[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_duy55"]
+emission_shape = 3
+emission_box_extents = Vector3(1, 1, 1)
+particle_flag_disable_z = true
+direction = Vector3(0, 1, 0)
+spread = 60.0
+gravity = Vector3(0, 0, 0)
+initial_velocity_min = 8.0
+initial_velocity_max = 16.0
+orbit_velocity_min = 0.0
+orbit_velocity_max = 0.0
+scale_min = 2.0
+scale_max = 2.0
+scale_curve = SubResource("CurveTexture_383y7")
+color = Color(1, 0, 1, 1)
+
+[sub_resource type="Animation" id="Animation_b7327"]
+length = 0.001
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath("Anchor:rotation")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 1,
+"values": [1.5708]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath("SwingSprite:frame")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 1,
+"values": [0]
+}
+tracks/2/type = "value"
+tracks/2/imported = false
+tracks/2/enabled = true
+tracks/2/path = NodePath("Anchor:position")
+tracks/2/interp = 1
+tracks/2/loop_wrap = true
+tracks/2/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 1,
+"values": [Vector2(0, 0)]
+}
+tracks/3/type = "value"
+tracks/3/imported = false
+tracks/3/enabled = true
+tracks/3/path = NodePath("Anchor/Node2D:rotation")
+tracks/3/interp = 1
+tracks/3/loop_wrap = true
+tracks/3/keys = {
+"times": PackedFloat32Array(0, 0.0001, 0.0002),
+"transitions": PackedFloat32Array(1, 1, 1),
+"update": 1,
+"values": [0.0, 0.0, 0.0]
+}
+tracks/4/type = "method"
+tracks/4/imported = false
+tracks/4/enabled = true
+tracks/4/path = NodePath(".")
+tracks/4/interp = 1
+tracks/4/loop_wrap = true
+tracks/4/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"values": [{
+"args": ["is_alternate", false],
+"method": &"SetAnimationCondition"
+}]
+}
+tracks/5/type = "value"
+tracks/5/imported = false
+tracks/5/enabled = true
+tracks/5/path = NodePath("SwingSprite:modulate")
+tracks/5/interp = 1
+tracks/5/loop_wrap = true
+tracks/5/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [Color(2, 2, 2, 1)]
+}
+
+[sub_resource type="Animation" id="Animation_ameas"]
+resource_name = "anticipate"
+length = 0.1
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath("Anchor:position")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0, 0.1),
+"transitions": PackedFloat32Array(1, 1),
+"update": 0,
+"values": [Vector2(0, 0), Vector2(-8, 0)]
+}
+tracks/1/type = "method"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath("UnsheatheSound")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"values": [{
+"args": [0.0],
+"method": &"play"
+}]
+}
+
+[sub_resource type="Animation" id="Animation_6jphj"]
+resource_name = "attack"
+step = 0.05
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath("Anchor:position")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0, 0.1, 0.65),
+"transitions": PackedFloat32Array(1, 1, 1),
+"update": 1,
+"values": [Vector2(-8, 0), Vector2(8, 0), Vector2(0, 0)]
+}
+tracks/1/type = "method"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath("SwingSound")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0.1),
+"transitions": PackedFloat32Array(1),
+"values": [{
+"args": [0.0],
+"method": &"play"
+}]
+}
+
+[sub_resource type="AnimationLibrary" id="AnimationLibrary_tao4k"]
+_data = {
+"RESET": SubResource("Animation_b7327"),
+"anticipate": SubResource("Animation_ameas"),
+"attack": SubResource("Animation_6jphj")
+}
+
+[sub_resource type="RectangleShape2D" id="RectangleShape2D_rrgwb"]
+size = Vector2(8, 32)
+
+[node name="DocLance" type="Node2D" node_paths=PackedStringArray("Hitbox", "AnimationPlayer", "ParryParticles", "StateMachine", "Anchor", "HandAnchor")]
+y_sort_enabled = true
+texture_filter = 3
+script = ExtResource("1_1oyma")
+Hitbox = NodePath("Hitbox")
+AnimationPlayer = NodePath("AnimationPlayer")
+AttackTime = 0.2
+AttackAnimationDuration = 0.75
+ParryParticles = NodePath("Anchor/Node2D/Sprite2D/ParryParticles")
+NPCAnticipateTime = 0.3
+StateMachine = NodePath("State")
+Anchor = NodePath("Anchor")
+Damage = 20.0
+UseTime = 0.55
+Knockback = 64.0
+ShouldHideIdle = true
+HandAnchor = NodePath("Anchor/Node2D/Sprite2D/Hand")
+ItemName = "VSM-93"
+Description = "\"Violence. Speed. Momentum.\""
+
+[node name="State" type="Node" parent="." node_paths=PackedStringArray("InitialState")]
+script = ExtResource("2_c41ov")
+InitialState = NodePath("Idle")
+
+[node name="Idle" type="Node" parent="State" node_paths=PackedStringArray("AnticipateState", "Sword")]
+script = ExtResource("3_sxffm")
+AnticipateState = NodePath("../Anticipate")
+Sword = NodePath("../..")
+
+[node name="Anticipate" type="Node" parent="State" node_paths=PackedStringArray("Sword", "AttackState")]
+script = ExtResource("4_t7af2")
+Sword = NodePath("../..")
+AttackState = NodePath("../Attack")
+
+[node name="Attack" type="Node" parent="State" node_paths=PackedStringArray("Sword", "IdleState")]
+script = ExtResource("5_i5v42")
+Sword = NodePath("../..")
+IdleState = NodePath("../Idle")
+
+[node name="Anchor" type="Node2D" parent="."]
+y_sort_enabled = true
+rotation = 1.5708
+
+[node name="Node2D" type="Node2D" parent="Anchor"]
+y_sort_enabled = true
+position = Vector2(-4, 0)
+
+[node name="Sprite2D" type="Sprite2D" parent="Anchor/Node2D"]
+y_sort_enabled = true
+position = Vector2(0, -8)
+texture = ExtResource("6_7t87o")
+
+[node name="ParryParticles" type="GPUParticles2D" parent="Anchor/Node2D/Sprite2D"]
+modulate = Color(1.2, 1.2, 1.2, 1)
+position = Vector2(-0.221825, -3.12132)
+rotation = 0.785398
+emitting = false
+amount = 16
+process_material = ExtResource("8_y2qyn")
+lifetime = 2.0
+one_shot = true
+explosiveness = 1.0
+trail_enabled = true
+trail_lifetime = 0.1
+trail_sections = 4
+
+[node name="GPUParticles2D" type="GPUParticles2D" parent="Anchor/Node2D/Sprite2D"]
+position = Vector2(-2.28882e-05, -6)
+amount = 4
+process_material = SubResource("ParticleProcessMaterial_duy55")
+lifetime = 0.25
+
+[node name="Hand" type="Sprite2D" parent="Anchor/Node2D/Sprite2D"]
+position = Vector2(-2.52724e-05, 7)
+rotation = 1.5708
+
+[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
+libraries = {
+"": SubResource("AnimationLibrary_tao4k")
+}
+
+[node name="Hitbox" parent="." instance=ExtResource("9_buajm")]
+position = Vector2(16, -4)
+IsDisabled = true
+
+[node name="CollisionShape2D" parent="Hitbox" index="0"]
+rotation = 1.5708
+shape = SubResource("RectangleShape2D_rrgwb")
+disabled = true
+
+[node name="SwingSprite" type="Sprite2D" parent="."]
+modulate = Color(2, 2, 2, 1)
+texture = ExtResource("11_46l1i")
+offset = Vector2(8, 0)
+hframes = 5
+
+[node name="SwingSound" type="AudioStreamPlayer2D" parent="."]
+stream = ExtResource("12_85vwu")
+max_distance = 256.0
+
+[node name="ParrySound" type="AudioStreamPlayer2D" parent="."]
+stream = ExtResource("13_p4djk")
+max_distance = 256.0
+
+[node name="UnsheatheSound" type="AudioStreamPlayer2D" parent="."]
+stream = ExtResource("12_khh4e")
+
+[editable path="Hitbox"]
diff --git a/Items/Weapons/DocLanceHold.tscn b/Items/Weapons/DocLanceHold.tscn
new file mode 100644
index 0000000..5e13544
--- /dev/null
+++ b/Items/Weapons/DocLanceHold.tscn
@@ -0,0 +1,20 @@
+[gd_scene load_steps=3 format=3 uid="uid://bauucuqvjwbxp"]
+
+[ext_resource type="PackedScene" uid="uid://p7oijq6dbvvk" path="res://Items/Weapons/DocLance.tscn" id="1_kmq5r"]
+[ext_resource type="Script" path="res://State/Weapon/SwordHoldAttackState.cs" id="2_7fom6"]
+
+[node name="DocLance" instance=ExtResource("1_kmq5r")]
+NPCAnticipateTime = 0.1
+
+[node name="Anticipate" parent="State" index="1" node_paths=PackedStringArray("AttackState")]
+AttackState = NodePath("../HoldAttack")
+
+[node name="Attack" parent="State" index="2"]
+script = ExtResource("2_7fom6")
+
+[node name="HoldAttack" type="Node" parent="State" index="3" node_paths=PackedStringArray("Sword", "IdleState")]
+script = ExtResource("2_7fom6")
+Sword = NodePath("../..")
+IdleState = NodePath("../Idle")
+
+[editable path="Hitbox"]
diff --git a/Items/Weapons/Lance.cs b/Items/Weapons/Lance.cs
new file mode 100644
index 0000000..b8702a2
--- /dev/null
+++ b/Items/Weapons/Lance.cs
@@ -0,0 +1,13 @@
+/*
+using Godot;
+
+namespace SupaLidlGame.Items.Weapons;
+
+public partial class Lance : Sword
+{
+ public override void _Ready()
+ {
+
+ }
+}
+*/
diff --git a/Items/Weapons/Sword.cs b/Items/Weapons/Sword.cs
index 12a719d..29bb16b 100644
--- a/Items/Weapons/Sword.cs
+++ b/Items/Weapons/Sword.cs
@@ -20,9 +20,6 @@ public partial class Sword : Weapon, IParryable
[Export]
public AnimationPlayer AnimationPlayer { get; set; }
- [Export]
- public AnimationTree AnimationTree { get; set; }
-
///
/// The time frame in seconds for which the weapon will deal damage.
///
@@ -37,7 +34,7 @@ public partial class Sword : Weapon, IParryable
public double AttackAnimationDuration { get; set; }
[Export]
- public CpuParticles2D ParryParticles { get; set; }
+ public GpuParticles2D ParryParticles { get; set; }
[Export]
public double NPCAnticipateTime { get; set; }
@@ -69,41 +66,7 @@ public partial class Sword : Weapon, IParryable
public override void Use()
{
- // we can't use if we're still using the weapon
- if (RemainingUseTime > 0)
- {
- //return;
- }
-
StateMachine.Use();
-
- /*
- // reset state of the weapon
- IsParried = false;
- IsParryable = true;
- ParryTimeOrigin = Time.GetTicksMsec();
-
- _playback.Travel("use");
- */
-
- // play animation depending on rotation of weapon
- /*
- string anim = "use";
-
- if (GetNode("Anchor").Rotation > Mathf.DegToRad(50))
- {
- anim = "use2";
- }
-
- if (Character is NPC)
- {
- // NPCs have a slower attack
- anim += "-npc";
- }
-
- AnimationPlayer.Play(anim);
- */
-
base.Use();
}
@@ -112,7 +75,6 @@ public partial class Sword : Weapon, IParryable
IsParried = false;
IsParryable = true;
ParryTimeOrigin = Time.GetTicksMsec();
- GD.Print(Character.Name);
}
public void DisableParry()
@@ -123,7 +85,8 @@ public partial class Sword : Weapon, IParryable
public override void Deuse()
{
//AnimationPlayer.Stop();
- Deattack();
+ //Deattack();
+ StateMachine.Deuse();
base.Deuse();
}
@@ -147,8 +110,7 @@ public partial class Sword : Weapon, IParryable
public override void _Ready()
{
Hitbox.Damage = Damage;
- _playback = (AnimationNodeStateMachinePlayback)AnimationTree
- .Get("parameters/playback");
+ Hitbox.Hit += OnHitboxHit;
}
public override void _Process(double delta)
@@ -166,9 +128,9 @@ public partial class Sword : Weapon, IParryable
foreach (BoundingBox box in Hitbox.Hits)
{
- GD.Print("processing hit");
if (box is Hurtbox hurtbox)
{
+ GD.Print("LUL");
hurtbox.InflictDamage(Damage, Character, Knockback);
}
}
@@ -176,32 +138,33 @@ public partial class Sword : Weapon, IParryable
public void AttemptParry(Weapon otherWeapon)
{
- //if (IsParryable && otherWeapon.IsParryable)
if (otherWeapon.IsParryable &&
- otherWeapon is IParryable otherParryable)
+ otherWeapon is IParryable otherParryable)
{
- ParryParticles.Emitting = true;
if (ParryTimeOrigin < otherParryable.ParryTimeOrigin)
{
// our character was parried
+ ParryParticles.CloneOnWorld().EmitOneShot();
}
else
{
otherParryable.Stun();
}
}
- //this.GetAncestor().AddChild(instance);
}
public void Stun()
{
IsParried = true;
AnimationPlayer.SpeedScale = 0.25f;
- Character.Stun(1.5f);
- GetNode("ParrySound").OnWorld().PlayOneShot();
+ Character.Stun(1);
+ GetNode("ParrySound")
+ .OnWorld()
+ .WithPitchDeviation(0.125f)
+ .PlayOneShot();
}
- public override void _on_hitbox_hit(BoundingBox box)
+ public override void OnHitboxHit(BoundingBox box)
{
if (IsParried)
{
@@ -232,6 +195,6 @@ public partial class Sword : Weapon, IParryable
protected void SetAnimationCondition(string condition, bool value)
{
- AnimationTree.Set("parameters/conditions/" + condition, value);
+
}
}
diff --git a/Items/Weapons/Sword.tscn b/Items/Weapons/Sword.tscn
index 0b53cac..c9d0d02 100644
--- a/Items/Weapons/Sword.tscn
+++ b/Items/Weapons/Sword.tscn
@@ -1,4 +1,4 @@
-[gd_scene load_steps=35 format=3 uid="uid://dvqap2uhcah63"]
+[gd_scene load_steps=36 format=3 uid="uid://dvqap2uhcah63"]
[ext_resource type="Script" path="res://Items/Weapons/Sword.cs" id="1_mlo73"]
[ext_resource type="Script" path="res://State/Weapon/WeaponStateMachine.cs" id="2_vwirq"]
@@ -8,8 +8,11 @@
[ext_resource type="Script" path="res://State/Weapon/SwordAnticipateState.cs" id="4_j3cud"]
[ext_resource type="PackedScene" uid="uid://cojxmcin13ihm" path="res://Utils/Trail.tscn" id="4_pt6lq"]
[ext_resource type="Script" path="res://State/Weapon/SwordAttackState.cs" id="5_hmisb"]
-[ext_resource type="Texture2D" uid="uid://do1bui3bblkk7" path="res://Assets/Sprites/sword-swing.png" id="5_pywek"]
[ext_resource type="AudioStream" uid="uid://c4n7ioxpukdwi" path="res://Assets/Sounds/parry.wav" id="6_8nxjm"]
+[ext_resource type="Material" uid="uid://cbfaqolx1ydvv" path="res://Assets/Sprites/Particles/ParryParticles.tres" id="8_10gir"]
+[ext_resource type="Shape2D" uid="uid://dw4e4r2yxwk1b" path="res://Items/Weapons/SwordCollisionShape.tres" id="9_wsprl"]
+[ext_resource type="Texture2D" uid="uid://cmvh6pc71ir1m" path="res://Assets/Sprites/sword-swing-large.png" id="10_672jv"]
+[ext_resource type="AudioStream" uid="uid://qvthq6tppp63" path="res://Assets/Sounds/whoosh.wav" id="10_mfnl7"]
[sub_resource type="Environment" id="Environment_72txp"]
background_mode = 3
@@ -24,10 +27,6 @@ point_count = 3
offsets = PackedFloat32Array(0.835938, 0.992188)
colors = PackedColorArray(1, 1, 1, 0.498039, 1, 1, 1, 0)
-[sub_resource type="Gradient" id="Gradient_jjxq2"]
-offsets = PackedFloat32Array(0, 0.945312)
-colors = PackedColorArray(1, 1, 1, 1, 0.687215, 0.687215, 0.687215, 0)
-
[sub_resource type="Animation" id="Animation_b7327"]
length = 0.001
tracks/0/type = "value"
@@ -92,6 +91,18 @@ tracks/4/keys = {
"method": &"SetAnimationCondition"
}]
}
+tracks/5/type = "value"
+tracks/5/imported = false
+tracks/5/enabled = true
+tracks/5/path = NodePath("SwingSprite:modulate")
+tracks/5/interp = 1
+tracks/5/loop_wrap = true
+tracks/5/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [Color(2, 2, 2, 1)]
+}
[sub_resource type="Animation" id="Animation_ameas"]
resource_name = "anticipate"
@@ -162,7 +173,7 @@ tracks/1/path = NodePath("SwingSprite:frame")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
-"times": PackedFloat32Array(0.1, 0.2, 0.4),
+"times": PackedFloat32Array(0.1, 0.3, 0.35),
"transitions": PackedFloat32Array(1, 1, 1),
"update": 1,
"values": [1, 2, 0]
@@ -202,6 +213,20 @@ tracks/4/keys = {
"transitions": PackedFloat32Array(),
"values": []
}
+tracks/5/type = "method"
+tracks/5/imported = false
+tracks/5/enabled = true
+tracks/5/path = NodePath("SwingSound")
+tracks/5/interp = 1
+tracks/5/loop_wrap = true
+tracks/5/keys = {
+"times": PackedFloat32Array(0.1),
+"transitions": PackedFloat32Array(1),
+"values": [{
+"args": [0.0],
+"method": &"play"
+}]
+}
[sub_resource type="Animation" id="Animation_pclfs"]
resource_name = "attack_alternate"
@@ -225,10 +250,10 @@ tracks/1/path = NodePath("SwingSprite:frame")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
-"times": PackedFloat32Array(0.1, 0.2, 0.4),
+"times": PackedFloat32Array(0.1, 0.3, 0.35),
"transitions": PackedFloat32Array(1, 1, 1),
"update": 1,
-"values": [1, 3, 0]
+"values": [3, 4, 0]
}
tracks/2/type = "value"
tracks/2/imported = false
@@ -328,11 +353,7 @@ graph_offset = Vector2(0, -104.073)
[sub_resource type="AnimationNodeStateMachinePlayback" id="AnimationNodeStateMachinePlayback_o5g2u"]
-[sub_resource type="CapsuleShape2D" id="CapsuleShape2D_ic623"]
-radius = 20.0
-height = 48.0
-
-[node name="Sword" type="Node2D" node_paths=PackedStringArray("Hitbox", "AnimationPlayer", "AnimationTree", "ParryParticles", "StateMachine", "Anchor")]
+[node name="Sword" type="Node2D" node_paths=PackedStringArray("Hitbox", "AnimationPlayer", "AnimationTree", "ParryParticles", "StateMachine", "Anchor", "HandAnchor")]
y_sort_enabled = true
texture_filter = 3
script = ExtResource("1_mlo73")
@@ -349,6 +370,7 @@ Damage = 20.0
UseTime = 0.55
Knockback = 64.0
ShouldHideIdle = true
+HandAnchor = NodePath("Anchor/Node2D/Sprite2D/Hand")
[node name="State" type="Node" parent="." node_paths=PackedStringArray("InitialState")]
script = ExtResource("2_vwirq")
@@ -392,23 +414,23 @@ y_sort_enabled = true
position = Vector2(0, -8)
texture = ExtResource("3_r75ni")
-[node name="ParryParticles" type="CPUParticles2D" parent="Anchor/Node2D/Sprite2D"]
+[node name="ParryParticles" type="GPUParticles2D" parent="Anchor/Node2D/Sprite2D"]
modulate = Color(1.2, 1.2, 1.2, 1)
position = Vector2(-0.221825, -3.12132)
rotation = 0.785398
emitting = false
-amount = 24
-lifetime = 0.4
+amount = 16
+process_material = ExtResource("8_10gir")
+lifetime = 2.0
one_shot = true
explosiveness = 1.0
-emission_shape = 1
-emission_sphere_radius = 4.0
-direction = Vector2(0, -1)
-spread = 180.0
-gravity = Vector2(0, 200)
-initial_velocity_min = 8.0
-initial_velocity_max = 64.0
-color_ramp = SubResource("Gradient_jjxq2")
+trail_enabled = true
+trail_lifetime = 0.1
+trail_sections = 4
+
+[node name="Hand" type="Sprite2D" parent="Anchor/Node2D/Sprite2D"]
+position = Vector2(-2.52724e-05, 7)
+rotation = 1.5708
[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
libraries = {
@@ -428,22 +450,21 @@ IsDisabled = true
[node name="CollisionShape2D" parent="Hitbox" index="0"]
position = Vector2(4, 0)
rotation = 1.5708
-shape = SubResource("CapsuleShape2D_ic623")
+shape = ExtResource("9_wsprl")
disabled = true
[node name="SwingSprite" type="Sprite2D" parent="."]
modulate = Color(2, 2, 2, 1)
-texture = ExtResource("5_pywek")
+texture = ExtResource("10_672jv")
offset = Vector2(8, 0)
-hframes = 4
+hframes = 5
[node name="SwingSound" type="AudioStreamPlayer2D" parent="."]
+stream = ExtResource("10_mfnl7")
max_distance = 256.0
[node name="ParrySound" type="AudioStreamPlayer2D" parent="."]
stream = ExtResource("6_8nxjm")
max_distance = 256.0
-[connection signal="Hit" from="Hitbox" to="." method="_on_hitbox_hit"]
-
[editable path="Hitbox"]
diff --git a/Items/Weapons/SwordCollisionShape.tres b/Items/Weapons/SwordCollisionShape.tres
new file mode 100644
index 0000000..5a21280
--- /dev/null
+++ b/Items/Weapons/SwordCollisionShape.tres
@@ -0,0 +1,4 @@
+[gd_resource type="ConvexPolygonShape2D" format=3 uid="uid://dw4e4r2yxwk1b"]
+
+[resource]
+points = PackedVector2Array(0, 0, -21.213, 21.213, -30, 0, -21.213, -21.213, 0, -30, 21.213, -21.213, 30, 0, 21.213, 21.213, 0, 0)
diff --git a/README.org b/README.org
index af43069..18eb7fa 100644
--- a/README.org
+++ b/README.org
@@ -2,8 +2,5 @@
Forsen-related game
-Issue below fixed with [[https://github.com/godotengine/godot/pull/68866]]. Please update your version to ~4.0.beta6.mono~.
-
-+*NOTE:* although the latest version at the time of writing is ~4.0.beta5.mono~, this project only works under ~4.0.beta4.mono~. The latest beta does not include node exports, which was previously in Beta 4.+
-
-+[[https://github.com/godotengine/godot/pull/67055]]+
+#+attr_html: :style margin-left: auto; margin-right: auto;
+[[./Assets/Sprites/Characters/forsen2-portrait.png]]
diff --git a/Scenes/Level.tscn b/Scenes/Level.tscn
index 910e672..4493032 100644
--- a/Scenes/Level.tscn
+++ b/Scenes/Level.tscn
@@ -1,8 +1,56 @@
-[gd_scene load_steps=3 format=3 uid="uid://1pb3mpmrl7lc"]
+[gd_scene load_steps=6 format=3 uid="uid://1pb3mpmrl7lc"]
[ext_resource type="Script" path="res://Utils/World.cs" id="1_1k6ew"]
[ext_resource type="PackedScene" uid="uid://b2x17su05ou5w" path="res://Scenes/Maps/Arena.tscn" id="2_avsrq"]
+[ext_resource type="PackedScene" uid="uid://bxo553hblp6nf" path="res://UI/HealthBar.tscn" id="3_5rhge"]
+[ext_resource type="Script" path="res://UI/UIController.cs" id="3_fe62s"]
+[ext_resource type="PackedScene" uid="uid://01d24ij5av1y" path="res://UI/BossBar.tscn" id="5_8njq4"]
[node name="World" type="Node2D"]
script = ExtResource("1_1k6ew")
StartingArea = ExtResource("2_avsrq")
+
+[node name="CanvasLayer" type="CanvasLayer" parent="."]
+
+[node name="UI" type="Control" parent="CanvasLayer"]
+z_index = 128
+layout_mode = 3
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+size_flags_horizontal = 3
+size_flags_vertical = 3
+script = ExtResource("3_fe62s")
+
+[node name="Top" type="HBoxContainer" parent="CanvasLayer/UI"]
+layout_mode = 1
+anchors_preset = 10
+anchor_right = 1.0
+offset_bottom = 40.0
+grow_horizontal = 2
+
+[node name="Margin" type="MarginContainer" parent="CanvasLayer/UI/Top"]
+layout_mode = 2
+theme_override_constants/margin_left = 16
+theme_override_constants/margin_top = 16
+
+[node name="HealthBar" parent="CanvasLayer/UI/Top/Margin" instance=ExtResource("3_5rhge")]
+layout_mode = 2
+size_flags_horizontal = 3
+
+[node name="Bottom" type="HBoxContainer" parent="CanvasLayer/UI"]
+visible = false
+layout_mode = 1
+anchors_preset = 12
+anchor_top = 1.0
+anchor_right = 1.0
+anchor_bottom = 1.0
+offset_top = -44.0
+grow_horizontal = 2
+grow_vertical = 0
+alignment = 1
+
+[node name="BossBar" parent="CanvasLayer/UI/Bottom" instance=ExtResource("5_8njq4")]
+layout_mode = 2
diff --git a/Scenes/Maps/Arena.tscn b/Scenes/Maps/Arena.tscn
index 4cf9b93..edd55cc 100644
--- a/Scenes/Maps/Arena.tscn
+++ b/Scenes/Maps/Arena.tscn
@@ -1,23 +1,51 @@
-[gd_scene load_steps=13 format=3 uid="uid://b2x17su05ou5w"]
+[gd_scene load_steps=15 format=3 uid="uid://b2x17su05ou5w"]
[ext_resource type="PackedScene" uid="uid://clwv2owvk6abe" path="res://Scenes/BaseMap.tscn" id="1_ifiic"]
[ext_resource type="Texture2D" uid="uid://b0yiy7w8nxmas" path="res://Assets/Sprites/arena-tileset.png" id="2_wnjm0"]
-[ext_resource type="PackedScene" uid="uid://d2skjvvx6fal0" path="res://Characters/Doc.tscn" id="4_c0csw"]
-[ext_resource type="Shader" path="res://Shaders/Flash.gdshader" id="5_aevwf"]
+[ext_resource type="PackedScene" uid="uid://d2skjvvx6fal0" path="res://Characters/Doc.tscn" id="4_ej0f3"]
+[ext_resource type="Shader" path="res://Shaders/Flash.gdshader" id="5_h8k5p"]
[ext_resource type="PackedScene" uid="uid://c1w7t6irnohfx" path="res://Entities/Torch.tscn" id="6_1wwor"]
[ext_resource type="PackedScene" uid="uid://ceadk7pam7vab" path="res://Entities/TorchLamp.tscn" id="6_jy3pc"]
+[ext_resource type="Texture2D" uid="uid://d1ukste16yq6v" path="res://Assets/Sprites/Particles/player-light.png" id="7_y7j0e"]
-[sub_resource type="OccluderPolygon2D" id="OccluderPolygon2D_8jil2"]
-polygon = PackedVector2Array(-8, -4, -6, -5, -6, -18, 6, -18, 6, -5, 8, -4, 8, 4, 4, 8, -4, 8, -8, 3.5)
+[sub_resource type="CanvasTexture" id="CanvasTexture_3n6aa"]
+diffuse_texture = ExtResource("2_wnjm0")
[sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_fcd6d"]
-texture = ExtResource("2_wnjm0")
+texture = SubResource("CanvasTexture_3n6aa")
+use_texture_padding = false
0:0/0 = 0
0:0/0/physics_layer_0/linear_velocity = Vector2(0, 0)
0:0/0/physics_layer_0/angular_velocity = 0.0
+1:1/0 = 0
+1:1/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+1:1/0/physics_layer_0/angular_velocity = 0.0
+2:1/0 = 0
+2:1/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+2:1/0/physics_layer_0/angular_velocity = 0.0
+2:1/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
+2:2/0 = 0
+2:2/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+2:2/0/physics_layer_0/angular_velocity = 0.0
+2:2/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, 0, 8, 0, 8, 8, -8, 8)
1:0/0 = 0
1:0/0/physics_layer_0/linear_velocity = Vector2(0, 0)
1:0/0/physics_layer_0/angular_velocity = 0.0
+0:1/0 = 0
+0:1/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+0:1/0/physics_layer_0/angular_velocity = 0.0
+0:2/0 = 0
+0:2/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+0:2/0/physics_layer_0/angular_velocity = 0.0
+0:3/0 = 0
+0:3/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+0:3/0/physics_layer_0/angular_velocity = 0.0
+1:3/0 = 0
+1:3/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+1:3/0/physics_layer_0/angular_velocity = 0.0
+1:2/0 = 0
+1:2/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+1:2/0/physics_layer_0/angular_velocity = 0.0
2:0/0 = 0
2:0/0/physics_layer_0/linear_velocity = Vector2(0, 0)
2:0/0/physics_layer_0/angular_velocity = 0.0
@@ -35,94 +63,68 @@ texture = ExtResource("2_wnjm0")
6:0/0 = 0
6:0/0/physics_layer_0/linear_velocity = Vector2(0, 0)
6:0/0/physics_layer_0/angular_velocity = 0.0
-7:0/size_in_atlas = Vector2i(1, 2)
-7:0/0 = 0
-7:0/0/texture_origin = Vector2i(0, 8)
-7:0/0/occlusion_layer_0/polygon = SubResource("OccluderPolygon2D_8jil2")
-7:0/0/physics_layer_0/linear_velocity = Vector2(0, 0)
-7:0/0/physics_layer_0/angular_velocity = 0.0
-7:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -4, 8, -4, 8, 3.5, 4.5, 8, -4, 8, -8, 4)
-0:1/0 = 0
-0:1/0/physics_layer_0/linear_velocity = Vector2(0, 0)
-0:1/0/physics_layer_0/angular_velocity = 0.0
-1:1/0 = 0
-1:1/0/physics_layer_0/linear_velocity = Vector2(0, 0)
-1:1/0/physics_layer_0/angular_velocity = 0.0
-2:1/0 = 0
-2:1/0/physics_layer_0/linear_velocity = Vector2(0, 0)
-2:1/0/physics_layer_0/angular_velocity = 0.0
-2:1/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
-3:1/0 = 0
-3:1/0/physics_layer_0/linear_velocity = Vector2(0, 0)
-3:1/0/physics_layer_0/angular_velocity = 0.0
-3:1/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
-4:1/0 = 0
-4:1/0/physics_layer_0/linear_velocity = Vector2(0, 0)
-4:1/0/physics_layer_0/angular_velocity = 0.0
-4:1/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
-5:1/0 = 0
-5:1/0/physics_layer_0/linear_velocity = Vector2(0, 0)
-5:1/0/physics_layer_0/angular_velocity = 0.0
-5:1/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
6:1/0 = 0
6:1/0/physics_layer_0/linear_velocity = Vector2(0, 0)
6:1/0/physics_layer_0/angular_velocity = 0.0
6:1/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
-0:2/0 = 0
-0:2/0/physics_layer_0/linear_velocity = Vector2(0, 0)
-0:2/0/physics_layer_0/angular_velocity = 0.0
-0:2/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
-1:2/0 = 0
-1:2/0/physics_layer_0/linear_velocity = Vector2(0, 0)
-1:2/0/physics_layer_0/angular_velocity = 0.0
-1:2/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
-2:2/0 = 0
-2:2/0/physics_layer_0/linear_velocity = Vector2(0, 0)
-2:2/0/physics_layer_0/angular_velocity = 0.0
+5:1/0 = 0
+5:1/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+5:1/0/physics_layer_0/angular_velocity = 0.0
+5:1/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
+4:1/0 = 0
+4:1/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+4:1/0/physics_layer_0/angular_velocity = 0.0
+4:1/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
+3:1/0 = 0
+3:1/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+3:1/0/physics_layer_0/angular_velocity = 0.0
+3:1/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
3:2/0 = 0
3:2/0/physics_layer_0/linear_velocity = Vector2(0, 0)
3:2/0/physics_layer_0/angular_velocity = 0.0
-3:2/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
+3:2/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 0, -8, 0)
+3:3/0 = 0
+3:3/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+3:3/0/physics_layer_0/angular_velocity = 0.0
+3:3/0/physics_layer_0/polygon_0/points = PackedVector2Array(0, -8, 8, -8, 8, 8, 0, 8)
+2:3/0 = 0
+2:3/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+2:3/0/physics_layer_0/angular_velocity = 0.0
+2:3/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 0, -8, 0, 8, -8, 8)
+4:3/0 = 0
+4:3/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+4:3/0/physics_layer_0/angular_velocity = 0.0
+4:3/0/physics_layer_0/polygon_0/points = PackedVector2Array(8, -8, 8, 0, 0, 0, 0, -8)
4:2/0 = 0
4:2/0/physics_layer_0/linear_velocity = Vector2(0, 0)
4:2/0/physics_layer_0/angular_velocity = 0.0
+4:2/0/physics_layer_0/polygon_0/points = PackedVector2Array(0, 0, 8, 0, 8, 8, 0, 8)
5:2/0 = 0
5:2/0/physics_layer_0/linear_velocity = Vector2(0, 0)
5:2/0/physics_layer_0/angular_velocity = 0.0
+5:2/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, 0, 0, 0, 0, 8, -8, 8)
+5:3/0 = 0
+5:3/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+5:3/0/physics_layer_0/angular_velocity = 0.0
+5:3/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 0, -8, 0, 0, -8, 0)
+6:3/0 = 0
+6:3/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+6:3/0/physics_layer_0/angular_velocity = 0.0
6:2/0 = 0
6:2/0/physics_layer_0/linear_velocity = Vector2(0, 0)
6:2/0/physics_layer_0/angular_velocity = 0.0
7:2/0 = 0
7:2/0/physics_layer_0/linear_velocity = Vector2(0, 0)
7:2/0/physics_layer_0/angular_velocity = 0.0
-0:3/0 = 0
-0:3/0/physics_layer_0/linear_velocity = Vector2(0, 0)
-0:3/0/physics_layer_0/angular_velocity = 0.0
-0:3/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
-1:3/0 = 0
-1:3/0/physics_layer_0/linear_velocity = Vector2(0, 0)
-1:3/0/physics_layer_0/angular_velocity = 0.0
-1:3/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
-2:3/0 = 0
-2:3/0/physics_layer_0/linear_velocity = Vector2(0, 0)
-2:3/0/physics_layer_0/angular_velocity = 0.0
-2:3/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
-3:3/0 = 0
-3:3/0/physics_layer_0/linear_velocity = Vector2(0, 0)
-3:3/0/physics_layer_0/angular_velocity = 0.0
-3:3/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
-4:3/0 = 0
-4:3/0/physics_layer_0/linear_velocity = Vector2(0, 0)
-4:3/0/physics_layer_0/angular_velocity = 0.0
-5:3/0 = 0
-5:3/0/physics_layer_0/linear_velocity = Vector2(0, 0)
-5:3/0/physics_layer_0/angular_velocity = 0.0
-6:3/0 = 0
-6:3/0/physics_layer_0/linear_velocity = Vector2(0, 0)
-6:3/0/physics_layer_0/angular_velocity = 0.0
7:3/0 = 0
7:3/0/physics_layer_0/linear_velocity = Vector2(0, 0)
7:3/0/physics_layer_0/angular_velocity = 0.0
+7:0/size_in_atlas = Vector2i(1, 2)
+7:0/0 = 0
+7:0/0/texture_origin = Vector2i(0, 8)
+7:0/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+7:0/0/physics_layer_0/angular_velocity = 0.0
+7:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -5, 8, -5, 8, 4, 4, 8, -4, 8, -8, 4)
[sub_resource type="OccluderPolygon2D" id="OccluderPolygon2D_kbvre"]
polygon = PackedVector2Array(-4, 8, -8, 4, -8, -4, -6, -4, -6, -20, 6, -20, 6, -4, 8, -4, 8, 4, 4, 8)
@@ -249,11 +251,15 @@ physics_layer_0/collision_layer = 1
sources/2 = SubResource("TileSetAtlasSource_5yxvt")
sources/0 = SubResource("TileSetAtlasSource_fcd6d")
-[sub_resource type="ShaderMaterial" id="ShaderMaterial_im5g2"]
+[sub_resource type="ShaderMaterial" id="ShaderMaterial_q3ile"]
resource_local_to_scene = true
-shader = ExtResource("5_aevwf")
+shader = ExtResource("5_h8k5p")
shader_parameter/color = Quaternion(1, 1, 1, 1)
shader_parameter/intensity = 0.0
+shader_parameter/alpha_modulate = 1.0
+
+[sub_resource type="RectangleShape2D" id="RectangleShape2D_gwpea"]
+size = Vector2(256, 256)
[node name="TileMap" instance=ExtResource("1_ifiic")]
tile_set = SubResource("TileSet_k1u48")
@@ -262,42 +268,99 @@ layer_3/tile_data = PackedInt32Array(-196612, 65536, 1, -131076, 65536, 1, -6554
layer_4/tile_data = PackedInt32Array(-524296, 327680, 0, -589818, 262144, 0, -589817, 262144, 1, -589819, 327680, 0, -589820, 196608, 1, -589821, 327680, 1, -589822, 131072, 1, -589823, 262144, 1, -589824, 327680, 0, -524289, 131072, 1, -524290, 327680, 0, -524291, 327680, 1, -524292, 327680, 1, -524293, 327680, 0, -524294, 131072, 1, -524295, 262144, 1, -589832, 131072, 2, -589831, 131072, 2, -589830, 131072, 2, -589829, 131072, 2, -589828, 131072, 2, -589827, 131072, 2, -589826, 131072, 2, -589825, 131072, 2, -655360, 131072, 2, -655359, 131072, 2, -655358, 131072, 2, -655357, 131072, 2, -655356, 131072, 2, -655355, 131072, 2, -655354, 131072, 2, -655353, 131072, 2, -655352, 327680, 2, -589833, 262144, 2, -524297, 196608, 3, -458761, 196608, 3, -393225, 196608, 3, -327689, 196608, 3, -262153, 196608, 3, -196617, 196608, 3, -131081, 196608, 3, -65545, 196608, 3, -9, 196608, 3, 65527, 196608, 3, 131063, 196608, 3, 196599, 196608, 3, 262135, 196608, 3, 327671, 196608, 3, 393207, 196608, 3, 458743, 196608, 3, 524279, 196608, 3, 262152, 131072, 3, 327688, 131072, 3, 393224, 131072, 3, 458760, 131072, 3, 196616, 131072, 3, 131080, 131072, 3, 65544, 131072, 3, 8, 131072, 3, -65528, 131072, 3, -131064, 131072, 3, -196600, 131072, 3, -262136, 131072, 3, -589816, 131072, 3, -524280, 131072, 3, -458744, 131072, 3, -393208, 131072, 3, -327672, 131072, 3, 589816, 196608, 2, 589817, 196608, 2, 589818, 196608, 2, 589819, 196608, 2, 589820, 196608, 2, 589821, 196608, 2, 589822, 196608, 2, 589823, 196608, 2, 524288, 196608, 2, 524289, 196608, 2, 524290, 196608, 2, 524291, 196608, 2, 524292, 196608, 2, 524293, 196608, 2, 524294, 196608, 2, 524295, 196608, 2, 524296, 327680, 3, 589815, 262144, 3)
[node name="CanvasModulate" parent="." index="0"]
-color = Color(0.501961, 0.501961, 0.501961, 1)
+color = Color(0.682353, 0.643137, 0.866667, 1)
-[node name="Doc" parent="Entities" index="0" instance=ExtResource("4_c0csw")]
-material = SubResource("ShaderMaterial_im5g2")
-PreferredWeightDistance = 256.0
-MaxWeightDistance = 32.0
-
-[node name="Torch" parent="Entities" index="1" instance=ExtResource("6_1wwor")]
-position = Vector2(-120, -112)
-
-[node name="Torch2" parent="Entities" index="2" instance=ExtResource("6_1wwor")]
-position = Vector2(-72, -112)
-
-[node name="Torch3" parent="Entities" index="3" instance=ExtResource("6_1wwor")]
-position = Vector2(-24, -113)
-
-[node name="Torch4" parent="Entities" index="4" instance=ExtResource("6_1wwor")]
-position = Vector2(24, -112)
-
-[node name="Torch5" parent="Entities" index="5" instance=ExtResource("6_1wwor")]
-position = Vector2(72, -112)
-
-[node name="Torch6" parent="Entities" index="6" instance=ExtResource("6_1wwor")]
-position = Vector2(120, -112)
-
-[node name="TorchLamp" parent="." index="6" instance=ExtResource("6_jy3pc")]
+[node name="TorchLamp" parent="Entities" index="0" instance=ExtResource("6_jy3pc")]
+y_sort_enabled = true
position = Vector2(-96, -120)
-[node name="TorchLamp2" parent="." index="7" instance=ExtResource("6_jy3pc")]
-position = Vector2(-48, -120)
-
-[node name="TorchLamp3" parent="." index="8" instance=ExtResource("6_jy3pc")]
+[node name="TorchLamp3" parent="Entities" index="1" instance=ExtResource("6_jy3pc")]
+y_sort_enabled = true
position = Vector2(0, -120)
-[node name="TorchLamp4" parent="." index="9" instance=ExtResource("6_jy3pc")]
-position = Vector2(48, -120)
-
-[node name="TorchLamp5" parent="." index="10" instance=ExtResource("6_jy3pc")]
+[node name="TorchLamp5" parent="Entities" index="2" instance=ExtResource("6_jy3pc")]
+y_sort_enabled = true
position = Vector2(96, -120)
+
+[node name="TorchLamp6" parent="Entities" index="3" instance=ExtResource("6_jy3pc")]
+y_sort_enabled = true
+position = Vector2(-120, -96)
+
+[node name="TorchLamp7" parent="Entities" index="4" instance=ExtResource("6_jy3pc")]
+y_sort_enabled = true
+position = Vector2(120, -96)
+
+[node name="TorchLamp9" parent="Entities" index="5" instance=ExtResource("6_jy3pc")]
+y_sort_enabled = true
+position = Vector2(120, -1)
+
+[node name="TorchLamp11" parent="Entities" index="6" instance=ExtResource("6_jy3pc")]
+y_sort_enabled = true
+position = Vector2(120, 95)
+
+[node name="TorchLamp12" parent="Entities" index="7" instance=ExtResource("6_jy3pc")]
+y_sort_enabled = true
+position = Vector2(97, 120)
+
+[node name="TorchLamp14" parent="Entities" index="8" instance=ExtResource("6_jy3pc")]
+y_sort_enabled = true
+position = Vector2(0, 120)
+
+[node name="TorchLamp16" parent="Entities" index="9" instance=ExtResource("6_jy3pc")]
+y_sort_enabled = true
+position = Vector2(-96, 120)
+
+[node name="TorchLamp17" parent="Entities" index="10" instance=ExtResource("6_jy3pc")]
+y_sort_enabled = true
+position = Vector2(-120, 95)
+
+[node name="TorchLamp19" parent="Entities" index="11" instance=ExtResource("6_jy3pc")]
+y_sort_enabled = true
+position = Vector2(-120, -1)
+
+[node name="Torch" parent="Entities" index="12" instance=ExtResource("6_1wwor")]
+visible = false
+position = Vector2(-120, -112)
+
+[node name="Torch2" parent="Entities" index="13" instance=ExtResource("6_1wwor")]
+visible = false
+position = Vector2(-72, -112)
+
+[node name="Torch3" parent="Entities" index="14" instance=ExtResource("6_1wwor")]
+visible = false
+position = Vector2(-24, -113)
+
+[node name="Torch4" parent="Entities" index="15" instance=ExtResource("6_1wwor")]
+visible = false
+position = Vector2(24, -112)
+
+[node name="Torch5" parent="Entities" index="16" instance=ExtResource("6_1wwor")]
+visible = false
+position = Vector2(72, -112)
+
+[node name="Torch6" parent="Entities" index="17" instance=ExtResource("6_1wwor")]
+visible = false
+position = Vector2(120, -112)
+
+[node name="Doc" parent="Entities" index="18" instance=ExtResource("4_ej0f3")]
+material = SubResource("ShaderMaterial_q3ile")
+
+[node name="PointLight2D" type="PointLight2D" parent="Entities" index="19"]
+position = Vector2(168, -42)
+energy = 1.5
+blend_mode = 2
+range_item_cull_mask = 0
+shadow_enabled = true
+shadow_color = Color(0.572549, 0.572549, 0.572549, 0)
+texture = ExtResource("7_y7j0e")
+height = 16.0
+
+[node name="CanvasGroup" type="CanvasGroup" parent="Entities" index="20"]
+
+[node name="Areas" parent="." index="2"]
+visible = false
+
+[node name="Area2D" type="Area2D" parent="Areas" index="0"]
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Areas/Area2D" index="0"]
+shape = SubResource("RectangleShape2D_gwpea")
diff --git a/Shaders/Flash.gdshader b/Shaders/Flash.gdshader
index 46a0666..9a668ec 100644
--- a/Shaders/Flash.gdshader
+++ b/Shaders/Flash.gdshader
@@ -2,9 +2,11 @@ shader_type canvas_item;
uniform vec4 color = vec4(1.0);
uniform float intensity : hint_range(0.0, 1.0) = 0.0;
+uniform float alpha_modulate : hint_range(0.0, 1.0) = 1.0;
void fragment() {
vec4 tex = texture(TEXTURE, UV);
tex.rgb = mix(tex.rgb, color.rgb, intensity);
COLOR = tex;
+ COLOR.a *= alpha_modulate;
}
\ No newline at end of file
diff --git a/State/Character/CharacterDashState.cs b/State/Character/CharacterDashState.cs
new file mode 100644
index 0000000..2e972fc
--- /dev/null
+++ b/State/Character/CharacterDashState.cs
@@ -0,0 +1,56 @@
+using Godot;
+using SupaLidlGame.Extensions;
+
+namespace SupaLidlGame.State.Character;
+
+public partial class CharacterDashState : CharacterState
+{
+ [Export]
+ public CharacterState IdleState { get; set; }
+
+ [Export]
+ public double TimeToDash { get; set; }
+
+ [Export]
+ public float VelocityModifier { get; set; }
+
+ private double _timeLeftToDash = 0;
+
+ public Vector2 DashDirection = Vector2.Zero;
+
+ public override IState Enter(IState previousState)
+ {
+ _timeLeftToDash = TimeToDash;
+ // dash the direction we were previously moving in
+ DashDirection = Character.Direction;
+ Character.MovementAnimation.Play("dash");
+ Character.MovementAnimation.Queue("idle");
+
+ // create ghost effect
+ var ghost = Character.Sprite.CloneOnWorld();
+ ghost.GlobalPosition = Character.Sprite.GlobalPosition;
+ var tween = ghost.GetTree().CreateTween();
+ tween.TweenProperty(ghost, "self_modulate", Colors.Transparent, 0.5);
+ tween.TweenCallback(new Callable(ghost, "queue_free"));
+ tween.Play();
+
+ return base.Enter(previousState);
+ }
+
+ public override void Exit(IState nextState)
+ {
+ _timeLeftToDash = 0;
+ DashDirection = Character.Direction;
+ base.Exit(nextState);
+ }
+
+ public override CharacterState Process(double delta)
+ {
+ Character.Direction = DashDirection;
+ if ((_timeLeftToDash -= delta) <= 0 || Character.Health <= 0)
+ {
+ return IdleState;
+ }
+ return null;
+ }
+}
diff --git a/State/Character/NPCIdleState.cs b/State/Character/NPCIdleState.cs
index 617bf06..910b978 100644
--- a/State/Character/NPCIdleState.cs
+++ b/State/Character/NPCIdleState.cs
@@ -10,7 +10,7 @@ public partial class NPCIdleState : NPCState
public override CharacterState Process(double delta)
{
base.Process(delta);
- if (Character.Direction.LengthSquared() > 0)
+ if (Character.Direction.LengthSquared() > 0.01f)
{
return MoveState;
}
@@ -19,7 +19,7 @@ public partial class NPCIdleState : NPCState
public override IState Enter(IState previousState)
{
- Character.Sprite.Play("idle");
+ Character.MovementAnimation.Play("idle");
return base.Enter(previousState);
}
}
diff --git a/State/Character/NPCMoveState.cs b/State/Character/NPCMoveState.cs
index 4a6879a..b428d72 100644
--- a/State/Character/NPCMoveState.cs
+++ b/State/Character/NPCMoveState.cs
@@ -19,7 +19,7 @@ public partial class NPCMoveState : NPCState
public override IState Enter(IState prev)
{
- Character.Sprite.Play("move");
+ Character.MovementAnimation.Play("move");
return base.Enter(prev);
}
}
diff --git a/State/Character/PlayerIdleState.cs b/State/Character/PlayerIdleState.cs
index fcc12f4..e6eff0e 100644
--- a/State/Character/PlayerIdleState.cs
+++ b/State/Character/PlayerIdleState.cs
@@ -9,7 +9,6 @@ public partial class PlayerIdleState : PlayerState
public override IState Enter(IState previousState)
{
- GD.Print("Entered idle state");
if (previousState is not PlayerMoveState)
{
if (Character.Direction.LengthSquared() > 0.01f)
@@ -21,7 +20,26 @@ public partial class PlayerIdleState : PlayerState
return MoveState;
}
}
- _player.Animation = "idle";
+
+ // must be moving at least 4 u/s for more than 0.5 seconds
+ bool shouldPlayStopAnim = false;
+
+ if (previousState is PlayerMoveState move)
+ {
+ shouldPlayStopAnim = move.MoveDuration > 0.5;
+ // NOTE: more conditions may be added soon
+ }
+
+ if (shouldPlayStopAnim)
+ {
+ _player.MovementAnimation.Play("stop");
+ _player.MovementAnimation.Queue("idle");
+ }
+ else
+ {
+ _player.MovementAnimation.Play("idle");
+ }
+
return base.Enter(previousState);
}
diff --git a/State/Character/PlayerMoveState.cs b/State/Character/PlayerMoveState.cs
index 38334e6..64d3732 100644
--- a/State/Character/PlayerMoveState.cs
+++ b/State/Character/PlayerMoveState.cs
@@ -7,16 +7,19 @@ public partial class PlayerMoveState : PlayerState
[Export]
public PlayerRollState RollState { get; set; }
+ public double MoveDuration { get; private set; }
+
public override IState Enter(IState previousState)
{
- Godot.GD.Print("Started moving");
- _player.Animation = "move";
+ _player.MovementAnimation.Play("move");
+ MoveDuration = 0;
return base.Enter(previousState);
}
public override CharacterState Process(double delta)
{
base.Process(delta);
+ MoveDuration += delta;
if (Character.Direction.LengthSquared() == 0)
{
return IdleState;
diff --git a/State/Character/PlayerRollState.cs b/State/Character/PlayerRollState.cs
index 4c0ddbc..dde6ce3 100644
--- a/State/Character/PlayerRollState.cs
+++ b/State/Character/PlayerRollState.cs
@@ -8,12 +8,12 @@ public partial class PlayerRollState : PlayerState
private Vector2 _rollDirection = Vector2.Zero;
- private AnimationPlayer _rollAnimation;
+ private GpuParticles2D _particles;
public override void _Ready()
{
- _rollAnimation = _player.GetNode("RollAnimation");
base._Ready();
+ _particles = _player.GetNode("Effects/RollParticles");
}
public override IState Enter(IState previousState)
@@ -24,12 +24,14 @@ public partial class PlayerRollState : PlayerState
Character.Target = Character.Direction;
if (Character.Direction.X >= 0)
{
- _rollAnimation.Play("roll");
+ _player.MovementAnimation.Play("roll");
}
else
{
- _rollAnimation.PlayBackwards("roll");
+ _player.MovementAnimation.PlayBackwards("roll");
}
+ _player.MovementAnimation.Queue("idle");
+ _particles.Emitting = true;
return base.Enter(previousState);
}
@@ -39,7 +41,7 @@ public partial class PlayerRollState : PlayerState
// this state (e.g. from death)
_timeLeftToRoll = 0;
_rollDirection = Character.Direction;
- _rollAnimation.Stop();
+ _particles.Emitting = false;
base.Exit(nextState);
}
diff --git a/State/Character/PlayerState.cs b/State/Character/PlayerState.cs
index ed57644..11ea5a8 100644
--- a/State/Character/PlayerState.cs
+++ b/State/Character/PlayerState.cs
@@ -51,9 +51,9 @@ public abstract partial class PlayerState : CharacterState
{
if (Character.Inventory.SelectedItem is Items.Weapon weapon)
{
+ var isPressed = Godot.Input.IsActionPressed("attack1");
if (!weapon.IsUsing)
{
- var isPressed = Godot.Input.IsActionPressed("attack1");
var ret = false;
if (!weapon.ShouldHideIdle || isPressed)
@@ -69,6 +69,13 @@ public abstract partial class PlayerState : CharacterState
return ret;
}
+ else
+ {
+ if (!isPressed)
+ {
+ Character.DeuseCurrentItem();
+ }
+ }
}
return false;
}
diff --git a/State/NPC/Doc/DocAttackState.cs b/State/NPC/Doc/DocAttackState.cs
index 2caf1ec..e8e6428 100644
--- a/State/NPC/Doc/DocAttackState.cs
+++ b/State/NPC/Doc/DocAttackState.cs
@@ -1,4 +1,5 @@
using Godot;
+using GodotUtilities;
namespace SupaLidlGame.State.NPC.Doc;
@@ -12,5 +13,25 @@ public abstract partial class DocAttackState : NPCState
public abstract DocChooseAttackState ChooseAttackState { get; set; }
+ protected Scenes.Map _map;
+ protected Utils.World _world;
+ protected Characters.Doc _doc;
+ protected double _currentDuration = 0;
+ protected double _currentAttackDuration = 0;
+
+ public override void _Ready()
+ {
+ _doc = NPC as Characters.Doc;
+ }
+
+ public override NPCState Enter(IState previousState)
+ {
+ _map = this.GetAncestor();
+ _world = this.GetAncestor();
+ _currentDuration = Duration;
+ _currentAttackDuration = AttackDuration;
+ return null;
+ }
+
protected abstract void Attack();
}
diff --git a/State/NPC/Doc/DocChooseAttackState.cs b/State/NPC/Doc/DocChooseAttackState.cs
index 0a31395..2b0453f 100644
--- a/State/NPC/Doc/DocChooseAttackState.cs
+++ b/State/NPC/Doc/DocChooseAttackState.cs
@@ -15,6 +15,9 @@ public partial class DocChooseAttackState : NPCState
[Export]
public DocUnwantedFrequencyState UnwantedFrequencyState { get; set; }
+ [Export]
+ public DocLanceState LanceState { get; set; }
+
[Export]
public DocExitState ExitState { get; set; }
@@ -39,18 +42,24 @@ public partial class DocChooseAttackState : NPCState
public override NPCState Enter(IState previous)
{
+ if (Doc.Intensity == 3)
+ {
+ return LanceState;
+ }
+
if (previous is not DocTelegraphState)
{
_consecutiveAttacks++;
}
else
{
- _consecutiveAttacks = 0;
+ _consecutiveAttacks = 1;
}
if (_consecutiveAttacks > Doc.Intensity)
{
- _consecutiveAttacks = 0;
+ _consecutiveAttacks = 1;
+ ResetStates();
return ExitState;
}
diff --git a/State/NPC/Doc/DocLanceState.cs b/State/NPC/Doc/DocLanceState.cs
new file mode 100644
index 0000000..59792ee
--- /dev/null
+++ b/State/NPC/Doc/DocLanceState.cs
@@ -0,0 +1,90 @@
+using Godot;
+
+namespace SupaLidlGame.State.NPC.Doc;
+
+public partial class DocLanceState : DocAttackState
+{
+ [Export]
+ public float DashSpeed { get; set; } = 212;
+
+ [Export]
+ public DocExitState ExitState { get; set; }
+
+ public override DocChooseAttackState ChooseAttackState
+ {
+ get => null;
+ set { }
+ }
+
+ public override PackedScene Projectile
+ {
+ get => null;
+ set { }
+ }
+
+ public override double AttackDuration { get; set; }
+
+ public override double Duration { get; set; }
+
+ protected Vector2 _dashDirection;
+
+ protected double _dashTime;
+
+ protected float _oldFriction = 0;
+
+ public override NPCState Enter(IState previousState)
+ {
+ var state = base.Enter(previousState);
+ _doc.ShouldMove = true;
+
+ //if (_doc.Intensity > 2)
+ //{
+ // if (_doc.Inventory.SelectedItem != _doc.LanceHold)
+ // {
+ // _doc.Inventory.SelectedItem = _doc.LanceHold;
+ // _doc.UseCurrentItem();
+ // _doc.CanAttack = false;
+ // }
+ //}
+ //else
+ //{
+ // // wtf are we doing here?
+ // throw new System.InvalidOperationException();
+ //}
+
+ //_oldFriction = _doc.Friction;
+ //_doc.Friction = 0;
+
+ //Attack();
+
+ return state;
+ }
+
+ public override void Exit(IState nextState)
+ {
+ //_doc.Friction = _oldFriction;
+ //_doc.ApplyImpulse(Vector2.Zero, true);
+ //_doc.DeuseCurrentItem();
+ //_doc.CanAttack = true;
+ base.Exit(nextState);
+ }
+
+ protected override void Attack()
+ {
+ //var pos = _doc.GlobalPosition;
+ //var player = _world.CurrentPlayer;
+ //var playerPos = player.GlobalPosition;
+ //var predictedPos = Utils.Physics.PredictNewPosition(
+ // pos, DashSpeed, playerPos, player.Velocity, out float time);
+ //var dir = _doc.GlobalPosition.DirectionTo(predictedPos);
+
+ //_currentAttackDuration = AttackDuration = time;
+
+ //_doc.ApplyImpulse(dir * DashSpeed, true);
+ }
+
+ public override NPCState Process(double delta)
+ {
+ return null;
+ }
+}
diff --git a/State/NPC/Doc/DocShungiteDartState.cs b/State/NPC/Doc/DocShungiteDartState.cs
index 23d90d5..f7515f6 100644
--- a/State/NPC/Doc/DocShungiteDartState.cs
+++ b/State/NPC/Doc/DocShungiteDartState.cs
@@ -6,12 +6,6 @@ namespace SupaLidlGame.State.NPC.Doc;
public partial class DocShungiteDartState : DocAttackState
{
- protected Scenes.Map _map;
- protected Utils.World _world;
-
- protected double _currentDuration = 0;
- protected double _currentAttackDuration = 0;
-
[Export]
public override double Duration { get; set; }
@@ -27,18 +21,8 @@ public partial class DocShungiteDartState : DocAttackState
[Export]
public Characters.Doc Doc { get; set; }
- public override NPCState Enter(IState previousState)
- {
- _map = this.GetAncestor();
- _world = this.GetAncestor();
- _currentDuration = Duration;
- _currentAttackDuration = AttackDuration;
- return null;
- }
-
public override void Exit(IState nextState)
{
-
}
protected virtual Projectile SpawnProjectile(
@@ -71,6 +55,11 @@ public partial class DocShungiteDartState : DocAttackState
public override NPCState Process(double delta)
{
+ if (Doc.StunTime > 0)
+ {
+ return null;
+ }
+
if ((_currentDuration -= delta) <= 0)
{
return ChooseAttackState;
diff --git a/State/NPC/Doc/DocShungiteSpikeState.cs b/State/NPC/Doc/DocShungiteSpikeState.cs
index aee3b37..c28f4ea 100644
--- a/State/NPC/Doc/DocShungiteSpikeState.cs
+++ b/State/NPC/Doc/DocShungiteSpikeState.cs
@@ -9,20 +9,38 @@ public partial class DocShungiteSpikeState : DocShungiteDartState
public override NPCState Enter(IState previous)
{
+ Doc.CanAttack = false;
+ if (this is not DocUnwantedFrequencyState)
+ {
+ Doc.TelegraphAnimation.Play("shungite_spike");
+ }
_currentAttacks = 0;
_currentAttackDuration = 1;
+ Doc.ShouldMove = true;
+ Doc.CanAttack = true;
return base.Enter(previous);
}
+ public override void Exit(IState nextState)
+ {
+ //Doc.TelegraphAnimation.Stop();
+ //Doc.TelegraphAnimation.Stop();
+ }
+
protected override Projectile SpawnProjectile(
Vector2 position,
Vector2 direction)
{
+ Doc.TelegraphAnimation.Play("shungite_spike");
var projectile = base.SpawnProjectile(position, direction)
as ShungiteSpike;
projectile.GlobalRotation = 0;
projectile.Delay = 0;
- projectile.Hitbox.Faction = projectile.Hurtbox.Faction = Doc.Faction;
+ projectile.Hitbox.Faction = Doc.Faction;
+ if (projectile.Hurtbox is not null)
+ {
+ projectile.Hurtbox.Faction = Doc.Faction;
+ }
return projectile;
}
@@ -43,7 +61,6 @@ public partial class DocShungiteSpikeState : DocShungiteDartState
out float time);
projectile.Direction = projectile.GlobalPosition.DirectionTo(targetPos);
projectile.FreezeTime = time + 0.25; // freeze when it reaches target
- GD.Print("projectile velocity: " + projectile.Velocity);
_currentAttackDuration = 1;
_currentAttacks++;
@@ -51,6 +68,11 @@ public partial class DocShungiteSpikeState : DocShungiteDartState
public override NPCState Process(double delta)
{
+ if (Doc.StunTime > 0)
+ {
+ return null;
+ }
+
if ((_currentAttackDuration -= delta) <= 0)
{
Attack();
diff --git a/State/NPC/Doc/DocTelegraphState.cs b/State/NPC/Doc/DocTelegraphState.cs
index 33649af..baa1cd6 100644
--- a/State/NPC/Doc/DocTelegraphState.cs
+++ b/State/NPC/Doc/DocTelegraphState.cs
@@ -1,4 +1,5 @@
using Godot;
+using GodotUtilities;
namespace SupaLidlGame.State.NPC.Doc;
@@ -17,11 +18,28 @@ public partial class DocTelegraphState : NPCState
public override NPCState Enter(IState previousState)
{
+ // TODO: clean this up
+ if (!(NPC as Characters.Doc).IsActive)
+ {
+ return null;
+ }
+
_currentDuration = Duration;
TelegraphAnimationPlayer.Play("enter_in");
- float randX = GD.RandRange(-128, 128);
- float randY = GD.RandRange(-128, 128);
- NPC.GlobalPosition = new Vector2(randX, randY);
+
+ var player = this.GetAncestor().CurrentPlayer;
+ Vector2 randVec;
+
+ do
+ {
+ float randX = GD.RandRange(-112, 112);
+ float randY = GD.RandRange(-112, 112);
+ randVec = new Vector2(randX, randY);
+ }
+ while (randVec.DistanceSquaredTo(player.GlobalPosition) < 1024);
+ // can not teleport within 32 units of the player
+
+ NPC.GlobalPosition = randVec;
return null;
}
diff --git a/State/NPC/Doc/DocUnwantedFrequencyState.cs b/State/NPC/Doc/DocUnwantedFrequencyState.cs
index e2b1048..f65d405 100644
--- a/State/NPC/Doc/DocUnwantedFrequencyState.cs
+++ b/State/NPC/Doc/DocUnwantedFrequencyState.cs
@@ -5,6 +5,20 @@ namespace SupaLidlGame.State.NPC.Doc;
public partial class DocUnwantedFrequencyState : DocShungiteSpikeState
{
+ public override NPCState Enter(IState previous)
+ {
+ Doc.TelegraphAnimation.Play("unwanted_frequencies");
+ return base.Enter(previous);
+ }
+
+ public override void Exit(IState nextState)
+ {
+ GetNode("../../Effects/UnwantedFrequenciesParticles")
+ .Emitting = false;
+ GD.Print("Exit unwanted frequency");
+ base.Exit(nextState);
+ }
+
protected override Projectile SpawnProjectile(
Vector2 position,
Vector2 direction)
@@ -19,6 +33,8 @@ public partial class DocUnwantedFrequencyState : DocShungiteSpikeState
protected override void Attack()
{
+ Doc.TelegraphAnimation.Play("unwanted_frequencies");
+ GD.Print("unwanted frequency");
var player = _world.CurrentPlayer;
var playerPos = player.GlobalPosition;
var docPos = NPC.GlobalPosition;
diff --git a/State/StateMachine.cs b/State/StateMachine.cs
index e204cc9..9b16242 100644
--- a/State/StateMachine.cs
+++ b/State/StateMachine.cs
@@ -1,8 +1,9 @@
using Godot;
+using SupaLidlGame.Extensions;
namespace SupaLidlGame.State;
-public abstract partial class StateMachine : Node where T : IState
+public abstract partial class StateMachine : Node where T : Node, IState
{
public T CurrentState { get; protected set; }
@@ -20,16 +21,19 @@ public abstract partial class StateMachine : Node where T : IState
return false;
}
+ // NOTE: proxied states can call Exit() more than once
if (CurrentState is not null)
{
CurrentState.Exit(nextState);
}
+ var previousState = CurrentState;
CurrentState = nextState;
// if the next state decides it should enter a different state,
// then we enter that different state instead
- var nextNextState = nextState.Enter(CurrentState);
+ var nextNextState = nextState.Enter(previousState);
+
if (nextNextState is T t)
{
return ChangeState(t, true);
@@ -37,4 +41,13 @@ public abstract partial class StateMachine : Node where T : IState
return true;
}
+
+ ///
+ /// Changes the current state to a state of type U which must inherit from T.
+ ///
+ public bool ChangeState(out U state) where U : T
+ {
+ state = this.FindChildOfType();
+ return ChangeState(state);
+ }
}
diff --git a/State/Weapon/SwordAnticipateState.cs b/State/Weapon/SwordAnticipateState.cs
index f393a65..789487f 100644
--- a/State/Weapon/SwordAnticipateState.cs
+++ b/State/Weapon/SwordAnticipateState.cs
@@ -10,18 +10,20 @@ public partial class SwordAnticipateState : WeaponState
[Export]
public SwordAttackState AttackState { get; set; }
+ [Export]
+ public bool HasAlternateAninmation { get; set; } = false;
+
private double _anticipateTime;
public override WeaponState Enter(IState prevState)
{
- Sword.EnableParry();
-
if (Sword.Character is SupaLidlGame.Characters.Player)
{
return AttackState;
}
- if (Sword.Anchor.Rotation > Mathf.DegToRad(50))
+ float rotThreshold = Mathf.DegToRad(50);
+ if (HasAlternateAninmation && Sword.Anchor.Rotation > rotThreshold)
{
Sword.AnimationPlayer.Play("anticipate_alternate");
}
diff --git a/State/Weapon/SwordAttackState.cs b/State/Weapon/SwordAttackState.cs
index 11014c7..3b921bd 100644
--- a/State/Weapon/SwordAttackState.cs
+++ b/State/Weapon/SwordAttackState.cs
@@ -8,10 +8,10 @@ public partial class SwordAttackState : WeaponState
public SupaLidlGame.Items.Weapons.Sword Sword { get; set; }
[Export]
- public SwordAnticipateState AnticipateState { get; set; }
+ public SwordIdleState IdleState { get; set; }
[Export]
- public SwordIdleState IdleState { get; set; }
+ public bool HasAlternateAnimation { get; set; } = false;
private double _attackDuration = 0;
@@ -23,10 +23,10 @@ public partial class SwordAttackState : WeaponState
public override WeaponState Enter(IState prevState)
{
- //Sword.AnimationPlayer.Stop();
+ Sword.EnableParry();
Sword.Attack();
- if (_isAlternate)
+ if (HasAlternateAnimation && _isAlternate)
{
Sword.AnimationPlayer.Play("attack_alternate");
}
diff --git a/State/Weapon/SwordHoldAttackState.cs b/State/Weapon/SwordHoldAttackState.cs
new file mode 100644
index 0000000..2edd697
--- /dev/null
+++ b/State/Weapon/SwordHoldAttackState.cs
@@ -0,0 +1,72 @@
+using Godot;
+
+namespace SupaLidlGame.State.Weapon;
+
+///
+/// This is a special state only meant to be used with certain bosses.
+///
+public partial class SwordHoldAttackState : SwordAttackState
+{
+ private bool _isAlternate = false;
+
+ public override WeaponState Enter(IState prevState)
+ {
+ Sword.EnableParry();
+ Sword.Attack();
+
+ if (HasAlternateAnimation && _isAlternate)
+ {
+ Sword.AnimationPlayer.Play("attack_alternate");
+ }
+ else
+ {
+ Sword.AnimationPlayer.Play("attack");
+ }
+
+ Sword.Visible = true;
+ Sword.UseDirection = Sword.Character.Target;
+ Sword.Hitbox.Hit += OnHitboxHit;
+ return null;
+ }
+
+ private void OnHitboxHit(BoundingBoxes.BoundingBox box)
+ {
+ if (box is BoundingBoxes.Hurtbox hurtbox)
+ {
+ hurtbox.InflictDamage(Sword.Damage,
+ Sword.Character,
+ Sword.Knockback);
+ }
+ // damage player if not parried
+ //Sword.OnHitboxHit(box);
+ }
+
+ public override void Exit(IState nextState)
+ {
+ // reset hit & ignore list first because players are not immediately
+ // removed from the list after being hit
+ Sword.Hitbox.Hit -= OnHitboxHit;
+ Sword.Hitbox.Hits.Clear();
+ GD.Print("Cleared now with " + Sword.Hitbox.Hits.Count);
+ Sword.Deattack();
+ }
+
+ public override WeaponState Use()
+ {
+ if (!Sword.IsAttacking)
+ {
+ GD.Print("Used (hold)");
+ Sword.Attack();
+ }
+
+ return null;
+ }
+
+ public override WeaponState Deuse()
+ {
+ GD.Print("Deused");
+ return IdleState;
+ }
+
+ public override WeaponState Process(double delta) => null;
+}
diff --git a/UI/BossBar.cs b/UI/BossBar.cs
new file mode 100644
index 0000000..cc09fd6
--- /dev/null
+++ b/UI/BossBar.cs
@@ -0,0 +1,63 @@
+using Godot;
+using SupaLidlGame.Characters;
+
+namespace SupaLidlGame.UI;
+
+public partial class BossBar : VBoxContainer
+{
+ public TextureProgressBar ProgressBar { get; set; }
+ public Label BossNameLabel { get; set; }
+
+ private Boss _boss;
+
+ public Boss Boss
+ {
+ get => _boss;
+ set
+ {
+ SetupBoss(value);
+ _boss = value;
+ }
+ }
+
+ public override void _Ready()
+ {
+ ProgressBar = GetNode("BarMargin/BossBar");
+ BossNameLabel = GetNode