feat/spellbook #12

Merged
3002102 merged 3 commits from feat/spellbook into main 2026-04-21 17:17:36 +02:00
48 changed files with 898 additions and 36 deletions

BIN
.DS_Store vendored

Binary file not shown.

BIN
assets/.DS_Store vendored

Binary file not shown.

View File

@ -0,0 +1,14 @@
Pixel Art License
Copyright © OceansCurse 2026 — All rights reserved.
You are free to:
- Use these assets in any personal or commercial project (including games, apps, merchandise, etc.).
- Modify, adapt, and create derivative works from these assets.
You are not permitted to:
- Redistribute, resell, or re-upload these assets (or substantial portions/modified versions) as standalone files, asset packs, or listings on itch.io, other marketplaces, or elsewhere.
- Present or claim these assets (original or modified) as your own original creation in a way that removes my authorship.
Attribution is not required, but always appreciated (e.g., "Assets by OceansCurse on itch.io").
These terms do not affect your rights under fair use or other applicable law.

Binary file not shown.

After

Width:  |  Height:  |  Size: 551 B

View File

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://blotgjvb5lg5n"
path="res://.godot/imported/books_blue_gem.png-6b9e1efe847341054172f4dc841820d4.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/books_set_2/books_blue_gem.png"
dest_files=["res://.godot/imported/books_blue_gem.png-6b9e1efe847341054172f4dc841820d4.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

Binary file not shown.

After

Width:  |  Height:  |  Size: 537 B

View File

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://b1dpo1suawep6"
path="res://.godot/imported/books_crimson_gem.png-e8e082c355c0dfd58d6abd9b647c9d64.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/books_set_2/books_crimson_gem.png"
dest_files=["res://.godot/imported/books_crimson_gem.png-e8e082c355c0dfd58d6abd9b647c9d64.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

Binary file not shown.

After

Width:  |  Height:  |  Size: 472 B

View File

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://b0p1bbqie3r44"
path="res://.godot/imported/books_cross.png-35551b7d8d063fdb0725cd59a672b335.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/books_set_2/books_cross.png"
dest_files=["res://.godot/imported/books_cross.png-35551b7d8d063fdb0725cd59a672b335.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

Binary file not shown.

After

Width:  |  Height:  |  Size: 621 B

View File

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://jghgdp2kyjo7"
path="res://.godot/imported/books_eye.png-0b5ed65a09665cddbdbac80092f229ee.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/books_set_2/books_eye.png"
dest_files=["res://.godot/imported/books_eye.png-0b5ed65a09665cddbdbac80092f229ee.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

Binary file not shown.

After

Width:  |  Height:  |  Size: 542 B

View File

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://colq7wi3ti117"
path="res://.godot/imported/books_green_gem.png-1a6532ce505dc88ac93cf48f05352ebe.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/books_set_2/books_green_gem.png"
dest_files=["res://.godot/imported/books_green_gem.png-1a6532ce505dc88ac93cf48f05352ebe.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

Binary file not shown.

After

Width:  |  Height:  |  Size: 583 B

View File

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cq4qf7to1wg0m"
path="res://.godot/imported/books_health_potion.png-f8c3182e75c659e8cd07cbcee2ba8296.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/books_set_2/books_health_potion.png"
dest_files=["res://.godot/imported/books_health_potion.png-f8c3182e75c659e8cd07cbcee2ba8296.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

Binary file not shown.

After

Width:  |  Height:  |  Size: 578 B

View File

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://lo5ocyv4wo3e"
path="res://.godot/imported/books_jewel.png-81cbdb01e058151fa333b7a570f883b8.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/books_set_2/books_jewel.png"
dest_files=["res://.godot/imported/books_jewel.png-81cbdb01e058151fa333b7a570f883b8.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

Binary file not shown.

After

Width:  |  Height:  |  Size: 545 B

View File

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://1pr5rqdnpnw5"
path="res://.godot/imported/books_mana_potion.png-e9b0c98b6782a5538a4f682f9d61384f.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/books_set_2/books_mana_potion.png"
dest_files=["res://.godot/imported/books_mana_potion.png-e9b0c98b6782a5538a4f682f9d61384f.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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dlygc6jakfapg"
path="res://.godot/imported/books_pentagram.png-3e29e3d9c342d860aa7f6d22635f65db.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/books_set_2/books_pentagram.png"
dest_files=["res://.godot/imported/books_pentagram.png-3e29e3d9c342d860aa7f6d22635f65db.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

Binary file not shown.

After

Width:  |  Height:  |  Size: 566 B

View File

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cogqoxfqsnvv1"
path="res://.godot/imported/books_poison.png-3e8beaf0e04a26a46016fddeb0daf0f8.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/books_set_2/books_poison.png"
dest_files=["res://.godot/imported/books_poison.png-3e8beaf0e04a26a46016fddeb0daf0f8.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

Binary file not shown.

After

Width:  |  Height:  |  Size: 548 B

View File

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://ryhfe1a3haxf"
path="res://.godot/imported/books_purple_gem.png-a017fe601493fdc75182a2e7b6cf68cb.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/books_set_2/books_purple_gem.png"
dest_files=["res://.godot/imported/books_purple_gem.png-a017fe601493fdc75182a2e7b6cf68cb.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

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bnlacakjmdnp1"
path="res://.godot/imported/books_set_2_preview.png-e47aaf46da7c1d64191f8dfb0958de3a.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/books_set_2/books_set_2_preview.png"
dest_files=["res://.godot/imported/books_set_2_preview.png-e47aaf46da7c1d64191f8dfb0958de3a.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

Binary file not shown.

After

Width:  |  Height:  |  Size: 458 B

View File

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dm3wtcchfipcf"
path="res://.godot/imported/books_upside_down_cross.png-f374141fa42ba8d66998f6c556ae5908.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/books_set_2/books_upside_down_cross.png"
dest_files=["res://.godot/imported/books_upside_down_cross.png-f374141fa42ba8d66998f6c556ae5908.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

View File

@ -589,7 +589,7 @@ animations = [{
}], }],
"loop": false, "loop": false,
"name": &"hurt_down", "name": &"hurt_down",
"speed": 10.0 "speed": 20.0
}, { }, {
"frames": [{ "frames": [{
"duration": 1.0, "duration": 1.0,
@ -609,7 +609,7 @@ animations = [{
}], }],
"loop": false, "loop": false,
"name": &"hurt_left", "name": &"hurt_left",
"speed": 10.0 "speed": 20.0
}, { }, {
"frames": [{ "frames": [{
"duration": 1.0, "duration": 1.0,
@ -629,7 +629,7 @@ animations = [{
}], }],
"loop": false, "loop": false,
"name": &"hurt_right", "name": &"hurt_right",
"speed": 10.0 "speed": 20.0
}, { }, {
"frames": [{ "frames": [{
"duration": 1.0, "duration": 1.0,
@ -649,7 +649,7 @@ animations = [{
}], }],
"loop": false, "loop": false,
"name": &"hurt_up", "name": &"hurt_up",
"speed": 10.0 "speed": 20.0
}, { }, {
"frames": [{ "frames": [{
"duration": 1.0, "duration": 1.0,

View File

@ -542,9 +542,9 @@ animations = [{
"duration": 1.0, "duration": 1.0,
"texture": SubResource("AtlasTexture_rdhnu") "texture": SubResource("AtlasTexture_rdhnu")
}], }],
"loop": true, "loop": false,
"name": &"hurt_down", "name": &"hurt_down",
"speed": 10.0 "speed": 20.0
}, { }, {
"frames": [{ "frames": [{
"duration": 1.0, "duration": 1.0,
@ -564,7 +564,7 @@ animations = [{
}], }],
"loop": true, "loop": true,
"name": &"hurt_left", "name": &"hurt_left",
"speed": 10.0 "speed": 20.0
}, { }, {
"frames": [{ "frames": [{
"duration": 1.0, "duration": 1.0,
@ -587,7 +587,7 @@ animations = [{
}], }],
"loop": true, "loop": true,
"name": &"hurt_right", "name": &"hurt_right",
"speed": 10.0 "speed": 20.0
}, { }, {
"frames": [{ "frames": [{
"duration": 1.0, "duration": 1.0,
@ -607,7 +607,7 @@ animations = [{
}], }],
"loop": true, "loop": true,
"name": &"hurt_up", "name": &"hurt_up",
"speed": 10.0 "speed": 20.0
}, { }, {
"frames": [{ "frames": [{
"duration": 1.0, "duration": 1.0,
@ -739,7 +739,7 @@ metadata/_custom_type_script = "uid://c0uv02nt5ocvg"
[node name="AnimatedSprite2D" type="AnimatedSprite2D" parent="." unique_id=1151813585] [node name="AnimatedSprite2D" type="AnimatedSprite2D" parent="." unique_id=1151813585]
texture_filter = 1 texture_filter = 1
sprite_frames = SubResource("SpriteFrames_05veu") sprite_frames = SubResource("SpriteFrames_05veu")
animation = &"walk_down" animation = &"hurt_up"
[node name="CollisionShape2D" type="CollisionShape2D" parent="." unique_id=2114857632] [node name="CollisionShape2D" type="CollisionShape2D" parent="." unique_id=2114857632]
position = Vector2(0, 1) position = Vector2(0, 1)

View File

@ -7,6 +7,7 @@
[ext_resource type="Texture2D" uid="uid://cxddvfs2wfwcl" path="res://assets/Slime1/Without_shadow/Slime1_Idle_without_shadow.png" id="3_rrqju"] [ext_resource type="Texture2D" uid="uid://cxddvfs2wfwcl" path="res://assets/Slime1/Without_shadow/Slime1_Idle_without_shadow.png" id="3_rrqju"]
[ext_resource type="Texture2D" uid="uid://b2bmw70co6noy" path="res://assets/Slime1/Without_shadow/Slime1_Walk_without_shadow.png" id="4_wyhst"] [ext_resource type="Texture2D" uid="uid://b2bmw70co6noy" path="res://assets/Slime1/Without_shadow/Slime1_Walk_without_shadow.png" id="4_wyhst"]
[ext_resource type="Texture2D" uid="uid://bshpjl3w1n0y1" path="res://assets/Slime1/With_shadow/Slime1_Death_with_shadow.png" id="5_gstla"] [ext_resource type="Texture2D" uid="uid://bshpjl3w1n0y1" path="res://assets/Slime1/With_shadow/Slime1_Death_with_shadow.png" id="5_gstla"]
[ext_resource type="Texture2D" uid="uid://dwpyocmvqptui" path="res://assets/Slime1/With_shadow/Slime1_Hurt_with_shadow.png" id="7_v5wyi"]
[sub_resource type="Resource" id="Resource_gstla"] [sub_resource type="Resource" id="Resource_gstla"]
script = ExtResource("2_2npkn") script = ExtResource("2_2npkn")
@ -238,6 +239,86 @@ region = Rect2(256, 0, 64, 64)
atlas = ExtResource("3_rrqju") atlas = ExtResource("3_rrqju")
region = Rect2(320, 0, 64, 64) region = Rect2(320, 0, 64, 64)
[sub_resource type="AtlasTexture" id="AtlasTexture_p5vph"]
atlas = ExtResource("7_v5wyi")
region = Rect2(0, 0, 64, 64)
[sub_resource type="AtlasTexture" id="AtlasTexture_4vxow"]
atlas = ExtResource("7_v5wyi")
region = Rect2(64, 0, 64, 64)
[sub_resource type="AtlasTexture" id="AtlasTexture_ymo5x"]
atlas = ExtResource("7_v5wyi")
region = Rect2(128, 0, 64, 64)
[sub_resource type="AtlasTexture" id="AtlasTexture_v338d"]
atlas = ExtResource("7_v5wyi")
region = Rect2(192, 0, 64, 64)
[sub_resource type="AtlasTexture" id="AtlasTexture_vn1yr"]
atlas = ExtResource("7_v5wyi")
region = Rect2(256, 0, 64, 64)
[sub_resource type="AtlasTexture" id="AtlasTexture_il7ig"]
atlas = ExtResource("7_v5wyi")
region = Rect2(0, 128, 64, 64)
[sub_resource type="AtlasTexture" id="AtlasTexture_5baf8"]
atlas = ExtResource("7_v5wyi")
region = Rect2(64, 128, 64, 64)
[sub_resource type="AtlasTexture" id="AtlasTexture_mmuop"]
atlas = ExtResource("7_v5wyi")
region = Rect2(128, 128, 64, 64)
[sub_resource type="AtlasTexture" id="AtlasTexture_7fqim"]
atlas = ExtResource("7_v5wyi")
region = Rect2(192, 128, 64, 64)
[sub_resource type="AtlasTexture" id="AtlasTexture_0ivba"]
atlas = ExtResource("7_v5wyi")
region = Rect2(256, 128, 64, 64)
[sub_resource type="AtlasTexture" id="AtlasTexture_0f1a3"]
atlas = ExtResource("7_v5wyi")
region = Rect2(0, 192, 64, 64)
[sub_resource type="AtlasTexture" id="AtlasTexture_3qxe4"]
atlas = ExtResource("7_v5wyi")
region = Rect2(64, 192, 64, 64)
[sub_resource type="AtlasTexture" id="AtlasTexture_8tsuk"]
atlas = ExtResource("7_v5wyi")
region = Rect2(128, 192, 64, 64)
[sub_resource type="AtlasTexture" id="AtlasTexture_uxjht"]
atlas = ExtResource("7_v5wyi")
region = Rect2(192, 192, 64, 64)
[sub_resource type="AtlasTexture" id="AtlasTexture_72t0a"]
atlas = ExtResource("7_v5wyi")
region = Rect2(256, 192, 64, 64)
[sub_resource type="AtlasTexture" id="AtlasTexture_e0x1h"]
atlas = ExtResource("7_v5wyi")
region = Rect2(0, 64, 64, 64)
[sub_resource type="AtlasTexture" id="AtlasTexture_eodiq"]
atlas = ExtResource("7_v5wyi")
region = Rect2(64, 64, 64, 64)
[sub_resource type="AtlasTexture" id="AtlasTexture_d4gio"]
atlas = ExtResource("7_v5wyi")
region = Rect2(128, 64, 64, 64)
[sub_resource type="AtlasTexture" id="AtlasTexture_q2l3s"]
atlas = ExtResource("7_v5wyi")
region = Rect2(192, 64, 64, 64)
[sub_resource type="AtlasTexture" id="AtlasTexture_3l0w5"]
atlas = ExtResource("7_v5wyi")
region = Rect2(256, 64, 64, 64)
[sub_resource type="AtlasTexture" id="AtlasTexture_fur4c"] [sub_resource type="AtlasTexture" id="AtlasTexture_fur4c"]
atlas = ExtResource("4_wyhst") atlas = ExtResource("4_wyhst")
region = Rect2(0, 0, 64, 64) region = Rect2(0, 0, 64, 64)
@ -568,6 +649,86 @@ animations = [{
}, { }, {
"frames": [{ "frames": [{
"duration": 1.0, "duration": 1.0,
"texture": SubResource("AtlasTexture_p5vph")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_4vxow")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_ymo5x")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_v338d")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_vn1yr")
}],
"loop": true,
"name": &"hurt_down",
"speed": 20.0
}, {
"frames": [{
"duration": 1.0,
"texture": SubResource("AtlasTexture_il7ig")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_5baf8")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_mmuop")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_7fqim")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_0ivba")
}],
"loop": true,
"name": &"hurt_left",
"speed": 20.0
}, {
"frames": [{
"duration": 1.0,
"texture": SubResource("AtlasTexture_0f1a3")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_3qxe4")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_8tsuk")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_uxjht")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_72t0a")
}],
"loop": true,
"name": &"hurt_right",
"speed": 20.0
}, {
"frames": [{
"duration": 1.0,
"texture": SubResource("AtlasTexture_e0x1h")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_eodiq")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_d4gio")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_q2l3s")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_3l0w5")
}],
"loop": true,
"name": &"hurt_up",
"speed": 20.0
}, {
"frames": [{
"duration": 1.0,
"texture": SubResource("AtlasTexture_fur4c") "texture": SubResource("AtlasTexture_fur4c")
}, { }, {
"duration": 1.0, "duration": 1.0,
@ -696,7 +857,7 @@ drop_table = Array[ExtResource("2_2npkn")]([SubResource("Resource_gstla")])
[node name="AnimatedSprite2D" type="AnimatedSprite2D" parent="." unique_id=752118449] [node name="AnimatedSprite2D" type="AnimatedSprite2D" parent="." unique_id=752118449]
texture_filter = 1 texture_filter = 1
sprite_frames = SubResource("SpriteFrames_cbi0b") sprite_frames = SubResource("SpriteFrames_cbi0b")
animation = &"walk_right" animation = &"hurt_up"
[node name="CollisionShape2D" type="CollisionShape2D" parent="." unique_id=769710804] [node name="CollisionShape2D" type="CollisionShape2D" parent="." unique_id=769710804]
position = Vector2(0, 1) position = Vector2(0, 1)

View File

@ -0,0 +1,35 @@
[gd_scene format=3 uid="uid://s5m6whnjl3cv"]
[ext_resource type="Script" uid="uid://c6w6hhayguqoj" path="res://scripts/spellbook.gd" id="1_f8wgx"]
[ext_resource type="Texture2D" uid="uid://dlygc6jakfapg" path="res://assets/books_set_2/books_pentagram.png" id="2_g1ouv"]
[sub_resource type="AtlasTexture" id="AtlasTexture_md3wj"]
atlas = ExtResource("2_g1ouv")
region = Rect2(0, 0, 32, 32)
[sub_resource type="SpriteFrames" id="SpriteFrames_qgan7"]
animations = [{
"frames": [{
"duration": 1.0,
"texture": SubResource("AtlasTexture_md3wj")
}],
"loop": true,
"name": &"default",
"speed": 10.0
}]
[sub_resource type="RectangleShape2D" id="RectangleShape2D_i8red"]
size = Vector2(22.5, 26.5)
[node name="Spellbook" type="Area2D" unique_id=1926827672]
script = ExtResource("1_f8wgx")
[node name="AnimatedSprite2D" type="AnimatedSprite2D" parent="." unique_id=1402601698]
texture_filter = 1
scale = Vector2(0.5, 0.5)
sprite_frames = SubResource("SpriteFrames_qgan7")
[node name="CollisionShape2D" type="CollisionShape2D" parent="." unique_id=609912720]
position = Vector2(-0.625, -0.625)
scale = Vector2(0.5, 0.5)
shape = SubResource("RectangleShape2D_i8red")

View File

@ -2,6 +2,7 @@ extends Area2D
class_name ProjectileBase class_name ProjectileBase
@export var size: float @export var size: float
@export var damage: int = 5
var speed = 200 var speed = 200
@export var element: String @export var element: String
var direction: Vector2 var direction: Vector2
@ -20,7 +21,7 @@ func launch(target: Vector2):
func _on_body_entered(body: Node2D) -> void: func _on_body_entered(body: Node2D) -> void:
if body.is_in_group("enemies"): if body.is_in_group("enemies"):
body.hit() body.take_damage(damage)
queue_free() queue_free()
func _remove(): func _remove():

View File

@ -3,7 +3,8 @@ extends EnemyBase
func _ready() -> void: func _ready() -> void:
super() super()
speed = 15.0 speed = 15.0
hits_remaining = 2 max_hp = 25
hp = max_hp
$Area2D.body_entered.connect(_on_area_2d_body_entered) $Area2D.body_entered.connect(_on_area_2d_body_entered)
func _process(delta: float) -> void: func _process(delta: float) -> void:
@ -14,4 +15,4 @@ func _process(delta: float) -> void:
func _on_area_2d_body_entered(body: Node2D) -> void: func _on_area_2d_body_entered(body: Node2D) -> void:
if body == player: if body == player:
hit() take_damage(player.damage)

View File

@ -6,9 +6,11 @@ extends CharacterBody2D
@export var damage: int = 2 @export var damage: int = 2
@export var max_hp: int = 10
var is_dying = false var is_dying = false
var is_hurt = false var is_hurt = false
var hits_remaining = 1 var hp: int
var _touching_witch: bool = false var _touching_witch: bool = false
var speed var speed
var witch var witch
@ -24,6 +26,7 @@ func _ready() -> void:
witch = get_node("/root/Game/Witch") witch = get_node("/root/Game/Witch")
player = get_node("/root/Game/Player") player = get_node("/root/Game/Player")
animated_sprite_2d.sprite_frames = animated_sprite_2d.sprite_frames.duplicate() animated_sprite_2d.sprite_frames = animated_sprite_2d.sprite_frames.duplicate()
hp = max_hp
$Area2D.body_entered.connect(_on_base_body_entered) $Area2D.body_entered.connect(_on_base_body_entered)
$Area2D.body_exited.connect(_on_base_body_exited) $Area2D.body_exited.connect(_on_base_body_exited)
@ -54,25 +57,30 @@ func die():
await animated_sprite_2d.animation_finished await animated_sprite_2d.animation_finished
queue_free() queue_free()
func hit() -> void: func take_damage(amount: int) -> void:
if is_dying or is_hurt: if is_dying or is_hurt:
return return
hits_remaining -= 1 hp -= amount
if hits_remaining <= 0: if hp <= 0:
die() die()
else: else:
_play_hurt() _play_hurt()
func hit() -> void:
take_damage(1)
func _play_hurt() -> void: func _play_hurt() -> void:
is_hurt = true
var hurt_anim: String var hurt_anim: String
if abs(last_direction.x) >= abs(last_direction.y): if abs(last_direction.x) >= abs(last_direction.y):
hurt_anim = "hurt_left" if last_direction.x < 0 else "hurt_right" hurt_anim = "hurt_left" if last_direction.x < 0 else "hurt_right"
else: else:
hurt_anim = "hurt_up" if last_direction.y < 0 else "hurt_down" hurt_anim = "hurt_up" if last_direction.y < 0 else "hurt_down"
if not animated_sprite_2d.sprite_frames.has_animation(hurt_anim):
return
is_hurt = true
animated_sprite_2d.sprite_frames.set_animation_loop(hurt_anim, false) animated_sprite_2d.sprite_frames.set_animation_loop(hurt_anim, false)
animated_sprite_2d.play(hurt_anim) animated_sprite_2d.play(hurt_anim)
await animated_sprite_2d.animation_finished await get_tree().create_timer(0.25, true).timeout
is_hurt = false is_hurt = false
func _process(delta: float) -> void: func _process(delta: float) -> void:

View File

@ -1,12 +1,12 @@
extends Area2D extends Area2D
@export var damage: int = 15
# Called when the node enters the scene tree for the first time.
func _ready(): func _ready():
await get_tree().physics_frame await get_tree().physics_frame
for body in get_overlapping_bodies(): for body in get_overlapping_bodies():
if body.is_in_group("enemies"): if body.is_in_group("enemies"):
body.hit() body.take_damage(damage)
await $AnimatedSprite2D.animation_finished await $AnimatedSprite2D.animation_finished
queue_free() queue_free()

View File

@ -3,7 +3,8 @@ extends EnemyBase
func _ready() -> void: func _ready() -> void:
super() super()
speed = 15.0 speed = 15.0
hits_remaining = 3 max_hp = 50
hp = max_hp
$Area2D.body_entered.connect(_on_area_2d_body_entered) $Area2D.body_entered.connect(_on_area_2d_body_entered)
func _process(delta: float) -> void: func _process(delta: float) -> void:
@ -14,4 +15,4 @@ func _process(delta: float) -> void:
func _on_area_2d_body_entered(body: Node2D) -> void: func _on_area_2d_body_entered(body: Node2D) -> void:
if body == player: if body == player:
hit() take_damage(player.damage)

View File

@ -15,9 +15,10 @@ const DIRS := [
func _on_body_entered(body: Node2D) -> void: func _on_body_entered(body: Node2D) -> void:
if body.is_in_group("enemies"): if body.is_in_group("enemies"):
body.hit() body.take_damage(damage)
func _ready() -> void: func _ready() -> void:
damage = 6
if _is_spread_child: if _is_spread_child:
super() super()
return return

View File

@ -2,11 +2,16 @@ extends ProjectileBase
var fireball_aoe = false var fireball_aoe = false
var explosion_scene = preload("res://scenes/explosion.tscn") var explosion_scene = preload("res://scenes/explosion.tscn")
@onready var perk_effects = get_node("/root/Game/PerkEffects")# Called when the node enters the scene tree for the first time. @onready var perk_effects = get_node("/root/Game/PerkEffects")
func _ready() -> void:
super()
damage = 8
func _on_body_entered(body: Node2D) -> void: func _on_body_entered(body: Node2D) -> void:
fireball_aoe = perk_effects.fireball_aoe_enabled fireball_aoe = perk_effects.fireball_aoe_enabled
if body.is_in_group("enemies"): if body.is_in_group("enemies"):
body.hit() body.take_damage(damage)
if fireball_aoe: if fireball_aoe:
var boom = explosion_scene.instantiate() var boom = explosion_scene.instantiate()
boom.global_position = global_position boom.global_position = global_position

View File

@ -9,8 +9,17 @@ var available_perks: Array[Perk] = []
var fireball_aoe_enabled = false var fireball_aoe_enabled = false
var throwing_knife_enabled = false var throwing_knife_enabled = false
var throwing_knife_cooldown: float = 2.0 var throwing_knife_cooldown: float = 2.0
var throwing_knife_count: int = 1
var _knife_timer: float = 0.0 var _knife_timer: float = 0.0
var spellbook_scene = preload("res://scenes/spellbook.tscn")
var spellbook_count: int = 0
var spellbook_damage: int = 12
var spellbook_speed: float = 1.5
const SPELLBOOK_RADIUS: float = 60.0
var _spellbook_angle: float = 0.0
var _spellbooks: Array = []
func _ready() -> void: func _ready() -> void:
cauldron = witch.get_node("CauldronBar") cauldron = witch.get_node("CauldronBar")
var dsh = Perk.new() var dsh = Perk.new()
@ -33,6 +42,11 @@ func _ready() -> void:
tk.description = "Automatically throw a knife at the nearest enemy every second" tk.description = "Automatically throw a knife at the nearest enemy every second"
tk.effect = enable_throwing_knife tk.effect = enable_throwing_knife
available_perks.append(tk) available_perks.append(tk)
var sb = Perk.new()
sb.name = "Spellbook"
sb.description = "A spellbook orbits the witch, dealing 12 damage to enemies it touches"
sb.effect = unlock_spellbook
available_perks.append(sb)
func _process(delta: float) -> void: func _process(delta: float) -> void:
if throwing_knife_enabled: if throwing_knife_enabled:
@ -40,6 +54,11 @@ func _process(delta: float) -> void:
if _knife_timer >= throwing_knife_cooldown: if _knife_timer >= throwing_knife_cooldown:
_knife_timer = 0.0 _knife_timer = 0.0
_shoot_throwing_knife() _shoot_throwing_knife()
if spellbook_count > 0:
_spellbook_angle += spellbook_speed * delta
for i in range(_spellbooks.size()):
var offset = (TAU / _spellbooks.size()) * i
_spellbooks[i].global_position = witch.global_position + Vector2(cos(_spellbook_angle + offset), sin(_spellbook_angle + offset)) * SPELLBOOK_RADIUS
func double_shuriken(): func double_shuriken():
witch.shuriken_count = 2 witch.shuriken_count = 2
@ -57,6 +76,20 @@ func enable_throwing_knife():
upg.description = "Reduce throwing knife cooldown by 0.2s (min 1s)" upg.description = "Reduce throwing knife cooldown by 0.2s (min 1s)"
upg.effect = knife_cooldown_upgrade upg.effect = knife_cooldown_upgrade
available_perks.append(upg) available_perks.append(upg)
var ek = Perk.new()
ek.name = "Extra Knife"
ek.description = "Throw one additional knife per attack (max 3)"
ek.effect = extra_knife
available_perks.append(ek)
func extra_knife():
throwing_knife_count = min(throwing_knife_count + 1, 3)
if throwing_knife_count < 3:
var ek = Perk.new()
ek.name = "Extra Knife"
ek.description = "Throw one additional knife per attack (max 3)"
ek.effect = extra_knife
available_perks.append(ek)
func knife_cooldown_upgrade(): func knife_cooldown_upgrade():
throwing_knife_cooldown = maxf(1.0, throwing_knife_cooldown - 0.2) throwing_knife_cooldown = maxf(1.0, throwing_knife_cooldown - 0.2)
@ -68,7 +101,65 @@ func knife_cooldown_upgrade():
available_perks.append(upg) available_perks.append(upg)
func _shoot_throwing_knife() -> void: func _shoot_throwing_knife() -> void:
for i in range(throwing_knife_count):
var knife = throwing_knife.instantiate() var knife = throwing_knife.instantiate()
knife.global_position = witch.global_position knife.global_position = witch.global_position
witch.get_parent().add_child(knife) witch.get_parent().add_child(knife)
func unlock_spellbook() -> void:
spellbook_count = 1
_rebuild_spellbooks()
var eb = Perk.new()
eb.name = "Extra Book"
eb.description = "Add another spellbook (max 5)"
eb.effect = extra_book
available_perks.append(eb)
var fo = Perk.new()
fo.name = "Faster Orbit"
fo.description = "Spellbooks orbit the witch faster"
fo.effect = faster_orbit
available_perks.append(fo)
var bd = Perk.new()
bd.name = "Book Damage"
bd.description = "Spellbooks deal 4 more damage"
bd.effect = book_damage
available_perks.append(bd)
func extra_book() -> void:
spellbook_count = min(spellbook_count + 1, 5)
_rebuild_spellbooks()
if spellbook_count < 5:
var eb = Perk.new()
eb.name = "Extra Book"
eb.description = "Add another spellbook (max 5)"
eb.effect = extra_book
available_perks.append(eb)
func faster_orbit() -> void:
spellbook_speed += 0.5
var fo = Perk.new()
fo.name = "Faster Orbit"
fo.description = "Spellbooks orbit the witch faster"
fo.effect = faster_orbit
available_perks.append(fo)
func book_damage() -> void:
spellbook_damage += 4
for book in _spellbooks:
book.damage = spellbook_damage
var bd = Perk.new()
bd.name = "Book Damage"
bd.description = "Spellbooks deal 4 more damage"
bd.effect = book_damage
available_perks.append(bd)
func _rebuild_spellbooks() -> void:
for book in _spellbooks:
book.queue_free()
_spellbooks.clear()
for i in range(spellbook_count):
var book = spellbook_scene.instantiate()
book.damage = spellbook_damage
witch.get_parent().add_child(book)
_spellbooks.append(book)

View File

@ -1,9 +1,10 @@
extends CharacterBody2D extends CharacterBody2D
@onready var animated_sprite_2d: AnimatedSprite2D = $AnimatedSprite2D @onready var animated_sprite_2d: AnimatedSprite2D = $AnimatedSprite2D
var current_xp = 0 var current_xp = 0
var max_xp =5 var max_xp = 5
var level = 1 var level = 1
var speed = 200 # speed in pixels/sec var speed = 200
var damage: int = 10
func _physics_process(delta): func _physics_process(delta):
var direction = Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down") var direction = Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")

View File

@ -6,6 +6,7 @@ var enemies_hit = 0
func _ready() -> void: func _ready() -> void:
speed = 500 speed = 500
super() super()
damage = 5
var first = get_nearest_enemy(global_position) var first = get_nearest_enemy(global_position)
if first == null: if first == null:
queue_free() queue_free()
@ -15,7 +16,7 @@ func _ready() -> void:
func _on_body_entered(body: Node2D) -> void: func _on_body_entered(body: Node2D) -> void:
if body.is_in_group("enemies") and not body.is_hurt and not body.is_dying: if body.is_in_group("enemies") and not body.is_hurt and not body.is_dying:
enemies_hit += 1 enemies_hit += 1
body.hit() body.take_damage(damage)
if enemies_hit == 20: if enemies_hit == 20:
queue_free() queue_free()
else: else:

View File

@ -3,10 +3,12 @@ extends EnemyBase
func _ready() -> void: func _ready() -> void:
super() super()
speed = 15.0 speed = 15.0
max_hp = 10
hp = max_hp
func _process(delta: float) -> void: func _process(delta: float) -> void:
super._process(delta) super._process(delta)
if is_dying: if is_dying or is_hurt:
return return
_chase_witch() _chase_witch()
@ -14,4 +16,4 @@ func _on_area_2d_body_entered(body: Node2D) -> void:
if is_dying: if is_dying:
return return
if body == player: if body == player:
die() take_damage(player.damage)

View File

@ -0,0 +1,18 @@
extends Area2D
var damage: int = 12
var _hit_cooldowns: Dictionary = {}
func _ready() -> void:
body_entered.connect(_on_body_entered)
func _process(delta: float) -> void:
for enemy in _hit_cooldowns.keys():
_hit_cooldowns[enemy] -= delta
if _hit_cooldowns[enemy] <= 0.0:
_hit_cooldowns.erase(enemy)
func _on_body_entered(body: Node2D) -> void:
if body.is_in_group("enemies") and not _hit_cooldowns.has(body):
body.take_damage(damage)
_hit_cooldowns[body] = 0.8

View File

@ -0,0 +1 @@
uid://c6w6hhayguqoj

View File

@ -5,6 +5,7 @@ var _target_enemy: Node = null
func _ready() -> void: func _ready() -> void:
super() super()
speed = 400.0 speed = 400.0
damage = 12
var witch = get_node("/root/Game/Witch") var witch = get_node("/root/Game/Witch")
_target_enemy = witch.get_nearest_enemy(witch.global_position, _knife_filter) _target_enemy = witch.get_nearest_enemy(witch.global_position, _knife_filter)
if _target_enemy == null: if _target_enemy == null: