Probably juiced the fuck out of this game. Added variois sounds, tweens etc. Also added centralized spelllibrary for future spells. Overhauled Card Perk Design

main
Artur 2026-05-20 19:07:39 +02:00
parent b7a3934daf
commit 320949fcb3
25 changed files with 468 additions and 80 deletions

View File

@ -0,0 +1,19 @@
[remap]
importer="mp3"
type="AudioStreamMP3"
uid="uid://b27862pnesv4a"
path="res://.godot/imported/47313572-experimental-8-bit-sound-270302.mp3-c4341312242ec2d6d5bacb1c4c433fda.mp3str"
[deps]
source_file="res://assets/music&sfx/sfx/47313572-experimental-8-bit-sound-270302.mp3"
dest_files=["res://.godot/imported/47313572-experimental-8-bit-sound-270302.mp3-c4341312242ec2d6d5bacb1c4c433fda.mp3str"]
[params]
loop=false
loop_offset=0.0
bpm=0.0
beat_count=0
bar_beats=4

Binary file not shown.

View File

@ -0,0 +1,24 @@
[remap]
importer="wav"
type="AudioStreamWAV"
uid="uid://3ubacx6k21aq"
path="res://.godot/imported/card_shuffle.wav-2df5de9a976f5727aeeddc7f5f41163e.sample"
[deps]
source_file="res://assets/music&sfx/sfx/card_shuffle.wav"
dest_files=["res://.godot/imported/card_shuffle.wav-2df5de9a976f5727aeeddc7f5f41163e.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

View File

@ -0,0 +1,19 @@
[remap]
importer="mp3"
type="AudioStreamMP3"
uid="uid://o81j4w2j1p16"
path="res://.godot/imported/data_pion-sfx9-fwoosh-324525.mp3-aae109eab17a5ca7e7981c978d3c52e3.mp3str"
[deps]
source_file="res://assets/music&sfx/sfx/data_pion-sfx9-fwoosh-324525.mp3"
dest_files=["res://.godot/imported/data_pion-sfx9-fwoosh-324525.mp3-aae109eab17a5ca7e7981c978d3c52e3.mp3str"]
[params]
loop=false
loop_offset=0.0
bpm=0.0
beat_count=0
bar_beats=4

Binary file not shown.

View File

@ -0,0 +1,24 @@
[remap]
importer="wav"
type="AudioStreamWAV"
uid="uid://buxdyhc4ih63f"
path="res://.godot/imported/fire.wav-a8c495294a82be1272b8f8a56ccb40f5.sample"
[deps]
source_file="res://assets/music&sfx/sfx/fire.wav"
dest_files=["res://.godot/imported/fire.wav-a8c495294a82be1272b8f8a56ccb40f5.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

View File

@ -0,0 +1,19 @@
[remap]
importer="mp3"
type="AudioStreamMP3"
uid="uid://bh8o5pk2cco1a"
path="res://.godot/imported/lesiakower-coin-collect-retro-8-bit-sound-effect-145251.mp3-0a5ea69aced7938e6b9174c8f11f81d9.mp3str"
[deps]
source_file="res://assets/music&sfx/sfx/lesiakower-coin-collect-retro-8-bit-sound-effect-145251.mp3"
dest_files=["res://.godot/imported/lesiakower-coin-collect-retro-8-bit-sound-effect-145251.mp3-0a5ea69aced7938e6b9174c8f11f81d9.mp3str"]
[params]
loop=false
loop_offset=0
bpm=0
beat_count=0
bar_beats=4

View File

@ -0,0 +1,19 @@
[remap]
importer="mp3"
type="AudioStreamMP3"
uid="uid://bjyttcuhiidrq"
path="res://.godot/imported/lesiakower-level-up-enhancement-8-bit-retro-sound-effect-153002.mp3-a2556229ce18ac544b49cfbc2bd40be8.mp3str"
[deps]
source_file="res://assets/music&sfx/sfx/lesiakower-level-up-enhancement-8-bit-retro-sound-effect-153002.mp3"
dest_files=["res://.godot/imported/lesiakower-level-up-enhancement-8-bit-retro-sound-effect-153002.mp3-a2556229ce18ac544b49cfbc2bd40be8.mp3str"]
[params]
loop=false
loop_offset=0.0
bpm=0.0
beat_count=0
bar_beats=4

View File

@ -22,6 +22,7 @@ buses/default_bus_layout="uid://5oswo22yvmtg"
[autoload] [autoload]
MusicManager="*uid://dmu7041wi1upt" MusicManager="*uid://dmu7041wi1upt"
SpellLibrary="*res://scripts/SpellLibrary.gd"
[display] [display]

View File

@ -13,25 +13,30 @@ region = Rect2(561, 17, 46, 62)
[sub_resource type="LabelSettings" id="LabelSettings_qag4p"] [sub_resource type="LabelSettings" id="LabelSettings_qag4p"]
line_spacing = 5.0 line_spacing = 5.0
font = ExtResource("3_n4umd") font = ExtResource("3_n4umd")
font_size = 12 font_size = 16
outline_size = 2
outline_color = Color(0, 0, 0, 1)
[sub_resource type="AtlasTexture" id="AtlasTexture_n4umd"] [sub_resource type="AtlasTexture" id="AtlasTexture_n4umd"]
atlas = ExtResource("4_nlhlf") atlas = ExtResource("4_nlhlf")
region = Rect2(258, 241, 25, 14) region = Rect2(258, 241, 25, 14)
[sub_resource type="LabelSettings" id="LabelSettings_ni87r"] [sub_resource type="LabelSettings" id="LabelSettings_ni87r"]
font = ExtResource("4_40ty6") line_spacing = 6.0
font_size = 11 font = ExtResource("3_n4umd")
font_size = 17
outline_size = 2
outline_color = Color(0, 0, 0, 1)
[node name="PerkCard" type="Control" unique_id=1471811151] [node name="PerkCard" type="Control" unique_id=1471811151]
custom_minimum_size = Vector2(200, 300) custom_minimum_size = Vector2(240, 360)
layout_mode = 3 layout_mode = 3
anchors_preset = 0 anchors_preset = 0
script = ExtResource("1_t8gqh") script = ExtResource("1_t8gqh")
[node name="Card" type="TextureRect" parent="." unique_id=1832247473] [node name="Card" type="TextureRect" parent="." unique_id=1832247473]
texture_filter = 1 texture_filter = 1
custom_minimum_size = Vector2(200, 300) custom_minimum_size = Vector2(240, 360)
layout_mode = 0 layout_mode = 0
offset_right = 40.0 offset_right = 40.0
offset_bottom = 40.0 offset_bottom = 40.0
@ -42,10 +47,10 @@ layout_mode = 1
anchors_preset = 5 anchors_preset = 5
anchor_left = 0.5 anchor_left = 0.5
anchor_right = 0.5 anchor_right = 0.5
offset_left = -50.5 offset_left = -65.0
offset_top = 43.0 offset_top = 43.0
offset_right = 50.5 offset_right = 65.0
offset_bottom = 92.0 offset_bottom = 100.0
grow_horizontal = 2 grow_horizontal = 2
text = "Zweizeilige text = "Zweizeilige
Überschrift Überschrift
@ -54,6 +59,7 @@ label_settings = SubResource("LabelSettings_qag4p")
horizontal_alignment = 1 horizontal_alignment = 1
[node name="TextureRect" type="TextureRect" parent="Card/Name" unique_id=2128840891] [node name="TextureRect" type="TextureRect" parent="Card/Name" unique_id=2128840891]
texture_filter = 1
layout_mode = 1 layout_mode = 1
anchors_preset = 7 anchors_preset = 7
anchor_left = 0.5 anchor_left = 0.5
@ -67,35 +73,33 @@ offset_bottom = 19.0
grow_horizontal = 2 grow_horizontal = 2
grow_vertical = 0 grow_vertical = 0
texture = SubResource("AtlasTexture_n4umd") texture = SubResource("AtlasTexture_n4umd")
stretch_mode = 5
[node name="Description" type="Label" parent="Card" unique_id=859816848] [node name="Description" type="RichTextLabel" parent="Card" unique_id=859816848]
layout_mode = 1 layout_mode = 1
anchors_preset = 7 anchors_preset = 7
anchor_left = 0.5 anchor_left = 0.5
anchor_top = 1.0 anchor_top = 1.0
anchor_right = 0.5 anchor_right = 0.5
anchor_bottom = 1.0 anchor_bottom = 1.0
offset_left = -65.0 offset_left = -100.0
offset_top = -176.0 offset_top = -215.0
offset_right = 69.0 offset_right = 100.0
offset_bottom = -43.0 offset_bottom = -36.0
grow_horizontal = 2 grow_horizontal = 2
grow_vertical = 0 grow_vertical = 0
text = "Text in Zeile Eins theme_override_fonts/normal_font = ExtResource("3_n4umd")
Text in Zeile Eins theme_override_font_sizes/normal_font_size = 17
Text in Zeile Eins theme_override_constants/outline_size = 2
Text in Zeile Eins theme_override_colors/default_color = Color(1, 1, 1, 1)
Text in Zeile Zwei theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
Text in Zeile Drei bbcode_enabled = true
Text in Zeile Vier scroll_active = false
Text in Zeile Fünf" text = ""
label_settings = SubResource("LabelSettings_ni87r")
horizontal_alignment = 1
autowrap_mode = 2
[node name="Button" type="Button" parent="." unique_id=1274377333] [node name="Button" type="Button" parent="." unique_id=1274377333]
layout_mode = 0 layout_mode = 0
offset_right = 200.0 offset_right = 240.0
offset_bottom = 300.0 offset_bottom = 360.0
[connection signal="pressed" from="Button" to="." method="_on_button_pressed"] [connection signal="pressed" from="Button" to="." method="_on_button_pressed"]

View File

@ -39,7 +39,7 @@ animations = [{
}], }],
"loop": true, "loop": true,
"name": &"default", "name": &"default",
"speed": 10.0 "speed": 35.0
}] }]
[node name="Fireball" type="Area2D" unique_id=2100779306] [node name="Fireball" type="Area2D" unique_id=2100779306]

View File

@ -15,9 +15,9 @@
[ext_resource type="Script" uid="uid://pmmc7tivuuo4" path="res://scripts/perk_effects.gd" id="16_ca42v"] [ext_resource type="Script" uid="uid://pmmc7tivuuo4" path="res://scripts/perk_effects.gd" id="16_ca42v"]
[ext_resource type="Script" uid="uid://dm1sntwjrv3vl" path="res://scripts/level_up_manager.gd" id="16_rysoc"] [ext_resource type="Script" uid="uid://dm1sntwjrv3vl" path="res://scripts/level_up_manager.gd" id="16_rysoc"]
[ext_resource type="Texture2D" uid="uid://dp8o40ssuh8ip" path="res://assets/Tiny RPG Mana Soul GUI v1.0/20250421barB-Sheet.png" id="16_ssvqc"] [ext_resource type="Texture2D" uid="uid://dp8o40ssuh8ip" path="res://assets/Tiny RPG Mana Soul GUI v1.0/20250421barB-Sheet.png" id="16_ssvqc"]
[ext_resource type="Script" path="res://scripts/pause_menu.gd" id="18_264po"] [ext_resource type="Script" uid="uid://duauc778wc3hd" path="res://scripts/pause_menu.gd" id="18_264po"]
[ext_resource type="FontFile" uid="uid://8v71dcws4q6o" path="res://assets/fonts/slkscre.ttf" id="19_1kice"] [ext_resource type="FontFile" uid="uid://8v71dcws4q6o" path="res://assets/fonts/slkscre.ttf" id="19_1kice"]
[ext_resource type="Script" path="res://scripts/options_menu_ingame.gd" id="20_1kice"] [ext_resource type="Script" uid="uid://586y330mhx8" path="res://scripts/options_menu_ingame.gd" id="20_1kice"]
[sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_vtaks"] [sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_vtaks"]
texture = ExtResource("7_gee14") texture = ExtResource("7_gee14")

View File

@ -5,14 +5,20 @@ var witch
var player var player
var is_spawning = true var is_spawning = true
signal collected signal collected
# Called when the node enters the scene tree for the first time.
var _collect_sfx = preload("res://assets/music&sfx/sfx/lesiakower-coin-collect-retro-8-bit-sound-effect-145251.mp3")
var _sfx_player: AudioStreamPlayer
func _ready() -> void: func _ready() -> void:
body_entered.connect(_on_body_entered) body_entered.connect(_on_body_entered)
witch = get_node("/root/Game/Witch") witch = get_node("/root/Game/Witch")
collected.connect(witch._on_collect) collected.connect(witch._on_collect)
player = get_node("/root/Game/Player") player = get_node("/root/Game/Player")
_sfx_player = AudioStreamPlayer.new()
_sfx_player.stream = _collect_sfx
_sfx_player.volume_db = -18
add_child(_sfx_player)
_animate_spawn() _animate_spawn()
pass # Replace with function body.
# Called every frame. 'delta' is the elapsed time since the previous frame. # Called every frame. 'delta' is the elapsed time since the previous frame.
@ -43,6 +49,8 @@ func _on_body_entered(body: Node2D) -> void:
pass pass
func collect(): func collect():
_sfx_player.pitch_scale = randf_range(0.85, 1.15)
_sfx_player.play()
is_spawning = true is_spawning = true
var position_drop = create_tween() var position_drop = create_tween()
var target = witch.global_position var target = witch.global_position

View File

@ -3,5 +3,7 @@ class_name Perk
@export var name: String @export var name: String
@export var description: String @export var description: String
@export var stats: String = ""
@export var spell: String = SpellLibrary.NONE
@export var icon: Texture2D = null @export var icon: Texture2D = null
var effect: Callable var effect: Callable

View File

@ -0,0 +1,32 @@
extends Node
const APPLE = 0
const GRAPE = 1
const NONE = "NONE"
const SHURIKEN = "SHURIKEN"
const FIREBALL = "FIREBALL"
const FIRE_SWIRL = "FIRE_SWIRL"
const TORNADO = "TORNADO"
# Each spell's display recipe: sorted apples-first, grapes-last
var recipes: Dictionary = {
SHURIKEN: [APPLE, GRAPE, GRAPE],
FIREBALL: [APPLE, APPLE, APPLE],
FIRE_SWIRL: [APPLE, APPLE, GRAPE],
TORNADO: [GRAPE, GRAPE, GRAPE],
}
# Takes cauldron slot_states (uses texture indices: 2 = apple, 4 = grape)
# and returns which spell that combination brews.
func identify(cauldron_slots: Array) -> String:
var apples = cauldron_slots.count(2)
var grapes = cauldron_slots.count(4)
for spell_id in recipes:
var r: Array = recipes[spell_id]
if r.count(APPLE) == apples and r.count(GRAPE) == grapes:
return spell_id
return NONE
func get_recipe(spell: String) -> Array:
return recipes.get(spell, [])

View File

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

View File

@ -12,8 +12,10 @@ var slot_states = [0, 0, 0]
var progres_index = 0 var progres_index = 0
var is_brewing var is_brewing
var brew_explosion = true var brew_explosion = true
@onready var witch = get_parent() @onready var witch = get_parent()
var explosion_scene = preload("res://scenes/explosion.tscn")# Called when the node enters the scene tree for the first time. var explosion_scene = preload("res://scenes/explosion.tscn")
var _ignite_sfx = preload("res://assets/music&sfx/sfx/data_pion-sfx9-fwoosh-324525.mp3")
var _ignite_player: AudioStreamPlayer# Called when the node enters the scene tree for the first time.
# Called when the node enters the scene tree for the first time. # Called when the node enters the scene tree for the first time.
func _ready() -> void: func _ready() -> void:
@ -31,7 +33,10 @@ func _ready() -> void:
slots = [$Empty1, $Empty2, $Empty3] slots = [$Empty1, $Empty2, $Empty3]
colors = [base, yellow, red, orange, purple] colors = [base, yellow, red, orange, purple]
enrich_burning_colors() enrich_burning_colors()
pass # Replace with function body. _ignite_player = AudioStreamPlayer.new()
_ignite_player.stream = _ignite_sfx
_ignite_player.volume_db = -15
add_child(_ignite_player)
# Called every frame. 'delta' is the elapsed time since the previous frame. # Called every frame. 'delta' is the elapsed time since the previous frame.
@ -51,6 +56,8 @@ func reset_texture():
func ignite_cauldrons(): func ignite_cauldrons():
for i in slots.size(): for i in slots.size():
slots[i].texture = burning_colors[slot_states[i]] slots[i].texture = burning_colors[slot_states[i]]
_ignite_player.pitch_scale = randf_range(0.8, 1.2)
_ignite_player.play()
await get_tree().create_timer(0.4).timeout await get_tree().create_timer(0.4).timeout
if brew_explosion: if brew_explosion:
var boom = explosion_scene.instantiate() var boom = explosion_scene.instantiate()
@ -83,16 +90,11 @@ func progres_bar(fruit):
func brew(fruits): func brew(fruits):
is_brewing = true is_brewing = true
await ignite_cauldrons() await ignite_cauldrons()
var apple_count = fruits.count(2) match SpellLibrary.identify(fruits):
var grape_count = fruits.count(4) SpellLibrary.SHURIKEN: witch.shoot_shuriken()
if apple_count == 2 and grape_count == 1: SpellLibrary.FIREBALL: witch.shoot_fireballs()
witch.shoot_fire_swirl() SpellLibrary.FIRE_SWIRL: witch.shoot_fire_swirl()
elif apple_count == 3: SpellLibrary.TORNADO: witch.shoot_tornado()
witch.shoot_fireballs()
elif grape_count == 3:
witch.shoot_tornado()
elif apple_count == 1 and grape_count == 2:
witch.shoot_shuriken()
reset_texture() reset_texture()
is_brewing = false is_brewing = false

View File

@ -2,21 +2,34 @@ extends Control
@onready var perk_effects = get_node("/root/Game/PerkEffects") @onready var perk_effects = get_node("/root/Game/PerkEffects")
var level_sound = preload("res://assets/music&sfx/sfx/lesiakower-level-up-enhancement-8-bit-retro-sound-effect-153002.mp3")
var select_sound = preload("res://assets/music&sfx/sfx/47313572-experimental-8-bit-sound-270302.mp3")
var card_shuffle_sound = preload("res://assets/music&sfx/sfx/card_shuffle.wav")
var perks var perks
var player = AudioStreamPlayer.new()
var select_player = AudioStreamPlayer.new()
var shuffle_player = AudioStreamPlayer.new()
@onready var perkCard = preload("res://scenes/PerkCard.tscn") @onready var perkCard = preload("res://scenes/PerkCard.tscn")
# Called when the node enters the scene tree for the first time.
func _ready() -> void: func _ready() -> void:
perks = perk_effects.available_perks perks = perk_effects.available_perks
get_node("/root/Game/DropManager").leveled_up.connect(show_perks) get_node("/root/Game/DropManager").leveled_up.connect(show_perks)
pass # Replace with function body. add_child(player)
add_child(select_player)
add_child(shuffle_player)
player.volume_db = -10
select_player.volume_db = -10
shuffle_player.volume_db = -10
select_player.stream = select_sound
shuffle_player.stream = card_shuffle_sound
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void: func _process(delta: float) -> void:
pass pass
func show_perks(): func show_perks():
player.stream = level_sound
player.play()
if perks.is_empty(): if perks.is_empty():
return return
var tween = create_tween() var tween = create_tween()
@ -25,11 +38,14 @@ func show_perks():
var shuffled = perks.duplicate() var shuffled = perks.duplicate()
shuffled.shuffle() shuffled.shuffle()
var chosen = shuffled.slice(0, 3) var chosen = shuffled.slice(0, 3)
await get_tree().create_timer(0.4).timeout
for x in chosen: for x in chosen:
var card = perkCard.instantiate() var card = perkCard.instantiate()
$HBoxContainer.add_child(card) $HBoxContainer.add_child(card)
card.setup(x, func(): select_perk(x)) card.setup(x, func(): select_perk(x), func(): select_player.play())
shuffle_player.play()
await get_tree().create_timer(0.25).timeout
func select_perk(perk): func select_perk(perk):
perk.effect.call() perk.effect.call()

