added some amazing changes
This commit is contained in:
BIN
src/assets/audio/sfx/jsfxr/bird_sound.wav
Normal file
BIN
src/assets/audio/sfx/jsfxr/bird_sound.wav
Normal file
Binary file not shown.
24
src/assets/audio/sfx/jsfxr/bird_sound.wav.import
Normal file
24
src/assets/audio/sfx/jsfxr/bird_sound.wav.import
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="wav"
|
||||||
|
type="AudioStreamWAV"
|
||||||
|
uid="uid://cjv4cf2kiomwo"
|
||||||
|
path="res://.godot/imported/bird_sound.wav-b46955955f9335504baeb1047dec1ef4.sample"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/audio/sfx/jsfxr/bird_sound.wav"
|
||||||
|
dest_files=["res://.godot/imported/bird_sound.wav-b46955955f9335504baeb1047dec1ef4.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=2
|
||||||
BIN
src/assets/audio/sfx/jsfxr/explosion.wav
Normal file
BIN
src/assets/audio/sfx/jsfxr/explosion.wav
Normal file
Binary file not shown.
24
src/assets/audio/sfx/jsfxr/explosion.wav.import
Normal file
24
src/assets/audio/sfx/jsfxr/explosion.wav.import
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="wav"
|
||||||
|
type="AudioStreamWAV"
|
||||||
|
uid="uid://di766omly0jae"
|
||||||
|
path="res://.godot/imported/explosion.wav-2ed54abe1b2d0516e2a9c43072521c6e.sample"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/audio/sfx/jsfxr/explosion.wav"
|
||||||
|
dest_files=["res://.godot/imported/explosion.wav-2ed54abe1b2d0516e2a9c43072521c6e.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=2
|
||||||
BIN
src/assets/audio/sfx/jsfxr/hitHurt (1).wav
Normal file
BIN
src/assets/audio/sfx/jsfxr/hitHurt (1).wav
Normal file
Binary file not shown.
24
src/assets/audio/sfx/jsfxr/hitHurt (1).wav.import
Normal file
24
src/assets/audio/sfx/jsfxr/hitHurt (1).wav.import
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="wav"
|
||||||
|
type="AudioStreamWAV"
|
||||||
|
uid="uid://8l0hx3sjh4ci"
|
||||||
|
path="res://.godot/imported/hitHurt (1).wav-6f28383ced03a2447f0c22e04c882b41.sample"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/audio/sfx/jsfxr/hitHurt (1).wav"
|
||||||
|
dest_files=["res://.godot/imported/hitHurt (1).wav-6f28383ced03a2447f0c22e04c882b41.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=2
|
||||||
BIN
src/assets/audio/sfx/jsfxr/hitHurt.wav
Normal file
BIN
src/assets/audio/sfx/jsfxr/hitHurt.wav
Normal file
Binary file not shown.
24
src/assets/audio/sfx/jsfxr/hitHurt.wav.import
Normal file
24
src/assets/audio/sfx/jsfxr/hitHurt.wav.import
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="wav"
|
||||||
|
type="AudioStreamWAV"
|
||||||
|
uid="uid://d0v3yf1mj4mxd"
|
||||||
|
path="res://.godot/imported/hitHurt.wav-fff3b933896d95faf3cb3183d82f9a2d.sample"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/audio/sfx/jsfxr/hitHurt.wav"
|
||||||
|
dest_files=["res://.godot/imported/hitHurt.wav-fff3b933896d95faf3cb3183d82f9a2d.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=2
|
||||||
BIN
src/assets/audio/sfx/jsfxr/pickupCoin.wav
Normal file
BIN
src/assets/audio/sfx/jsfxr/pickupCoin.wav
Normal file
Binary file not shown.
24
src/assets/audio/sfx/jsfxr/pickupCoin.wav.import
Normal file
24
src/assets/audio/sfx/jsfxr/pickupCoin.wav.import
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="wav"
|
||||||
|
type="AudioStreamWAV"
|
||||||
|
uid="uid://bho5u81vx5gmg"
|
||||||
|
path="res://.godot/imported/pickupCoin.wav-b11b34a264bd8fc8a2381f3c47f6a13b.sample"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/audio/sfx/jsfxr/pickupCoin.wav"
|
||||||
|
dest_files=["res://.godot/imported/pickupCoin.wav-b11b34a264bd8fc8a2381f3c47f6a13b.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=2
|
||||||
BIN
src/assets/audio/sfx/wizard/animevox/boing_1769364535327.wav
Normal file
BIN
src/assets/audio/sfx/wizard/animevox/boing_1769364535327.wav
Normal file
Binary file not shown.
@@ -0,0 +1,24 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="wav"
|
||||||
|
type="AudioStreamWAV"
|
||||||
|
uid="uid://cmmjgvktb5j8n"
|
||||||
|
path="res://.godot/imported/boing_1769364535327.wav-acb4f31a69bec50ac3aa9aa01f6bdfea.sample"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/audio/sfx/wizard/animevox/boing_1769364535327.wav"
|
||||||
|
dest_files=["res://.godot/imported/boing_1769364535327.wav-acb4f31a69bec50ac3aa9aa01f6bdfea.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=2
|
||||||
BIN
src/assets/audio/sfx/wizard/animevox/boing_1769364542682.wav
Normal file
BIN
src/assets/audio/sfx/wizard/animevox/boing_1769364542682.wav
Normal file
Binary file not shown.
@@ -0,0 +1,24 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="wav"
|
||||||
|
type="AudioStreamWAV"
|
||||||
|
uid="uid://b5o2pj5tykc88"
|
||||||
|
path="res://.godot/imported/boing_1769364542682.wav-bffa589516e2aa97aa405dd0c55f9efd.sample"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/audio/sfx/wizard/animevox/boing_1769364542682.wav"
|
||||||
|
dest_files=["res://.godot/imported/boing_1769364542682.wav-bffa589516e2aa97aa405dd0c55f9efd.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=2
|
||||||
BIN
src/assets/audio/sfx/wizard/animevox/boing_1769364598383.wav
Normal file
BIN
src/assets/audio/sfx/wizard/animevox/boing_1769364598383.wav
Normal file
Binary file not shown.
@@ -0,0 +1,24 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="wav"
|
||||||
|
type="AudioStreamWAV"
|
||||||
|
uid="uid://bglxp21vu17ve"
|
||||||
|
path="res://.godot/imported/boing_1769364598383.wav-d03eba7d368599ddcbde2a695474497f.sample"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/audio/sfx/wizard/animevox/boing_1769364598383.wav"
|
||||||
|
dest_files=["res://.godot/imported/boing_1769364598383.wav-d03eba7d368599ddcbde2a695474497f.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=2
|
||||||
BIN
src/assets/audio/sfx/wizard/animevox/boing_1769364606981.wav
Normal file
BIN
src/assets/audio/sfx/wizard/animevox/boing_1769364606981.wav
Normal file
Binary file not shown.
@@ -0,0 +1,24 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="wav"
|
||||||
|
type="AudioStreamWAV"
|
||||||
|
uid="uid://bpxdu1j6xlbw"
|
||||||
|
path="res://.godot/imported/boing_1769364606981.wav-ade7a7cf5e600ba22d23fb18eb5b5015.sample"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/audio/sfx/wizard/animevox/boing_1769364606981.wav"
|
||||||
|
dest_files=["res://.godot/imported/boing_1769364606981.wav-ade7a7cf5e600ba22d23fb18eb5b5015.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=2
|
||||||
BIN
src/assets/audio/sfx/wizard/animevox/boing_1769364651821.wav
Normal file
BIN
src/assets/audio/sfx/wizard/animevox/boing_1769364651821.wav
Normal file
Binary file not shown.
@@ -0,0 +1,24 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="wav"
|
||||||
|
type="AudioStreamWAV"
|
||||||
|
uid="uid://cm1d4xo5s76u5"
|
||||||
|
path="res://.godot/imported/boing_1769364651821.wav-502e03ca23e2fbeb991f072fca1dacbe.sample"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/audio/sfx/wizard/animevox/boing_1769364651821.wav"
|
||||||
|
dest_files=["res://.godot/imported/boing_1769364651821.wav-502e03ca23e2fbeb991f072fca1dacbe.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=2
|
||||||
BIN
src/assets/audio/sfx/wizard/animevox/boing_1769364702890.wav
Normal file
BIN
src/assets/audio/sfx/wizard/animevox/boing_1769364702890.wav
Normal file
Binary file not shown.
@@ -0,0 +1,24 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="wav"
|
||||||
|
type="AudioStreamWAV"
|
||||||
|
uid="uid://ccajvghy4x8wv"
|
||||||
|
path="res://.godot/imported/boing_1769364702890.wav-04301d3cc6eb2efe6c63ce7510d613c6.sample"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/audio/sfx/wizard/animevox/boing_1769364702890.wav"
|
||||||
|
dest_files=["res://.godot/imported/boing_1769364702890.wav-04301d3cc6eb2efe6c63ce7510d613c6.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=2
|
||||||
BIN
src/assets/audio/sfx/wizard/animevox/impact_1769286037120.wav
Normal file
BIN
src/assets/audio/sfx/wizard/animevox/impact_1769286037120.wav
Normal file
Binary file not shown.
@@ -0,0 +1,24 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="wav"
|
||||||
|
type="AudioStreamWAV"
|
||||||
|
uid="uid://crfns2hgo7lxt"
|
||||||
|
path="res://.godot/imported/impact_1769286037120.wav-9efc780a91cd15d59f549ad1b1418ebb.sample"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/audio/sfx/wizard/animevox/impact_1769286037120.wav"
|
||||||
|
dest_files=["res://.godot/imported/impact_1769286037120.wav-9efc780a91cd15d59f549ad1b1418ebb.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=2
|
||||||
BIN
src/assets/audio/sfx/wizard/animevox/impact_1769364721189.wav
Normal file
BIN
src/assets/audio/sfx/wizard/animevox/impact_1769364721189.wav
Normal file
Binary file not shown.
@@ -0,0 +1,24 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="wav"
|
||||||
|
type="AudioStreamWAV"
|
||||||
|
uid="uid://cij3m0pt7r5ga"
|
||||||
|
path="res://.godot/imported/impact_1769364721189.wav-1a31c60693df98332e9227a98533524a.sample"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/audio/sfx/wizard/animevox/impact_1769364721189.wav"
|
||||||
|
dest_files=["res://.godot/imported/impact_1769364721189.wav-1a31c60693df98332e9227a98533524a.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=2
|
||||||
BIN
src/assets/audio/sfx/wizard/animevox/slash_1769364693031.wav
Normal file
BIN
src/assets/audio/sfx/wizard/animevox/slash_1769364693031.wav
Normal file
Binary file not shown.
@@ -0,0 +1,24 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="wav"
|
||||||
|
type="AudioStreamWAV"
|
||||||
|
uid="uid://beeix80itbwb5"
|
||||||
|
path="res://.godot/imported/slash_1769364693031.wav-2ad2e9bd0168a91968bf485e2a5cc1cb.sample"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/audio/sfx/wizard/animevox/slash_1769364693031.wav"
|
||||||
|
dest_files=["res://.godot/imported/slash_1769364693031.wav-2ad2e9bd0168a91968bf485e2a5cc1cb.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=2
|
||||||
BIN
src/assets/audio/sfx/wizard/animevox/sparkle_1769364495063.wav
Normal file
BIN
src/assets/audio/sfx/wizard/animevox/sparkle_1769364495063.wav
Normal file
Binary file not shown.
@@ -0,0 +1,24 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="wav"
|
||||||
|
type="AudioStreamWAV"
|
||||||
|
uid="uid://cag7alnbxymki"
|
||||||
|
path="res://.godot/imported/sparkle_1769364495063.wav-b61c6c787bf6a4f817a470f87062f181.sample"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/audio/sfx/wizard/animevox/sparkle_1769364495063.wav"
|
||||||
|
dest_files=["res://.godot/imported/sparkle_1769364495063.wav-b61c6c787bf6a4f817a470f87062f181.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=2
|
||||||
BIN
src/assets/audio/sfx/wizard/animevox/sparkle_1769364641348.wav
Normal file
BIN
src/assets/audio/sfx/wizard/animevox/sparkle_1769364641348.wav
Normal file
Binary file not shown.
@@ -0,0 +1,24 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="wav"
|
||||||
|
type="AudioStreamWAV"
|
||||||
|
uid="uid://5rlt4sjeinxq"
|
||||||
|
path="res://.godot/imported/sparkle_1769364641348.wav-74b365bbefc51d0c6d49332149fc1d42.sample"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/audio/sfx/wizard/animevox/sparkle_1769364641348.wav"
|
||||||
|
dest_files=["res://.godot/imported/sparkle_1769364641348.wav-74b365bbefc51d0c6d49332149fc1d42.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=2
|
||||||
BIN
src/assets/audio/sfx/wizard/animevox/whoosh_1769286051051.wav
Normal file
BIN
src/assets/audio/sfx/wizard/animevox/whoosh_1769286051051.wav
Normal file
Binary file not shown.
@@ -0,0 +1,24 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="wav"
|
||||||
|
type="AudioStreamWAV"
|
||||||
|
uid="uid://cgrpvbrntl4lb"
|
||||||
|
path="res://.godot/imported/whoosh_1769286051051.wav-e59e3dabebb5cba9d2a412aeff0b4b12.sample"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/audio/sfx/wizard/animevox/whoosh_1769286051051.wav"
|
||||||
|
dest_files=["res://.godot/imported/whoosh_1769286051051.wav-e59e3dabebb5cba9d2a412aeff0b4b12.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=2
|
||||||
BIN
src/assets/audio/sfx/wizard/animevox/whoosh_1769364574009.wav
Normal file
BIN
src/assets/audio/sfx/wizard/animevox/whoosh_1769364574009.wav
Normal file
Binary file not shown.
@@ -0,0 +1,24 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="wav"
|
||||||
|
type="AudioStreamWAV"
|
||||||
|
uid="uid://ghi1yh80t2ae"
|
||||||
|
path="res://.godot/imported/whoosh_1769364574009.wav-6576e552fe9371f5faa6f2aba79af16f.sample"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/audio/sfx/wizard/animevox/whoosh_1769364574009.wav"
|
||||||
|
dest_files=["res://.godot/imported/whoosh_1769364574009.wav-6576e552fe9371f5faa6f2aba79af16f.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=2
|
||||||
BIN
src/assets/audio/sfx/wizard/animevox/whoosh_1769364646131.wav
Normal file
BIN
src/assets/audio/sfx/wizard/animevox/whoosh_1769364646131.wav
Normal file
Binary file not shown.
@@ -0,0 +1,24 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="wav"
|
||||||
|
type="AudioStreamWAV"
|
||||||
|
uid="uid://cuyvxnkjx6usa"
|
||||||
|
path="res://.godot/imported/whoosh_1769364646131.wav-280c0e6a35d590f20e89e29b6655ad2d.sample"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/audio/sfx/wizard/animevox/whoosh_1769364646131.wav"
|
||||||
|
dest_files=["res://.godot/imported/whoosh_1769364646131.wav-280c0e6a35d590f20e89e29b6655ad2d.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=2
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 19 KiB |
@@ -35,9 +35,6 @@ polygon = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
|||||||
[sub_resource type="OccluderPolygon2D" id="OccluderPolygon2D_bqa6v"]
|
[sub_resource type="OccluderPolygon2D" id="OccluderPolygon2D_bqa6v"]
|
||||||
polygon = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
polygon = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||||
|
|
||||||
[sub_resource type="OccluderPolygon2D" id="OccluderPolygon2D_c2t7l"]
|
|
||||||
polygon = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
|
||||||
|
|
||||||
[sub_resource type="OccluderPolygon2D" id="OccluderPolygon2D_br5gx"]
|
[sub_resource type="OccluderPolygon2D" id="OccluderPolygon2D_br5gx"]
|
||||||
polygon = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
polygon = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||||
|
|
||||||
@@ -167,7 +164,6 @@ separation = Vector2i(1, 1)
|
|||||||
1:2/0 = 0
|
1:2/0 = 0
|
||||||
1:2/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
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 = 0
|
||||||
2:2/0/occlusion_layer_0/polygon_0/polygon = SubResource("OccluderPolygon2D_c2t7l")
|
|
||||||
3:2/0 = 0
|
3:2/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, 8, -8, 8)
|
||||||
4:2/0 = 0
|
4:2/0 = 0
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 8.5 KiB |
BIN
src/assets/gfx/enemies/spider.png
Normal file
BIN
src/assets/gfx/enemies/spider.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.8 KiB |
40
src/assets/gfx/enemies/spider.png.import
Normal file
40
src/assets/gfx/enemies/spider.png.import
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://bmogyono02pl3"
|
||||||
|
path="res://.godot/imported/spider.png-80ad78c1ab808d8ac5dd1c6fa58f6c10.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/gfx/enemies/spider.png"
|
||||||
|
dest_files=["res://.godot/imported/spider.png-80ad78c1ab808d8ac5dd1c6fa58f6c10.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
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/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
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
|
||||||
@@ -1,30 +1,47 @@
|
|||||||
[gd_scene format=3 uid="uid://d1u8p5rop4vye"]
|
[gd_scene format=3 uid="uid://d1u8p5rop4vye"]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://scripts/attack_spell_frostspike.gd" id="1_script"]
|
[ext_resource type="Script" uid="uid://cy3rt80axidqg" path="res://scripts/attack_spell_frostspike.gd" id="1_script"]
|
||||||
[ext_resource type="Texture2D" uid="uid://bf158atxi7ucy" path="res://assets/gfx/fx/shade_spell_effects.png" id="2_tex"]
|
[ext_resource type="Texture2D" uid="uid://bf158atxi7ucy" path="res://assets/gfx/fx/shade_spell_effects.png" id="2_tex"]
|
||||||
|
[ext_resource type="AudioStream" uid="uid://cij3m0pt7r5ga" path="res://assets/audio/sfx/wizard/animevox/impact_1769364721189.wav" id="3_y7fsv"]
|
||||||
|
|
||||||
|
[sub_resource type="Gradient" id="Gradient_3jvtj"]
|
||||||
|
offsets = PackedFloat32Array(0.5839416, 0.7177616)
|
||||||
|
colors = PackedColorArray(1, 1, 1, 1, 1, 1, 1, 0)
|
||||||
|
|
||||||
|
[sub_resource type="GradientTexture2D" id="GradientTexture2D_y7fsv"]
|
||||||
|
gradient = SubResource("Gradient_3jvtj")
|
||||||
|
fill = 1
|
||||||
|
fill_from = Vector2(0.517094, 0.50427353)
|
||||||
|
fill_to = Vector2(0.94871795, 0.102564104)
|
||||||
|
|
||||||
[sub_resource type="RectangleShape2D" id="RectangleShape2D_frost"]
|
[sub_resource type="RectangleShape2D" id="RectangleShape2D_frost"]
|
||||||
size = Vector2(16, 16)
|
size = Vector2(16, 16)
|
||||||
|
|
||||||
[node name="FrostspikeSpell" type="Node2D"]
|
[node name="FrostspikeSpell" type="Node2D" unique_id=2076098743]
|
||||||
z_index = 4
|
z_index = 4
|
||||||
script = ExtResource("1_script")
|
script = ExtResource("1_script")
|
||||||
|
|
||||||
[node name="Sprite2D" type="Sprite2D" parent="."]
|
[node name="Sprite2D" type="Sprite2D" parent="." unique_id=804594305]
|
||||||
texture = ExtResource("2_tex")
|
texture = ExtResource("2_tex")
|
||||||
hframes = 105
|
hframes = 105
|
||||||
vframes = 79
|
vframes = 79
|
||||||
frame = 4413
|
frame = 4413
|
||||||
|
|
||||||
[node name="SpikeLight" type="PointLight2D" parent="."]
|
[node name="SpikeLight" type="PointLight2D" parent="." unique_id=1041040958]
|
||||||
color = Color(0.35, 0.6, 1, 1)
|
color = Color(0.35, 0.6, 1, 1)
|
||||||
energy = 1.0
|
texture = SubResource("GradientTexture2D_y7fsv")
|
||||||
texture_scale = 0.5
|
texture_scale = 0.5
|
||||||
enabled = true
|
|
||||||
|
|
||||||
[node name="Area2D" type="Area2D" parent="."]
|
[node name="Area2D" type="Area2D" parent="." unique_id=1349643659]
|
||||||
collision_layer = 4
|
collision_layer = 4
|
||||||
collision_mask = 3
|
collision_mask = 3
|
||||||
|
|
||||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="Area2D"]
|
[node name="CollisionShape2D" type="CollisionShape2D" parent="Area2D" unique_id=358504371]
|
||||||
shape = SubResource("RectangleShape2D_frost")
|
shape = SubResource("RectangleShape2D_frost")
|
||||||
|
|
||||||
|
[node name="SfxSpike" type="AudioStreamPlayer2D" parent="." unique_id=399258294]
|
||||||
|
stream = ExtResource("3_y7fsv")
|
||||||
|
max_distance = 1456.0
|
||||||
|
attenuation = 5.4641595
|
||||||
|
panning_strength = 1.06
|
||||||
|
bus = &"Sfx"
|
||||||
|
|||||||
128
src/scenes/enemy_hand.tscn
Normal file
128
src/scenes/enemy_hand.tscn
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
[gd_scene format=3 uid="uid://cx2jm5ua6evmb"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://bkeyokaahe2fd" path="res://scripts/enemy_hand.gd" id="1_hqcsv"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://dyid2xlxo1gnn" path="res://assets/gfx/enemies/hand_monster.png" id="1_lpach"]
|
||||||
|
|
||||||
|
[sub_resource type="Animation" id="Animation_hqcsv"]
|
||||||
|
length = 0.001
|
||||||
|
tracks/0/type = "value"
|
||||||
|
tracks/0/imported = false
|
||||||
|
tracks/0/enabled = true
|
||||||
|
tracks/0/path = NodePath("Sprite2D: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_go7b8"]
|
||||||
|
resource_name = "emerge"
|
||||||
|
length = 0.4
|
||||||
|
tracks/0/type = "value"
|
||||||
|
tracks/0/imported = false
|
||||||
|
tracks/0/enabled = true
|
||||||
|
tracks/0/path = NodePath("Sprite2D:frame")
|
||||||
|
tracks/0/interp = 1
|
||||||
|
tracks/0/loop_wrap = true
|
||||||
|
tracks/0/keys = {
|
||||||
|
"times": PackedFloat32Array(0, 0.099999994, 0.2, 0.3),
|
||||||
|
"transitions": PackedFloat32Array(1, 1, 1, 1),
|
||||||
|
"update": 1,
|
||||||
|
"values": [0, 1, 2, 3]
|
||||||
|
}
|
||||||
|
|
||||||
|
[sub_resource type="Animation" id="Animation_ptw5w"]
|
||||||
|
resource_name = "idle"
|
||||||
|
length = 0.8
|
||||||
|
loop_mode = 1
|
||||||
|
tracks/0/type = "value"
|
||||||
|
tracks/0/imported = false
|
||||||
|
tracks/0/enabled = true
|
||||||
|
tracks/0/path = NodePath("Sprite2D:frame")
|
||||||
|
tracks/0/interp = 1
|
||||||
|
tracks/0/loop_wrap = true
|
||||||
|
tracks/0/keys = {
|
||||||
|
"times": PackedFloat32Array(0, 0.2, 0.4, 0.6),
|
||||||
|
"transitions": PackedFloat32Array(1, 1, 1, 1),
|
||||||
|
"update": 1,
|
||||||
|
"values": [4, 5, 6, 5]
|
||||||
|
}
|
||||||
|
|
||||||
|
[sub_resource type="Animation" id="Animation_0vh4e"]
|
||||||
|
resource_name = "snatch"
|
||||||
|
length = 0.4
|
||||||
|
tracks/0/type = "value"
|
||||||
|
tracks/0/imported = false
|
||||||
|
tracks/0/enabled = true
|
||||||
|
tracks/0/path = NodePath("Sprite2D:frame")
|
||||||
|
tracks/0/interp = 1
|
||||||
|
tracks/0/loop_wrap = true
|
||||||
|
tracks/0/keys = {
|
||||||
|
"times": PackedFloat32Array(0, 0.033333335, 0.06666667, 0.10000001, 0.13333334, 0.16666667, 0.20000002, 0.23333335, 0.26666668, 0.3, 0.33333334),
|
||||||
|
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
|
||||||
|
"update": 1,
|
||||||
|
"values": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
|
||||||
|
}
|
||||||
|
|
||||||
|
[sub_resource type="AnimationLibrary" id="AnimationLibrary_ptw5w"]
|
||||||
|
_data = {
|
||||||
|
&"RESET": SubResource("Animation_hqcsv"),
|
||||||
|
&"emerge": SubResource("Animation_go7b8"),
|
||||||
|
&"idle": SubResource("Animation_ptw5w"),
|
||||||
|
&"snatch": SubResource("Animation_0vh4e")
|
||||||
|
}
|
||||||
|
|
||||||
|
[sub_resource type="CircleShape2D" id="CircleShape2D_lpach"]
|
||||||
|
radius = 3.1622777
|
||||||
|
|
||||||
|
[sub_resource type="CircleShape2D" id="CircleShape2D_hqcsv"]
|
||||||
|
radius = 38.0
|
||||||
|
|
||||||
|
[sub_resource type="CircleShape2D" id="CircleShape2D_go7b8"]
|
||||||
|
radius = 5.0
|
||||||
|
|
||||||
|
[sub_resource type="CircleShape2D" id="CircleShape2D_ptw5w"]
|
||||||
|
radius = 58.30952
|
||||||
|
|
||||||
|
[node name="EnemyHand" type="CharacterBody2D" unique_id=512887809]
|
||||||
|
collision_mask = 64
|
||||||
|
script = ExtResource("1_hqcsv")
|
||||||
|
|
||||||
|
[node name="Sprite2D" type="Sprite2D" parent="." unique_id=63819619]
|
||||||
|
position = Vector2(0, -6)
|
||||||
|
texture = ExtResource("1_lpach")
|
||||||
|
hframes = 4
|
||||||
|
vframes = 4
|
||||||
|
|
||||||
|
[node name="AnimationPlayer" type="AnimationPlayer" parent="." unique_id=939531210]
|
||||||
|
libraries/ = SubResource("AnimationLibrary_ptw5w")
|
||||||
|
|
||||||
|
[node name="CollisionShape2D" type="CollisionShape2D" parent="." unique_id=448410993]
|
||||||
|
shape = SubResource("CircleShape2D_lpach")
|
||||||
|
|
||||||
|
[node name="EmergeArea" type="Area2D" parent="." unique_id=1688073969]
|
||||||
|
collision_layer = 0
|
||||||
|
|
||||||
|
[node name="CollisionShape2D" type="CollisionShape2D" parent="EmergeArea" unique_id=1403525746]
|
||||||
|
shape = SubResource("CircleShape2D_hqcsv")
|
||||||
|
|
||||||
|
[node name="GrabPlayerArea" type="Area2D" parent="." unique_id=812102876]
|
||||||
|
|
||||||
|
[node name="CollisionShape2D" type="CollisionShape2D" parent="GrabPlayerArea" unique_id=1531888936]
|
||||||
|
shape = SubResource("CircleShape2D_go7b8")
|
||||||
|
debug_color = Color(0.70196074, 0, 0.05113532, 0.41960785)
|
||||||
|
|
||||||
|
[node name="PlayerInterestArea" type="Area2D" parent="." unique_id=1613094277]
|
||||||
|
collision_layer = 0
|
||||||
|
|
||||||
|
[node name="CollisionShape2D" type="CollisionShape2D" parent="PlayerInterestArea" unique_id=1847542345]
|
||||||
|
shape = SubResource("CircleShape2D_ptw5w")
|
||||||
|
debug_color = Color(0.70196074, 0.6745404, 0.69139016, 0.41960785)
|
||||||
|
|
||||||
|
[connection signal="body_entered" from="EmergeArea" to="." method="_on_emerge_area_body_entered"]
|
||||||
|
[connection signal="body_entered" from="GrabPlayerArea" to="." method="_on_grab_player_area_body_entered"]
|
||||||
|
[connection signal="body_entered" from="PlayerInterestArea" to="." method="_on_player_interest_area_body_entered"]
|
||||||
|
[connection signal="body_exited" from="PlayerInterestArea" to="." method="_on_player_interest_area_body_exited"]
|
||||||
@@ -2,6 +2,25 @@
|
|||||||
|
|
||||||
[ext_resource type="Script" uid="uid://dx5oym20rr2ei" path="res://scripts/floating_text.gd" id="1"]
|
[ext_resource type="Script" uid="uid://dx5oym20rr2ei" path="res://scripts/floating_text.gd" id="1"]
|
||||||
[ext_resource type="FontFile" uid="uid://cbmcfue0ek0tk" path="res://assets/fonts/dmg_numbers.png" id="2_dmg_font"]
|
[ext_resource type="FontFile" uid="uid://cbmcfue0ek0tk" path="res://assets/fonts/dmg_numbers.png" id="2_dmg_font"]
|
||||||
|
[ext_resource type="Shader" uid="uid://ldl7vaq5n13f" path="res://shaders/cloth.gdshader" id="2_ki2nc"]
|
||||||
|
|
||||||
|
[sub_resource type="ShaderMaterial" id="ShaderMaterial_27d3m"]
|
||||||
|
shader = ExtResource("2_ki2nc")
|
||||||
|
shader_parameter/original_0 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_1 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_2 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_3 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_4 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_5 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_6 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_0 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_1 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_2 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_3 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_4 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_5 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_6 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/tint = Color(1, 1, 1, 1)
|
||||||
|
|
||||||
[sub_resource type="Theme" id="Theme_floating_text"]
|
[sub_resource type="Theme" id="Theme_floating_text"]
|
||||||
default_font = ExtResource("2_dmg_font")
|
default_font = ExtResource("2_dmg_font")
|
||||||
@@ -13,6 +32,7 @@ script = ExtResource("1")
|
|||||||
|
|
||||||
[node name="ItemSprite" type="Sprite2D" parent="." unique_id=1657362510]
|
[node name="ItemSprite" type="Sprite2D" parent="." unique_id=1657362510]
|
||||||
visible = false
|
visible = false
|
||||||
|
material = SubResource("ShaderMaterial_27d3m")
|
||||||
offset = Vector2(0, -8)
|
offset = Vector2(0, -8)
|
||||||
|
|
||||||
[node name="Label" type="Label" parent="." unique_id=1387220833]
|
[node name="Label" type="Label" parent="." unique_id=1387220833]
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
[ext_resource type="Shader" uid="uid://dob36l1rwi2en" path="res://shaders/game_world.gdshader" id="4_bhwwd"]
|
[ext_resource type="Shader" uid="uid://dob36l1rwi2en" path="res://shaders/game_world.gdshader" id="4_bhwwd"]
|
||||||
[ext_resource type="Script" uid="uid://wff5063ctp7g" path="res://scripts/debug_overlay.gd" id="5"]
|
[ext_resource type="Script" uid="uid://wff5063ctp7g" path="res://scripts/debug_overlay.gd" id="5"]
|
||||||
[ext_resource type="AudioStream" uid="uid://dthr2w8x0cj6v" path="res://assets/audio/sfx/ambience/wind-castle-loop.wav.mp3" id="6_6c6v5"]
|
[ext_resource type="AudioStream" uid="uid://dthr2w8x0cj6v" path="res://assets/audio/sfx/ambience/wind-castle-loop.wav.mp3" id="6_6c6v5"]
|
||||||
|
[ext_resource type="AudioStream" uid="uid://ba6csajuxujrg" path="res://assets/audio/music/Gelhein - Evil.mp3" id="8_pdbwf"]
|
||||||
[ext_resource type="TileSet" uid="uid://dqem5tbvooxrg" path="res://assets/gfx/RPG DUNGEON VOL 3.tres" id="9"]
|
[ext_resource type="TileSet" uid="uid://dqem5tbvooxrg" path="res://assets/gfx/RPG DUNGEON VOL 3.tres" id="9"]
|
||||||
|
|
||||||
[sub_resource type="ShaderMaterial" id="ShaderMaterial_pdbwf"]
|
[sub_resource type="ShaderMaterial" id="ShaderMaterial_pdbwf"]
|
||||||
@@ -108,5 +109,11 @@ light_mask = 1048575
|
|||||||
visibility_layer = 1048575
|
visibility_layer = 1048575
|
||||||
color = Color(0.69140625, 0.69140625, 0.69140625, 1)
|
color = Color(0.69140625, 0.69140625, 0.69140625, 1)
|
||||||
|
|
||||||
[node name="AudioStreamPlayer2D" type="AudioStreamPlayer2D" parent="." unique_id=1141138343]
|
[node name="SfxWinds" type="AudioStreamPlayer2D" parent="." unique_id=1141138343]
|
||||||
stream = ExtResource("6_6c6v5")
|
stream = ExtResource("6_6c6v5")
|
||||||
|
volume_db = -3.085
|
||||||
|
autoplay = true
|
||||||
|
|
||||||
|
[node name="BgMusic" type="AudioStreamPlayer2D" parent="." unique_id=628820950]
|
||||||
|
stream = ExtResource("8_pdbwf")
|
||||||
|
autoplay = true
|
||||||
|
|||||||
@@ -1,21 +1,38 @@
|
|||||||
[gd_scene format=3 uid="uid://d3heal8fx2kqm"]
|
[gd_scene format=3 uid="uid://d3heal8fx2kqm"]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://scripts/healing_effect.gd" id="1_script"]
|
[ext_resource type="Script" uid="uid://27wuloudfkme" path="res://scripts/healing_effect.gd" id="1_script"]
|
||||||
[ext_resource type="Texture2D" uid="uid://bf158atxi7ucy" path="res://assets/gfx/fx/shade_spell_effects.png" id="2_tex"]
|
[ext_resource type="Texture2D" uid="uid://bf158atxi7ucy" path="res://assets/gfx/fx/shade_spell_effects.png" id="2_tex"]
|
||||||
|
[ext_resource type="AudioStream" uid="uid://cag7alnbxymki" path="res://assets/audio/sfx/wizard/animevox/sparkle_1769364495063.wav" id="3_5s4aw"]
|
||||||
|
|
||||||
[node name="HealingEffect" type="Node2D"]
|
[sub_resource type="Gradient" id="Gradient_eqtlk"]
|
||||||
|
offsets = PackedFloat32Array(0.6593674, 0.7858881)
|
||||||
|
colors = PackedColorArray(1, 1, 1, 1, 1, 1, 1, 0)
|
||||||
|
|
||||||
|
[sub_resource type="GradientTexture2D" id="GradientTexture2D_5s4aw"]
|
||||||
|
gradient = SubResource("Gradient_eqtlk")
|
||||||
|
fill = 1
|
||||||
|
fill_from = Vector2(0.517094, 0.46581197)
|
||||||
|
fill_to = Vector2(0.08974359, 0.16239317)
|
||||||
|
|
||||||
|
[node name="HealingEffect" type="Node2D" unique_id=1363248185]
|
||||||
z_index = 5
|
z_index = 5
|
||||||
script = ExtResource("1_script")
|
script = ExtResource("1_script")
|
||||||
|
|
||||||
[node name="FxSprite" type="Sprite2D" parent="."]
|
[node name="FxSprite" type="Sprite2D" parent="." unique_id=972494408]
|
||||||
offset = Vector2(0, -24)
|
|
||||||
texture = ExtResource("2_tex")
|
texture = ExtResource("2_tex")
|
||||||
hframes = 105
|
hframes = 105
|
||||||
vframes = 79
|
vframes = 79
|
||||||
frame = 589
|
frame = 589
|
||||||
|
|
||||||
[node name="HealLight" type="PointLight2D" parent="."]
|
[node name="HealLight" type="PointLight2D" parent="." unique_id=1824746179]
|
||||||
|
enabled = false
|
||||||
color = Color(0.3, 1, 0.35, 1)
|
color = Color(0.3, 1, 0.35, 1)
|
||||||
energy = 0.8
|
energy = 0.8
|
||||||
|
texture = SubResource("GradientTexture2D_5s4aw")
|
||||||
texture_scale = 0.5
|
texture_scale = 0.5
|
||||||
enabled = false
|
|
||||||
|
[node name="SfxHeal" type="AudioStreamPlayer2D" parent="." unique_id=1867863062]
|
||||||
|
stream = ExtResource("3_5s4aw")
|
||||||
|
attenuation = 4.2870927
|
||||||
|
panning_strength = 1.08
|
||||||
|
bus = &"Sfx"
|
||||||
|
|||||||
41
src/scenes/minimap.tscn
Normal file
41
src/scenes/minimap.tscn
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
[gd_scene format=3 uid="uid://b5minimap01"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://scripts/minimap.gd" id="1_minimap"]
|
||||||
|
|
||||||
|
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_bg"]
|
||||||
|
bg_color = Color(0.06, 0.06, 0.08, 0.85)
|
||||||
|
corner_radius_top_left = 4
|
||||||
|
corner_radius_top_right = 4
|
||||||
|
corner_radius_bottom_right = 4
|
||||||
|
corner_radius_bottom_left = 4
|
||||||
|
border_width_left = 1
|
||||||
|
border_width_top = 1
|
||||||
|
border_width_right = 1
|
||||||
|
border_width_bottom = 1
|
||||||
|
border_color = Color(0.2, 0.2, 0.25, 1)
|
||||||
|
|
||||||
|
[node name="Minimap" type="CanvasLayer"]
|
||||||
|
layer = 198
|
||||||
|
|
||||||
|
[node name="MarginContainer" type="MarginContainer" parent="."]
|
||||||
|
anchors_preset = 1
|
||||||
|
anchor_left = 1.0
|
||||||
|
anchor_right = 1.0
|
||||||
|
offset_left = -136.0
|
||||||
|
offset_top = 8.0
|
||||||
|
offset_right = -8.0
|
||||||
|
offset_bottom = 104.0
|
||||||
|
grow_horizontal = 0
|
||||||
|
theme_override_constants/margin_left = 4
|
||||||
|
theme_override_constants/margin_top = 4
|
||||||
|
theme_override_constants/margin_right = 4
|
||||||
|
theme_override_constants/margin_bottom = 4
|
||||||
|
|
||||||
|
[node name="MinimapView" type="PanelContainer" parent="MarginContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_styles/panel = SubResource("StyleBoxFlat_bg")
|
||||||
|
|
||||||
|
[node name="MinimapDraw" type="Control" parent="MarginContainer/MinimapView"]
|
||||||
|
custom_minimum_size = Vector2(128, 96)
|
||||||
|
layout_mode = 2
|
||||||
|
script = ExtResource("1_minimap")
|
||||||
@@ -45,6 +45,8 @@
|
|||||||
[ext_resource type="AudioStream" uid="uid://ch3p57i7fvd1v" path="res://assets/audio/sfx/shield/shield2.wav" id="43_mx1m4"]
|
[ext_resource type="AudioStream" uid="uid://ch3p57i7fvd1v" path="res://assets/audio/sfx/shield/shield2.wav" id="43_mx1m4"]
|
||||||
[ext_resource type="AudioStream" uid="uid://t0sg2rxlfech" path="res://assets/audio/sfx/shield/shield3.wav" id="44_4gjji"]
|
[ext_resource type="AudioStream" uid="uid://t0sg2rxlfech" path="res://assets/audio/sfx/shield/shield3.wav" id="44_4gjji"]
|
||||||
[ext_resource type="AudioStream" uid="uid://dvq72502qa46f" path="res://assets/audio/sfx/shield/denied_activate_Shield2.wav" id="45_g5jhy"]
|
[ext_resource type="AudioStream" uid="uid://dvq72502qa46f" path="res://assets/audio/sfx/shield/denied_activate_Shield2.wav" id="45_g5jhy"]
|
||||||
|
[ext_resource type="AudioStream" uid="uid://8l0hx3sjh4ci" path="res://assets/audio/sfx/jsfxr/hitHurt (1).wav" id="46_holxr"]
|
||||||
|
[ext_resource type="AudioStream" uid="uid://cjv4cf2kiomwo" path="res://assets/audio/sfx/jsfxr/bird_sound.wav" id="47_mx1m4"]
|
||||||
|
|
||||||
[sub_resource type="Gradient" id="Gradient_wqfne"]
|
[sub_resource type="Gradient" id="Gradient_wqfne"]
|
||||||
colors = PackedColorArray(0, 0, 0, 1, 1, 0.13732082, 0.092538536, 1)
|
colors = PackedColorArray(0, 0, 0, 1, 1, 0.13732082, 0.092538536, 1)
|
||||||
@@ -573,12 +575,12 @@ scale = Vector2(1.984375, 2.0937502)
|
|||||||
texture = SubResource("GradientTexture2D_wnwbv")
|
texture = SubResource("GradientTexture2D_wnwbv")
|
||||||
|
|
||||||
[node name="ConeLight" type="PointLight2D" parent="." unique_id=120780131]
|
[node name="ConeLight" type="PointLight2D" parent="." unique_id=120780131]
|
||||||
blend_mode = 0
|
blend_mode = 2
|
||||||
shadow_enabled = true
|
shadow_enabled = true
|
||||||
|
|
||||||
[node name="PointLight2D" type="PointLight2D" parent="." unique_id=1250823818]
|
[node name="PointLight2D" type="PointLight2D" parent="." unique_id=1250823818]
|
||||||
position = Vector2(-1, 0)
|
position = Vector2(-1, 0)
|
||||||
blend_mode = 0
|
blend_mode = 2
|
||||||
shadow_enabled = true
|
shadow_enabled = true
|
||||||
texture = SubResource("GradientTexture2D_f1ej7")
|
texture = SubResource("GradientTexture2D_f1ej7")
|
||||||
|
|
||||||
@@ -745,7 +747,6 @@ panning_strength = 1.11
|
|||||||
visible = false
|
visible = false
|
||||||
rotation = 3.1869712
|
rotation = 3.1869712
|
||||||
energy = 0.13
|
energy = 0.13
|
||||||
blend_mode = 0
|
|
||||||
shadow_enabled = true
|
shadow_enabled = true
|
||||||
max_distance = 100.0
|
max_distance = 100.0
|
||||||
|
|
||||||
@@ -811,3 +812,16 @@ frame = 711
|
|||||||
[node name="AnimationPlayerStatus" type="AnimationPlayer" parent="Sprite2DStatus" unique_id=721795152]
|
[node name="AnimationPlayerStatus" type="AnimationPlayer" parent="Sprite2DStatus" unique_id=721795152]
|
||||||
libraries/ = SubResource("AnimationLibrary_mx1m4")
|
libraries/ = SubResource("AnimationLibrary_mx1m4")
|
||||||
autoplay = &"idle"
|
autoplay = &"idle"
|
||||||
|
|
||||||
|
[node name="SfxFallDownLand" type="AudioStreamPlayer2D" parent="." unique_id=1674409490]
|
||||||
|
stream = ExtResource("46_holxr")
|
||||||
|
max_distance = 1677.0
|
||||||
|
attenuation = 1.8660662
|
||||||
|
bus = &"Sfx"
|
||||||
|
|
||||||
|
[node name="SfxBirdSound" type="AudioStreamPlayer2D" parent="." unique_id=1946085725]
|
||||||
|
stream = ExtResource("47_mx1m4")
|
||||||
|
volume_db = -13.255
|
||||||
|
attenuation = 3.2490087
|
||||||
|
panning_strength = 1.12
|
||||||
|
bus = &"Sfx"
|
||||||
|
|||||||
826
src/scenes/player.tscn69243350395.tmp
Normal file
826
src/scenes/player.tscn69243350395.tmp
Normal file
@@ -0,0 +1,826 @@
|
|||||||
|
[gd_scene format=3 uid="uid://cxfvw8y7jqn2p"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://ck72vhkja7nbo" path="res://scripts/player.gd" id="1"]
|
||||||
|
[ext_resource type="Script" uid="uid://cpxabh3uq1kl4" path="res://scripts/create_shadow_sprite.gd" id="3"]
|
||||||
|
[ext_resource type="Shader" uid="uid://ldl7vaq5n13f" path="res://shaders/cloth.gdshader" id="3_wnwbv"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://bkninujaqqvb1" path="res://assets/gfx/Puny-Characters/Layer 0 - Skins/Human1_1.png" id="4"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://dx1fovugabbwc" path="res://assets/gfx/Puny-Characters/Layer 1 - Shoes/IronBoots.png" id="5"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://bbqk2lcs772q3" path="res://assets/gfx/Puny-Characters/Layer 2 - Clothes/Armour Body/BronzeArmour.png" id="6"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://bkiexfnpcaxwa" path="res://assets/gfx/Puny-Characters/Layer 4 - Hairstyle/Facial Hairstyles/Mustache1White.png" id="7"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://ccu5cpyo7jpdr" path="res://assets/gfx/Puny-Characters/Layer 4 - Hairstyle/Hairstyles/MHairstyle8White.png" id="8"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://0lmhxwt7k3e4" path="res://assets/gfx/Puny-Characters/Layer 5 - Eyes/Eye Color/EyecolorLightLime.png" id="9"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://b4vh2v0x58v2f" path="res://assets/gfx/Puny-Characters/Layer 5 - Eyes/Eyelashes/MEyelash1.png" id="10"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://jxo0e2x145rs" path="res://assets/gfx/Puny-Characters/Layer 7 - Add-ons/Elf Add-ons/ElfEars3.png" id="11"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://cu5fkio3ajr5i" path="res://assets/gfx/Puny-Characters/Layer 6 - Headgears/French/MusketeerHatPurple.png" id="12"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://bloqx3mibftjn" path="res://assets/gfx/Puny-Characters/WeaponOverlayer.png" id="13"]
|
||||||
|
[ext_resource type="AudioStream" uid="uid://cbio6f0ssxvd6" path="res://assets/audio/sfx/walk/stone/walk_stone_1.wav.mp3" id="13_fulsm"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://bkca7nmt4du5e" path="res://assets/gfx/Puny-Characters/ShieldOverlayer.png" id="13_t4otl"]
|
||||||
|
[ext_resource type="AudioStream" uid="uid://dq1va2882v23v" path="res://assets/audio/sfx/walk/stone/walk_stone_2.wav.mp3" id="14_4r5pv"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://bpxxpdpow5qyl" path="res://assets/gfx/Puny-Characters/ShieldOverlayerHolding.png" id="14_j2b1d"]
|
||||||
|
[ext_resource type="AudioStream" uid="uid://dsuf4oa710gi8" path="res://assets/audio/sfx/walk/stone/walk_stone_3.wav.mp3" id="15_60mlk"]
|
||||||
|
[ext_resource type="AudioStream" uid="uid://fvhvmxtcq018" path="res://assets/audio/sfx/walk/stone/walk_stone_4.wav.mp3" id="16_i4ail"]
|
||||||
|
[ext_resource type="AudioStream" uid="uid://cw74evef8fm0t" path="res://assets/audio/sfx/walk/stone/walk_stone_5.wav.mp3" id="17_a38lo"]
|
||||||
|
[ext_resource type="AudioStream" uid="uid://c43fyqtos11fd" path="res://assets/audio/sfx/walk/stone/walk_stone_6.wav.mp3" id="18_4ni07"]
|
||||||
|
[ext_resource type="AudioStream" uid="uid://b4ng0o2en2hkm" path="res://assets/audio/sfx/player/fall_out/player_fall_infinitely-02.wav.mp3" id="19_4r5pv"]
|
||||||
|
[ext_resource type="AudioStream" uid="uid://bi546r2d771yg" path="res://assets/audio/sfx/player/take_damage/player_damaged_01.wav.mp3" id="20_ujl30"]
|
||||||
|
[ext_resource type="AudioStream" uid="uid://b8trgc0pbomud" path="res://assets/audio/sfx/player/take_damage/player_damaged_02.wav.mp3" id="21_31cv2"]
|
||||||
|
[ext_resource type="AudioStream" uid="uid://dsnvagvhs152x" path="res://assets/audio/sfx/player/take_damage/player_damaged_03.wav.mp3" id="22_pf23h"]
|
||||||
|
[ext_resource type="AudioStream" uid="uid://ce51n4tvvflro" path="res://assets/audio/sfx/player/take_damage/player_damaged_04.wav.mp3" id="23_dt7fs"]
|
||||||
|
[ext_resource type="AudioStream" uid="uid://caclaiagfnr2o" path="res://assets/audio/sfx/player/take_damage/player_damaged_05.wav.mp3" id="24_wqfne"]
|
||||||
|
[ext_resource type="AudioStream" uid="uid://dighi525ty7sl" path="res://assets/audio/sfx/player/take_damage/player_damaged_06.wav.mp3" id="25_wnwbv"]
|
||||||
|
[ext_resource type="AudioStream" uid="uid://bdhmel5vyixng" path="res://assets/audio/sfx/player/take_damage/player_damaged_07.wav.mp3" id="26_gl8cc"]
|
||||||
|
[ext_resource type="AudioStream" uid="uid://4vulahdsj4i2" path="res://assets/audio/sfx/swoosh/throw_01.wav.mp3" id="27_31cv2"]
|
||||||
|
[ext_resource type="AudioStream" uid="uid://w6yon88kjfml" path="res://assets/audio/sfx/nickes/lift_sfx.ogg" id="28_pf23h"]
|
||||||
|
[ext_resource type="AudioStream" uid="uid://b6klanrso0vvq" path="res://assets/audio/sfx/weapons/bow/bow_release_1.mp3" id="30_md1ol"]
|
||||||
|
[ext_resource type="AudioStream" uid="uid://mbtpqlb5n3gd" path="res://assets/audio/sfx/weapons/bow/bow_no_arrow.mp3" id="31_487ah"]
|
||||||
|
[ext_resource type="AudioStream" uid="uid://b6mwlp2ap0wbj" path="res://assets/audio/sfx/weapons/bow/bow_release2.mp3" id="31_bj30b"]
|
||||||
|
[ext_resource type="AudioStream" uid="uid://cgya50qrx8gms" path="res://assets/audio/sfx/weapons/bow/buckle_bow.mp3" id="32_gl8cc"]
|
||||||
|
[ext_resource type="AudioStream" uid="uid://d1ut5lnlch0k2" path="res://assets/audio/sfx/weapons/bow/bow_release3.mp3" id="32_jc3p3"]
|
||||||
|
[ext_resource type="AudioStream" uid="uid://bvi00vbftbgc5" path="res://assets/audio/sfx/player/ultra_run/shinespark_start.wav" id="35_bj30b"]
|
||||||
|
[ext_resource type="AudioStream" uid="uid://0xm3gyh8051h" path="res://assets/audio/sfx/wizard/incantations/indignation.mp3" id="36_jc3p3"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://bf158atxi7ucy" path="res://assets/gfx/fx/shade_spell_effects.png" id="37_hax0n"]
|
||||||
|
[ext_resource type="AudioStream" uid="uid://c10ju1f6d4ed3" path="res://assets/audio/sfx/shield/activate_shield.wav" id="40_hhpqf"]
|
||||||
|
[ext_resource type="AudioStream" uid="uid://ly1euk0v3jxy" path="res://assets/audio/sfx/shield/shield.wav" id="41_g5jhy"]
|
||||||
|
[ext_resource type="AudioStream" uid="uid://c4lh535yj010h" path="res://assets/audio/sfx/shield/shield1.wav" id="42_holxr"]
|
||||||
|
[ext_resource type="AudioStream" uid="uid://ch3p57i7fvd1v" path="res://assets/audio/sfx/shield/shield2.wav" id="43_mx1m4"]
|
||||||
|
[ext_resource type="AudioStream" uid="uid://t0sg2rxlfech" path="res://assets/audio/sfx/shield/shield3.wav" id="44_4gjji"]
|
||||||
|
[ext_resource type="AudioStream" uid="uid://dvq72502qa46f" path="res://assets/audio/sfx/shield/denied_activate_Shield2.wav" id="45_g5jhy"]
|
||||||
|
[ext_resource type="AudioStream" uid="uid://8l0hx3sjh4ci" path="res://assets/audio/sfx/jsfxr/hitHurt (1).wav" id="46_holxr"]
|
||||||
|
[ext_resource type="AudioStream" uid="uid://cjv4cf2kiomwo" path="res://assets/audio/sfx/jsfxr/bird_sound.wav" id="47_mx1m4"]
|
||||||
|
|
||||||
|
[sub_resource type="Gradient" id="Gradient_wqfne"]
|
||||||
|
colors = PackedColorArray(0, 0, 0, 1, 1, 0.13732082, 0.092538536, 1)
|
||||||
|
|
||||||
|
[sub_resource type="GradientTexture2D" id="GradientTexture2D_wnwbv"]
|
||||||
|
gradient = SubResource("Gradient_wqfne")
|
||||||
|
fill_from = Vector2(0.46153846, 0.87606835)
|
||||||
|
fill_to = Vector2(0.46153846, 0.11965812)
|
||||||
|
|
||||||
|
[sub_resource type="Gradient" id="Gradient_jej6c"]
|
||||||
|
offsets = PackedFloat32Array(0.7710843, 0.77710843)
|
||||||
|
colors = PackedColorArray(1, 1, 1, 1, 1, 1, 1, 0)
|
||||||
|
|
||||||
|
[sub_resource type="GradientTexture2D" id="GradientTexture2D_f1ej7"]
|
||||||
|
gradient = SubResource("Gradient_jej6c")
|
||||||
|
use_hdr = true
|
||||||
|
fill = 1
|
||||||
|
fill_from = Vector2(0.51304346, 0.51304346)
|
||||||
|
fill_to = Vector2(0.8974359, 0.08547009)
|
||||||
|
|
||||||
|
[sub_resource type="CircleShape2D" id="CircleShape2D_pf23h"]
|
||||||
|
radius = 32.0
|
||||||
|
|
||||||
|
[sub_resource type="Gradient" id="Gradient_3v2ag"]
|
||||||
|
offsets = PackedFloat32Array(0.3883721, 0.8372093)
|
||||||
|
colors = PackedColorArray(0, 0, 0, 0.74509805, 0, 0, 0, 0)
|
||||||
|
|
||||||
|
[sub_resource type="GradientTexture2D" id="GradientTexture2D_jej6c"]
|
||||||
|
gradient = SubResource("Gradient_3v2ag")
|
||||||
|
width = 12
|
||||||
|
height = 6
|
||||||
|
fill = 1
|
||||||
|
fill_from = Vector2(0.51304346, 0.46086955)
|
||||||
|
fill_to = Vector2(0, 0)
|
||||||
|
|
||||||
|
[sub_resource type="ShaderMaterial" id="ShaderMaterial_md1ol"]
|
||||||
|
shader = ExtResource("3_wnwbv")
|
||||||
|
shader_parameter/original_0 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_1 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_2 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_3 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_4 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_5 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_6 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_0 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_1 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_2 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_3 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_4 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_5 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_6 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/tint = Color(1, 1, 1, 1)
|
||||||
|
|
||||||
|
[sub_resource type="ShaderMaterial" id="ShaderMaterial_bj30b"]
|
||||||
|
shader = ExtResource("3_wnwbv")
|
||||||
|
shader_parameter/original_0 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_1 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_2 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_3 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_4 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_5 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_6 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_0 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_1 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_2 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_3 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_4 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_5 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_6 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/tint = Color(1, 1, 1, 1)
|
||||||
|
|
||||||
|
[sub_resource type="ShaderMaterial" id="ShaderMaterial_jc3p3"]
|
||||||
|
shader = ExtResource("3_wnwbv")
|
||||||
|
shader_parameter/original_0 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_1 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_2 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_3 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_4 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_5 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_6 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_0 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_1 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_2 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_3 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_4 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_5 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_6 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/tint = Color(1, 1, 1, 1)
|
||||||
|
|
||||||
|
[sub_resource type="ShaderMaterial" id="ShaderMaterial_hax0n"]
|
||||||
|
shader = ExtResource("3_wnwbv")
|
||||||
|
shader_parameter/original_0 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_1 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_2 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_3 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_4 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_5 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_6 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_0 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_1 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_2 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_3 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_4 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_5 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_6 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/tint = Color(1, 1, 1, 1)
|
||||||
|
|
||||||
|
[sub_resource type="ShaderMaterial" id="ShaderMaterial_t4otl"]
|
||||||
|
shader = ExtResource("3_wnwbv")
|
||||||
|
shader_parameter/original_0 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_1 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_2 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_3 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_4 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_5 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_6 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_0 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_1 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_2 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_3 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_4 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_5 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_6 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/tint = Color(1, 1, 1, 1)
|
||||||
|
|
||||||
|
[sub_resource type="ShaderMaterial" id="ShaderMaterial_j2b1d"]
|
||||||
|
shader = ExtResource("3_wnwbv")
|
||||||
|
shader_parameter/original_0 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_1 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_2 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_3 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_4 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_5 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_6 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_0 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_1 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_2 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_3 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_4 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_5 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_6 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/tint = Color(1, 1, 1, 1)
|
||||||
|
|
||||||
|
[sub_resource type="ShaderMaterial" id="ShaderMaterial_cs1tg"]
|
||||||
|
shader = ExtResource("3_wnwbv")
|
||||||
|
shader_parameter/original_0 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_1 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_2 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_3 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_4 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_5 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_6 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_0 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_1 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_2 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_3 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_4 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_5 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_6 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/tint = Color(1, 1, 1, 1)
|
||||||
|
|
||||||
|
[sub_resource type="ShaderMaterial" id="ShaderMaterial_2dvfe"]
|
||||||
|
shader = ExtResource("3_wnwbv")
|
||||||
|
shader_parameter/original_0 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_1 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_2 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_3 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_4 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_5 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_6 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_0 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_1 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_2 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_3 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_4 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_5 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_6 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/tint = Color(1, 1, 1, 1)
|
||||||
|
|
||||||
|
[sub_resource type="ShaderMaterial" id="ShaderMaterial_giy8y"]
|
||||||
|
shader = ExtResource("3_wnwbv")
|
||||||
|
shader_parameter/original_0 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_1 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_2 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_3 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_4 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_5 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_6 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_0 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_1 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_2 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_3 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_4 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_5 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_6 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/tint = Color(1, 1, 1, 1)
|
||||||
|
|
||||||
|
[sub_resource type="ShaderMaterial" id="ShaderMaterial_hhpqf"]
|
||||||
|
shader = ExtResource("3_wnwbv")
|
||||||
|
shader_parameter/original_0 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_1 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_2 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_3 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_4 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_5 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_6 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_0 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_1 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_2 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_3 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_4 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_5 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_6 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/tint = Color(1, 1, 1, 1)
|
||||||
|
|
||||||
|
[sub_resource type="ShaderMaterial" id="ShaderMaterial_fdfoy"]
|
||||||
|
shader = ExtResource("3_wnwbv")
|
||||||
|
shader_parameter/original_0 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_1 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_2 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_3 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_4 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_5 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/original_6 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_0 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_1 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_2 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_3 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_4 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_5 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/replace_6 = Color(0, 0, 0, 1)
|
||||||
|
shader_parameter/tint = Color(1, 1, 1, 1)
|
||||||
|
|
||||||
|
[sub_resource type="CircleShape2D" id="CircleShape2D_wnwbv"]
|
||||||
|
radius = 4.0
|
||||||
|
|
||||||
|
[sub_resource type="CircleShape2D" id="CircleShape2D_2"]
|
||||||
|
radius = 8.0
|
||||||
|
|
||||||
|
[sub_resource type="AudioStreamRandomizer" id="AudioStreamRandomizer_l71n6"]
|
||||||
|
playback_mode = 1
|
||||||
|
random_pitch = 1.0118532
|
||||||
|
streams_count = 6
|
||||||
|
stream_0/stream = ExtResource("13_fulsm")
|
||||||
|
stream_1/stream = ExtResource("14_4r5pv")
|
||||||
|
stream_2/stream = ExtResource("15_60mlk")
|
||||||
|
stream_3/stream = ExtResource("16_i4ail")
|
||||||
|
stream_4/stream = ExtResource("17_a38lo")
|
||||||
|
stream_5/stream = ExtResource("18_4ni07")
|
||||||
|
|
||||||
|
[sub_resource type="AudioStreamRandomizer" id="AudioStreamRandomizer_487ah"]
|
||||||
|
playback_mode = 1
|
||||||
|
random_pitch = 1.0118532
|
||||||
|
streams_count = 7
|
||||||
|
stream_0/stream = ExtResource("20_ujl30")
|
||||||
|
stream_1/stream = ExtResource("21_31cv2")
|
||||||
|
stream_2/stream = ExtResource("22_pf23h")
|
||||||
|
stream_3/stream = ExtResource("23_dt7fs")
|
||||||
|
stream_4/stream = ExtResource("24_wqfne")
|
||||||
|
stream_5/stream = ExtResource("25_wnwbv")
|
||||||
|
stream_6/stream = ExtResource("26_gl8cc")
|
||||||
|
|
||||||
|
[sub_resource type="AudioStreamRandomizer" id="AudioStreamRandomizer_bj30b"]
|
||||||
|
playback_mode = 1
|
||||||
|
random_pitch = 1.0123794
|
||||||
|
streams_count = 3
|
||||||
|
stream_0/stream = ExtResource("30_md1ol")
|
||||||
|
stream_1/stream = ExtResource("31_bj30b")
|
||||||
|
stream_2/stream = ExtResource("32_jc3p3")
|
||||||
|
|
||||||
|
[sub_resource type="AudioStreamRandomizer" id="AudioStreamRandomizer_hhpqf"]
|
||||||
|
random_pitch = 1.0630184
|
||||||
|
streams_count = 1
|
||||||
|
stream_0/stream = ExtResource("31_487ah")
|
||||||
|
|
||||||
|
[sub_resource type="Animation" id="Animation_t4otl"]
|
||||||
|
length = 0.001
|
||||||
|
tracks/0/type = "value"
|
||||||
|
tracks/0/imported = false
|
||||||
|
tracks/0/enabled = true
|
||||||
|
tracks/0/path = NodePath("IncantationSprite:frame")
|
||||||
|
tracks/0/interp = 1
|
||||||
|
tracks/0/loop_wrap = true
|
||||||
|
tracks/0/keys = {
|
||||||
|
"times": PackedFloat32Array(0),
|
||||||
|
"transitions": PackedFloat32Array(1),
|
||||||
|
"update": 1,
|
||||||
|
"values": [2037]
|
||||||
|
}
|
||||||
|
|
||||||
|
[sub_resource type="Animation" id="Animation_j2b1d"]
|
||||||
|
resource_name = "fire_charging"
|
||||||
|
length = 0.4
|
||||||
|
loop_mode = 1
|
||||||
|
tracks/0/type = "value"
|
||||||
|
tracks/0/imported = false
|
||||||
|
tracks/0/enabled = true
|
||||||
|
tracks/0/path = NodePath("IncantationSprite:frame")
|
||||||
|
tracks/0/interp = 1
|
||||||
|
tracks/0/loop_wrap = true
|
||||||
|
tracks/0/keys = {
|
||||||
|
"times": PackedFloat32Array(0, 0.03333334, 0.06666667, 0.10000002, 0.13333336, 0.16666669, 0.20000002, 0.23333335, 0.26666668, 0.30000004, 0.33333337, 0.3666667, 0.4, 0.43333337, 0.46666673, 0.5, 0.53333336),
|
||||||
|
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
|
||||||
|
"update": 1,
|
||||||
|
"values": [2037, 2038, 2039, 2040, 2041, 2042, 2043, 2044, 2045, 2046, 2047, 2048, 2049, 2050, 2051, 2052, 2053]
|
||||||
|
}
|
||||||
|
|
||||||
|
[sub_resource type="Animation" id="Animation_cs1tg"]
|
||||||
|
resource_name = "fire_ready"
|
||||||
|
length = 0.6
|
||||||
|
tracks/0/type = "value"
|
||||||
|
tracks/0/imported = false
|
||||||
|
tracks/0/enabled = true
|
||||||
|
tracks/0/path = NodePath("IncantationSprite:frame")
|
||||||
|
tracks/0/interp = 1
|
||||||
|
tracks/0/loop_wrap = true
|
||||||
|
tracks/0/keys = {
|
||||||
|
"times": PackedFloat32Array(0, 0.03333334, 0.06666667, 0.10000002, 0.13333336, 0.16666669, 0.20000002, 0.23333335, 0.26666668, 0.30000004, 0.33333337, 0.3666667, 0.4, 0.43333337, 0.46666673, 0.5, 0.53333336),
|
||||||
|
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
|
||||||
|
"update": 1,
|
||||||
|
"values": [2037, 2038, 2039, 2040, 2041, 2042, 2043, 2044, 2045, 2046, 2047, 2048, 2049, 2050, 2051, 2052, 2053]
|
||||||
|
}
|
||||||
|
|
||||||
|
[sub_resource type="Animation" id="Animation_frost_ch"]
|
||||||
|
resource_name = "frost_charging"
|
||||||
|
length = 0.566
|
||||||
|
loop_mode = 1
|
||||||
|
tracks/0/type = "value"
|
||||||
|
tracks/0/imported = false
|
||||||
|
tracks/0/enabled = true
|
||||||
|
tracks/0/path = NodePath("IncantationSprite:frame")
|
||||||
|
tracks/0/interp = 1
|
||||||
|
tracks/0/loop_wrap = true
|
||||||
|
tracks/0/keys = {
|
||||||
|
"times": PackedFloat32Array(0, 0.03333334, 0.06666667, 0.1, 0.13333334, 0.16666667, 0.2, 0.23333333, 0.26666668, 0.3, 0.33333334, 0.36666667, 0.4, 0.43333334, 0.46666667, 0.5, 0.53333336),
|
||||||
|
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
|
||||||
|
"update": 1,
|
||||||
|
"values": [3678, 3679, 3680, 3681, 3682, 3683, 3684, 3685, 3686, 3687, 3688, 3689, 3690, 3691, 3692, 3693, 3694]
|
||||||
|
}
|
||||||
|
|
||||||
|
[sub_resource type="Animation" id="Animation_frost_rdy"]
|
||||||
|
resource_name = "frost_ready"
|
||||||
|
length = 0.566
|
||||||
|
loop_mode = 1
|
||||||
|
tracks/0/type = "value"
|
||||||
|
tracks/0/imported = false
|
||||||
|
tracks/0/enabled = true
|
||||||
|
tracks/0/path = NodePath("IncantationSprite:frame")
|
||||||
|
tracks/0/interp = 1
|
||||||
|
tracks/0/loop_wrap = true
|
||||||
|
tracks/0/keys = {
|
||||||
|
"times": PackedFloat32Array(0, 0.03333334, 0.06666667, 0.1, 0.13333334, 0.16666667, 0.2, 0.23333333, 0.26666668, 0.3, 0.33333334, 0.36666667, 0.4, 0.43333334, 0.46666667, 0.5, 0.53333336),
|
||||||
|
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
|
||||||
|
"update": 1,
|
||||||
|
"values": [3678, 3679, 3680, 3681, 3682, 3683, 3684, 3685, 3686, 3687, 3688, 3689, 3690, 3691, 3692, 3693, 3694]
|
||||||
|
}
|
||||||
|
|
||||||
|
[sub_resource type="Animation" id="Animation_heal_ch"]
|
||||||
|
resource_name = "healing_charging"
|
||||||
|
length = 0.5
|
||||||
|
loop_mode = 1
|
||||||
|
tracks/0/type = "value"
|
||||||
|
tracks/0/imported = false
|
||||||
|
tracks/0/enabled = true
|
||||||
|
tracks/0/path = NodePath("IncantationSprite:frame")
|
||||||
|
tracks/0/interp = 1
|
||||||
|
tracks/0/loop_wrap = true
|
||||||
|
tracks/0/keys = {
|
||||||
|
"times": PackedFloat32Array(0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45),
|
||||||
|
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
|
||||||
|
"update": 1,
|
||||||
|
"values": [589, 590, 591, 592, 593, 594, 595, 596, 597, 598]
|
||||||
|
}
|
||||||
|
|
||||||
|
[sub_resource type="Animation" id="Animation_heal_rdy"]
|
||||||
|
resource_name = "healing_ready"
|
||||||
|
length = 0.5
|
||||||
|
tracks/0/type = "value"
|
||||||
|
tracks/0/imported = false
|
||||||
|
tracks/0/enabled = true
|
||||||
|
tracks/0/path = NodePath("IncantationSprite:frame")
|
||||||
|
tracks/0/interp = 1
|
||||||
|
tracks/0/loop_wrap = true
|
||||||
|
tracks/0/keys = {
|
||||||
|
"times": PackedFloat32Array(0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45),
|
||||||
|
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
|
||||||
|
"update": 1,
|
||||||
|
"values": [589, 590, 591, 592, 593, 594, 595, 596, 597, 598]
|
||||||
|
}
|
||||||
|
|
||||||
|
[sub_resource type="Animation" id="Animation_hax0n"]
|
||||||
|
resource_name = "idle"
|
||||||
|
length = 0.1
|
||||||
|
tracks/0/type = "value"
|
||||||
|
tracks/0/imported = false
|
||||||
|
tracks/0/enabled = true
|
||||||
|
tracks/0/path = NodePath("IncantationSprite: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="AnimationLibrary" id="AnimationLibrary_2dvfe"]
|
||||||
|
_data = {
|
||||||
|
&"RESET": SubResource("Animation_t4otl"),
|
||||||
|
&"fire_charging": SubResource("Animation_j2b1d"),
|
||||||
|
&"fire_ready": SubResource("Animation_cs1tg"),
|
||||||
|
&"frost_charging": SubResource("Animation_frost_ch"),
|
||||||
|
&"frost_ready": SubResource("Animation_frost_rdy"),
|
||||||
|
&"healing_charging": SubResource("Animation_heal_ch"),
|
||||||
|
&"healing_ready": SubResource("Animation_heal_rdy"),
|
||||||
|
&"idle": SubResource("Animation_hax0n")
|
||||||
|
}
|
||||||
|
|
||||||
|
[sub_resource type="AudioStreamRandomizer" id="AudioStreamRandomizer_u2ulf"]
|
||||||
|
streams_count = 4
|
||||||
|
stream_0/stream = ExtResource("41_g5jhy")
|
||||||
|
stream_1/stream = ExtResource("42_holxr")
|
||||||
|
stream_2/stream = ExtResource("43_mx1m4")
|
||||||
|
stream_3/stream = ExtResource("44_4gjji")
|
||||||
|
|
||||||
|
[sub_resource type="Animation" id="Animation_g5jhy"]
|
||||||
|
length = 0.001
|
||||||
|
tracks/0/type = "value"
|
||||||
|
tracks/0/imported = false
|
||||||
|
tracks/0/enabled = true
|
||||||
|
tracks/0/path = NodePath(".:frame")
|
||||||
|
tracks/0/interp = 1
|
||||||
|
tracks/0/loop_wrap = true
|
||||||
|
tracks/0/keys = {
|
||||||
|
"times": PackedFloat32Array(0),
|
||||||
|
"transitions": PackedFloat32Array(1),
|
||||||
|
"update": 1,
|
||||||
|
"values": [711]
|
||||||
|
}
|
||||||
|
|
||||||
|
[sub_resource type="Animation" id="Animation_holxr"]
|
||||||
|
resource_name = "concussion"
|
||||||
|
length = 1.0666667
|
||||||
|
loop_mode = 1
|
||||||
|
tracks/0/type = "value"
|
||||||
|
tracks/0/imported = false
|
||||||
|
tracks/0/enabled = true
|
||||||
|
tracks/0/path = NodePath(".:frame")
|
||||||
|
tracks/0/interp = 1
|
||||||
|
tracks/0/loop_wrap = true
|
||||||
|
tracks/0/keys = {
|
||||||
|
"times": PackedFloat32Array(0, 0.06666667, 0.13333333, 0.2, 0.26666668, 0.33333334, 0.4, 0.46666667, 0.53333336, 0.6, 0.6666667, 0.73333335, 0.8, 0.8666667, 0.93333334, 1),
|
||||||
|
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
|
||||||
|
"update": 1,
|
||||||
|
"values": [711, 712, 713, 714, 715, 716, 717, 718, 719, 720, 721, 722, 723, 724, 725, 726]
|
||||||
|
}
|
||||||
|
|
||||||
|
[sub_resource type="Animation" id="Animation_u2ulf"]
|
||||||
|
resource_name = "idle"
|
||||||
|
length = 0.46666667
|
||||||
|
tracks/0/type = "value"
|
||||||
|
tracks/0/imported = false
|
||||||
|
tracks/0/enabled = true
|
||||||
|
tracks/0/path = NodePath(".: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_4gjji"]
|
||||||
|
resource_name = "poison"
|
||||||
|
length = 0.6
|
||||||
|
loop_mode = 1
|
||||||
|
tracks/0/type = "value"
|
||||||
|
tracks/0/imported = false
|
||||||
|
tracks/0/enabled = true
|
||||||
|
tracks/0/path = NodePath(".:frame")
|
||||||
|
tracks/0/interp = 1
|
||||||
|
tracks/0/loop_wrap = true
|
||||||
|
tracks/0/keys = {
|
||||||
|
"times": PackedFloat32Array(0, 0.06666667, 0.13333334, 0.2, 0.26666668, 0.33333334, 0.4, 0.46666667, 0.53333336),
|
||||||
|
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1),
|
||||||
|
"update": 1,
|
||||||
|
"values": [1893, 1894, 1895, 1896, 1897, 1898, 1899, 1900, 1901]
|
||||||
|
}
|
||||||
|
|
||||||
|
[sub_resource type="Animation" id="Animation_mx1m4"]
|
||||||
|
resource_name = "sleep"
|
||||||
|
length = 0.6
|
||||||
|
loop_mode = 1
|
||||||
|
tracks/0/type = "value"
|
||||||
|
tracks/0/imported = false
|
||||||
|
tracks/0/enabled = true
|
||||||
|
tracks/0/path = NodePath(".: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": [291, 292, 293, 294, 295, 296]
|
||||||
|
}
|
||||||
|
|
||||||
|
[sub_resource type="AnimationLibrary" id="AnimationLibrary_mx1m4"]
|
||||||
|
_data = {
|
||||||
|
&"RESET": SubResource("Animation_g5jhy"),
|
||||||
|
&"concussion": SubResource("Animation_holxr"),
|
||||||
|
&"idle": SubResource("Animation_u2ulf"),
|
||||||
|
&"poison": SubResource("Animation_4gjji"),
|
||||||
|
&"sleep": SubResource("Animation_mx1m4")
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="Player" type="CharacterBody2D" unique_id=937429705]
|
||||||
|
collision_mask = 67
|
||||||
|
motion_mode = 1
|
||||||
|
script = ExtResource("1")
|
||||||
|
|
||||||
|
[node name="Sprite2D" type="Sprite2D" parent="." unique_id=720799975]
|
||||||
|
visible = false
|
||||||
|
position = Vector2(1.499999, -2.0000038)
|
||||||
|
scale = Vector2(1.984375, 2.0937502)
|
||||||
|
texture = SubResource("GradientTexture2D_wnwbv")
|
||||||
|
|
||||||
|
[node name="ConeLight" type="PointLight2D" parent="." unique_id=120780131]
|
||||||
|
blend_mode = 2
|
||||||
|
shadow_enabled = true
|
||||||
|
|
||||||
|
[node name="PointLight2D" type="PointLight2D" parent="." unique_id=1250823818]
|
||||||
|
position = Vector2(-1, 0)
|
||||||
|
blend_mode = 2
|
||||||
|
shadow_enabled = true
|
||||||
|
texture = SubResource("GradientTexture2D_f1ej7")
|
||||||
|
|
||||||
|
[node name="LightCollision" type="Area2D" parent="PointLight2D" unique_id=502090625]
|
||||||
|
collision_layer = 0
|
||||||
|
collision_mask = 16384
|
||||||
|
|
||||||
|
[node name="CollisionShape2D" type="CollisionShape2D" parent="PointLight2D/LightCollision" unique_id=1350075834]
|
||||||
|
shape = SubResource("CircleShape2D_pf23h")
|
||||||
|
|
||||||
|
[node name="Shadow" type="Sprite2D" parent="." unique_id=937683521]
|
||||||
|
position = Vector2(0, 7)
|
||||||
|
texture = SubResource("GradientTexture2D_jej6c")
|
||||||
|
script = ExtResource("3")
|
||||||
|
|
||||||
|
[node name="Sprite2DBody" type="Sprite2D" parent="." unique_id=2113577699]
|
||||||
|
y_sort_enabled = true
|
||||||
|
material = SubResource("ShaderMaterial_md1ol")
|
||||||
|
texture = ExtResource("4")
|
||||||
|
hframes = 35
|
||||||
|
vframes = 8
|
||||||
|
|
||||||
|
[node name="Sprite2DBoots" type="Sprite2D" parent="." unique_id=598174931]
|
||||||
|
y_sort_enabled = true
|
||||||
|
material = SubResource("ShaderMaterial_bj30b")
|
||||||
|
texture = ExtResource("5")
|
||||||
|
hframes = 35
|
||||||
|
vframes = 8
|
||||||
|
|
||||||
|
[node name="Sprite2DArmour" type="Sprite2D" parent="." unique_id=2130297502]
|
||||||
|
y_sort_enabled = true
|
||||||
|
material = SubResource("ShaderMaterial_jc3p3")
|
||||||
|
texture = ExtResource("6")
|
||||||
|
hframes = 35
|
||||||
|
vframes = 8
|
||||||
|
|
||||||
|
[node name="Sprite2DFacialHair" type="Sprite2D" parent="." unique_id=1050766722]
|
||||||
|
y_sort_enabled = true
|
||||||
|
material = SubResource("ShaderMaterial_hax0n")
|
||||||
|
texture = ExtResource("7")
|
||||||
|
hframes = 35
|
||||||
|
vframes = 8
|
||||||
|
|
||||||
|
[node name="Sprite2DHair" type="Sprite2D" parent="." unique_id=927492041]
|
||||||
|
y_sort_enabled = true
|
||||||
|
material = SubResource("ShaderMaterial_t4otl")
|
||||||
|
texture = ExtResource("8")
|
||||||
|
hframes = 35
|
||||||
|
vframes = 8
|
||||||
|
|
||||||
|
[node name="Sprite2DEyes" type="Sprite2D" parent="." unique_id=2054421939]
|
||||||
|
y_sort_enabled = true
|
||||||
|
material = SubResource("ShaderMaterial_j2b1d")
|
||||||
|
texture = ExtResource("9")
|
||||||
|
hframes = 35
|
||||||
|
vframes = 8
|
||||||
|
|
||||||
|
[node name="Sprite2DEyeLashes" type="Sprite2D" parent="." unique_id=1437938522]
|
||||||
|
y_sort_enabled = true
|
||||||
|
material = SubResource("ShaderMaterial_cs1tg")
|
||||||
|
texture = ExtResource("10")
|
||||||
|
hframes = 35
|
||||||
|
vframes = 8
|
||||||
|
|
||||||
|
[node name="Sprite2DAddons" type="Sprite2D" parent="." unique_id=962307958]
|
||||||
|
y_sort_enabled = true
|
||||||
|
material = SubResource("ShaderMaterial_2dvfe")
|
||||||
|
texture = ExtResource("11")
|
||||||
|
hframes = 35
|
||||||
|
vframes = 8
|
||||||
|
|
||||||
|
[node name="Sprite2DHeadgear" type="Sprite2D" parent="." unique_id=526463008]
|
||||||
|
y_sort_enabled = true
|
||||||
|
material = SubResource("ShaderMaterial_giy8y")
|
||||||
|
texture = ExtResource("12")
|
||||||
|
hframes = 35
|
||||||
|
vframes = 8
|
||||||
|
|
||||||
|
[node name="Sprite2DShield" type="Sprite2D" parent="." unique_id=738217548]
|
||||||
|
material = SubResource("ShaderMaterial_hhpqf")
|
||||||
|
texture = ExtResource("13_t4otl")
|
||||||
|
hframes = 35
|
||||||
|
vframes = 8
|
||||||
|
|
||||||
|
[node name="Sprite2DShieldHolding" type="Sprite2D" parent="." unique_id=1000811066]
|
||||||
|
material = SubResource("ShaderMaterial_hhpqf")
|
||||||
|
texture = ExtResource("14_j2b1d")
|
||||||
|
hframes = 35
|
||||||
|
vframes = 8
|
||||||
|
|
||||||
|
[node name="Sprite2DWeapon" type="Sprite2D" parent="." unique_id=1889932388]
|
||||||
|
z_index = 1
|
||||||
|
y_sort_enabled = true
|
||||||
|
material = SubResource("ShaderMaterial_fdfoy")
|
||||||
|
texture = ExtResource("13")
|
||||||
|
hframes = 35
|
||||||
|
vframes = 8
|
||||||
|
|
||||||
|
[node name="CollisionShape2D" type="CollisionShape2D" parent="." unique_id=989315141]
|
||||||
|
position = Vector2(0, 4)
|
||||||
|
rotation = -1.5707964
|
||||||
|
shape = SubResource("CircleShape2D_wnwbv")
|
||||||
|
|
||||||
|
[node name="GrabArea" type="Area2D" parent="." unique_id=518653365]
|
||||||
|
position = Vector2(0, 4)
|
||||||
|
collision_layer = 0
|
||||||
|
collision_mask = 3
|
||||||
|
|
||||||
|
[node name="CollisionShape2D" type="CollisionShape2D" parent="GrabArea" unique_id=432299400]
|
||||||
|
shape = SubResource("CircleShape2D_2")
|
||||||
|
debug_color = Color(0.70196074, 0.6126261, 0.19635464, 0.41960785)
|
||||||
|
|
||||||
|
[node name="InteractionIndicator" type="Sprite2D" parent="." unique_id=1661043470]
|
||||||
|
visible = false
|
||||||
|
modulate = Color(1, 1, 0, 0.5)
|
||||||
|
position = Vector2(0, -12)
|
||||||
|
scale = Vector2(4, 4)
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="." unique_id=227628720]
|
||||||
|
offset_left = -10.0
|
||||||
|
offset_top = -15.0
|
||||||
|
offset_right = 10.0
|
||||||
|
offset_bottom = -9.0
|
||||||
|
horizontal_alignment = 1
|
||||||
|
|
||||||
|
[node name="SfxWalk" type="AudioStreamPlayer2D" parent="." unique_id=1693322702]
|
||||||
|
stream = SubResource("AudioStreamRandomizer_l71n6")
|
||||||
|
volume_db = -18.527
|
||||||
|
max_distance = 1412.0
|
||||||
|
attenuation = 8.282109
|
||||||
|
panning_strength = 1.11
|
||||||
|
|
||||||
|
[node name="TimerWalk" type="Timer" parent="SfxWalk" unique_id=590325386]
|
||||||
|
wait_time = 0.3
|
||||||
|
one_shot = true
|
||||||
|
|
||||||
|
[node name="SfxDie" type="AudioStreamPlayer2D" parent="." unique_id=1173215688]
|
||||||
|
stream = ExtResource("19_4r5pv")
|
||||||
|
volume_db = -2.537
|
||||||
|
attenuation = 8.876548
|
||||||
|
bus = &"Sfx"
|
||||||
|
|
||||||
|
[node name="SfxTakeDamage" type="AudioStreamPlayer2D" parent="." unique_id=322150091]
|
||||||
|
stream = SubResource("AudioStreamRandomizer_487ah")
|
||||||
|
volume_db = -6.092
|
||||||
|
attenuation = 7.7274756
|
||||||
|
panning_strength = 1.1
|
||||||
|
bus = &"Sfx"
|
||||||
|
|
||||||
|
[node name="SfxThrow" type="AudioStreamPlayer2D" parent="." unique_id=961008127]
|
||||||
|
stream = ExtResource("27_31cv2")
|
||||||
|
pitch_scale = 0.61
|
||||||
|
max_distance = 983.0
|
||||||
|
attenuation = 8.876549
|
||||||
|
panning_strength = 1.04
|
||||||
|
|
||||||
|
[node name="SfxLift" type="AudioStreamPlayer2D" parent="." unique_id=1261167113]
|
||||||
|
stream = ExtResource("28_pf23h")
|
||||||
|
max_distance = 1246.0
|
||||||
|
attenuation = 6.964403
|
||||||
|
panning_strength = 1.11
|
||||||
|
|
||||||
|
[node name="DirectionalLight2D" type="DirectionalLight2D" parent="." unique_id=1013099358]
|
||||||
|
visible = false
|
||||||
|
rotation = 3.1869712
|
||||||
|
energy = 0.13
|
||||||
|
shadow_enabled = true
|
||||||
|
max_distance = 100.0
|
||||||
|
|
||||||
|
[node name="SfxBowShoot" type="AudioStreamPlayer2D" parent="." unique_id=340970961]
|
||||||
|
stream = SubResource("AudioStreamRandomizer_bj30b")
|
||||||
|
pitch_scale = 1.33
|
||||||
|
attenuation = 6.7271657
|
||||||
|
|
||||||
|
[node name="SfxBowWithoutArrow" type="AudioStreamPlayer2D" parent="." unique_id=189976587]
|
||||||
|
stream = SubResource("AudioStreamRandomizer_hhpqf")
|
||||||
|
max_distance = 1455.0
|
||||||
|
attenuation = 7.4642572
|
||||||
|
|
||||||
|
[node name="SfxBuckleBow" type="AudioStreamPlayer2D" parent="." unique_id=1991119205]
|
||||||
|
stream = ExtResource("32_gl8cc")
|
||||||
|
attenuation = 7.727478
|
||||||
|
panning_strength = 1.03
|
||||||
|
|
||||||
|
[node name="SfxSpellCharge" type="AudioStreamPlayer2D" parent="." unique_id=282455991]
|
||||||
|
stream = ExtResource("35_bj30b")
|
||||||
|
|
||||||
|
[node name="SfxSpellIncantation" type="AudioStreamPlayer2D" parent="." unique_id=300820616]
|
||||||
|
stream = ExtResource("36_jc3p3")
|
||||||
|
volume_db = -46.271
|
||||||
|
attenuation = 7.727487
|
||||||
|
panning_strength = 1.04
|
||||||
|
bus = &"Sfx"
|
||||||
|
|
||||||
|
[node name="IncantationSprite" type="Sprite2D" parent="." unique_id=1655944614]
|
||||||
|
texture = ExtResource("37_hax0n")
|
||||||
|
hframes = 105
|
||||||
|
vframes = 79
|
||||||
|
frame = 2037
|
||||||
|
|
||||||
|
[node name="AnimationIncantation" type="AnimationPlayer" parent="." unique_id=17658820]
|
||||||
|
libraries/ = SubResource("AnimationLibrary_2dvfe")
|
||||||
|
autoplay = &"idle"
|
||||||
|
|
||||||
|
[node name="SfxActivateShield" type="AudioStreamPlayer2D" parent="." unique_id=1247414383]
|
||||||
|
stream = ExtResource("40_hhpqf")
|
||||||
|
volume_db = 9.695
|
||||||
|
attenuation = 1.3660401
|
||||||
|
panning_strength = 1.78
|
||||||
|
|
||||||
|
[node name="SfxBlockWithShield" type="AudioStreamPlayer2D" parent="." unique_id=1010944313]
|
||||||
|
stream = SubResource("AudioStreamRandomizer_u2ulf")
|
||||||
|
volume_db = 7.254
|
||||||
|
attenuation = 1.3195078
|
||||||
|
panning_strength = 1.06
|
||||||
|
bus = &"Sfx"
|
||||||
|
|
||||||
|
[node name="SfxDenyActivateShield" type="AudioStreamPlayer2D" parent="." unique_id=1239738371]
|
||||||
|
stream = ExtResource("45_g5jhy")
|
||||||
|
volume_db = 9.458
|
||||||
|
|
||||||
|
[node name="Sprite2DStatus" type="Sprite2D" parent="." unique_id=1335748461]
|
||||||
|
position = Vector2(0, -10)
|
||||||
|
texture = ExtResource("37_hax0n")
|
||||||
|
hframes = 105
|
||||||
|
vframes = 79
|
||||||
|
frame = 711
|
||||||
|
|
||||||
|
[node name="AnimationPlayerStatus" type="AnimationPlayer" parent="Sprite2DStatus" unique_id=721795152]
|
||||||
|
libraries/ = SubResource("AnimationLibrary_mx1m4")
|
||||||
|
autoplay = &"idle"
|
||||||
|
|
||||||
|
[node name="SfxFallDownLand" type="AudioStreamPlayer2D" parent="." unique_id=1674409490]
|
||||||
|
stream = ExtResource("46_holxr")
|
||||||
|
attenuation = 1.8025011
|
||||||
|
bus = &"Sfx"
|
||||||
|
|
||||||
|
[node name="SfxBirdSound" type="AudioStreamPlayer2D" parent="." unique_id=1946085725]
|
||||||
|
stream = ExtResource("47_mx1m4")
|
||||||
|
volume_db = -13.255
|
||||||
|
attenuation = 3.2490087
|
||||||
|
panning_strength = 1.12
|
||||||
|
bus = &"Sfx"
|
||||||
@@ -456,7 +456,11 @@ func _on_collection_area_body_entered(body: Node2D):
|
|||||||
print("ERROR: character_stats missing add_item method")
|
print("ERROR: character_stats missing add_item method")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
var was_encumbered = body.character_stats.is_over_encumbered()
|
||||||
body.character_stats.add_item(inventory_arrow)
|
body.character_stats.add_item(inventory_arrow)
|
||||||
|
if not was_encumbered and body.character_stats.is_over_encumbered():
|
||||||
|
if body.has_method("show_floating_status"):
|
||||||
|
body.show_floating_status("Encumbered!", Color(1.0, 0.5, 0.2))
|
||||||
is_collected = true
|
is_collected = true
|
||||||
$SfxPickup.play()
|
$SfxPickup.play()
|
||||||
print(body.name, " collected arrow from wall into inventory!")
|
print(body.name, " collected arrow from wall into inventory!")
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ var player_owner: Node = null
|
|||||||
var damage: float = 15.0
|
var damage: float = 15.0
|
||||||
var damage_mult: float = 1.0
|
var damage_mult: float = 1.0
|
||||||
var is_center: bool = false
|
var is_center: bool = false
|
||||||
|
var skip_sfx: bool = false
|
||||||
var damage_dealt: bool = false
|
var damage_dealt: bool = false
|
||||||
var elapsed: float = 0.0
|
var elapsed: float = 0.0
|
||||||
var _frames: Array = [4413, 4414, 4415, 4416]
|
var _frames: Array = [4413, 4414, 4415, 4416]
|
||||||
@@ -23,15 +24,18 @@ func _ready() -> void:
|
|||||||
if sprite:
|
if sprite:
|
||||||
sprite.frame = _frames[0]
|
sprite.frame = _frames[0]
|
||||||
sprite.modulate = Color(0.6, 0.8, 1.0)
|
sprite.modulate = Color(0.6, 0.8, 1.0)
|
||||||
|
if not skip_sfx and has_node("SfxSpike"):
|
||||||
|
$SfxSpike.play()
|
||||||
if is_center:
|
if is_center:
|
||||||
_spawn_adjacent_after_delay()
|
_spawn_adjacent_after_delay()
|
||||||
|
|
||||||
func setup(target_pos: Vector2, owner_player: Node, damage_value: float, center: bool, scale_mult: float = 1.0, dmg_mult: float = 1.0) -> void:
|
func setup(target_pos: Vector2, owner_player: Node, damage_value: float, center: bool, scale_mult: float = 1.0, dmg_mult: float = 1.0, _skip_sfx: bool = false) -> void:
|
||||||
global_position = target_pos
|
global_position = target_pos
|
||||||
player_owner = owner_player
|
player_owner = owner_player
|
||||||
damage = damage_value
|
damage = damage_value
|
||||||
damage_mult = dmg_mult
|
damage_mult = dmg_mult
|
||||||
is_center = center
|
is_center = center
|
||||||
|
skip_sfx = _skip_sfx
|
||||||
if scale_mult != 1.0:
|
if scale_mult != 1.0:
|
||||||
scale = Vector2(scale_mult, scale_mult)
|
scale = Vector2(scale_mult, scale_mult)
|
||||||
|
|
||||||
@@ -52,12 +56,14 @@ func _spawn_adjacent_after_delay() -> void:
|
|||||||
var par = get_parent()
|
var par = get_parent()
|
||||||
for pos in adjacent:
|
for pos in adjacent:
|
||||||
var sp = scene.instantiate()
|
var sp = scene.instantiate()
|
||||||
sp.setup(pos, player_owner, damage, false)
|
sp.setup(pos, player_owner, damage, false, 1.0, 1.0, true)
|
||||||
par.add_child(sp)
|
par.add_child(sp)
|
||||||
# Third wave: center again, 2x scale, 2x damage (most damage)
|
# Third wave: center again, 2x scale, 2x damage (most damage)
|
||||||
var third = scene.instantiate()
|
var third = scene.instantiate()
|
||||||
third.setup(global_position, player_owner, damage, false, 2.0, 2.0)
|
third.setup(global_position, player_owner, damage, false, 2.0, 2.0, true)
|
||||||
par.add_child(third)
|
par.add_child(third)
|
||||||
|
if has_node("SfxSpike"):
|
||||||
|
$SfxSpike.play()
|
||||||
_finish_center_spike()
|
_finish_center_spike()
|
||||||
|
|
||||||
func _finish_center_spike() -> void:
|
func _finish_center_spike() -> void:
|
||||||
|
|||||||
@@ -41,6 +41,11 @@ var bonusmaxmp: float = 0.0
|
|||||||
var kills: int = 0
|
var kills: int = 0
|
||||||
var deaths: int = 0
|
var deaths: int = 0
|
||||||
|
|
||||||
|
# Level-up stat allocation: when true, player must open inventory and choose a stat to +1
|
||||||
|
var pending_level_up: bool = false
|
||||||
|
var pending_stat_points: int = 0
|
||||||
|
const LEVEL_UP_STAT_NAMES: Array = ["str", "dex", "int", "end", "wis", "lck", "per"]
|
||||||
|
|
||||||
#calculated values
|
#calculated values
|
||||||
var stats:Array = [
|
var stats:Array = [
|
||||||
5,
|
5,
|
||||||
@@ -236,49 +241,46 @@ func _init() -> void:
|
|||||||
|
|
||||||
func add_xp(amount: float) -> void:
|
func add_xp(amount: float) -> void:
|
||||||
xp += amount
|
xp += amount
|
||||||
|
xp = max(0.0, xp)
|
||||||
xp_changed.emit(xp, xp_to_next_level)
|
xp_changed.emit(xp, xp_to_next_level)
|
||||||
|
|
||||||
while xp >= xp_to_next_level:
|
while xp >= xp_to_next_level:
|
||||||
level_up()
|
level_up()
|
||||||
|
xp = max(0.0, xp)
|
||||||
|
xp_changed.emit(xp, xp_to_next_level)
|
||||||
|
|
||||||
# Level up - randomly increases 2-3 stats instead of all
|
# Level up - grant pending stat point(s); player allocates in inventory
|
||||||
func level_up() -> void:
|
func level_up() -> void:
|
||||||
|
# Subtract threshold for current level *before* incrementing (xp_to_next_level uses level)
|
||||||
|
var xp_threshold = xp_to_next_level
|
||||||
level += 1
|
level += 1
|
||||||
xp -= xp_to_next_level
|
xp -= xp_threshold
|
||||||
|
xp = max(0.0, xp)
|
||||||
|
|
||||||
# Randomly select 2-3 stats to increase (random 2 or 3)
|
pending_level_up = true
|
||||||
var num_stats_to_increase = randi_range(2, 3)
|
pending_stat_points += 1
|
||||||
|
|
||||||
# All available stats (excluding cha for now as per user request)
|
|
||||||
var available_stats = ["str", "dex", "int", "end", "wis", "lck", "per"]
|
|
||||||
|
|
||||||
# Shuffle and pick random stats
|
|
||||||
var stats_to_increase = []
|
|
||||||
var shuffled_stats = available_stats.duplicate()
|
|
||||||
shuffled_stats.shuffle()
|
|
||||||
|
|
||||||
for i in range(min(num_stats_to_increase, shuffled_stats.size())):
|
|
||||||
stats_to_increase.append(shuffled_stats[i])
|
|
||||||
|
|
||||||
# Increase selected stats
|
|
||||||
for stat_name in stats_to_increase:
|
|
||||||
baseStats[stat_name] += 1
|
|
||||||
|
|
||||||
# Store which stats were increased (for display)
|
|
||||||
var stats_increased = stats_to_increase
|
|
||||||
|
|
||||||
# Restore health and mana on level up
|
# Restore health and mana on level up
|
||||||
hp = maxhp
|
hp = maxhp
|
||||||
mp = maxmp
|
mp = maxmp
|
||||||
|
|
||||||
# Emit level_changed signal
|
|
||||||
level_changed.emit(level)
|
level_changed.emit(level)
|
||||||
# Emit level_up_stats signal with which stats were increased
|
level_up_stats.emit([])
|
||||||
level_up_stats.emit(stats_increased)
|
|
||||||
|
|
||||||
health_changed.emit(hp, maxhp)
|
health_changed.emit(hp, maxhp)
|
||||||
mana_changed.emit(mp, maxmp)
|
mana_changed.emit(mp, maxmp)
|
||||||
|
|
||||||
|
func allocate_stat_point(stat_name: String) -> bool:
|
||||||
|
if not pending_level_up or pending_stat_points <= 0:
|
||||||
|
return false
|
||||||
|
if stat_name not in LEVEL_UP_STAT_NAMES:
|
||||||
|
return false
|
||||||
|
baseStats[stat_name] += 1
|
||||||
|
pending_stat_points -= 1
|
||||||
|
if pending_stat_points <= 0:
|
||||||
|
pending_level_up = false
|
||||||
|
character_changed.emit(self)
|
||||||
|
return true
|
||||||
|
|
||||||
func modify_health(amount: float, allow_overheal: bool = false) -> void:
|
func modify_health(amount: float, allow_overheal: bool = false) -> void:
|
||||||
hp += amount
|
hp += amount
|
||||||
if allow_overheal:
|
if allow_overheal:
|
||||||
@@ -388,6 +390,8 @@ func save() -> Dictionary:
|
|||||||
|
|
||||||
"kills": kills,
|
"kills": kills,
|
||||||
"deaths": deaths,
|
"deaths": deaths,
|
||||||
|
"pending_level_up": pending_level_up,
|
||||||
|
"pending_stat_points": pending_stat_points,
|
||||||
|
|
||||||
"skin": skin,
|
"skin": skin,
|
||||||
"facial_hair": facial_hair,
|
"facial_hair": facial_hair,
|
||||||
@@ -427,11 +431,15 @@ func load(iDic: Dictionary) -> void:
|
|||||||
if iDic.has("coin"):
|
if iDic.has("coin"):
|
||||||
coin = iDic.get("coin")
|
coin = iDic.get("coin")
|
||||||
if iDic.has("exp"):
|
if iDic.has("exp"):
|
||||||
xp = iDic.get("exp")
|
xp = max(0.0, float(iDic.get("exp")))
|
||||||
if iDic.has("kills"):
|
if iDic.has("kills"):
|
||||||
kills = iDic.get("kills")
|
kills = iDic.get("kills")
|
||||||
if iDic.has("deaths"):
|
if iDic.has("deaths"):
|
||||||
deaths = iDic.get("deaths")
|
deaths = iDic.get("deaths")
|
||||||
|
if iDic.has("pending_level_up"):
|
||||||
|
pending_level_up = bool(iDic.get("pending_level_up"))
|
||||||
|
if iDic.has("pending_stat_points"):
|
||||||
|
pending_stat_points = int(iDic.get("pending_stat_points"))
|
||||||
|
|
||||||
inventory.clear()
|
inventory.clear()
|
||||||
if iDic.has("inventory"):
|
if iDic.has("inventory"):
|
||||||
|
|||||||
@@ -16,6 +16,18 @@ func _ready() -> void:
|
|||||||
pass # Replace with function body.
|
pass # Replace with function body.
|
||||||
|
|
||||||
func _initialize_damage_number() -> void:
|
func _initialize_damage_number() -> void:
|
||||||
|
# Reparent to FloatingTextLayer (not affected by CanvasModulate).
|
||||||
|
# Layer has follow_viewport_enabled = true so it scrolls with world → use world position, not screen.
|
||||||
|
var gw = get_tree().get_first_node_in_group("game_world")
|
||||||
|
var layer = gw.get_node_or_null("FloatingTextLayer") if gw else null
|
||||||
|
if layer and gw:
|
||||||
|
var world_pos = global_position
|
||||||
|
get_parent().remove_child(self)
|
||||||
|
layer.add_child(self)
|
||||||
|
global_position = world_pos
|
||||||
|
# Ensure visible: use default layer so camera/viewport always draws us (fixes layer 262144 not being shown)
|
||||||
|
visibility_layer = 1
|
||||||
|
light_mask = 1
|
||||||
# Set color (red by default) and text
|
# Set color (red by default) and text
|
||||||
self.modulate = color
|
self.modulate = color
|
||||||
self.text = label
|
self.text = label
|
||||||
@@ -25,7 +37,7 @@ func _initialize_damage_number() -> void:
|
|||||||
var random_angle = randf_range(-PI/6, PI/6) # ±30 degrees from straight up
|
var random_angle = randf_range(-PI/6, PI/6) # ±30 degrees from straight up
|
||||||
direction = Vector2(sin(random_angle), -cos(random_angle)) # Mostly upward with slight variation
|
direction = Vector2(sin(random_angle), -cos(random_angle)) # Mostly upward with slight variation
|
||||||
|
|
||||||
# Calculate target position (move upward with slight horizontal variation)
|
# Calculate target position (move upward with slight horizontal variation; in screen space if on layer)
|
||||||
var move_target = global_position + (direction.normalized() * rise_distance)
|
var move_target = global_position + (direction.normalized() * rise_distance)
|
||||||
|
|
||||||
# Total animation duration = display (0.6s) + fade (0.4s) = 1.0s
|
# Total animation duration = display (0.6s) + fade (0.4s) = 1.0s
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ extends CharacterBody2D
|
|||||||
var current_health: float = 50.0
|
var current_health: float = 50.0
|
||||||
var character_stats: CharacterStats # RPG stats system (same as players)
|
var character_stats: CharacterStats # RPG stats system (same as players)
|
||||||
var is_dead: bool = false
|
var is_dead: bool = false
|
||||||
|
@export var is_undead: bool = false # Zombies etc.; healing spell damages them
|
||||||
var target_player: Node = null
|
var target_player: Node = null
|
||||||
var attack_timer: float = 0.0
|
var attack_timer: float = 0.0
|
||||||
var killer_player: Node = null # Track who killed this enemy (for kill credit)
|
var killer_player: Node = null # Track who killed this enemy (for kill credit)
|
||||||
|
|||||||
214
src/scripts/enemy_hand.gd
Normal file
214
src/scripts/enemy_hand.gd
Normal file
@@ -0,0 +1,214 @@
|
|||||||
|
extends "res://scripts/enemy_base.gd"
|
||||||
|
|
||||||
|
# Enemy Hand: hidden until player near (EmergeArea), then emerge -> idle.
|
||||||
|
# Moves toward player if in PlayerInterestArea, else random. Collides with walls.
|
||||||
|
# If player enters GrabPlayerArea and alive: grab, lock player, snatch anim, deal damage, release + knockback.
|
||||||
|
|
||||||
|
enum HandState { HIDDEN, EMERGING, IDLE, GRABBING }
|
||||||
|
|
||||||
|
var state: HandState = HandState.HIDDEN
|
||||||
|
var players_in_interest: Array[Node] = []
|
||||||
|
var grabbed_player: Node = null
|
||||||
|
var random_move_dir: Vector2 = Vector2.ZERO
|
||||||
|
var random_move_timer: float = 0.0
|
||||||
|
const RANDOM_MOVE_INTERVAL: float = 1.2
|
||||||
|
const SNATCH_DURATION: float = 0.4
|
||||||
|
const SNATCH_DAMAGE: float = 12.0
|
||||||
|
@onready var emerge_area: Area2D = $EmergeArea
|
||||||
|
@onready var grab_area: Area2D = $GrabPlayerArea
|
||||||
|
@onready var interest_area: Area2D = $PlayerInterestArea
|
||||||
|
@onready var anim_player: AnimationPlayer = $AnimationPlayer
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
super._ready()
|
||||||
|
max_health = 25.0
|
||||||
|
current_health = max_health
|
||||||
|
move_speed = 55.0
|
||||||
|
damage = SNATCH_DAMAGE
|
||||||
|
exp_reward = 8.0
|
||||||
|
collision_layer = 2
|
||||||
|
collision_mask = 1 | 2 | 64
|
||||||
|
|
||||||
|
# Start hidden
|
||||||
|
modulate.a = 0.0
|
||||||
|
# Areas detect players (layer 1)
|
||||||
|
for area in [emerge_area, grab_area, interest_area]:
|
||||||
|
if area:
|
||||||
|
area.set_collision_mask_value(1, true)
|
||||||
|
area.monitoring = true
|
||||||
|
area.monitorable = false
|
||||||
|
|
||||||
|
if anim_player:
|
||||||
|
if not anim_player.animation_finished.is_connected(_on_animation_finished):
|
||||||
|
anim_player.animation_finished.connect(_on_animation_finished)
|
||||||
|
|
||||||
|
|
||||||
|
func _initialize_character_stats() -> void:
|
||||||
|
super._initialize_character_stats()
|
||||||
|
character_stats.baseStats.str = 10
|
||||||
|
character_stats.baseStats.end = 6
|
||||||
|
character_stats.baseStats.dex = 8
|
||||||
|
character_stats.hp = character_stats.maxhp
|
||||||
|
character_stats.mp = character_stats.maxmp
|
||||||
|
max_health = character_stats.maxhp
|
||||||
|
current_health = character_stats.hp
|
||||||
|
|
||||||
|
|
||||||
|
func _check_player_collision() -> void:
|
||||||
|
# No contact-based attack; we use GrabPlayerArea instead
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
func _die() -> void:
|
||||||
|
if grabbed_player != null and is_instance_valid(grabbed_player):
|
||||||
|
var v = grabbed_player
|
||||||
|
grabbed_player = null
|
||||||
|
if v.has_method("rpc_released_from_enemy_hand"):
|
||||||
|
var pid = v.get_multiplayer_authority()
|
||||||
|
if multiplayer.get_unique_id() == pid:
|
||||||
|
v.rpc_released_from_enemy_hand()
|
||||||
|
elif pid != 0:
|
||||||
|
v.rpc_released_from_enemy_hand.rpc_id(pid)
|
||||||
|
else:
|
||||||
|
v.rpc_released_from_enemy_hand.rpc()
|
||||||
|
super._die()
|
||||||
|
|
||||||
|
|
||||||
|
func _ai_behavior(delta: float) -> void:
|
||||||
|
if state == HandState.HIDDEN or state == HandState.EMERGING:
|
||||||
|
velocity = Vector2.ZERO
|
||||||
|
return
|
||||||
|
if state == HandState.GRABBING:
|
||||||
|
velocity = Vector2.ZERO
|
||||||
|
return
|
||||||
|
|
||||||
|
# IDLE: move toward player if in interest, else random
|
||||||
|
var target: Node = null
|
||||||
|
for p in players_in_interest:
|
||||||
|
if is_instance_valid(p) and p.is_in_group("player") and (not "is_dead" in p or not p.is_dead):
|
||||||
|
target = p
|
||||||
|
break
|
||||||
|
|
||||||
|
if target:
|
||||||
|
var dir = (target.global_position - global_position).normalized()
|
||||||
|
velocity = dir * move_speed
|
||||||
|
else:
|
||||||
|
# Random movement
|
||||||
|
random_move_timer -= delta
|
||||||
|
if random_move_timer <= 0.0:
|
||||||
|
random_move_timer = RANDOM_MOVE_INTERVAL
|
||||||
|
var ang = randf() * TAU
|
||||||
|
random_move_dir = Vector2(cos(ang), sin(ang))
|
||||||
|
velocity = random_move_dir * move_speed
|
||||||
|
|
||||||
|
move_and_slide()
|
||||||
|
|
||||||
|
|
||||||
|
func _on_emerge_area_body_entered(body: Node2D) -> void:
|
||||||
|
if state != HandState.HIDDEN:
|
||||||
|
return
|
||||||
|
if not body.is_in_group("player"):
|
||||||
|
return
|
||||||
|
if "is_dead" in body and body.is_dead:
|
||||||
|
return
|
||||||
|
if not is_multiplayer_authority():
|
||||||
|
return
|
||||||
|
|
||||||
|
state = HandState.EMERGING
|
||||||
|
modulate.a = 1.0
|
||||||
|
if anim_player and anim_player.has_animation("emerge"):
|
||||||
|
anim_player.play("emerge")
|
||||||
|
|
||||||
|
|
||||||
|
func _on_animation_finished(anim_name: StringName) -> void:
|
||||||
|
if anim_name == "emerge":
|
||||||
|
state = HandState.IDLE
|
||||||
|
if anim_player and anim_player.has_animation("idle"):
|
||||||
|
anim_player.play("idle")
|
||||||
|
# snatch completion driven by timer (SNATCH_DURATION), not animation_finished
|
||||||
|
|
||||||
|
|
||||||
|
func _on_player_interest_area_body_entered(body: Node2D) -> void:
|
||||||
|
if not body.is_in_group("player"):
|
||||||
|
return
|
||||||
|
if body in players_in_interest:
|
||||||
|
return
|
||||||
|
players_in_interest.append(body)
|
||||||
|
|
||||||
|
|
||||||
|
func _on_player_interest_area_body_exited(body: Node2D) -> void:
|
||||||
|
players_in_interest.erase(body)
|
||||||
|
|
||||||
|
|
||||||
|
func _on_grab_player_area_body_entered(body: Node2D) -> void:
|
||||||
|
if state != HandState.IDLE or is_dead:
|
||||||
|
return
|
||||||
|
if not body.is_in_group("player"):
|
||||||
|
return
|
||||||
|
if "is_dead" in body and body.is_dead:
|
||||||
|
return
|
||||||
|
if "grabbed_by_enemy_hand" in body and body.grabbed_by_enemy_hand != null:
|
||||||
|
return
|
||||||
|
if grabbed_player != null:
|
||||||
|
return
|
||||||
|
if not is_multiplayer_authority():
|
||||||
|
return
|
||||||
|
|
||||||
|
grabbed_player = body
|
||||||
|
state = HandState.GRABBING
|
||||||
|
velocity = Vector2.ZERO
|
||||||
|
|
||||||
|
# Lock player movement via RPC (victim's authority runs their physics)
|
||||||
|
if body.has_method("rpc_grabbed_by_enemy_hand"):
|
||||||
|
var pid = body.get_multiplayer_authority()
|
||||||
|
if multiplayer.get_unique_id() == pid:
|
||||||
|
body.rpc_grabbed_by_enemy_hand(name)
|
||||||
|
elif pid != 0:
|
||||||
|
body.rpc_grabbed_by_enemy_hand.rpc_id(pid, name)
|
||||||
|
else:
|
||||||
|
body.rpc_grabbed_by_enemy_hand.rpc(name)
|
||||||
|
|
||||||
|
if anim_player and anim_player.has_animation("snatch"):
|
||||||
|
anim_player.play("snatch")
|
||||||
|
get_tree().create_timer(SNATCH_DURATION).timeout.connect(_finish_snatch)
|
||||||
|
|
||||||
|
|
||||||
|
func _finish_snatch() -> void:
|
||||||
|
if not is_instance_valid(self):
|
||||||
|
return
|
||||||
|
var victim = grabbed_player
|
||||||
|
grabbed_player = null
|
||||||
|
state = HandState.IDLE
|
||||||
|
if anim_player and anim_player.has_animation("idle"):
|
||||||
|
anim_player.play("idle")
|
||||||
|
if not is_instance_valid(victim):
|
||||||
|
return
|
||||||
|
|
||||||
|
# Deal damage (applies knockback via take_damage)
|
||||||
|
var attack_pos = global_position
|
||||||
|
if victim.has_method("rpc_take_damage"):
|
||||||
|
var pid = victim.get_multiplayer_authority()
|
||||||
|
if pid != 0:
|
||||||
|
if multiplayer.get_unique_id() == pid:
|
||||||
|
victim.take_damage(SNATCH_DAMAGE, attack_pos, false, false)
|
||||||
|
else:
|
||||||
|
victim.rpc_take_damage.rpc_id(pid, SNATCH_DAMAGE, attack_pos, false, false)
|
||||||
|
else:
|
||||||
|
victim.rpc_take_damage.rpc(SNATCH_DAMAGE, attack_pos, false, false)
|
||||||
|
|
||||||
|
# Release player (RPC so victim's authority clears grabbed_by_enemy_hand)
|
||||||
|
if victim.has_method("rpc_released_from_enemy_hand"):
|
||||||
|
var pid = victim.get_multiplayer_authority()
|
||||||
|
if multiplayer.get_unique_id() == pid:
|
||||||
|
victim.rpc_released_from_enemy_hand()
|
||||||
|
elif pid != 0:
|
||||||
|
victim.rpc_released_from_enemy_hand.rpc_id(pid)
|
||||||
|
else:
|
||||||
|
victim.rpc_released_from_enemy_hand.rpc()
|
||||||
|
|
||||||
|
|
||||||
|
func _sync_position(pos: Vector2, vel: Vector2, z_pos: float = 0.0, dir: int = 0, frame: int = 0, anim: String = "", frame_num: int = 0, state_value: int = -1) -> void:
|
||||||
|
super._sync_position(pos, vel, z_pos, dir, frame, anim, frame_num, state_value)
|
||||||
|
# Client: keep AnimationPlayer in sync with state if we add state sync later
|
||||||
|
pass
|
||||||
1
src/scripts/enemy_hand.gd.uid
Normal file
1
src/scripts/enemy_hand.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://bkeyokaahe2fd
|
||||||
@@ -213,6 +213,9 @@ func _ready():
|
|||||||
# Set up stats based on type
|
# Set up stats based on type
|
||||||
_setup_stats()
|
_setup_stats()
|
||||||
|
|
||||||
|
# Undead types (e.g. skeleton) take damage from healing spell
|
||||||
|
is_undead = (humanoid_type == HumanoidType.SKELETON)
|
||||||
|
|
||||||
# Start in idle state
|
# Start in idle state
|
||||||
ai_state = AIState.IDLE
|
ai_state = AIState.IDLE
|
||||||
state_timer = 2.0
|
state_timer = 2.0
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ var fade_duration: float = 0.5 # How long fade out takes
|
|||||||
var rise_distance: float = 30.0
|
var rise_distance: float = 30.0
|
||||||
var is_coin: bool = false # Track if this is a coin (to animate)
|
var is_coin: bool = false # Track if this is a coin (to animate)
|
||||||
|
|
||||||
func setup(text_value: String, text_color: Color, show_time: float = 0.5, fade_time: float = 0.5, item_texture: Texture2D = null, sprite_hframes: int = 1, sprite_vframes: int = 1, sprite_frame: int = 0):
|
func setup(text_value: String, text_color: Color, show_time: float = 0.5, fade_time: float = 0.5, item_texture: Texture2D = null, sprite_hframes: int = 1, sprite_vframes: int = 1, sprite_frame: int = 0, item = null):
|
||||||
text = text_value
|
text = text_value
|
||||||
color = text_color
|
color = text_color
|
||||||
display_duration = show_time
|
display_duration = show_time
|
||||||
@@ -39,7 +39,9 @@ func setup(text_value: String, text_color: Color, show_time: float = 0.5, fade_t
|
|||||||
item_sprite.position = Vector2(0, -12) # Just above the text (sprite is ~16px tall)
|
item_sprite.position = Vector2(0, -12) # Just above the text (sprite is ~16px tall)
|
||||||
else:
|
else:
|
||||||
item_sprite.position = Vector2(0, 0)
|
item_sprite.position = Vector2(0, 0)
|
||||||
|
# Apply item colorization (cloth shader + colorReplacements) when we have an item
|
||||||
|
if item and ItemDatabase:
|
||||||
|
ItemDatabase.apply_item_colors_to_sprite(item_sprite, item)
|
||||||
# Check if this is a coin (6 frames horizontal, 1 frame vertical) - animate it
|
# Check if this is a coin (6 frames horizontal, 1 frame vertical) - animate it
|
||||||
if sprite_hframes == 6 and sprite_vframes == 1:
|
if sprite_hframes == 6 and sprite_vframes == 1:
|
||||||
is_coin = true
|
is_coin = true
|
||||||
@@ -50,6 +52,14 @@ func setup(text_value: String, text_color: Color, show_time: float = 0.5, fade_t
|
|||||||
is_coin = false
|
is_coin = false
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
|
# Reparent to FloatingTextLayer (not affected by CanvasModulate) and use screen position
|
||||||
|
var gw = get_tree().get_first_node_in_group("game_world")
|
||||||
|
var layer = gw.get_node_or_null("FloatingTextLayer") if gw else null
|
||||||
|
if layer and gw and gw.has_method("world_to_screen"):
|
||||||
|
var world_pos = global_position
|
||||||
|
get_parent().remove_child(self)
|
||||||
|
layer.add_child(self)
|
||||||
|
global_position = gw.world_to_screen(world_pos)
|
||||||
# Start coin animation if needed
|
# Start coin animation if needed
|
||||||
if is_coin and item_sprite:
|
if is_coin and item_sprite:
|
||||||
_animate_coin()
|
_animate_coin()
|
||||||
|
|||||||
@@ -157,6 +157,9 @@ func _ready():
|
|||||||
# Create inventory UI
|
# Create inventory UI
|
||||||
_create_inventory_ui()
|
_create_inventory_ui()
|
||||||
|
|
||||||
|
# Layer for damage numbers / floating text (not affected by CanvasModulate)
|
||||||
|
_load_floating_text_layer()
|
||||||
|
|
||||||
# Initialize mouse cursor system
|
# Initialize mouse cursor system
|
||||||
_init_mouse_cursor()
|
_init_mouse_cursor()
|
||||||
|
|
||||||
@@ -1136,14 +1139,33 @@ func _show_loot_floating_text(player: Node, text: String, color: Color, item_tex
|
|||||||
floating_text.global_position = Vector2(player.global_position.x, player.global_position.y - 20)
|
floating_text.global_position = Vector2(player.global_position.x, player.global_position.y - 20)
|
||||||
floating_text.setup(text, color, 0.5, 0.5, item_texture, sprite_hframes, sprite_vframes, sprite_frame)
|
floating_text.setup(text, color, 0.5, 0.5, item_texture, sprite_hframes, sprite_vframes, sprite_frame)
|
||||||
|
|
||||||
func _apply_heal_spell_sync(target_name: String, amount_to_apply: float, display_amount: int, is_crit: bool, is_overheal: bool, allow_overheal: bool, is_revive: bool = false):
|
func _apply_heal_spell_sync(target_name: String, amount_to_apply: float, display_amount: int, is_crit: bool, is_overheal: bool, allow_overheal: bool, is_revive: bool = false, is_damage_to_enemy: bool = false):
|
||||||
var target: Node = null
|
var target: Node = null
|
||||||
|
if is_damage_to_enemy:
|
||||||
|
for e in get_tree().get_nodes_in_group("enemy"):
|
||||||
|
if e.name == target_name and is_instance_valid(e):
|
||||||
|
target = e
|
||||||
|
break
|
||||||
|
else:
|
||||||
for p in get_tree().get_nodes_in_group("player"):
|
for p in get_tree().get_nodes_in_group("player"):
|
||||||
if p.name == target_name and is_instance_valid(p):
|
if p.name == target_name and is_instance_valid(p):
|
||||||
target = p
|
target = p
|
||||||
break
|
break
|
||||||
if not target:
|
if not target:
|
||||||
return
|
return
|
||||||
|
if is_damage_to_enemy:
|
||||||
|
# Damage already applied by caster; just spawn effect for other clients
|
||||||
|
var entities = get_node_or_null("Entities")
|
||||||
|
var parent = entities if entities else target.get_parent()
|
||||||
|
if parent:
|
||||||
|
var eff_scene = load("res://scenes/healing_effect.tscn") as PackedScene
|
||||||
|
if eff_scene:
|
||||||
|
var eff = eff_scene.instantiate()
|
||||||
|
parent.add_child(eff)
|
||||||
|
eff.global_position = target.global_position
|
||||||
|
if eff.has_method("setup"):
|
||||||
|
eff.setup(target)
|
||||||
|
return
|
||||||
var me = multiplayer.get_unique_id()
|
var me = multiplayer.get_unique_id()
|
||||||
var tid = target.get_multiplayer_authority()
|
var tid = target.get_multiplayer_authority()
|
||||||
if is_revive:
|
if is_revive:
|
||||||
@@ -2263,12 +2285,17 @@ func _update_fog_of_war(delta: float) -> void:
|
|||||||
if not current_room.is_empty():
|
if not current_room.is_empty():
|
||||||
_mark_room_explored(current_room)
|
_mark_room_explored(current_room)
|
||||||
_mark_room_visible(current_room)
|
_mark_room_visible(current_room)
|
||||||
|
# Only hide other rooms; keep corridor visible when we can see into it (no closed door in way)
|
||||||
for y in range(map_size.y):
|
for y in range(map_size.y):
|
||||||
for x in range(map_size.x):
|
for x in range(map_size.x):
|
||||||
if not _is_tile_in_room_or_walls(Vector2i(x, y), current_room):
|
|
||||||
var idx = x + y * map_size.x
|
var idx = x + y * map_size.x
|
||||||
if idx >= 0 and idx < combined_seen.size():
|
if idx < 0 or idx >= combined_seen.size():
|
||||||
combined_seen[idx] = 0
|
continue
|
||||||
|
var tile_room = _find_room_at_tile(Vector2i(x, y))
|
||||||
|
if tile_room.is_empty():
|
||||||
|
continue # Corridor: keep (already revealed by raycast if visible)
|
||||||
|
if tile_room.x != current_room.x or tile_room.y != current_room.y or tile_room.w != current_room.w or tile_room.h != current_room.h:
|
||||||
|
combined_seen[idx] = 0 # Other room: hide
|
||||||
else:
|
else:
|
||||||
# In corridors (no room), only show tiles connected to the corridor component
|
# In corridors (no room), only show tiles connected to the corridor component
|
||||||
# AND explicitly clear combined_seen for all tiles in rooms that aren't connected
|
# AND explicitly clear combined_seen for all tiles in rooms that aren't connected
|
||||||
@@ -2344,6 +2371,29 @@ func _update_fog_of_war(delta: float) -> void:
|
|||||||
fog_node.set_maps(explored_map, combined_seen)
|
fog_node.set_maps(explored_map, combined_seen)
|
||||||
if fog_node.has_method("set_debug_lines"):
|
if fog_node.has_method("set_debug_lines"):
|
||||||
fog_node.set_debug_lines(fog_debug_lines, FOG_DEBUG_DRAW)
|
fog_node.set_debug_lines(fog_debug_lines, FOG_DEBUG_DRAW)
|
||||||
|
var player_tile := Vector2i(-1, -1)
|
||||||
|
if local_player_list.size() > 0 and local_player_list[0]:
|
||||||
|
player_tile = Vector2i(int(local_player_list[0].global_position.x / FOG_TILE_SIZE), int(local_player_list[0].global_position.y / FOG_TILE_SIZE))
|
||||||
|
var minimap_draw = get_node_or_null("Minimap/MarginContainer/MinimapView/MinimapDraw")
|
||||||
|
if minimap_draw and minimap_draw.has_method("set_maps") and dungeon_data.has("grid"):
|
||||||
|
var exit_tile := Vector2i(-1, -1)
|
||||||
|
var exit_discovered := false
|
||||||
|
if dungeon_data.has("stairs") and not dungeon_data.stairs.is_empty():
|
||||||
|
var s = dungeon_data.stairs
|
||||||
|
if s.has("x") and s.has("y") and s.has("w") and s.has("h"):
|
||||||
|
exit_tile = Vector2i(s.x + s.w / 2, s.y + s.h / 2)
|
||||||
|
for dx in range(s.w):
|
||||||
|
for dy in range(s.h):
|
||||||
|
var tx := s.x + dx
|
||||||
|
var ty := s.y + dy
|
||||||
|
if tx >= 0 and ty >= 0 and tx < map_size.x and ty < map_size.y:
|
||||||
|
var idx := tx + ty * map_size.x
|
||||||
|
if idx >= 0 and idx < explored_map.size() and explored_map[idx] != 0:
|
||||||
|
exit_discovered = true
|
||||||
|
break
|
||||||
|
if exit_discovered:
|
||||||
|
break
|
||||||
|
minimap_draw.set_maps(explored_map, map_size, dungeon_data.grid, player_tile, exit_tile, exit_discovered)
|
||||||
|
|
||||||
func _create_seen_array(map_size: Vector2i) -> PackedInt32Array:
|
func _create_seen_array(map_size: Vector2i) -> PackedInt32Array:
|
||||||
var size = map_size.x * map_size.y
|
var size = map_size.x * map_size.y
|
||||||
@@ -2391,9 +2441,7 @@ func _update_seen_for_player(player: Node, seen_map: PackedInt32Array) -> void:
|
|||||||
last_tile = tile
|
last_tile = tile
|
||||||
if tile.x < 0 or tile.y < 0 or tile.x >= map_size.x or tile.y >= map_size.y:
|
if tile.x < 0 or tile.y < 0 or tile.x >= map_size.x or tile.y >= map_size.y:
|
||||||
break
|
break
|
||||||
# If player is inside a room, don't reveal tiles outside that room (including walls)
|
# If player is in a room: allow seeing into corridor through open doorways (ray stops at wall/closed door only)
|
||||||
if not current_room.is_empty() and not _is_tile_in_room_or_walls(tile, current_room):
|
|
||||||
break
|
|
||||||
# If player is in corridor, only allow seeing tiles in corridor or connected rooms
|
# If player is in corridor, only allow seeing tiles in corridor or connected rooms
|
||||||
if current_room.is_empty() and allowed_rooms_for_corridor != null:
|
if current_room.is_empty() and allowed_rooms_for_corridor != null:
|
||||||
var tile_room = _find_room_at_tile(tile)
|
var tile_room = _find_room_at_tile(tile)
|
||||||
@@ -6864,6 +6912,35 @@ func _load_hud():
|
|||||||
print("GameWorld: HUD is_inside_tree: ", hud.is_inside_tree())
|
print("GameWorld: HUD is_inside_tree: ", hud.is_inside_tree())
|
||||||
|
|
||||||
_load_off_screen_indicators()
|
_load_off_screen_indicators()
|
||||||
|
_load_minimap()
|
||||||
|
_load_floating_text_layer()
|
||||||
|
|
||||||
|
func _load_floating_text_layer() -> void:
|
||||||
|
var existing = get_node_or_null("FloatingTextLayer")
|
||||||
|
if existing and is_instance_valid(existing):
|
||||||
|
return
|
||||||
|
var layer = CanvasLayer.new()
|
||||||
|
layer.name = "FloatingTextLayer"
|
||||||
|
layer.layer = 210
|
||||||
|
layer.follow_viewport_enabled = true
|
||||||
|
add_child(layer)
|
||||||
|
|
||||||
|
func world_to_screen(world_pos: Vector2) -> Vector2:
|
||||||
|
var vp = get_viewport()
|
||||||
|
if not vp:
|
||||||
|
return world_pos
|
||||||
|
return vp.get_canvas_transform() * world_pos
|
||||||
|
|
||||||
|
func _load_minimap() -> void:
|
||||||
|
var existing = get_node_or_null("Minimap")
|
||||||
|
if existing and is_instance_valid(existing):
|
||||||
|
return
|
||||||
|
var scene = load("res://scenes/minimap.tscn") as PackedScene
|
||||||
|
if not scene:
|
||||||
|
return
|
||||||
|
var layer = scene.instantiate()
|
||||||
|
layer.name = "Minimap"
|
||||||
|
add_child(layer)
|
||||||
|
|
||||||
func _load_off_screen_indicators():
|
func _load_off_screen_indicators():
|
||||||
var existing = get_node_or_null("OffScreenIndicators")
|
var existing = get_node_or_null("OffScreenIndicators")
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ func setup(p_target: Node) -> void:
|
|||||||
if not target_player or not is_instance_valid(target_player):
|
if not target_player or not is_instance_valid(target_player):
|
||||||
queue_free()
|
queue_free()
|
||||||
return
|
return
|
||||||
|
$SfxHeal.play()
|
||||||
global_position = target_player.global_position
|
global_position = target_player.global_position
|
||||||
elapsed = 0.0
|
elapsed = 0.0
|
||||||
if fx_sprite and _frames.size() > 0:
|
if fx_sprite and _frames.size() > 0:
|
||||||
|
|||||||
@@ -4,6 +4,10 @@ extends CanvasLayer
|
|||||||
|
|
||||||
var label_life: Label = null
|
var label_life: Label = null
|
||||||
var texture_progress_bar_hp: TextureProgressBar = null
|
var texture_progress_bar_hp: TextureProgressBar = null
|
||||||
|
var label_hp_value: Label = null
|
||||||
|
var vbox_mp: VBoxContainer = null
|
||||||
|
var progress_bar_mp: ProgressBar = null
|
||||||
|
var label_mp_value: Label = null
|
||||||
var label_keys: Label = null
|
var label_keys: Label = null
|
||||||
var label_keys_value: Label = null
|
var label_keys_value: Label = null
|
||||||
var label_level: Label = null
|
var label_level: Label = null
|
||||||
@@ -108,6 +112,9 @@ func _ready():
|
|||||||
player_search_attempts = 0
|
player_search_attempts = 0
|
||||||
_find_local_player()
|
_find_local_player()
|
||||||
|
|
||||||
|
# Add HP value label (curr/max, like inventory) and MP bar
|
||||||
|
_setup_hp_mp_ui()
|
||||||
|
|
||||||
func _on_player_connected(_peer_id: int, _player_info: Dictionary):
|
func _on_player_connected(_peer_id: int, _player_info: Dictionary):
|
||||||
_update_host_info()
|
_update_host_info()
|
||||||
|
|
||||||
@@ -194,9 +201,10 @@ func _process(_delta):
|
|||||||
if not label_time_value:
|
if not label_time_value:
|
||||||
return # Nodes not initialized yet, skip updates
|
return # Nodes not initialized yet, skip updates
|
||||||
|
|
||||||
# Update player health
|
# Update player health and MP
|
||||||
if local_player and is_instance_valid(local_player):
|
if local_player and is_instance_valid(local_player):
|
||||||
_update_player_health()
|
_update_player_health()
|
||||||
|
_update_player_mp()
|
||||||
_update_keys_display()
|
_update_keys_display()
|
||||||
|
|
||||||
# Update level display
|
# Update level display
|
||||||
@@ -219,6 +227,58 @@ func _update_hud_scale():
|
|||||||
scale_factor = 1
|
scale_factor = 1
|
||||||
scale = Vector2.ONE * scale_factor
|
scale = Vector2.ONE * scale_factor
|
||||||
|
|
||||||
|
func _setup_hp_mp_ui() -> void:
|
||||||
|
var life_vbox = get_node_or_null("UpperLeft/HBoxContainer/VBoxContainerLIFE")
|
||||||
|
var hbox = get_node_or_null("UpperLeft/HBoxContainer")
|
||||||
|
if not life_vbox or not hbox:
|
||||||
|
return
|
||||||
|
# HP value label (curr/max, like inventory)
|
||||||
|
label_hp_value = Label.new()
|
||||||
|
label_hp_value.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||||
|
if ResourceLoader.exists("res://assets/fonts/standard_font.png"):
|
||||||
|
var fr = load("res://assets/fonts/standard_font.png")
|
||||||
|
if fr:
|
||||||
|
label_hp_value.add_theme_font_override("font", fr)
|
||||||
|
label_hp_value.add_theme_font_size_override("font_size", 10)
|
||||||
|
label_hp_value.text = "0/0"
|
||||||
|
life_vbox.add_child(label_hp_value)
|
||||||
|
# MP VBox (label + bar + value)
|
||||||
|
vbox_mp = VBoxContainer.new()
|
||||||
|
vbox_mp.name = "VBoxContainerMP"
|
||||||
|
vbox_mp.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||||
|
var mp_title = Label.new()
|
||||||
|
mp_title.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||||
|
if ResourceLoader.exists("res://assets/fonts/standard_font.png"):
|
||||||
|
var fr = load("res://assets/fonts/standard_font.png")
|
||||||
|
if fr:
|
||||||
|
mp_title.add_theme_font_override("font", fr)
|
||||||
|
mp_title.add_theme_font_size_override("font_size", 10)
|
||||||
|
mp_title.text = "MP"
|
||||||
|
vbox_mp.add_child(mp_title)
|
||||||
|
progress_bar_mp = ProgressBar.new()
|
||||||
|
progress_bar_mp.custom_minimum_size = Vector2(100, 12)
|
||||||
|
progress_bar_mp.show_percentage = false
|
||||||
|
var bg = StyleBoxFlat.new()
|
||||||
|
bg.bg_color = Color(0.2, 0.2, 0.2, 0.8)
|
||||||
|
bg.set_border_width_all(1)
|
||||||
|
bg.border_color = Color(0.4, 0.4, 0.4)
|
||||||
|
progress_bar_mp.add_theme_stylebox_override("background", bg)
|
||||||
|
var fill = StyleBoxFlat.new()
|
||||||
|
fill.bg_color = Color(0.25, 0.45, 0.9)
|
||||||
|
progress_bar_mp.add_theme_stylebox_override("fill", fill)
|
||||||
|
vbox_mp.add_child(progress_bar_mp)
|
||||||
|
label_mp_value = Label.new()
|
||||||
|
label_mp_value.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||||
|
if ResourceLoader.exists("res://assets/fonts/standard_font.png"):
|
||||||
|
var fr = load("res://assets/fonts/standard_font.png")
|
||||||
|
if fr:
|
||||||
|
label_mp_value.add_theme_font_override("font", fr)
|
||||||
|
label_mp_value.add_theme_font_size_override("font_size", 10)
|
||||||
|
label_mp_value.text = "0/0"
|
||||||
|
vbox_mp.add_child(label_mp_value)
|
||||||
|
hbox.add_child(vbox_mp)
|
||||||
|
hbox.move_child(vbox_mp, 1)
|
||||||
|
|
||||||
func _update_player_health():
|
func _update_player_health():
|
||||||
if not local_player or not texture_progress_bar_hp:
|
if not local_player or not texture_progress_bar_hp:
|
||||||
return
|
return
|
||||||
@@ -239,6 +299,35 @@ func _update_player_health():
|
|||||||
texture_progress_bar_hp.max_value = max_health
|
texture_progress_bar_hp.max_value = max_health
|
||||||
texture_progress_bar_hp.value = health
|
texture_progress_bar_hp.value = health
|
||||||
|
|
||||||
|
# HP value label (like inventory)
|
||||||
|
if label_hp_value:
|
||||||
|
label_hp_value.text = str(int(health)) + "/" + str(int(max_health))
|
||||||
|
|
||||||
|
# Race label: "- DWARF -" / "- ELF -" / "- WIZARD -" (Human -> Wizard)
|
||||||
|
if label_life and local_player.character_stats:
|
||||||
|
var r = local_player.character_stats.race
|
||||||
|
var t = "- "
|
||||||
|
if r == "Dwarf":
|
||||||
|
t += "DWARF"
|
||||||
|
elif r == "Elf":
|
||||||
|
t += "ELF"
|
||||||
|
elif r == "Human":
|
||||||
|
t += "WIZARD"
|
||||||
|
else:
|
||||||
|
t += "LIFE"
|
||||||
|
label_life.text = t + " -"
|
||||||
|
|
||||||
|
func _update_player_mp() -> void:
|
||||||
|
if not local_player or not progress_bar_mp or not label_mp_value:
|
||||||
|
return
|
||||||
|
if not local_player.character_stats:
|
||||||
|
return
|
||||||
|
var mp = local_player.character_stats.mp
|
||||||
|
var max_mp = local_player.character_stats.maxmp
|
||||||
|
progress_bar_mp.max_value = max(1.0, max_mp)
|
||||||
|
progress_bar_mp.value = mp
|
||||||
|
label_mp_value.text = str(int(mp)) + "/" + str(int(max_mp))
|
||||||
|
|
||||||
func _update_keys_display():
|
func _update_keys_display():
|
||||||
if not local_player or not label_keys_value:
|
if not local_player or not label_keys_value:
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -838,7 +838,11 @@ func _open_chest(by_player: Node = null):
|
|||||||
if by_player and is_instance_valid(by_player) and by_player.is_in_group("player") and chest_item:
|
if by_player and is_instance_valid(by_player) and by_player.is_in_group("player") and chest_item:
|
||||||
# Add item to player inventory
|
# Add item to player inventory
|
||||||
if by_player.character_stats:
|
if by_player.character_stats:
|
||||||
|
var was_encumbered = by_player.character_stats.is_over_encumbered()
|
||||||
by_player.character_stats.add_item(chest_item)
|
by_player.character_stats.add_item(chest_item)
|
||||||
|
if not was_encumbered and by_player.character_stats.is_over_encumbered():
|
||||||
|
if by_player.has_method("show_floating_status"):
|
||||||
|
by_player.show_floating_status("Encumbered!", Color(1.0, 0.5, 0.2))
|
||||||
|
|
||||||
# Show pickup notification
|
# Show pickup notification
|
||||||
var items_texture = load(chest_item.spritePath) if chest_item.spritePath != "" else null
|
var items_texture = load(chest_item.spritePath) if chest_item.spritePath != "" else null
|
||||||
@@ -853,12 +857,11 @@ func _open_chest(by_player: Node = null):
|
|||||||
else:
|
else:
|
||||||
item_color = Color.WHITE
|
item_color = Color.WHITE
|
||||||
|
|
||||||
# Show notification with item sprite
|
# Show notification with item sprite (pass chest_item for ItemSprite colorization)
|
||||||
if items_texture:
|
if items_texture:
|
||||||
_show_item_pickup_notification(by_player, display_text, item_color, items_texture, chest_item.spriteFrames.x, chest_item.spriteFrames.y, chest_item.spriteFrame)
|
_show_item_pickup_notification(by_player, display_text, item_color, items_texture, chest_item.spriteFrames.x, chest_item.spriteFrames.y, chest_item.spriteFrame, chest_item)
|
||||||
else:
|
else:
|
||||||
# Fallback: just show text
|
_show_item_pickup_notification(by_player, display_text, item_color, null, 0, 0, 0, chest_item)
|
||||||
_show_item_pickup_notification(by_player, display_text, item_color, null, 0, 0, 0)
|
|
||||||
|
|
||||||
# Play chest open sound
|
# Play chest open sound
|
||||||
if has_node("SfxChestOpen"):
|
if has_node("SfxChestOpen"):
|
||||||
@@ -955,9 +958,9 @@ func _sync_chest_open(loot_type_str: String = "coin", player_peer_id: int = 0, i
|
|||||||
item_color = Color.CYAN # Cyan for equipment (matches loot pickup color)
|
item_color = Color.CYAN # Cyan for equipment (matches loot pickup color)
|
||||||
|
|
||||||
if items_texture:
|
if items_texture:
|
||||||
_show_item_pickup_notification(player, display_text, item_color, items_texture, chest_item.spriteFrames.x, chest_item.spriteFrames.y, chest_item.spriteFrame)
|
_show_item_pickup_notification(player, display_text, item_color, items_texture, chest_item.spriteFrames.x, chest_item.spriteFrames.y, chest_item.spriteFrame, chest_item)
|
||||||
else:
|
else:
|
||||||
_show_item_pickup_notification(player, display_text, item_color, null, 0, 0, 0)
|
_show_item_pickup_notification(player, display_text, item_color, null, 0, 0, 0, chest_item)
|
||||||
else:
|
else:
|
||||||
# Fallback to old loot type system (for backwards compatibility)
|
# Fallback to old loot type system (for backwards compatibility)
|
||||||
match loot_type_str:
|
match loot_type_str:
|
||||||
@@ -980,7 +983,7 @@ func _sync_chest_open(loot_type_str: String = "coin", player_peer_id: int = 0, i
|
|||||||
var items_texture = load("res://assets/gfx/pickups/items_n_shit.png")
|
var items_texture = load("res://assets/gfx/pickups/items_n_shit.png")
|
||||||
_show_item_pickup_notification(player, "+1 KEY", Color.YELLOW, items_texture, 20, 14, (13 * 20) + 10)
|
_show_item_pickup_notification(player, "+1 KEY", Color.YELLOW, items_texture, 20, 14, (13 * 20) + 10)
|
||||||
|
|
||||||
func _show_item_pickup_notification(player: Node, text: String, text_color: Color, item_texture: Texture2D = null, sprite_hframes: int = 1, sprite_vframes: int = 1, sprite_frame: int = 0):
|
func _show_item_pickup_notification(player: Node, text: String, text_color: Color, item_texture: Texture2D = null, sprite_hframes: int = 1, sprite_vframes: int = 1, sprite_frame: int = 0, item = null):
|
||||||
# Show item graphic and text above player's head for 0.5s, then fade out over 0.5s
|
# Show item graphic and text above player's head for 0.5s, then fade out over 0.5s
|
||||||
var floating_text_scene = preload("res://scenes/floating_text.tscn")
|
var floating_text_scene = preload("res://scenes/floating_text.tscn")
|
||||||
if floating_text_scene and player and is_instance_valid(player):
|
if floating_text_scene and player and is_instance_valid(player):
|
||||||
@@ -990,7 +993,7 @@ func _show_item_pickup_notification(player: Node, text: String, text_color: Colo
|
|||||||
parent.add_child(floating_text)
|
parent.add_child(floating_text)
|
||||||
# Position at player.position.y - 20 (just above head)
|
# Position at player.position.y - 20 (just above head)
|
||||||
floating_text.global_position = Vector2(player.global_position.x, player.global_position.y - 20)
|
floating_text.global_position = Vector2(player.global_position.x, player.global_position.y - 20)
|
||||||
floating_text.setup(text, text_color, 0.5, 0.5, item_texture, sprite_hframes, sprite_vframes, sprite_frame) # Show for 0.5s, fade over 0.5s
|
floating_text.setup(text, text_color, 0.5, 0.5, item_texture, sprite_hframes, sprite_vframes, sprite_frame, item)
|
||||||
|
|
||||||
func play_destroy_sound():
|
func play_destroy_sound():
|
||||||
if object_type == "Pot":
|
if object_type == "Pot":
|
||||||
|
|||||||
@@ -78,6 +78,21 @@ var equipment_buttons: Dictionary = {} # slot_name -> button
|
|||||||
var inventory_items_list: Array = [] # Flat list of items for navigation
|
var inventory_items_list: Array = [] # Flat list of items for navigation
|
||||||
var inventory_rows_list: Array = [] # List of HBoxContainers (rows)
|
var inventory_rows_list: Array = [] # List of HBoxContainers (rows)
|
||||||
|
|
||||||
|
# Level-up stat allocation (when pending_level_up)
|
||||||
|
var level_up_label: Label = null
|
||||||
|
var level_up_stat_buttons: Array = [] # Buttons for STR, DEX, INT, END, WIS, LCK, PER
|
||||||
|
var level_up_stat_container: HBoxContainer = null
|
||||||
|
var selected_level_up_stat_index: int = -1
|
||||||
|
const STAT_DESCRIPTIONS: Dictionary = {
|
||||||
|
"str": "STR: Physical damage, carry capacity.",
|
||||||
|
"dex": "DEX: Dodge, hit chance, move & attack speed.",
|
||||||
|
"int": "INT: Spell damage, mana, sight.",
|
||||||
|
"end": "END: Max HP.",
|
||||||
|
"wis": "WIS: Mana regen, resistances.",
|
||||||
|
"lck": "LCK: Critical hit chance.",
|
||||||
|
"per": "PER: Trap detection, perception."
|
||||||
|
}
|
||||||
|
|
||||||
# Equipment slot buttons
|
# Equipment slot buttons
|
||||||
var equipment_slots: Dictionary = {
|
var equipment_slots: Dictionary = {
|
||||||
"mainhand": null,
|
"mainhand": null,
|
||||||
@@ -116,6 +131,9 @@ func _ready():
|
|||||||
_create_exp_ui()
|
_create_exp_ui()
|
||||||
_create_coin_ui()
|
_create_coin_ui()
|
||||||
|
|
||||||
|
# Level-up stat allocation UI (label + stat buttons)
|
||||||
|
_setup_level_up_ui()
|
||||||
|
|
||||||
# Setup selection rectangle (already in scene, just configure it)
|
# Setup selection rectangle (already in scene, just configure it)
|
||||||
_setup_selection_rectangle()
|
_setup_selection_rectangle()
|
||||||
|
|
||||||
@@ -208,6 +226,16 @@ func _update_stats():
|
|||||||
var race_text = char_stats.race
|
var race_text = char_stats.race
|
||||||
stats_label.text = "Stats - " + race_text
|
stats_label.text = "Stats - " + race_text
|
||||||
|
|
||||||
|
# Level-up UI: "Level X - LEVEL UP" in green, stat allocation buttons
|
||||||
|
var pending = char_stats.pending_level_up and char_stats.pending_stat_points > 0
|
||||||
|
if level_up_label:
|
||||||
|
level_up_label.visible = pending
|
||||||
|
if pending:
|
||||||
|
level_up_label.text = "Level " + str(char_stats.level) + " - LEVEL UP"
|
||||||
|
level_up_label.add_theme_color_override("font_color", Color(0.2, 1.0, 0.4))
|
||||||
|
if level_up_stat_container:
|
||||||
|
level_up_stat_container.visible = pending
|
||||||
|
|
||||||
# Base stats: Level, STR, DEX, END, INT, WIS, LCK, PER (HP/MP are bars below)
|
# Base stats: Level, STR, DEX, END, INT, WIS, LCK, PER (HP/MP are bars below)
|
||||||
if label_base_stats:
|
if label_base_stats:
|
||||||
label_base_stats.text = "Level\n\nSTR\nDEX\nEND\nINT\nWIS\nLCK\nPER"
|
label_base_stats.text = "Level\n\nSTR\nDEX\nEND\nINT\nWIS\nLCK\nPER"
|
||||||
@@ -279,6 +307,82 @@ func _update_stats():
|
|||||||
fill_style.bg_color = Color(0.9, 0.3, 0.2)
|
fill_style.bg_color = Color(0.9, 0.3, 0.2)
|
||||||
weight_progress_bar.add_theme_stylebox_override("fill", fill_style)
|
weight_progress_bar.add_theme_stylebox_override("fill", fill_style)
|
||||||
|
|
||||||
|
func _setup_level_up_ui() -> void:
|
||||||
|
if not stats_panel:
|
||||||
|
return
|
||||||
|
level_up_label = Label.new()
|
||||||
|
level_up_label.name = "LevelUpLabel"
|
||||||
|
level_up_label.add_theme_font_size_override("font_size", 14)
|
||||||
|
level_up_label.add_theme_color_override("font_color", Color(0.2, 1.0, 0.4))
|
||||||
|
if ResourceLoader.exists("res://assets/fonts/standard_font.png"):
|
||||||
|
var fr = load("res://assets/fonts/standard_font.png")
|
||||||
|
if fr:
|
||||||
|
level_up_label.add_theme_font_override("font", fr)
|
||||||
|
level_up_label.visible = false
|
||||||
|
stats_panel.add_child(level_up_label)
|
||||||
|
stats_panel.move_child(level_up_label, 1)
|
||||||
|
level_up_stat_container = HBoxContainer.new()
|
||||||
|
level_up_stat_container.name = "LevelUpStatButtons"
|
||||||
|
level_up_stat_container.add_theme_constant_override("separation", 4)
|
||||||
|
level_up_stat_container.visible = false
|
||||||
|
for stat_name in CharacterStats.LEVEL_UP_STAT_NAMES:
|
||||||
|
var btn = Button.new()
|
||||||
|
btn.name = "LevelUp_" + stat_name
|
||||||
|
btn.text = stat_name.to_upper()
|
||||||
|
btn.custom_minimum_size = Vector2(32, 24)
|
||||||
|
btn.flat = true
|
||||||
|
if ResourceLoader.exists("res://assets/fonts/standard_font.png"):
|
||||||
|
var fr = load("res://assets/fonts/standard_font.png")
|
||||||
|
if fr:
|
||||||
|
btn.add_theme_font_override("font", fr)
|
||||||
|
btn.add_theme_font_size_override("font_size", 9)
|
||||||
|
btn.focus_mode = Control.FOCUS_ALL
|
||||||
|
btn.pressed.connect(_on_level_up_stat_pressed.bind(stat_name))
|
||||||
|
btn.mouse_entered.connect(_on_level_up_stat_hover_entered.bind(stat_name))
|
||||||
|
btn.mouse_exited.connect(_on_level_up_stat_hover_exited)
|
||||||
|
btn.gui_input.connect(_on_level_up_stat_gui_input.bind(stat_name, btn))
|
||||||
|
level_up_stat_container.add_child(btn)
|
||||||
|
level_up_stat_buttons.append(btn)
|
||||||
|
stats_panel.add_child(level_up_stat_container)
|
||||||
|
stats_panel.move_child(level_up_stat_container, 2)
|
||||||
|
|
||||||
|
func _on_level_up_stat_pressed(stat_name: String) -> void:
|
||||||
|
if not local_player or not local_player.character_stats:
|
||||||
|
return
|
||||||
|
if local_player.character_stats.allocate_stat_point(stat_name):
|
||||||
|
if sfx_armour:
|
||||||
|
sfx_armour.play()
|
||||||
|
_update_stats()
|
||||||
|
if not local_player.character_stats.pending_level_up:
|
||||||
|
selected_type = "equipment"
|
||||||
|
selected_level_up_stat_index = -1
|
||||||
|
var next_index = _find_next_filled_equipment_slot(-1, 1)
|
||||||
|
if next_index >= 0:
|
||||||
|
equipment_selection_index = next_index
|
||||||
|
selected_slot = equipment_slots_list[next_index]
|
||||||
|
selected_item = local_player.character_stats.equipment[selected_slot]
|
||||||
|
else:
|
||||||
|
selected_slot = ""
|
||||||
|
selected_item = null
|
||||||
|
if inventory_items_list.size() > 0:
|
||||||
|
selected_type = "item"
|
||||||
|
inventory_selection_row = 0
|
||||||
|
inventory_selection_col = 0
|
||||||
|
_update_ui()
|
||||||
|
|
||||||
|
func _on_level_up_stat_hover_entered(stat_name: String) -> void:
|
||||||
|
if info_label and stat_name in STAT_DESCRIPTIONS:
|
||||||
|
info_label.text = STAT_DESCRIPTIONS[stat_name]
|
||||||
|
|
||||||
|
func _on_level_up_stat_hover_exited() -> void:
|
||||||
|
if info_label:
|
||||||
|
_update_info_panel()
|
||||||
|
|
||||||
|
func _on_level_up_stat_gui_input(event: InputEvent, stat_name: String, btn: Button) -> void:
|
||||||
|
if event is InputEventKey and event.pressed and not event.echo:
|
||||||
|
if event.keycode == KEY_ENTER or event.keycode == KEY_KP_ENTER or event.keycode == KEY_SPACE:
|
||||||
|
_on_level_up_stat_pressed(stat_name)
|
||||||
|
|
||||||
func _create_equipment_slots():
|
func _create_equipment_slots():
|
||||||
# Equipment slot order: mainhand, offhand, headgear, armour, boots, accessory
|
# Equipment slot order: mainhand, offhand, headgear, armour, boots, accessory
|
||||||
var slot_names = ["mainhand", "offhand", "headgear", "armour", "boots", "accessory"]
|
var slot_names = ["mainhand", "offhand", "headgear", "armour", "boots", "accessory"]
|
||||||
@@ -1062,6 +1166,17 @@ func _navigate_equipment(direction: String):
|
|||||||
var next_index = _find_next_filled_equipment_slot(equipment_selection_index, -1)
|
var next_index = _find_next_filled_equipment_slot(equipment_selection_index, -1)
|
||||||
if next_index >= 0:
|
if next_index >= 0:
|
||||||
equipment_selection_index = next_index
|
equipment_selection_index = next_index
|
||||||
|
elif local_player and local_player.character_stats and local_player.character_stats.pending_level_up and local_player.character_stats.pending_stat_points > 0 and level_up_stat_buttons.size() > 0:
|
||||||
|
selected_type = "level_up_stat"
|
||||||
|
selected_level_up_stat_index = 0
|
||||||
|
selected_slot = ""
|
||||||
|
selected_item = null
|
||||||
|
level_up_stat_buttons[0].call_deferred("grab_focus")
|
||||||
|
if info_label and CharacterStats.LEVEL_UP_STAT_NAMES.size() > 0:
|
||||||
|
var sn = CharacterStats.LEVEL_UP_STAT_NAMES[0]
|
||||||
|
if sn in STAT_DESCRIPTIONS:
|
||||||
|
info_label.text = STAT_DESCRIPTIONS[sn]
|
||||||
|
return
|
||||||
"right":
|
"right":
|
||||||
var next_index = _find_next_filled_equipment_slot(equipment_selection_index, 1)
|
var next_index = _find_next_filled_equipment_slot(equipment_selection_index, 1)
|
||||||
if next_index >= 0:
|
if next_index >= 0:
|
||||||
@@ -1125,6 +1240,44 @@ func _navigate_equipment(direction: String):
|
|||||||
_update_selection_rectangle()
|
_update_selection_rectangle()
|
||||||
_update_info_panel()
|
_update_info_panel()
|
||||||
|
|
||||||
|
func _navigate_level_up_stats(direction: String) -> void:
|
||||||
|
var n = level_up_stat_buttons.size()
|
||||||
|
if n == 0:
|
||||||
|
return
|
||||||
|
match direction:
|
||||||
|
"left":
|
||||||
|
selected_level_up_stat_index = (selected_level_up_stat_index - 1 + n) % n
|
||||||
|
level_up_stat_buttons[selected_level_up_stat_index].call_deferred("grab_focus")
|
||||||
|
if info_label and selected_level_up_stat_index < CharacterStats.LEVEL_UP_STAT_NAMES.size():
|
||||||
|
var sn = CharacterStats.LEVEL_UP_STAT_NAMES[selected_level_up_stat_index]
|
||||||
|
if sn in STAT_DESCRIPTIONS:
|
||||||
|
info_label.text = STAT_DESCRIPTIONS[sn]
|
||||||
|
"right":
|
||||||
|
if selected_level_up_stat_index >= n - 1:
|
||||||
|
# Past last stat: go to equipment
|
||||||
|
selected_type = "equipment"
|
||||||
|
selected_level_up_stat_index = -1
|
||||||
|
selected_slot = ""
|
||||||
|
selected_item = null
|
||||||
|
var next_index = _find_next_filled_equipment_slot(-1, 1)
|
||||||
|
if next_index >= 0:
|
||||||
|
equipment_selection_index = next_index
|
||||||
|
selected_slot = equipment_slots_list[next_index]
|
||||||
|
selected_item = local_player.character_stats.equipment[selected_slot] if local_player and local_player.character_stats else null
|
||||||
|
_update_selection_from_navigation()
|
||||||
|
_update_selection_rectangle()
|
||||||
|
_update_info_panel()
|
||||||
|
return
|
||||||
|
selected_level_up_stat_index += 1
|
||||||
|
level_up_stat_buttons[selected_level_up_stat_index].call_deferred("grab_focus")
|
||||||
|
if info_label and selected_level_up_stat_index < CharacterStats.LEVEL_UP_STAT_NAMES.size():
|
||||||
|
var sn = CharacterStats.LEVEL_UP_STAT_NAMES[selected_level_up_stat_index]
|
||||||
|
if sn in STAT_DESCRIPTIONS:
|
||||||
|
info_label.text = STAT_DESCRIPTIONS[sn]
|
||||||
|
"up", "down":
|
||||||
|
pass
|
||||||
|
# Don't call _update_info_panel - we've set stat description above
|
||||||
|
|
||||||
func _on_inventory_item_pressed(item: Item):
|
func _on_inventory_item_pressed(item: Item):
|
||||||
if not local_player or not local_player.character_stats:
|
if not local_player or not local_player.character_stats:
|
||||||
return
|
return
|
||||||
@@ -1221,7 +1374,9 @@ func _input(event):
|
|||||||
direction = "down"
|
direction = "down"
|
||||||
|
|
||||||
if direction != "":
|
if direction != "":
|
||||||
if selected_type == "equipment":
|
if selected_type == "level_up_stat":
|
||||||
|
_navigate_level_up_stats(direction)
|
||||||
|
elif selected_type == "equipment":
|
||||||
_navigate_equipment(direction)
|
_navigate_equipment(direction)
|
||||||
else:
|
else:
|
||||||
_navigate_inventory(direction)
|
_navigate_inventory(direction)
|
||||||
@@ -1240,6 +1395,16 @@ func _input(event):
|
|||||||
get_viewport().set_input_as_handled()
|
get_viewport().set_input_as_handled()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# Attack: Allocate level-up stat when a stat button is focused
|
||||||
|
if event.is_action_pressed("attack") and not event.is_echo():
|
||||||
|
var fc = get_viewport().gui_get_focus_owner()
|
||||||
|
if level_up_stat_container and fc and is_instance_valid(level_up_stat_container) and fc.get_parent() == level_up_stat_container:
|
||||||
|
var idx = level_up_stat_buttons.find(fc)
|
||||||
|
if idx >= 0 and idx < CharacterStats.LEVEL_UP_STAT_NAMES.size():
|
||||||
|
_on_level_up_stat_pressed(CharacterStats.LEVEL_UP_STAT_NAMES[idx])
|
||||||
|
get_viewport().set_input_as_handled()
|
||||||
|
return
|
||||||
|
|
||||||
func _handle_f_key():
|
func _handle_f_key():
|
||||||
if not local_player or not local_player.character_stats:
|
if not local_player or not local_player.character_stats:
|
||||||
return
|
return
|
||||||
@@ -1562,6 +1727,7 @@ func _open_inventory():
|
|||||||
selected_slot = ""
|
selected_slot = ""
|
||||||
|
|
||||||
_update_ui()
|
_update_ui()
|
||||||
|
_update_stats()
|
||||||
|
|
||||||
if not local_player:
|
if not local_player:
|
||||||
_find_local_player()
|
_find_local_player()
|
||||||
|
|||||||
@@ -613,6 +613,7 @@ func _process_pickup_on_server(player: Node):
|
|||||||
sfx_loot_collect.play()
|
sfx_loot_collect.play()
|
||||||
|
|
||||||
# Handle item pickup based on type
|
# Handle item pickup based on type
|
||||||
|
var was_encumbered = player.character_stats.is_over_encumbered() if player.character_stats else false
|
||||||
if item.item_type == Item.ItemType.Equippable:
|
if item.item_type == Item.ItemType.Equippable:
|
||||||
# Equippable item - add to inventory
|
# Equippable item - add to inventory
|
||||||
if player.character_stats:
|
if player.character_stats:
|
||||||
@@ -623,6 +624,9 @@ func _process_pickup_on_server(player: Node):
|
|||||||
if player.character_stats:
|
if player.character_stats:
|
||||||
player.character_stats.add_item(item)
|
player.character_stats.add_item(item)
|
||||||
print(name, " picked up item: ", item.item_name, " (added to inventory)")
|
print(name, " picked up item: ", item.item_name, " (added to inventory)")
|
||||||
|
if player.character_stats and not was_encumbered and player.character_stats.is_over_encumbered():
|
||||||
|
if player.has_method("show_floating_status"):
|
||||||
|
player.show_floating_status("Encumbered!", Color(1.0, 0.5, 0.2))
|
||||||
|
|
||||||
# Sync inventory+equipment to joiner (server added to their copy; joiner's client must apply)
|
# Sync inventory+equipment to joiner (server added to their copy; joiner's client must apply)
|
||||||
if multiplayer.has_multiplayer_peer() and multiplayer.is_server():
|
if multiplayer.has_multiplayer_peer() and multiplayer.is_server():
|
||||||
@@ -649,7 +653,7 @@ func _process_pickup_on_server(player: Node):
|
|||||||
elif item.item_type == Item.ItemType.Restoration:
|
elif item.item_type == Item.ItemType.Restoration:
|
||||||
text_color = Color.GREEN # Green for consumables
|
text_color = Color.GREEN # Green for consumables
|
||||||
|
|
||||||
_show_floating_text(player, display_text, text_color, 0.5, 0.5, items_texture, item.spriteFrames.x, item.spriteFrames.y, item.spriteFrame)
|
_show_floating_text(player, display_text, text_color, 0.5, 0.5, items_texture, item.spriteFrames.x, item.spriteFrames.y, item.spriteFrame, item)
|
||||||
|
|
||||||
# Sync floating text to client via GameWorld to avoid loot node path RPCs
|
# Sync floating text to client via GameWorld to avoid loot node path RPCs
|
||||||
if multiplayer.has_multiplayer_peer() and player.get_multiplayer_authority() != 1:
|
if multiplayer.has_multiplayer_peer() and player.get_multiplayer_authority() != 1:
|
||||||
@@ -812,7 +816,7 @@ func _sync_show_floating_text(loot_type_value: int, text: String, color_value: C
|
|||||||
# Show floating text on client
|
# Show floating text on client
|
||||||
_show_floating_text(player, text, color_value, 0.5, 0.5, item_texture, sprite_hframes, sprite_vframes, sprite_frame_value)
|
_show_floating_text(player, text, color_value, 0.5, 0.5, item_texture, sprite_hframes, sprite_vframes, sprite_frame_value)
|
||||||
|
|
||||||
func _show_floating_text(player: Node, text: String, color: Color, show_time: float = 0.5, fade_time: float = 0.5, item_texture: Texture2D = null, sprite_hframes: int = 1, sprite_vframes: int = 1, sprite_frame: int = 0):
|
func _show_floating_text(player: Node, text: String, color: Color, show_time: float = 0.5, fade_time: float = 0.5, item_texture: Texture2D = null, sprite_hframes: int = 1, sprite_vframes: int = 1, sprite_frame: int = 0, item = null):
|
||||||
# Create floating text and item graphic above player's head
|
# Create floating text and item graphic above player's head
|
||||||
# Shows for show_time seconds, then fades out over fade_time seconds
|
# Shows for show_time seconds, then fades out over fade_time seconds
|
||||||
var floating_text_scene = preload("res://scenes/floating_text.tscn")
|
var floating_text_scene = preload("res://scenes/floating_text.tscn")
|
||||||
@@ -822,4 +826,4 @@ func _show_floating_text(player: Node, text: String, color: Color, show_time: fl
|
|||||||
if parent:
|
if parent:
|
||||||
parent.add_child(floating_text)
|
parent.add_child(floating_text)
|
||||||
floating_text.global_position = Vector2(player.global_position.x, player.global_position.y - 20)
|
floating_text.global_position = Vector2(player.global_position.x, player.global_position.y - 20)
|
||||||
floating_text.setup(text, color, show_time, fade_time, item_texture, sprite_hframes, sprite_vframes, sprite_frame)
|
floating_text.setup(text, color, show_time, fade_time, item_texture, sprite_hframes, sprite_vframes, sprite_frame, item)
|
||||||
|
|||||||
82
src/scripts/minimap.gd
Normal file
82
src/scripts/minimap.gd
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
extends Control
|
||||||
|
|
||||||
|
# Minimap: shows explored dungeon tiles (uses same "explored" data as fog of war).
|
||||||
|
# Populates as the player explores. Drawn in upper-right corner.
|
||||||
|
|
||||||
|
const MINIMAP_WIDTH: int = 128
|
||||||
|
const MINIMAP_HEIGHT: int = 96
|
||||||
|
const COLOR_UNEXPLORED: Color = Color(0.08, 0.08, 0.1)
|
||||||
|
const COLOR_WALL: Color = Color(0.22, 0.22, 0.26)
|
||||||
|
const COLOR_FLOOR: Color = Color(0.38, 0.38, 0.44)
|
||||||
|
const COLOR_PLAYER: Color = Color(1.0, 0.35, 0.35)
|
||||||
|
const COLOR_EXIT: Color = Color(1.0, 1.0, 1.0)
|
||||||
|
|
||||||
|
var _map_size: Vector2i = Vector2i.ZERO
|
||||||
|
var _explored_map: PackedInt32Array = PackedInt32Array()
|
||||||
|
var _grid: Array = [] # 2D grid [x][y]: 0=wall, 1=floor, 2=door, 3=corridor
|
||||||
|
var _player_tile: Vector2i = Vector2i(-1, -1)
|
||||||
|
var _exit_tile: Vector2i = Vector2i(-1, -1)
|
||||||
|
var _exit_discovered: bool = false
|
||||||
|
|
||||||
|
|
||||||
|
func set_maps(explored_map: PackedInt32Array, map_size: Vector2i, grid: Array, player_tile: Vector2i = Vector2i(-1, -1), exit_tile: Vector2i = Vector2i(-1, -1), exit_discovered: bool = false) -> void:
|
||||||
|
_explored_map = explored_map
|
||||||
|
_map_size = map_size
|
||||||
|
_grid = grid
|
||||||
|
_player_tile = player_tile
|
||||||
|
_exit_tile = exit_tile
|
||||||
|
_exit_discovered = exit_discovered
|
||||||
|
queue_redraw()
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
custom_minimum_size = Vector2(MINIMAP_WIDTH, MINIMAP_HEIGHT)
|
||||||
|
mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
|
|
||||||
|
|
||||||
|
func _process(_delta: float) -> void:
|
||||||
|
if _exit_discovered:
|
||||||
|
queue_redraw()
|
||||||
|
|
||||||
|
|
||||||
|
func _draw() -> void:
|
||||||
|
if _map_size.x <= 0 or _map_size.y <= 0 or _explored_map.is_empty():
|
||||||
|
return
|
||||||
|
var bw := float(MINIMAP_WIDTH)
|
||||||
|
var bh := float(MINIMAP_HEIGHT)
|
||||||
|
var tw := bw / float(_map_size.x)
|
||||||
|
var th := bh / float(_map_size.y)
|
||||||
|
for x in range(_map_size.x):
|
||||||
|
for y in range(_map_size.y):
|
||||||
|
var idx := x + y * _map_size.x
|
||||||
|
if idx < 0 or idx >= _explored_map.size():
|
||||||
|
continue
|
||||||
|
var explored := _explored_map[idx] != 0
|
||||||
|
var px := float(x) * tw
|
||||||
|
var py := float(y) * th
|
||||||
|
var rect := Rect2(px, py, tw, th)
|
||||||
|
var col: Color
|
||||||
|
if not explored:
|
||||||
|
col = COLOR_UNEXPLORED
|
||||||
|
else:
|
||||||
|
var g: int = 0
|
||||||
|
if _grid.size() > x and _grid[x] is Array and (_grid[x] as Array).size() > y:
|
||||||
|
var row = _grid[x] as Array
|
||||||
|
g = int(row[y])
|
||||||
|
if g == 0:
|
||||||
|
col = COLOR_WALL
|
||||||
|
else:
|
||||||
|
col = COLOR_FLOOR
|
||||||
|
draw_rect(rect, col, true)
|
||||||
|
if _player_tile.x >= 0 and _player_tile.y >= 0 and _player_tile.x < _map_size.x and _player_tile.y < _map_size.y:
|
||||||
|
var px := float(_player_tile.x) * tw + tw * 0.5
|
||||||
|
var py := float(_player_tile.y) * th + th * 0.5
|
||||||
|
var r := maxf(2.0, minf(tw, th) * 0.4)
|
||||||
|
draw_circle(Vector2(px, py), r, COLOR_PLAYER)
|
||||||
|
if _exit_discovered and _exit_tile.x >= 0 and _exit_tile.y >= 0 and _exit_tile.x < _map_size.x and _exit_tile.y < _map_size.y:
|
||||||
|
var ex := float(_exit_tile.x) * tw + tw * 0.5
|
||||||
|
var ey := float(_exit_tile.y) * th + th * 0.5
|
||||||
|
var er := maxf(2.0, minf(tw, th) * 0.35)
|
||||||
|
var blink := sin(Time.get_ticks_msec() * 0.004) * 0.5 + 0.5
|
||||||
|
var exit_col := Color(COLOR_EXIT.r, COLOR_EXIT.g, COLOR_EXIT.b, 0.45 + 0.55 * blink)
|
||||||
|
draw_circle(Vector2(ex, ey), er, exit_col)
|
||||||
1
src/scripts/minimap.gd.uid
Normal file
1
src/scripts/minimap.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://bd4vtqviya6bd
|
||||||
@@ -59,6 +59,7 @@ var controls_disabled: bool = false # True when player has reached exit and cont
|
|||||||
|
|
||||||
# Being held state
|
# Being held state
|
||||||
var being_held_by: Node = null
|
var being_held_by: Node = null
|
||||||
|
var grabbed_by_enemy_hand: Node = null # Set when enemy hand grabs (snatch); locks movement until release
|
||||||
var struggle_time: float = 0.0
|
var struggle_time: float = 0.0
|
||||||
var struggle_threshold: float = 0.8 # Seconds to break free
|
var struggle_threshold: float = 0.8 # Seconds to break free
|
||||||
var struggle_direction: Vector2 = Vector2.ZERO
|
var struggle_direction: Vector2 = Vector2.ZERO
|
||||||
@@ -97,7 +98,8 @@ var burn_debuff_duration: float = 5.0 # Burn lasts 5 seconds
|
|||||||
var burn_debuff_damage_per_second: float = 1.0 # 1 HP per second
|
var burn_debuff_damage_per_second: float = 1.0 # 1 HP per second
|
||||||
var burn_debuff_visual: Node2D = null # Visual indicator for burn debuff
|
var burn_debuff_visual: Node2D = null # Visual indicator for burn debuff
|
||||||
var burn_damage_timer: float = 0.0 # Timer for burn damage ticks
|
var burn_damage_timer: float = 0.0 # Timer for burn damage ticks
|
||||||
var movement_lock_timer: float = 0.0 # Lock movement when bow is released
|
var movement_lock_timer: float = 0.0 # Lock movement when bow is released or after casting spell
|
||||||
|
const SPELL_CAST_LOCK_DURATION: float = 0.28 # Lock in place briefly after casting a spell
|
||||||
var direction_lock_timer: float = 0.0 # Lock facing direction when attacking
|
var direction_lock_timer: float = 0.0 # Lock facing direction when attacking
|
||||||
var locked_facing_direction: Vector2 = Vector2.ZERO # Locked facing direction during attack
|
var locked_facing_direction: Vector2 = Vector2.ZERO # Locked facing direction during attack
|
||||||
var damage_direction_lock_timer: float = 0.0 # Lock facing when taking damage (enemies/players)
|
var damage_direction_lock_timer: float = 0.0 # Lock facing when taking damage (enemies/players)
|
||||||
@@ -124,9 +126,22 @@ var velocity_z: float = 0.0
|
|||||||
var gravity_z: float = 500.0 # Gravity pulling down (scaled for 1x scale)
|
var gravity_z: float = 500.0 # Gravity pulling down (scaled for 1x scale)
|
||||||
var is_airborne: bool = false
|
var is_airborne: bool = false
|
||||||
|
|
||||||
|
# Spawn fall-down: hidden at start, fall from high Z, land with DIE+concussion, then stand up
|
||||||
|
const SPAWN_FALL_INITIAL_Z: float = 700.0 # High enough to start off-screen (y_offset = -350)
|
||||||
|
const SPAWN_FALL_GRAVITY: float = 180.0 # Slower fall so descent is visible (~2.8s from 700)
|
||||||
|
const SPAWN_LANDING_BOUNCE_GRAVITY: float = 420.0 # Heavier gravity during bounce so it's snappier
|
||||||
|
const SPAWN_LANDING_BOUNCE_UP: float = 95.0 # Upward velocity on first impact for a noticeable bounce
|
||||||
|
const SPAWN_LANDING_LAND_DURATION: float = 0.85 # Time in LAND (and concussion) before switching to STAND
|
||||||
|
const SPAWN_LANDING_STAND_DURATION: float = 0.16 # STAND anim duration (40+40+40+40 ms) before allow control
|
||||||
|
var spawn_landing: bool = false
|
||||||
|
var spawn_landing_landed: bool = false
|
||||||
|
var spawn_landing_bounced: bool = false
|
||||||
|
|
||||||
# Components
|
# Components
|
||||||
# @onready var sprite = $Sprite2D # REMOVED: Now using layered sprites
|
# @onready var sprite = $Sprite2D # REMOVED: Now using layered sprites
|
||||||
@onready var shadow = $Shadow
|
@onready var shadow = $Shadow
|
||||||
|
@onready var cone_light = $ConeLight
|
||||||
|
@onready var point_light = $PointLight2D
|
||||||
@onready var collision_shape = $CollisionShape2D
|
@onready var collision_shape = $CollisionShape2D
|
||||||
@onready var grab_area = $GrabArea
|
@onready var grab_area = $GrabArea
|
||||||
@onready var interaction_indicator = $InteractionIndicator
|
@onready var interaction_indicator = $InteractionIndicator
|
||||||
@@ -150,7 +165,6 @@ var is_airborne: bool = false
|
|||||||
@onready var sprite_shield = $Sprite2DShield
|
@onready var sprite_shield = $Sprite2DShield
|
||||||
@onready var sprite_shield_holding = $Sprite2DShieldHolding
|
@onready var sprite_shield_holding = $Sprite2DShieldHolding
|
||||||
@onready var sprite_weapon = $Sprite2DWeapon
|
@onready var sprite_weapon = $Sprite2DWeapon
|
||||||
@onready var cone_light = $ConeLight
|
|
||||||
|
|
||||||
# Player stats (legacy - now using character_stats)
|
# Player stats (legacy - now using character_stats)
|
||||||
var max_health: float:
|
var max_health: float:
|
||||||
@@ -308,6 +322,24 @@ const ANIMATIONS = {
|
|||||||
"frameDurations": [260, 260, 260, 260],
|
"frameDurations": [260, 260, 260, 260],
|
||||||
"loop": true,
|
"loop": true,
|
||||||
"nextAnimation": null
|
"nextAnimation": null
|
||||||
|
},
|
||||||
|
"FALL": {
|
||||||
|
"frames": [19, 21],
|
||||||
|
"frameDurations": [10, 10],
|
||||||
|
"loop": true,
|
||||||
|
"nextAnimation": null
|
||||||
|
},
|
||||||
|
"LAND": {
|
||||||
|
"frames": [23],
|
||||||
|
"frameDurations": [10],
|
||||||
|
"loop": true,
|
||||||
|
"nextAnimation": null
|
||||||
|
},
|
||||||
|
"STAND": {
|
||||||
|
"frames": [23,24,22,1],
|
||||||
|
"frameDurations": [40,40,40,40],
|
||||||
|
"loop": false,
|
||||||
|
"nextAnimation": "IDLE"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -321,6 +353,20 @@ func _ready():
|
|||||||
# Add to player group for easy identification
|
# Add to player group for easy identification
|
||||||
add_to_group("player")
|
add_to_group("player")
|
||||||
|
|
||||||
|
# Spawn fall-down: hidden at start for everyone, then show and fall from high Z
|
||||||
|
visible = false
|
||||||
|
spawn_landing = true
|
||||||
|
spawn_landing_landed = false
|
||||||
|
spawn_landing_bounced = false
|
||||||
|
position_z = SPAWN_FALL_INITIAL_Z
|
||||||
|
velocity_z = 0.0
|
||||||
|
is_airborne = true
|
||||||
|
if cone_light:
|
||||||
|
cone_light.visible = false
|
||||||
|
if point_light:
|
||||||
|
point_light.visible = false
|
||||||
|
call_deferred("_spawn_landing_show")
|
||||||
|
|
||||||
# Set respawn point to starting position
|
# Set respawn point to starting position
|
||||||
respawn_point = global_position
|
respawn_point = global_position
|
||||||
|
|
||||||
@@ -469,6 +515,11 @@ func _ready():
|
|||||||
# Emit character_changed to trigger appearance sync for any newly connected clients
|
# Emit character_changed to trigger appearance sync for any newly connected clients
|
||||||
character_stats.character_changed.emit(character_stats)
|
character_stats.character_changed.emit(character_stats)
|
||||||
|
|
||||||
|
func _spawn_landing_show():
|
||||||
|
if not is_instance_valid(self):
|
||||||
|
return
|
||||||
|
visible = true
|
||||||
|
|
||||||
func _duplicate_sprite_materials():
|
func _duplicate_sprite_materials():
|
||||||
# Duplicate shader materials for ALL sprites that use tint parameters
|
# Duplicate shader materials for ALL sprites that use tint parameters
|
||||||
# This prevents shared material state between players
|
# This prevents shared material state between players
|
||||||
@@ -1530,6 +1581,9 @@ func _update_facing_from_mouse(mouse_direction: Vector2):
|
|||||||
# Don't update facing when dead
|
# Don't update facing when dead
|
||||||
if is_dead:
|
if is_dead:
|
||||||
return
|
return
|
||||||
|
# Don't update facing during spawn fall/land/stand (locked to DOWN until stand up)
|
||||||
|
if spawn_landing:
|
||||||
|
return
|
||||||
|
|
||||||
# Only update if using keyboard input (not gamepad)
|
# Only update if using keyboard input (not gamepad)
|
||||||
if input_device != -1:
|
if input_device != -1:
|
||||||
@@ -1702,8 +1756,11 @@ func _snap_to_8_directions(direction: Vector2) -> Vector2:
|
|||||||
return best_dir
|
return best_dir
|
||||||
|
|
||||||
func _update_z_physics(delta):
|
func _update_z_physics(delta):
|
||||||
# Apply gravity
|
# Apply gravity (slower spawn-fall; snappier bounce)
|
||||||
velocity_z -= gravity_z * delta
|
var g = gravity_z
|
||||||
|
if spawn_landing and not spawn_landing_landed:
|
||||||
|
g = SPAWN_LANDING_BOUNCE_GRAVITY if spawn_landing_bounced else SPAWN_FALL_GRAVITY
|
||||||
|
velocity_z -= g * delta
|
||||||
|
|
||||||
# Update Z position
|
# Update Z position
|
||||||
position_z += velocity_z * delta
|
position_z += velocity_z * delta
|
||||||
@@ -1711,15 +1768,28 @@ func _update_z_physics(delta):
|
|||||||
# Check if landed
|
# Check if landed
|
||||||
if position_z <= 0.0:
|
if position_z <= 0.0:
|
||||||
position_z = 0.0
|
position_z = 0.0
|
||||||
|
# Spawn landing: first impact -> bounce + LAND; second impact -> settle, then STAND
|
||||||
|
if spawn_landing and not spawn_landing_landed and is_multiplayer_authority() and not spawn_landing_bounced:
|
||||||
|
spawn_landing_bounced = true
|
||||||
|
velocity_z = SPAWN_LANDING_BOUNCE_UP
|
||||||
|
velocity = velocity * 0.3
|
||||||
|
current_direction = Direction.RIGHT
|
||||||
|
facing_direction_vector = Vector2.RIGHT
|
||||||
|
_set_animation("LAND")
|
||||||
|
if has_node("SfxFallDownLand"):
|
||||||
|
$SfxFallDownLand.play()
|
||||||
|
if multiplayer.has_multiplayer_peer() and can_send_rpcs and is_inside_tree():
|
||||||
|
_rpc_to_ready_peers("_sync_spawn_bounced", [name])
|
||||||
|
# keep is_airborne true, continue falling after bounce
|
||||||
|
else:
|
||||||
velocity_z = 0.0
|
velocity_z = 0.0
|
||||||
is_airborne = false
|
is_airborne = false
|
||||||
|
|
||||||
# Stop horizontal movement on landing (with some friction)
|
|
||||||
velocity = velocity * 0.3
|
velocity = velocity * 0.3
|
||||||
|
if not spawn_landing:
|
||||||
# Visual effect when landing (removed - using layered sprites now)
|
|
||||||
|
|
||||||
print(name, " landed!")
|
print(name, " landed!")
|
||||||
|
elif spawn_landing and not spawn_landing_landed and is_multiplayer_authority():
|
||||||
|
spawn_landing_landed = true
|
||||||
|
_spawn_landing_on_land()
|
||||||
|
|
||||||
# Update visual offset based on height for all sprite layers
|
# Update visual offset based on height for all sprite layers
|
||||||
var y_offset = - position_z * 0.5 # Visual height is half of z for perspective
|
var y_offset = - position_z * 0.5 # Visual height is half of z for perspective
|
||||||
@@ -1754,6 +1824,19 @@ func _physics_process(delta):
|
|||||||
# Reset teleport flag at start of frame
|
# Reset teleport flag at start of frame
|
||||||
teleported_this_frame = false
|
teleported_this_frame = false
|
||||||
|
|
||||||
|
# Spawn fall: DOWN during fall; RIGHT on landing (bounce + rest). FALL until first impact, then LAND.
|
||||||
|
if spawn_landing:
|
||||||
|
if not spawn_landing_bounced:
|
||||||
|
current_direction = Direction.DOWN
|
||||||
|
facing_direction_vector = Vector2.DOWN
|
||||||
|
else:
|
||||||
|
current_direction = Direction.RIGHT
|
||||||
|
facing_direction_vector = Vector2.RIGHT
|
||||||
|
if is_airborne and not spawn_landing_landed and not spawn_landing_bounced:
|
||||||
|
_set_animation("FALL")
|
||||||
|
elif is_airborne and spawn_landing_bounced:
|
||||||
|
_set_animation("LAND")
|
||||||
|
|
||||||
# Update animations
|
# Update animations
|
||||||
_update_animation(delta)
|
_update_animation(delta)
|
||||||
|
|
||||||
@@ -1898,15 +1981,15 @@ func _physics_process(delta):
|
|||||||
burn_damage_timer = 0.0
|
burn_damage_timer = 0.0
|
||||||
_remove_burn_debuff()
|
_remove_burn_debuff()
|
||||||
|
|
||||||
# Skip input if controls are disabled (e.g., when inventory is open)
|
# Skip input if controls are disabled (e.g., when inventory is open) or spawn landing (fall → DIE → stand up)
|
||||||
# But still allow knockback to continue (handled above)
|
# But still allow knockback to continue (handled above)
|
||||||
var skip_input = controls_disabled
|
var skip_input = controls_disabled or spawn_landing
|
||||||
if controls_disabled:
|
if controls_disabled or spawn_landing:
|
||||||
if not is_knocked_back:
|
if not is_knocked_back:
|
||||||
# Immediately stop movement when controls are disabled (e.g., inventory opened)
|
# Immediately stop movement when controls are disabled (e.g., inventory opened)
|
||||||
velocity = Vector2.ZERO
|
velocity = Vector2.ZERO
|
||||||
# Reset animation to IDLE if not in a special state
|
# Reset animation to IDLE if not in a special state (skip when spawn_landing: we use DIE until stand up)
|
||||||
if current_animation != "THROW" and current_animation != "DAMAGE" and current_animation != "SWORD" and current_animation != "BOW" and current_animation != "STAFF":
|
if not spawn_landing and current_animation != "THROW" and current_animation != "DAMAGE" and current_animation != "SWORD" and current_animation != "BOW" and current_animation != "STAFF":
|
||||||
if is_lifting:
|
if is_lifting:
|
||||||
_set_animation("IDLE_HOLD")
|
_set_animation("IDLE_HOLD")
|
||||||
elif is_pushing:
|
elif is_pushing:
|
||||||
@@ -1914,7 +1997,7 @@ func _physics_process(delta):
|
|||||||
else:
|
else:
|
||||||
_set_animation("IDLE")
|
_set_animation("IDLE")
|
||||||
|
|
||||||
# Check if being held by someone
|
# Check if being held by someone (another player) or grabbed by enemy hand
|
||||||
var being_held_by_someone = false
|
var being_held_by_someone = false
|
||||||
for other_player in get_tree().get_nodes_in_group("player"):
|
for other_player in get_tree().get_nodes_in_group("player"):
|
||||||
if other_player != self and other_player.held_object == self:
|
if other_player != self and other_player.held_object == self:
|
||||||
@@ -1928,6 +2011,11 @@ func _physics_process(delta):
|
|||||||
_update_shield_visibility()
|
_update_shield_visibility()
|
||||||
# Handle struggle mechanic
|
# Handle struggle mechanic
|
||||||
_handle_struggle(delta)
|
_handle_struggle(delta)
|
||||||
|
elif grabbed_by_enemy_hand:
|
||||||
|
velocity = Vector2.ZERO
|
||||||
|
is_shielding = false
|
||||||
|
was_shielding_last_frame = false
|
||||||
|
_update_shield_visibility()
|
||||||
elif is_knocked_back:
|
elif is_knocked_back:
|
||||||
is_shielding = false
|
is_shielding = false
|
||||||
was_shielding_last_frame = false
|
was_shielding_last_frame = false
|
||||||
@@ -2378,6 +2466,8 @@ func _handle_interactions():
|
|||||||
heal_target = _get_heal_target()
|
heal_target = _get_heal_target()
|
||||||
|
|
||||||
var has_valid_target = ((is_fire or is_frost) and target_pos != Vector2.ZERO) or (is_heal and heal_target != null)
|
var has_valid_target = ((is_fire or is_frost) and target_pos != Vector2.ZERO) or (is_heal and heal_target != null)
|
||||||
|
# Healing: allow charge even without target (don't disable charge when hovering enemy/wall/etc.)
|
||||||
|
var can_start_charge = is_heal or has_valid_target
|
||||||
|
|
||||||
# Check if there's a grabbable object nearby - prioritize grabbing over spell casting
|
# Check if there's a grabbable object nearby - prioritize grabbing over spell casting
|
||||||
var nearby_grabbable = null
|
var nearby_grabbable = null
|
||||||
@@ -2399,7 +2489,7 @@ func _handle_interactions():
|
|||||||
nearby_grabbable = body
|
nearby_grabbable = body
|
||||||
break
|
break
|
||||||
|
|
||||||
if grab_just_pressed and not is_charging_spell and has_valid_target and not nearby_grabbable and not is_lifting and not held_object:
|
if grab_just_pressed and not is_charging_spell and can_start_charge and not nearby_grabbable and not is_lifting and not held_object:
|
||||||
is_charging_spell = true
|
is_charging_spell = true
|
||||||
current_spell_element = "healing" if is_heal else ("frost" if is_frost else "fire")
|
current_spell_element = "healing" if is_heal else ("frost" if is_frost else "fire")
|
||||||
spell_charge_start_time = Time.get_ticks_msec() / 1000.0
|
spell_charge_start_time = Time.get_ticks_msec() / 1000.0
|
||||||
@@ -2448,6 +2538,7 @@ func _handle_interactions():
|
|||||||
else:
|
else:
|
||||||
_cast_heal_spell(heal_target)
|
_cast_heal_spell(heal_target)
|
||||||
_set_animation("FINISH_SPELL")
|
_set_animation("FINISH_SPELL")
|
||||||
|
movement_lock_timer = SPELL_CAST_LOCK_DURATION
|
||||||
is_charging_spell = false
|
is_charging_spell = false
|
||||||
current_spell_element = "fire"
|
current_spell_element = "fire"
|
||||||
spell_incantation_played = false
|
spell_incantation_played = false
|
||||||
@@ -2474,7 +2565,8 @@ func _handle_interactions():
|
|||||||
print(name, " released spell (", "healing" if is_heal else ("frost" if is_frost else "fire"), ", fully: ", is_fully_charged, ")")
|
print(name, " released spell (", "healing" if is_heal else ("frost" if is_frost else "fire"), ", fully: ", is_fully_charged, ")")
|
||||||
just_grabbed_this_frame = false
|
just_grabbed_this_frame = false
|
||||||
return
|
return
|
||||||
elif is_charging_spell and (not has_valid_target or is_lifting or held_object):
|
elif is_charging_spell and (is_lifting or held_object or ((not is_heal) and not has_valid_target)):
|
||||||
|
# Don't cancel heal charge for no target (allow hover over enemy/wall); cancel fire/frost
|
||||||
is_charging_spell = false
|
is_charging_spell = false
|
||||||
current_spell_element = "fire"
|
current_spell_element = "fire"
|
||||||
spell_incantation_played = false
|
spell_incantation_played = false
|
||||||
@@ -2488,7 +2580,7 @@ func _handle_interactions():
|
|||||||
$SfxSpellIncantation.stop()
|
$SfxSpellIncantation.stop()
|
||||||
if multiplayer.has_multiplayer_peer():
|
if multiplayer.has_multiplayer_peer():
|
||||||
_sync_spell_charge_end.rpc()
|
_sync_spell_charge_end.rpc()
|
||||||
print(name, " spell charge cancelled (no target)")
|
print(name, " spell charge cancelled (no target / lift / held)")
|
||||||
|
|
||||||
# Check for trap disarm (Dwarf only)
|
# Check for trap disarm (Dwarf only)
|
||||||
if character_stats and character_stats.race == "Dwarf":
|
if character_stats and character_stats.race == "Dwarf":
|
||||||
@@ -4068,14 +4160,31 @@ func _cast_heal_spell(target: Node):
|
|||||||
if is_crit:
|
if is_crit:
|
||||||
amount = floor(amount * 2.0)
|
amount = floor(amount * 2.0)
|
||||||
|
|
||||||
var is_revive = "is_dead" in target and target.is_dead
|
|
||||||
var display_amount = int(amount)
|
var display_amount = int(amount)
|
||||||
|
|
||||||
|
# Undead enemies take damage from healing spell
|
||||||
|
if target.is_in_group("enemy") and "is_undead" in target and target.is_undead:
|
||||||
|
var damage_amount = float(display_amount)
|
||||||
|
var eid = target.get_multiplayer_authority()
|
||||||
|
var my_id = multiplayer.get_unique_id()
|
||||||
|
if eid == my_id:
|
||||||
|
target.take_damage(damage_amount, global_position, is_crit)
|
||||||
|
elif multiplayer.has_multiplayer_peer() and can_send_rpcs and is_inside_tree():
|
||||||
|
target.rpc_take_damage.rpc_id(eid, damage_amount, global_position, is_crit, false, false)
|
||||||
|
else:
|
||||||
|
target.rpc_take_damage.rpc(damage_amount, global_position, is_crit, false, false)
|
||||||
|
_spawn_heal_effect_and_text(target, display_amount, is_crit, false, true)
|
||||||
|
if gw and gw.has_method("_apply_heal_spell_sync"):
|
||||||
|
_rpc_to_ready_peers("_sync_heal_spell_via_gw", [target.name, damage_amount, display_amount, is_crit, false, false, false, true])
|
||||||
|
print(name, " cast heal on undead ", target.name, " for ", display_amount, " damage (crit: ", is_crit, ")")
|
||||||
|
return
|
||||||
|
|
||||||
|
var is_revive = "is_dead" in target and target.is_dead
|
||||||
var actual_heal = amount
|
var actual_heal = amount
|
||||||
var allow_overheal = false
|
var allow_overheal = false
|
||||||
var is_overheal = false
|
var is_overheal = false
|
||||||
|
|
||||||
if is_revive:
|
if is_revive:
|
||||||
# Tome revive: no overheal, full amount revives
|
|
||||||
actual_heal = amount
|
actual_heal = amount
|
||||||
else:
|
else:
|
||||||
var overheal_chance_pct = 1.0 + lck_val * 0.3
|
var overheal_chance_pct = 1.0 + lck_val * 0.3
|
||||||
@@ -4099,12 +4208,12 @@ func _cast_heal_spell(target: Node):
|
|||||||
else:
|
else:
|
||||||
if me == tid and actual_heal > 0:
|
if me == tid and actual_heal > 0:
|
||||||
target.heal(actual_heal, allow_overheal)
|
target.heal(actual_heal, allow_overheal)
|
||||||
_spawn_heal_effect_and_text(target, display_amount, is_crit, is_overheal)
|
_spawn_heal_effect_and_text(target, display_amount, is_crit, is_overheal, false)
|
||||||
if multiplayer.has_multiplayer_peer() and can_send_rpcs and is_inside_tree() and gw and gw.has_method("_apply_heal_spell_sync"):
|
if multiplayer.has_multiplayer_peer() and can_send_rpcs and is_inside_tree() and gw and gw.has_method("_apply_heal_spell_sync"):
|
||||||
_rpc_to_ready_peers("_sync_heal_spell_via_gw", [target.name, actual_heal, display_amount, is_crit, is_overheal, allow_overheal, is_revive])
|
_rpc_to_ready_peers("_sync_heal_spell_via_gw", [target.name, actual_heal, display_amount, is_crit, is_overheal, allow_overheal, is_revive, false])
|
||||||
print(name, " cast heal on ", target.name, " for ", display_amount, " HP", " (actual: ", actual_heal, ", crit: ", is_crit, ", overheal: ", is_overheal, ", revive: ", is_revive, ")")
|
print(name, " cast heal on ", target.name, " for ", display_amount, " HP", " (actual: ", actual_heal, ", crit: ", is_crit, ", overheal: ", is_overheal, ", revive: ", is_revive, ")")
|
||||||
|
|
||||||
func _spawn_heal_effect_and_text(target: Node, display_amount: int, is_crit: bool, is_overheal: bool):
|
func _spawn_heal_effect_and_text(target: Node, display_amount: int, is_crit: bool, is_overheal: bool, is_damage_to_enemy: bool = false):
|
||||||
if not target or not is_instance_valid(target):
|
if not target or not is_instance_valid(target):
|
||||||
return
|
return
|
||||||
var game_world = get_tree().get_first_node_in_group("game_world")
|
var game_world = get_tree().get_first_node_in_group("game_world")
|
||||||
@@ -4118,6 +4227,9 @@ func _spawn_heal_effect_and_text(target: Node, display_amount: int, is_crit: boo
|
|||||||
eff.global_position = target.global_position
|
eff.global_position = target.global_position
|
||||||
if eff.has_method("setup"):
|
if eff.has_method("setup"):
|
||||||
eff.setup(target)
|
eff.setup(target)
|
||||||
|
if is_damage_to_enemy:
|
||||||
|
# Undead: enemy's take_damage already shows damage number; we only spawn effect
|
||||||
|
return
|
||||||
var prefix = ""
|
var prefix = ""
|
||||||
if is_crit and is_overheal:
|
if is_crit and is_overheal:
|
||||||
prefix = "CRIT OVERHEAL! "
|
prefix = "CRIT OVERHEAL! "
|
||||||
@@ -4134,12 +4246,12 @@ func _spawn_heal_effect_and_text(target: Node, display_amount: int, is_crit: boo
|
|||||||
ft.setup(heal_text, Color.GREEN, 0.5, 0.5, null, 1, 1, 0)
|
ft.setup(heal_text, Color.GREEN, 0.5, 0.5, null, 1, 1, 0)
|
||||||
|
|
||||||
@rpc("any_peer", "reliable")
|
@rpc("any_peer", "reliable")
|
||||||
func _sync_heal_spell_via_gw(target_name: String, amount_to_apply: float, display_amount: int, is_crit: bool, is_overheal: bool, allow_overheal: bool, is_revive: bool = false):
|
func _sync_heal_spell_via_gw(target_name: String, amount_to_apply: float, display_amount: int, is_crit: bool, is_overheal: bool, allow_overheal: bool, is_revive: bool = false, is_damage_to_enemy: bool = false):
|
||||||
if is_multiplayer_authority():
|
if is_multiplayer_authority():
|
||||||
return
|
return
|
||||||
var gw = get_tree().get_first_node_in_group("game_world")
|
var gw = get_tree().get_first_node_in_group("game_world")
|
||||||
if gw and gw.has_method("_apply_heal_spell_sync"):
|
if gw and gw.has_method("_apply_heal_spell_sync"):
|
||||||
gw._apply_heal_spell_sync(target_name, amount_to_apply, display_amount, is_crit, is_overheal, allow_overheal, is_revive)
|
gw._apply_heal_spell_sync(target_name, amount_to_apply, display_amount, is_crit, is_overheal, allow_overheal, is_revive, is_damage_to_enemy)
|
||||||
|
|
||||||
func _is_healing_spell() -> bool:
|
func _is_healing_spell() -> bool:
|
||||||
if not character_stats or not character_stats.equipment.has("offhand"):
|
if not character_stats or not character_stats.equipment.has("offhand"):
|
||||||
@@ -4169,6 +4281,15 @@ func _get_heal_target() -> Node:
|
|||||||
if d < best_d:
|
if d < best_d:
|
||||||
best_d = d
|
best_d = d
|
||||||
best = p
|
best = p
|
||||||
|
for e in get_tree().get_nodes_in_group("enemy"):
|
||||||
|
if not is_instance_valid(e) or ("is_dead" in e and e.is_dead):
|
||||||
|
continue
|
||||||
|
if not ("is_undead" in e and e.is_undead):
|
||||||
|
continue
|
||||||
|
var d = e.global_position.distance_to(mouse_world)
|
||||||
|
if d < best_d:
|
||||||
|
best_d = d
|
||||||
|
best = e
|
||||||
return best
|
return best
|
||||||
|
|
||||||
func _can_cast_spell_at(target_position: Vector2) -> bool:
|
func _can_cast_spell_at(target_position: Vector2) -> bool:
|
||||||
@@ -5580,6 +5701,34 @@ func set_being_held(held: bool):
|
|||||||
struggle_direction = Vector2.ZERO
|
struggle_direction = Vector2.ZERO
|
||||||
being_held_by = null
|
being_held_by = null
|
||||||
|
|
||||||
|
@rpc("any_peer", "reliable")
|
||||||
|
func rpc_grabbed_by_enemy_hand(enemy_name: String) -> void:
|
||||||
|
var en: Node = null
|
||||||
|
var gw = get_tree().get_first_node_in_group("game_world")
|
||||||
|
if gw:
|
||||||
|
var entities = gw.get_node_or_null("Entities")
|
||||||
|
if entities:
|
||||||
|
en = entities.get_node_or_null(enemy_name)
|
||||||
|
if not en:
|
||||||
|
en = _find_node_by_name(gw, enemy_name)
|
||||||
|
grabbed_by_enemy_hand = en if en and is_instance_valid(en) else null
|
||||||
|
velocity = Vector2.ZERO
|
||||||
|
|
||||||
|
@rpc("any_peer", "reliable")
|
||||||
|
func rpc_released_from_enemy_hand() -> void:
|
||||||
|
grabbed_by_enemy_hand = null
|
||||||
|
|
||||||
|
func _find_node_by_name(node: Node, n: String) -> Node:
|
||||||
|
if not node:
|
||||||
|
return null
|
||||||
|
if node.name == n:
|
||||||
|
return node
|
||||||
|
for c in node.get_children():
|
||||||
|
var found = _find_node_by_name(c, n)
|
||||||
|
if found:
|
||||||
|
return found
|
||||||
|
return null
|
||||||
|
|
||||||
# RPC function called by attacker to deal damage to this player
|
# RPC function called by attacker to deal damage to this player
|
||||||
@rpc("any_peer", "reliable")
|
@rpc("any_peer", "reliable")
|
||||||
func rpc_take_damage(amount: float, attacker_position: Vector2, is_burn_damage: bool = false, apply_burn_debuff: bool = false):
|
func rpc_take_damage(amount: float, attacker_position: Vector2, is_burn_damage: bool = false, apply_burn_debuff: bool = false):
|
||||||
@@ -5903,6 +6052,64 @@ func _are_all_players_dead() -> bool:
|
|||||||
return false
|
return false
|
||||||
return true
|
return true
|
||||||
|
|
||||||
|
func _spawn_landing_on_land():
|
||||||
|
if has_node("SfxFallDownLand"):
|
||||||
|
$SfxFallDownLand.play()
|
||||||
|
_set_animation("LAND")
|
||||||
|
var status_anim = get_node_or_null("Sprite2DStatus/AnimationPlayerStatus")
|
||||||
|
if status_anim and status_anim.has_animation("concussion"):
|
||||||
|
status_anim.play("concussion")
|
||||||
|
var gw = get_tree().get_first_node_in_group("game_world")
|
||||||
|
if gw and gw.has_method("add_screenshake"):
|
||||||
|
gw.add_screenshake(7.0, 0.28)
|
||||||
|
if multiplayer.has_multiplayer_peer() and can_send_rpcs and is_inside_tree():
|
||||||
|
_rpc_to_ready_peers("_sync_spawn_landed", [name])
|
||||||
|
get_tree().create_timer(SPAWN_LANDING_LAND_DURATION).timeout.connect(_spawn_landing_to_stand)
|
||||||
|
|
||||||
|
@rpc("any_peer", "reliable")
|
||||||
|
func _sync_spawn_bounced(_player_name: String):
|
||||||
|
spawn_landing_bounced = true
|
||||||
|
current_direction = Direction.RIGHT
|
||||||
|
facing_direction_vector = Vector2.RIGHT
|
||||||
|
_set_animation("LAND")
|
||||||
|
if has_node("SfxFallDownLand"):
|
||||||
|
$SfxFallDownLand.play()
|
||||||
|
|
||||||
|
@rpc("any_peer", "reliable")
|
||||||
|
func _sync_spawn_landed(_player_name: String):
|
||||||
|
# Received on remote copies when authority lands from spawn fall
|
||||||
|
spawn_landing_landed = true
|
||||||
|
position_z = 0.0
|
||||||
|
velocity_z = 0.0
|
||||||
|
is_airborne = false
|
||||||
|
if has_node("SfxFallDownLand"):
|
||||||
|
$SfxFallDownLand.play()
|
||||||
|
_set_animation("LAND")
|
||||||
|
var status_anim = get_node_or_null("Sprite2DStatus/AnimationPlayerStatus")
|
||||||
|
if status_anim and status_anim.has_animation("concussion"):
|
||||||
|
status_anim.play("concussion")
|
||||||
|
get_tree().create_timer(SPAWN_LANDING_LAND_DURATION).timeout.connect(_spawn_landing_to_stand)
|
||||||
|
|
||||||
|
func _spawn_landing_to_stand():
|
||||||
|
if not is_instance_valid(self):
|
||||||
|
return
|
||||||
|
_set_animation("STAND")
|
||||||
|
get_tree().create_timer(SPAWN_LANDING_STAND_DURATION).timeout.connect(_spawn_landing_stand_up)
|
||||||
|
|
||||||
|
func _spawn_landing_stand_up():
|
||||||
|
if not is_instance_valid(self):
|
||||||
|
return
|
||||||
|
# Clear concussion status (was showing during LAND)
|
||||||
|
var status_anim = get_node_or_null("Sprite2DStatus/AnimationPlayerStatus")
|
||||||
|
if status_anim and status_anim.has_animation("idle"):
|
||||||
|
status_anim.play("idle")
|
||||||
|
# STAND's nextAnimation -> IDLE, so we're already IDLE or about to be
|
||||||
|
spawn_landing = false
|
||||||
|
if cone_light:
|
||||||
|
cone_light.visible = true
|
||||||
|
if point_light:
|
||||||
|
point_light.visible = true
|
||||||
|
|
||||||
func _respawn():
|
func _respawn():
|
||||||
print(name, " respawning!")
|
print(name, " respawning!")
|
||||||
was_revived = false
|
was_revived = false
|
||||||
@@ -6542,6 +6749,24 @@ func _show_revive_cost_number(amount: int):
|
|||||||
get_tree().current_scene.add_child(damage_label)
|
get_tree().current_scene.add_child(damage_label)
|
||||||
damage_label.global_position = global_position + Vector2(0, -16)
|
damage_label.global_position = global_position + Vector2(0, -16)
|
||||||
|
|
||||||
|
func show_floating_status(text: String, col: Color = Color.WHITE) -> void:
|
||||||
|
"""Show a damage-number-style floating text above player (e.g. 'Encumbered!')."""
|
||||||
|
var damage_number_scene = preload("res://scenes/damage_number.tscn")
|
||||||
|
if not damage_number_scene:
|
||||||
|
return
|
||||||
|
var lbl = damage_number_scene.instantiate()
|
||||||
|
if not lbl:
|
||||||
|
return
|
||||||
|
lbl.label = text
|
||||||
|
lbl.color = col
|
||||||
|
lbl.z_index = 5
|
||||||
|
lbl.direction = Vector2(0, -1)
|
||||||
|
var game_world = get_tree().get_first_node_in_group("game_world")
|
||||||
|
var parent = game_world.get_node_or_null("Entities") if game_world else get_tree().current_scene
|
||||||
|
if parent:
|
||||||
|
parent.add_child(lbl)
|
||||||
|
lbl.global_position = global_position + Vector2(0, -20)
|
||||||
|
|
||||||
@rpc("any_peer", "reliable")
|
@rpc("any_peer", "reliable")
|
||||||
func _sync_revive_cost(amount: int):
|
func _sync_revive_cost(amount: int):
|
||||||
if is_multiplayer_authority():
|
if is_multiplayer_authority():
|
||||||
@@ -6589,12 +6814,16 @@ func _on_level_up_stats(stats_increased: Array):
|
|||||||
var base_y_offset = -32.0 # Start above player head
|
var base_y_offset = -32.0 # Start above player head
|
||||||
var y_spacing = 12.0 # Space between each text
|
var y_spacing = 12.0 # Space between each text
|
||||||
|
|
||||||
# Show "LEVEL UP!" first (in white)
|
# Show "LEVEL UP +1!" prominently (gold, larger, longer on screen)
|
||||||
var level_up_text = damage_number_scene.instantiate()
|
var level_up_text = damage_number_scene.instantiate()
|
||||||
if level_up_text:
|
if level_up_text:
|
||||||
level_up_text.label = "LEVEL UP!"
|
level_up_text.label = "LEVEL UP +1!"
|
||||||
level_up_text.color = Color.WHITE
|
level_up_text.color = Color(1.0, 0.88, 0.2) # Gold
|
||||||
level_up_text.direction = Vector2(0, -1) # Straight up
|
level_up_text.direction = Vector2(0, -1)
|
||||||
|
level_up_text.rise_distance = 48.0
|
||||||
|
level_up_text.fade_delay = 1.4
|
||||||
|
level_up_text.fade_duration = 0.6
|
||||||
|
level_up_text.add_theme_font_size_override("font_size", 20)
|
||||||
entities_node.add_child(level_up_text)
|
entities_node.add_child(level_up_text)
|
||||||
level_up_text.global_position = global_position + Vector2(0, base_y_offset)
|
level_up_text.global_position = global_position + Vector2(0, base_y_offset)
|
||||||
base_y_offset -= y_spacing
|
base_y_offset -= y_spacing
|
||||||
|
|||||||
Reference in New Issue
Block a user