Compare commits
5 Commits
e13368ab17
...
31b368bc65
| Author | SHA1 | Date |
|---|---|---|
|
|
31b368bc65 | |
|
|
1c54f7f2db | |
|
|
a2646d9690 | |
|
|
4ce2603d40 | |
|
|
7743a9b8d2 |
|
|
@ -20,6 +20,12 @@ var death_sound = preload("res://assets/music&sfx/sfx/hit2.wav")
|
|||
var last_direction := Vector2.DOWN
|
||||
signal died
|
||||
var xp = 1
|
||||
var explosion_scene = preload("res://scenes/explosion.tscn")
|
||||
var is_tagged: bool = false
|
||||
var _push_velocity: Vector2 = Vector2.ZERO
|
||||
|
||||
func apply_push(dir: Vector2, strength: float) -> void:
|
||||
_push_velocity = dir * strength
|
||||
|
||||
func _ready() -> void:
|
||||
add_to_group("enemies")
|
||||
|
|
@ -41,6 +47,8 @@ func _on_base_body_exited(body: Node2D) -> void:
|
|||
|
||||
func die():
|
||||
is_dying = true
|
||||
if is_tagged:
|
||||
modulate = Color.WHITE
|
||||
collision_layer = 0
|
||||
var death_anim: String
|
||||
if abs(last_direction.x) >= abs(last_direction.y):
|
||||
|
|
@ -66,6 +74,12 @@ func _play_hit_sound() -> void:
|
|||
func take_damage(amount: int) -> void:
|
||||
if is_dying:
|
||||
return
|
||||
if is_tagged:
|
||||
is_tagged = false
|
||||
modulate = Color.WHITE
|
||||
var boom = explosion_scene.instantiate()
|
||||
boom.global_position = global_position
|
||||
get_parent().call_deferred("add_child", boom)
|
||||
hp -= amount
|
||||
if hp <= 0:
|
||||
die()
|
||||
|
|
@ -99,6 +113,11 @@ func _chase_witch() -> void:
|
|||
if direction != Vector2.ZERO:
|
||||
last_direction = direction
|
||||
velocity = direction * speed
|
||||
if _push_velocity != Vector2.ZERO:
|
||||
velocity += _push_velocity
|
||||
_push_velocity *= 0.82
|
||||
if _push_velocity.length() < 5.0:
|
||||
_push_velocity = Vector2.ZERO
|
||||
|
||||
if direction == Vector2.ZERO:
|
||||
animated_sprite_2d.play("idle")
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
extends ProjectileBase
|
||||
|
||||
var _is_spread_child := false
|
||||
var _spiral_rotation_rate: float = 0.0
|
||||
var _lifetime: float = 0.0
|
||||
var _max_lifetime: float = 0.0
|
||||
|
||||
const DIRS := [
|
||||
Vector2(1, 0),
|
||||
|
|
@ -17,11 +20,29 @@ func _on_body_entered(body: Node2D) -> void:
|
|||
if body.is_in_group("enemies"):
|
||||
body.take_damage(damage)
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
if _max_lifetime > 0.0:
|
||||
_lifetime += delta
|
||||
if _lifetime >= _max_lifetime:
|
||||
queue_free()
|
||||
return
|
||||
if _spiral_rotation_rate != 0.0:
|
||||
direction = direction.rotated(_spiral_rotation_rate * delta)
|
||||
super(delta)
|
||||
|
||||
func _ready() -> void:
|
||||
damage = 6
|
||||
if _is_spread_child:
|
||||
super()
|
||||
return
|
||||
var perk_effects = get_node("/root/Game/PerkEffects")
|
||||
if perk_effects.get_mode("fire_swirl.cast") == "spiral":
|
||||
_spawn_spiral()
|
||||
else:
|
||||
_spawn_burst()
|
||||
queue_free()
|
||||
|
||||
func _spawn_burst() -> void:
|
||||
var spawn_pos = global_position
|
||||
for dir in DIRS:
|
||||
var bullet = duplicate()
|
||||
|
|
@ -29,4 +50,15 @@ func _ready() -> void:
|
|||
get_parent().add_child(bullet)
|
||||
bullet.global_position = spawn_pos
|
||||
bullet.launch(spawn_pos + dir * 1000)
|
||||
queue_free()
|
||||
|
||||
func _spawn_spiral() -> void:
|
||||
var spawn_pos = global_position
|
||||
for i in range(8):
|
||||
var angle = TAU * float(i) / 8.0
|
||||
var bullet = duplicate()
|
||||
bullet._is_spread_child = true
|
||||
bullet._spiral_rotation_rate = 2.0
|
||||
bullet._max_lifetime = 3.0
|
||||
get_parent().add_child(bullet)
|
||||
bullet.global_position = spawn_pos
|
||||
bullet.launch(spawn_pos + Vector2.from_angle(angle) * 1000)
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ const FADE_OUT := 0.5
|
|||
@onready var perk_effects = get_node("/root/Game/PerkEffects")
|
||||
|
||||
var beam_seg := preload("res://scenes/beam.tscn")
|
||||
var shuriken_scene := preload("res://scenes/shuriken.tscn")
|
||||
var target: Node2D = null
|
||||
var all_segs: Array = []
|
||||
var mid_segs: Array = []
|
||||
|
|
@ -123,6 +124,10 @@ func retarget(new_target: Node2D) -> void:
|
|||
func do_damage_tick() -> void:
|
||||
if is_instance_valid(target) and not target.is_dying:
|
||||
target.take_damage(PRIMARY_TICK_DMG)
|
||||
if perk_effects.laser_shuriken_on_kill and target.is_dying:
|
||||
var sh = shuriken_scene.instantiate()
|
||||
sh.global_position = target.global_position
|
||||
get_parent().add_child(sh)
|
||||
|
||||
var hit: Array = []
|
||||
for seg in mid_segs:
|
||||
|
|
|
|||
|
|
@ -8,6 +8,11 @@ var cauldron
|
|||
var available_perks: Array[Perk] = []
|
||||
var spell_modes: Dictionary = {}
|
||||
var laser_retarget_enabled = false
|
||||
var shuriken_tag_enabled = false
|
||||
var tornado_push_on_cast = false
|
||||
var tornado_fruit_collect = false
|
||||
var laser_shuriken_on_kill = false
|
||||
var _icon_fire_swirl: AtlasTexture
|
||||
var throwing_knife_enabled = false
|
||||
var throwing_knife_cooldown: float = 2.0
|
||||
var throwing_knife_count: int = 1
|
||||
|
|
@ -24,6 +29,7 @@ var _spellbooks: Array = []
|
|||
|
||||
var _icon_knife = preload("res://assets/weapons/knvie.png")
|
||||
var _icon_laser: AtlasTexture
|
||||
var _icon_tornado: AtlasTexture
|
||||
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
|
||||
|
|
@ -64,6 +70,14 @@ func _ready() -> void:
|
|||
_icon_laser.atlas = preload("res://assets/Fire Pixel Bullet 16x16/All_Fire_Bullet_Pixel_16x16_05.png")
|
||||
_icon_laser.region = Rect2(96, 16, 16, 16)
|
||||
|
||||
_icon_tornado = AtlasTexture.new()
|
||||
_icon_tornado.atlas = preload("res://assets/Free Effect Bullet Impact Explosion 32x32 V1/Purple Effect Bullet Impact Explosion 32x32.png")
|
||||
_icon_tornado.region = Rect2(192, 0, 32, 32)
|
||||
|
||||
_icon_fire_swirl = AtlasTexture.new()
|
||||
_icon_fire_swirl.atlas = preload("res://assets/Free Effect Bullet Impact Explosion 32x32 V1/Red Effect Bullet Impact Explosion 32x32.png")
|
||||
_icon_fire_swirl.region = Rect2(352, 64, 32, 32)
|
||||
|
||||
var lrt = Perk.new()
|
||||
lrt.name = "Laser Lock-On"
|
||||
lrt.description = "Laser retargets to the next highest health enemy on kill"
|
||||
|
|
@ -197,6 +211,52 @@ func _ready() -> void:
|
|||
bh.effect = battle_hardened
|
||||
available_perks.append(bh)
|
||||
|
||||
var rp = Perk.new()
|
||||
rp.name = "Reaper's Pull"
|
||||
rp.description = "Tornado continuously collects nearby fruits for its entire lifetime"
|
||||
rp.stats = _stat_toggle("Auto-Collect")
|
||||
rp.spell = SpellLibrary.TORNADO
|
||||
rp.icon = _icon_tornado
|
||||
rp.effect = enable_tornado_fruit_collect
|
||||
available_perks.append(rp)
|
||||
|
||||
var rw = Perk.new()
|
||||
rw.name = "Repulsion Wave"
|
||||
rw.description = "Casting Tornado blasts all enemies away from the witch"
|
||||
rw.stats = _stat_toggle("Push on Cast")
|
||||
rw.spell = SpellLibrary.TORNADO
|
||||
rw.icon = _icon_tornado
|
||||
rw.effect = enable_tornado_push
|
||||
available_perks.append(rw)
|
||||
|
||||
var ssp = Perk.new()
|
||||
ssp.name = "Spiral Swirl"
|
||||
ssp.description = "Fire Swirl fires all 8 swirls simultaneously in a rotating spiral pattern"
|
||||
ssp.stats = _stat_toggle("Spiral")
|
||||
ssp.spell = SpellLibrary.FIRE_SWIRL
|
||||
ssp.archetype_slot = "fire_swirl.cast"
|
||||
ssp.icon = _icon_fire_swirl
|
||||
ssp.effect = enable_fire_swirl_spiral
|
||||
available_perks.append(ssp)
|
||||
|
||||
var lsk = Perk.new()
|
||||
lsk.name = "Chain Kill"
|
||||
lsk.description = "Laser spawns a free Shuriken at every enemy it kills"
|
||||
lsk.stats = _stat_toggle("Shuriken on Kill")
|
||||
lsk.spell = SpellLibrary.LASER
|
||||
lsk.icon = _icon_laser
|
||||
lsk.effect = enable_laser_shuriken_on_kill
|
||||
available_perks.append(lsk)
|
||||
|
||||
var mp = Perk.new()
|
||||
mp.name = "Marked Prey"
|
||||
mp.description = "Shuriken marks enemies. The next spell that hits them triggers an extra explosion"
|
||||
mp.stats = _stat_toggle("Mark on Hit")
|
||||
mp.spell = SpellLibrary.SHURIKEN
|
||||
mp.icon = _icon_shuriken
|
||||
mp.effect = enable_marked_prey
|
||||
available_perks.append(mp)
|
||||
|
||||
var ss = Perk.new()
|
||||
ss.name = "Swift Strike"
|
||||
ss.description = "Attack more often"
|
||||
|
|
@ -221,6 +281,21 @@ func _process(delta: float) -> void:
|
|||
func laser_retarget():
|
||||
laser_retarget_enabled = true
|
||||
|
||||
func enable_marked_prey() -> void:
|
||||
shuriken_tag_enabled = true
|
||||
|
||||
func enable_tornado_push() -> void:
|
||||
tornado_push_on_cast = true
|
||||
|
||||
func enable_tornado_fruit_collect() -> void:
|
||||
tornado_fruit_collect = true
|
||||
|
||||
func enable_laser_shuriken_on_kill() -> void:
|
||||
laser_shuriken_on_kill = true
|
||||
|
||||
func enable_fire_swirl_spiral() -> void:
|
||||
set_mode("fire_swirl.cast", "spiral")
|
||||
|
||||
func double_shuriken():
|
||||
witch.shuriken_count += 2
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
extends ProjectileBase
|
||||
|
||||
var enemies_hit = 0
|
||||
@onready var perk_effects = get_node("/root/Game/PerkEffects")
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
speed = 500
|
||||
super()
|
||||
|
|
@ -17,6 +17,9 @@ func _on_body_entered(body: Node2D) -> void:
|
|||
if body.is_in_group("enemies") and not body.is_hurt and not body.is_dying:
|
||||
enemies_hit += 1
|
||||
body.take_damage(damage)
|
||||
if perk_effects.shuriken_tag_enabled and not body.is_dying:
|
||||
body.is_tagged = true
|
||||
body.modulate = Color(1.0, 1.0, 0.45)
|
||||
if enemies_hit == 20:
|
||||
queue_free()
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ extends Area2D
|
|||
@onready var explosion_collision: CollisionShape2D = $ExplosionCollision
|
||||
|
||||
var _is_pulling := true
|
||||
@onready var perk_effects = get_node("/root/Game/PerkEffects")
|
||||
|
||||
func _ready() -> void:
|
||||
tornado_area.disabled = false
|
||||
|
|
@ -19,6 +20,8 @@ func _ready() -> void:
|
|||
_explode()
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
if perk_effects.tornado_fruit_collect:
|
||||
_collect_nearby_fruits()
|
||||
if not _is_pulling:
|
||||
return
|
||||
for enemy in get_overlapping_bodies():
|
||||
|
|
@ -28,6 +31,15 @@ func _physics_process(delta: float) -> void:
|
|||
continue
|
||||
enemy.global_position = enemy.global_position.move_toward(global_position, pull_strength * delta)
|
||||
|
||||
func _collect_nearby_fruits() -> void:
|
||||
var drop_manager = get_node_or_null("/root/Game/DropManager")
|
||||
if drop_manager == null:
|
||||
return
|
||||
for child in drop_manager.get_children():
|
||||
if child is DropsBase and not child.is_spawning and not child.in_orbit:
|
||||
if global_position.distance_to(child.global_position) < 120.0:
|
||||
child.collect()
|
||||
|
||||
func _explode() -> void:
|
||||
_is_pulling = false
|
||||
var targets = get_overlapping_bodies().filter(func(b): return b.is_in_group("enemies") and not b.is_dying)
|
||||
|
|
|
|||
|
|
@ -150,6 +150,11 @@ func shoot_shuriken():
|
|||
|
||||
func shoot_tornado():
|
||||
StatsManager.on_spell_cast("tornado")
|
||||
if perk_effects.tornado_push_on_cast:
|
||||
for enemy in get_tree().get_nodes_in_group("enemies"):
|
||||
if is_instance_valid(enemy) and not enemy.is_dying:
|
||||
var push_dir = global_position.direction_to(enemy.global_position)
|
||||
enemy.apply_push(push_dir, 500.0)
|
||||
var target = get_nearest_enemy(global_position)
|
||||
var tw = tornado.instantiate()
|
||||
tw.global_position = target.global_position if target != null else global_position
|
||||
|
|
|
|||
Loading…
Reference in New Issue