View File

@ -1,42 +1,155 @@
extends Control extends Control
@export var icon: Texture2D @export var icon: Texture2D
# Called when the node enters the scene tree for the first time.
var on_select: Callable var on_select: Callable
var play_sound: Callable
var _recipe_panel: Control = null
var _panel_tween: Tween = null
const _PANEL_REST_Y = 18
const _FRUIT_ATLAS = preload("res://assets/16x16 Pixelart Food Icons/Pixel_Foods(ARTLİNE).png")
const _FONT_BOLD = preload("res://assets/fonts/slkscrb.ttf")
func setup(perk: Perk, select: Callable, sound: Callable):
func setup(perk: Perk, select: Callable): $Button.button_down.connect(_on_button_down)
$Button.modulate.a = 0 $Button.modulate.a = 0
$Card/Name.text = perk.name $Card/Name.text = perk.name
$Card/Description.text = perk.description var content = perk.description
if perk.stats != "":
content += "\n\n" + perk.stats
$Card/Description.text = "[center]" + content + "[/center]"
if perk.icon != null: if perk.icon != null:
$Card/Name/TextureRect.texture = perk.icon $Card/Name/TextureRect.texture = perk.icon
_build_recipe_panel(perk)
animate_in() animate_in()
$Button.modulate.a = 0.3 $Button.mouse_entered.connect(_on_hover_enter)
$Button.mouse_entered.connect(func(): $Button.modulate.a = 0.6) $Button.mouse_exited.connect(_on_hover_exit)
$Button.mouse_exited.connect(func(): $Button.modulate.a = 0.3)
on_select = select on_select = select
play_sound = sound
func _on_button_pressed() -> void: func _build_recipe_panel(perk: Perk) -> void:
var is_brewed = perk.spell != SpellLibrary.NONE
var panel_w := 240
var panel_h := 74 if is_brewed else 38
_recipe_panel = Control.new()
_recipe_panel.position = Vector2(0, _PANEL_REST_Y)
_recipe_panel.size = Vector2(panel_w, panel_h)
_recipe_panel.mouse_filter = Control.MOUSE_FILTER_IGNORE
var border := ColorRect.new()
border.mouse_filter = Control.MOUSE_FILTER_IGNORE
border.color = Color(0.55, 0.4, 0.1, 1.0)
border.size = Vector2(panel_w, panel_h)
_recipe_panel.add_child(border)
var bg := ColorRect.new()
bg.mouse_filter = Control.MOUSE_FILTER_IGNORE
bg.color = Color(0.08, 0.04, 0.14, 0.96)
bg.position = Vector2(2, 2)
bg.size = Vector2(panel_w - 4, panel_h - 4)
_recipe_panel.add_child(bg)
var header := Label.new()
header.mouse_filter = Control.MOUSE_FILTER_IGNORE
header.add_theme_font_override("font", _FONT_BOLD)
header.add_theme_font_size_override("font_size", 13)
header.add_theme_color_override("font_color", Color(0.85, 0.72, 0.45, 1.0))
header.add_theme_constant_override("outline_size", 2)
header.add_theme_color_override("font_outline_color", Color(0, 0, 0, 1))
header.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
header.size = Vector2(panel_w, 22)
if is_brewed:
header.text = "BREW RECIPE"
header.position = Vector2(0, 6)
_recipe_panel.add_child(header)
var hbox := HBoxContainer.new()
hbox.mouse_filter = Control.MOUSE_FILTER_IGNORE
hbox.add_theme_constant_override("separation", 4)
hbox.alignment = BoxContainer.ALIGNMENT_CENTER
hbox.size = Vector2(panel_w, 36)
hbox.position = Vector2(0, 32)
var recipe := SpellLibrary.get_recipe(perk.spell)
for i in recipe.size():
if i > 0:
var plus := Label.new()
plus.mouse_filter = Control.MOUSE_FILTER_IGNORE
plus.text = "+"
plus.add_theme_font_override("font", _FONT_BOLD)
plus.add_theme_font_size_override("font_size", 14)
plus.add_theme_color_override("font_color", Color(1, 1, 1, 0.6))
plus.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
hbox.add_child(plus)
var fruit := TextureRect.new()
fruit.mouse_filter = Control.MOUSE_FILTER_IGNORE
var atlas := AtlasTexture.new()
atlas.atlas = _FRUIT_ATLAS
atlas.region = Rect2(1, 2, 16, 15) if recipe[i] == SpellLibrary.APPLE else Rect2(55, 19, 15, 16)
fruit.texture = atlas
fruit.custom_minimum_size = Vector2(32, 32)
fruit.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
fruit.texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST
hbox.add_child(fruit)
_recipe_panel.add_child(hbox)
else:
header.text = "AUTO / PASSIVE"
header.position = Vector2(0, panel_h / 2 - 11)
_recipe_panel.add_child(header)
add_child(_recipe_panel)
move_child(_recipe_panel, 0)
func _on_hover_enter():
if _panel_tween:
_panel_tween.kill()
_panel_tween = create_tween().set_parallel()
_panel_tween.tween_property(self, "scale", Vector2(0.93, 0.93), 0.1).set_ease(Tween.EASE_OUT).set_trans(Tween.TRANS_QUAD)
_panel_tween.tween_property(_recipe_panel, "position:y", -float(_recipe_panel.size.y), 0.22).set_ease(Tween.EASE_OUT).set_trans(Tween.TRANS_CUBIC)
func _on_hover_exit():
if _panel_tween:
_panel_tween.kill()
_panel_tween = create_tween().set_parallel()
_panel_tween.tween_property(self, "scale", Vector2(1.0, 1.0), 0.1).set_ease(Tween.EASE_OUT).set_trans(Tween.TRANS_QUAD)
_panel_tween.tween_property(_recipe_panel, "position:y", float(_PANEL_REST_Y), 0.15).set_ease(Tween.EASE_IN).set_trans(Tween.TRANS_QUAD)
func _on_button_down() -> void:
if _recipe_panel:
_recipe_panel.visible = false
play_sound.call()
await animate_out() await animate_out()
on_select.call() on_select.call()
pass # Replace with function body.
func animate_in(): func animate_in():
await get_tree().process_frame await get_tree().process_frame
pivot_offset = size / 2
var icon_node = $Card/Name/TextureRect
icon_node.pivot_offset = icon_node.size / 2
var pulse = create_tween().set_loops()
pulse.tween_property(icon_node, "scale", Vector2(1.12, 1.12), 0.9).set_ease(Tween.EASE_IN_OUT).set_trans(Tween.TRANS_SINE)
pulse.tween_property(icon_node, "scale", Vector2(1.0, 1.0), 0.9).set_ease(Tween.EASE_IN_OUT).set_trans(Tween.TRANS_SINE)
var start_y = global_position.y + 500 var start_y = global_position.y + 500
var end_y = global_position.y var end_y = global_position.y
global_position.y = start_y global_position.y = start_y
var tween = create_tween() var tween = create_tween()
tween.tween_property(self, "global_position:y", end_y, 0.3).set_ease(Tween.EASE_OUT).set_trans(Tween.TRANS_QUAD) tween.tween_property(self, "global_position:y", end_y, 0.3).set_ease(Tween.EASE_OUT).set_trans(Tween.TRANS_QUAD)
func animate_out(): func animate_out():
var start_y = global_position.y var start_y = global_position.y
var end_y = global_position.y - 500 var end_y = global_position.y - 500
global_position.y = start_y global_position.y = start_y
var tween = create_tween() var tween = create_tween()
tween.tween_property(self, "global_position:y", end_y, 0.3).set_ease(Tween.EASE_IN).set_trans(Tween.TRANS_QUAD) tween.tween_property(self, "global_position:y", end_y, 0.3).set_ease(Tween.EASE_IN).set_trans(Tween.TRANS_QUAD)
await tween.finished await tween.finished

View File

@ -20,31 +20,74 @@ const SPELLBOOK_RADIUS: float = 60.0
var _spellbook_angle: float = 0.0 var _spellbook_angle: float = 0.0
var _spellbooks: Array = [] var _spellbooks: Array = []
var _icon_knife = preload("res://assets/weapons/knvie.png")
var _icon_book = preload("res://assets/books_set_2/books_pentagram.png")
var _icon_brew = preload("res://assets/books_set_2/books_health_potion.png")
var _icon_shuriken: AtlasTexture
var _icon_fireball: AtlasTexture
func _stat(label: String, from: String, to: String) -> String:
return "[color=#aaaaaa]" + label + "[/color]\n[color=#888888]" + from + "[/color] → [color=#77dd77]" + to + "[/color]"
func _stat_new(label: String, val: String) -> String:
return "[color=#aaaaaa]" + label + "[/color]\n[color=#77dd77]" + val + "[/color]"
func _stat_toggle(label: String) -> String:
return "[color=#aaaaaa]" + label + "[/color]\n[color=#888888]OFF[/color] → [color=#77dd77]ON[/color]"
func _ready() -> void: func _ready() -> void:
cauldron = witch.get_node("CauldronBar") cauldron = witch.get_node("CauldronBar")
_icon_shuriken = AtlasTexture.new()
_icon_shuriken.atlas = preload("res://assets/Fire Pixel Bullet 16x16/All_Fire_Bullet_Pixel_16x16_02.png")
_icon_shuriken.region = Rect2(496, 32, 16, 16)
_icon_fireball = AtlasTexture.new()
_icon_fireball.atlas = preload("res://assets/Fire Pixel Bullet 16x16/All_Fire_Bullet_Pixel_16x16_00.png")
_icon_fireball.region = Rect2(576, 1, 16, 16)
var dsh = Perk.new() var dsh = Perk.new()
dsh.name = "Double Shuriken" dsh.name = "Double Shuriken"
dsh.description = "Throw two shurikens instead of one" dsh.description = "Fire two shurikens at once"
dsh.stats = _stat("Shurikens", "1", "2")
dsh.spell = SpellLibrary.SHURIKEN
dsh.icon = _icon_shuriken
dsh.effect = double_shuriken dsh.effect = double_shuriken
available_perks.append(dsh) available_perks.append(dsh)
var faoe = Perk.new() var faoe = Perk.new()
faoe.name = "AOE Fireball" faoe.name = "AOE Fireball"
faoe.description = "Fireballs spawn an explosion on contact" faoe.description = "Fireballs explode on impact"
faoe.stats = _stat_toggle("AOE")
faoe.spell = SpellLibrary.FIREBALL
faoe.icon = _icon_fireball
faoe.effect = fireball_aoe faoe.effect = fireball_aoe
available_perks.append(faoe) available_perks.append(faoe)
var bexp = Perk.new() var bexp = Perk.new()
bexp.name = "Brew Explosion" bexp.name = "Brew Explosion"
bexp.description = "The Witch casts an explosion on finishing a brew" bexp.description = "Trigger an explosion on brew"
bexp.stats = _stat_toggle("Explosion")
bexp.spell = SpellLibrary.NONE
bexp.icon = _icon_brew
bexp.effect = brew_explosion bexp.effect = brew_explosion
available_perks.append(bexp) available_perks.append(bexp)
var tk = Perk.new() var tk = Perk.new()
tk.name = "Throwing Knife" tk.name = "Throwing Knife"
tk.description = "Automatically throw a knife at the nearest enemy every second" tk.description = "Auto-throw at nearby enemies"
tk.stats = _stat_new("Cooldown", "%.1fs" % throwing_knife_cooldown)
tk.spell = SpellLibrary.NONE
tk.icon = _icon_knife
tk.effect = enable_throwing_knife tk.effect = enable_throwing_knife
available_perks.append(tk) available_perks.append(tk)
var sb = Perk.new() var sb = Perk.new()
sb.name = "Spellbook" sb.name = "Spellbook"
sb.description = "A spellbook orbits the witch, dealing 12 damage to enemies it touches" sb.description = "An orbiting book hits enemies"
sb.stats = "[color=#aaaaaa]Damage Count[/color]\n[color=#77dd77]" + str(spellbook_damage) + " 1[/color]"
sb.spell = SpellLibrary.NONE
sb.icon = _icon_book
sb.effect = unlock_spellbook sb.effect = unlock_spellbook
available_perks.append(sb) available_perks.append(sb)
@ -73,12 +116,16 @@ func enable_throwing_knife():
throwing_knife_enabled = true throwing_knife_enabled = true
var upg = Perk.new() var upg = Perk.new()
upg.name = "Knife Cooldown" upg.name = "Knife Cooldown"
upg.description = "Reduce throwing knife cooldown by 0.2s (min 1s)" upg.description = "Throw knives more often"
upg.stats = _stat("Cooldown", "%.1fs" % throwing_knife_cooldown, "%.1fs" % maxf(1.0, throwing_knife_cooldown - 0.2))
upg.icon = _icon_knife
upg.effect = knife_cooldown_upgrade upg.effect = knife_cooldown_upgrade
available_perks.append(upg) available_perks.append(upg)
var ek = Perk.new() var ek = Perk.new()
ek.name = "Extra Knife" ek.name = "Extra Knife"
ek.description = "Throw one additional knife per attack (max 3)" ek.description = "Throw one more knife"
ek.stats = _stat("Knives", str(throwing_knife_count), str(throwing_knife_count + 1))
ek.icon = _icon_knife
ek.effect = extra_knife ek.effect = extra_knife
available_perks.append(ek) available_perks.append(ek)
@ -87,7 +134,9 @@ func extra_knife():
if throwing_knife_count < 3: if throwing_knife_count < 3:
var ek = Perk.new() var ek = Perk.new()
ek.name = "Extra Knife" ek.name = "Extra Knife"
ek.description = "Throw one additional knife per attack (max 3)" ek.description = "Throw one more knife"
ek.stats = _stat("Knives", str(throwing_knife_count), str(throwing_knife_count + 1))
ek.icon = _icon_knife
ek.effect = extra_knife ek.effect = extra_knife
available_perks.append(ek) available_perks.append(ek)
@ -96,7 +145,9 @@ func knife_cooldown_upgrade():
if throwing_knife_cooldown > 1.0: if throwing_knife_cooldown > 1.0:
var upg = Perk.new() var upg = Perk.new()
upg.name = "Knife Cooldown" upg.name = "Knife Cooldown"
upg.description = "Reduce throwing knife cooldown by 0.2s (min 1s)" upg.description = "Throw knives more often"
upg.stats = _stat("Cooldown", "%.1fs" % throwing_knife_cooldown, "%.1fs" % maxf(1.0, throwing_knife_cooldown - 0.2))
upg.icon = _icon_knife
upg.effect = knife_cooldown_upgrade upg.effect = knife_cooldown_upgrade
available_perks.append(upg) available_perks.append(upg)
@ -111,17 +162,23 @@ func unlock_spellbook() -> void:
_rebuild_spellbooks() _rebuild_spellbooks()
var eb = Perk.new() var eb = Perk.new()
eb.name = "Extra Book" eb.name = "Extra Book"
eb.description = "Add another spellbook (max 5)" eb.description = "Add one more orbiting book"
eb.stats = _stat("Books", str(spellbook_count), str(spellbook_count + 1))
eb.icon = _icon_book
eb.effect = extra_book eb.effect = extra_book
available_perks.append(eb) available_perks.append(eb)
var fo = Perk.new() var fo = Perk.new()
fo.name = "Faster Orbit" fo.name = "Faster Orbit"
fo.description = "Spellbooks orbit the witch faster" fo.description = "Books orbit faster"
fo.stats = _stat("Speed", "%.1f" % spellbook_speed, "%.1f" % (spellbook_speed + 0.5))
fo.icon = _icon_book
fo.effect = faster_orbit fo.effect = faster_orbit
available_perks.append(fo) available_perks.append(fo)
var bd = Perk.new() var bd = Perk.new()
bd.name = "Book Damage" bd.name = "Book Damage"
bd.description = "Spellbooks deal 4 more damage" bd.description = "Books hit harder"
bd.stats = _stat("Damage", str(spellbook_damage), str(spellbook_damage + 4))
bd.icon = _icon_book
bd.effect = book_damage bd.effect = book_damage
available_perks.append(bd) available_perks.append(bd)
@ -131,7 +188,9 @@ func extra_book() -> void:
if spellbook_count < 5: if spellbook_count < 5:
var eb = Perk.new() var eb = Perk.new()
eb.name = "Extra Book" eb.name = "Extra Book"
eb.description = "Add another spellbook (max 5)" eb.description = "Add one more orbiting book"
eb.stats = _stat("Books", str(spellbook_count), str(spellbook_count + 1))
eb.icon = _icon_book
eb.effect = extra_book eb.effect = extra_book
available_perks.append(eb) available_perks.append(eb)
@ -139,7 +198,9 @@ func faster_orbit() -> void:
spellbook_speed += 0.5 spellbook_speed += 0.5
var fo = Perk.new() var fo = Perk.new()
fo.name = "Faster Orbit" fo.name = "Faster Orbit"
fo.description = "Spellbooks orbit the witch faster" fo.description = "Books orbit faster"
fo.stats = _stat("Speed", "%.1f" % spellbook_speed, "%.1f" % (spellbook_speed + 0.5))
fo.icon = _icon_book
fo.effect = faster_orbit fo.effect = faster_orbit
available_perks.append(fo) available_perks.append(fo)
@ -149,7 +210,9 @@ func book_damage() -> void:
book.damage = spellbook_damage book.damage = spellbook_damage
var bd = Perk.new() var bd = Perk.new()
bd.name = "Book Damage" bd.name = "Book Damage"
bd.description = "Spellbooks deal 4 more damage" bd.description = "Books hit harder"
bd.stats = _stat("Damage", str(spellbook_damage), str(spellbook_damage + 4))
bd.icon = _icon_book
bd.effect = book_damage bd.effect = book_damage
available_perks.append(bd) available_perks.append(bd)
@ -162,4 +225,3 @@ func _rebuild_spellbooks() -> void:
book.damage = spellbook_damage book.damage = spellbook_damage
witch.get_parent().add_child(book) witch.get_parent().add_child(book)
_spellbooks.append(book) _spellbooks.append(book)

