Compare commits

...

15 Commits

Author SHA1 Message Date
Artur David a2a9ca7f5f Finished Full Purge Spell. Instakills Enemies and damages Elite Enemeies. Spawns with three fruits combined 2026-06-18 10:54:19 +02:00
Artur David f00a0718d2 summon circle fades out over 0.3s after flash 2026-06-18 10:51:41 +02:00
Artur David a106adb0b8 shake fade 2x faster (0.8 -> 0.4), revert flash to 0.6 2026-06-18 10:50:11 +02:00
Artur David 33ed358a8a flash fade 2x faster (0.6 -> 0.3) 2026-06-18 10:49:51 +02:00
Artur David 773c729016 purge: more subtle summon shake (0.5), payoff shake fades alongside flash (0.8s) 2026-06-18 10:48:56 +02:00
Artur David d00afe5772 fix purge shake: smooth Tween-based summon tremble, visible payoff before flash 2026-06-18 10:47:18 +02:00
Artur David 6f529e3ffd purge summon: continuous light jitter during animation, short sharp shake on unleash 2026-06-18 10:42:29 +02:00
Artur David 111cc87df1 fix purge flash persisting on level-up: tween ignores pause 2026-06-18 10:39:35 +02:00
Artur David 19b203de4b Revert "fix camera shake intensities (20x) so shake is actually visible"
This reverts commit 4780d9ae36.
2026-06-18 10:38:15 +02:00
Artur David 341e09d2a9 fix camera shake: use Tween instead of _process, remove rogue Camera2D from worldborder 2026-06-18 10:37:02 +02:00
Artur David 4780d9ae36 fix camera shake intensities (20x) so shake is actually visible 2026-06-18 10:31:00 +02:00
Artur David 376930483a add purge spell scene and effect script 2026-06-18 10:05:04 +02:00
Artur David b98780ae89 route purge recipe to witch.shoot_purge() 2026-06-18 10:05:02 +02:00
Artur David 6c088f3afb add witch.shoot_purge() 2026-06-18 10:05:00 +02:00
Artur David 0b20add24a add purge recipe (apple+grape+chili) 2026-06-18 10:04:59 +02:00
10 changed files with 101 additions and 25 deletions

View File

@ -2352,6 +2352,12 @@ script = ExtResource("1_vtaks")
[node name="Worldborder" parent="." unique_id=985455729 instance=ExtResource("2_dinhu")]
[node name="TileMapLayer(Background)2" parent="." unique_id=1138596890 instance=ExtResource("8_vtaks")]
texture_filter = 1
[node name="TileMapLayer(Overlay)" parent="." unique_id=659138705 instance=ExtResource("10_dinhu")]
texture_filter = 1
[node name="World" type="Node2D" parent="." unique_id=555444333]
y_sort_enabled = true
@ -2373,6 +2379,7 @@ position = Vector2(1, 5)
anchor_mode = 0
zoom = Vector2(2.11, 2.11)
script = ExtResource("3_kvpfn")
current = true
[node name="SpawnControl" type="Control" parent="." unique_id=1780647990]
layout_mode = 3
@ -2381,12 +2388,6 @@ offset_right = 40.0
offset_bottom = 40.0
script = ExtResource("6_p57ef")
[node name="TileMapLayer(Background)2" parent="." unique_id=1138596890 instance=ExtResource("8_vtaks")]
texture_filter = 1
[node name="TileMapLayer(Overlay)" parent="." unique_id=659138705 instance=ExtResource("10_dinhu")]
texture_filter = 1
[node name="DropManager" type="Node2D" parent="." unique_id=1629996711]
script = ExtResource("10_vtaks")

12
scenes/purge.tscn 100644
View File