View File

@ -9,6 +9,7 @@ var shuriken = preload("res://scenes/shuriken.tscn")
var fire_swirl = preload("res://scenes/fire_swirl.tscn") var fire_swirl = preload("res://scenes/fire_swirl.tscn")
var tornado = preload("res://scenes/tornado.tscn") var tornado = preload("res://scenes/tornado.tscn")
var shuriken_count = 1 var shuriken_count = 1
var _fire_sfx = preload("res://assets/music&sfx/sfx/fire.wav")
var max_hp: int = 100 var max_hp: int = 100
var current_hp: int = 100 var current_hp: int = 100
@ -51,11 +52,33 @@ func _on_collect(DropsBase):
func shoot_fireballs(): func shoot_fireballs():
var enemies = get_tree().get_nodes_in_group("enemies") var enemies = get_tree().get_nodes_in_group("enemies")
for enemy in enemies: for enemy in enemies:
if not is_instance_valid(enemy):
continue
var dir = global_position.direction_to(enemy.global_position)
_face_direction(dir)
var fb = fireball.instantiate() var fb = fireball.instantiate()
fb.global_position = global_position fb.global_position = global_position
get_parent().add_child(fb) get_parent().add_child(fb)
fb.launch(enemy.global_position) fb.launch(enemy.global_position)
camera.shake(0.3,0.8) _play_fire_sfx()
camera.shake(0.15, 0.5)
await get_tree().create_timer(0.12).timeout
$AnimatedSprite2D.play("south")
func _face_direction(dir: Vector2) -> void:
if abs(dir.x) >= abs(dir.y):
$AnimatedSprite2D.play("east" if dir.x > 0 else "west")
else:
$AnimatedSprite2D.play("south" if dir.y > 0 else "north")
func _play_fire_sfx() -> void:
var asp = AudioStreamPlayer.new()
asp.stream = _fire_sfx
asp.volume_db = -10
asp.pitch_scale = randf_range(0.9, 1.1)
get_parent().add_child(asp)
asp.play()
asp.finished.connect(asp.queue_free)
func shoot_fire_swirl(): func shoot_fire_swirl():
var fs = fire_swirl.instantiate() var fs = fire_swirl.instantiate()