@ -0,0 +1,12 @@
[gd_scene format=3 uid="uid://cygkgv4jm4kny"]
[ext_resource type="PackedScene" uid="uid://b4g2fudopgct4" path="res://scenes/summon_circle.tscn" id="1_summon"]
[ext_resource type="Script" uid="uid://bromcspk7dk6s" path="res://scripts/purge.gd" id="2_script"]
[node name="Purge" type="Node2D" unique_id=1274298337]
script = ExtResource("2_script")
[node name="SummonCircle" parent="." unique_id=665490341 instance=ExtResource("1_summon")]
z_index = -1
position = Vector2(0, 12)
scale = Vector2(0.2, 0.2)

View File

@ -1,6 +1,5 @@
[gd_scene format=4 uid="uid://7vohdw0xop0g"]
[ext_resource type="Script" uid="uid://coplu13jpw4xq" path="res://scripts/camera_2d.gd" id="1_cdr13"]
[ext_resource type="Texture2D" uid="uid://50fc7a64032e" path="res://assets/tileset/PNG/Water_coasts.png" id="2_eppfv"]
[sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_lvc68"]
@ -773,12 +772,6 @@ sources/0 = SubResource("TileSetAtlasSource_lvc68")
[node name="Worldborder" type="Node2D" unique_id=985455729]
[node name="Camera2D" type="Camera2D" parent="." unique_id=1311217942]
position = Vector2(1, 5)
anchor_mode = 0
zoom = Vector2(2.11, 2.11)
script = ExtResource("1_cdr13")
[node name="TileMapLayer" type="TileMapLayer" parent="." unique_id=1270876518]
tile_map_data = PackedByteArray("AAD//wAAAAAYAA4AAAD//wEAAAAYAA4AAAD//wIAAAAYAA4AAAD//wMAAAAYAA4AAAD//wQAAAAYAA4AAAD//w4AAAAYAA4AAAD//w0AAAAYAA4AAAD//wwAAAAYAA4AAAD//wsAAAAYAA4AAAD//woAAAAYAA4AAAD//wkAAAAYAA4AAAD//wgAAAAYAA4AAAD//wcAAAAYAA4AAAD//wYAAAAYAA4AAAD//wUAAAAYAA4AAAD//w8AAAAYAA4AAAD//xAAAAAYAA4AAAD//xEAAAAYAA4AAAD//xIAAAAYAA4AAAD//xMAAAAYAA4AAAD//xQAAAAYAA4AAAD//xUAAAAYAA4AAAD//xYAAAAYAA4AAAAAABYAAAAYAA4AAAABABYAAAAYAA4AAAACABYAAAAYAA4AAAADABYAAAAYAA4AAAAEABYAAAAYAA4AAAAFABYAAAAYAA4AAAAGABYAAAAYAA4AAAAHABYAAAAYAA4AAAAIABYAAAAYAA4AAAAJABYAAAAYAA4AAAAKABYAAAAYAA4AAAALABYAAAAYAA4AAAAMABYAAAAYAA4AAAANABYAAAAYAA4AAAAOABYAAAAYAA4AAAAPABYAAAAYAA4AAAAQABYAAAAYAA4AAAARABYAAAAYAA4AAAASABYAAAAYAA4AAAATABYAAAAYAA4AAAAUABYAAAAYAA4AAAAVABYAAAAYAA4AAAAWABYAAAAYAA4AAAAXABYAAAAYAA4AAAAYABYAAAAYAA4AAAAZABYAAAAYAA4AAAAaABYAAAAYAA4AAAAbABYAAAAYAA4AAAAcABYAAAAYAA4AAAAdABYAAAAYAA4AAAAeABYAAAAYAA4AAAAfABYAAAAYAA4AAAAgABYAAAAYAA4AAAAhABYAAAAYAA4AAAAiABYAAAAYAA4AAAAjABYAAAAYAA4AAAAkABYAAAAYAA4AAAAlABYAAAAYAA4AAAAmABYAAAAYAA4AAAAmABUAAAAYAA4AAAAmABQAAAAYAA4AAAAmABMAAAAYAA4AAAAmABIAAAAYAA4AAAAmABEAAAAYAA4AAAAmABAAAAAYAA4AAAAmAA8AAAAYAA4AAAAmAA4AAAAYAA4AAAAmAA0AAAAYAA4AAAAmAAwAAAAYAA4AAAAmAAsAAAAYAA4AAAAmAAoAAAAYAA4AAAAmAAkAAAAYAA4AAAAmAAgAAAAYAA4AAAAmAAcAAAAYAA4AAAAmAAYAAAAYAA4AAAAmAAUAAAAYAA4AAAAmAAQAAAAYAA4AAAAmAAMAAAAYAA4AAAAmAAIAAAAYAA4AAAAmAAEAAAAYAA4AAAAmAAAAAAAYAA4AAAAmAP//AAAYAA4AAAAlAP//AAAYAA4AAAAkAP//AAAYAA4AAAAjAP//AAAYAA4AAAAiAP//AAAYAA4AAAAhAP//AAAYAA4AAAAgAP//AAAYAA4AAAAfAP//AAAYAA4AAAAeAP//AAAYAA4AAAAdAP//AAAYAA4AAAAcAP//AAAYAA4AAAAbAP//AAAYAA4AAAAaAP//AAAYAA4AAAAZAP//AAAYAA4AAAAYAP//AAAYAA4AAAAXAP//AAAYAA4AAAAWAP//AAAYAA4AAAAVAP//AAAYAA4AAAAUAP//AAAYAA4AAAATAP//AAAYAA4AAAASAP//AAAYAA4AAAARAP//AAAYAA4AAAAQAP//AAAYAA4AAAAPAP//AAAYAA4AAAAOAP//AAAYAA4AAAANAP//AAAYAA4AAAAMAP//AAAYAA4AAAALAP//AAAYAA4AAAAKAP//AAAYAA4AAAAJAP//AAAYAA4AAAAIAP//AAAYAA4AAAAHAP//AAAYAA4AAAAGAP//AAAYAA4AAAAFAP//AAAYAA4AAAAEAP//AAAYAA4AAAADAP//AAAYAA4AAAACAP//AAAYAA4AAAABAP//AAAYAA4AAAAAAP//AAAYAA4AAAD/////AAAYAA4AAAA=")
tile_set = SubResource("TileSet_jveav")

View File

@ -10,6 +10,7 @@ const FIREBALL = "FIREBALL"
const FIRE_SWIRL = "FIRE_SWIRL"
const TORNADO = "TORNADO"
const LASER = "LASER"
const PURGE = "PURGE"
var recipes: Dictionary = {
FIREBALL: [APPLE],
@ -17,6 +18,7 @@ var recipes: Dictionary = {
LASER: [CHILI],
SHURIKEN: [APPLE, GRAPE],
FIRE_SWIRL: [APPLE, CHILI],
PURGE: [APPLE, GRAPE, CHILI],
}
func identify(cauldron_slots: Array) -> String:

View File

@ -1,16 +1,27 @@
extends Camera2D
var shake_duration = 0.0
var shake_intensity = 5.0
var shake_tween: Tween
func shake(duration: float, intensity: float) -> void:
shake_duration = duration
shake_intensity = intensity
func shake(duration: float, intensity: float, constant: bool = false) -> void:
if shake_tween and shake_tween.is_valid():
shake_tween.kill()
func _process(delta: float) -> void:
if shake_duration > 0:
shake_duration -= delta
offset = Vector2(randf_range(-shake_intensity, shake_intensity),
randf_range(-shake_intensity, shake_intensity))
else:
offset = Vector2.ZERO
offset = Vector2.ZERO
shake_tween = create_tween()
shake_tween.set_pause_mode(Tween.TWEEN_PAUSE_PROCESS)
var step_duration := 0.05
var steps := maxi(1, int(duration / step_duration))
for i in steps:
var t := float(i) / float(steps)
var si := intensity
if not constant:
si *= 1.0 - t
var target := Vector2(
randf_range(-si, si),
randf_range(-si, si)
)
shake_tween.tween_property(self, "offset", target, step_duration)
shake_tween.tween_property(self, "offset", Vector2.ZERO, 0.05)

View File

@ -121,6 +121,7 @@ func brew(fruits):
SpellLibrary.FIRE_SWIRL: witch.shoot_fire_swirl()
SpellLibrary.TORNADO: witch.shoot_tornado()
SpellLibrary.LASER: witch.shoot_laser()
SpellLibrary.PURGE: witch.shoot_purge()
reset_texture()
is_brewing = false
player.flush_queue()

View File

@ -22,6 +22,7 @@ func _ready() -> void:
SpellLibrary.FIRE_SWIRL: _witch.shoot_fire_swirl,
SpellLibrary.TORNADO: _witch.shoot_tornado,
SpellLibrary.LASER: _witch.shoot_laser,
SpellLibrary.PURGE: _witch.shoot_purge,
}
_build_ui()
hide()

48
scripts/purge.gd 100644
View File

@ -0,0 +1,48 @@
extends Node2D
const ELITE_DAMAGE_PCT := 0.75
const FLASH_FADE_DURATION := 0.6
@onready var summon_circle: AnimatedSprite2D = $SummonCircle/AnimatedSprite2D
@onready var camera = get_node("/root/Game/Camera2D")
func _ready() -> void:
summon_circle.sprite_frames = summon_circle.sprite_frames.duplicate()
summon_circle.sprite_frames.set_animation_loop("default", false)
summon_circle.animation_finished.connect(_unleash)
summon_circle.play("default")
camera.shake(6.0, 0.5, true)
func _unleash() -> void:
for enemy in get_tree().get_nodes_in_group("enemies"):
if not is_instance_valid(enemy):
continue
if enemy.scale.x > 1.0:
enemy.take_damage(int(enemy.max_hp * ELITE_DAMAGE_PCT))
else:
enemy.take_damage(enemy.hp)
_flash()
func _flash() -> void:
camera.shake(0.4, 8.0)
var circle_tween = create_tween()
circle_tween.set_pause_mode(Tween.TWEEN_PAUSE_PROCESS)
circle_tween.tween_property(summon_circle, "modulate:a", 0.0, 0.6)
var layer = CanvasLayer.new()
layer.layer = 100
add_child(layer)
var rect = ColorRect.new()
rect.color = Color(1, 1, 1, 1)
rect.set_anchors_preset(Control.PRESET_FULL_RECT)
rect.mouse_filter = Control.MOUSE_FILTER_IGNORE
layer.add_child(rect)
var tween = create_tween()
tween.set_pause_mode(Tween.TWEEN_PAUSE_PROCESS)
tween.tween_property(rect, "color:a", 0.0, FLASH_FADE_DURATION)
await tween.finished
queue_free()

View File

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

View File

@ -10,6 +10,7 @@ var shuriken = preload("res://scenes/shuriken.tscn")
var fire_swirl = preload("res://scenes/fire_swirl.tscn")
var tornado = preload("res://scenes/tornado.tscn")
var laser = preload("res://scenes/laser.tscn")
var purge = preload("res://scenes/purge.tscn")
var shuriken_count = 1
var _fire_sfx = preload("res://assets/music&sfx/sfx/fire.wav")
var _laser_sfx = preload("res://assets/music&sfx/sfx/laser.wav")
@ -119,6 +120,11 @@ func shoot_laser():
get_parent().add_child(asp)
asp.play()
asp.finished.connect(asp.queue_free)
func shoot_purge():
var pg = purge.instantiate()
pg.global_position = global_position
get_parent().add_child(pg)
func take_damage(amount: int, attacker = null) -> void:
if is_invincible: