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
|
var last_direction := Vector2.DOWN
|
||||||
signal died
|
signal died
|
||||||
var xp = 1
|
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:
|
func _ready() -> void:
|
||||||
add_to_group("enemies")
|
add_to_group("enemies")
|
||||||
|
|
@ -41,6 +47,8 @@ func _on_base_body_exited(body: Node2D) -> void:
|
||||||
|
|
||||||
func die():
|
func die():
|
||||||
is_dying = true
|
is_dying = true
|
||||||
|
if is_tagged:
|
||||||
|
modulate = Color.WHITE
|
||||||
collision_layer = 0
|
collision_layer = 0
|
||||||
var death_anim: String
|
var death_anim: String
|
||||||
if abs(last_direction.x) >= abs(last_direction.y):
|
if abs(last_direction.x) >= abs(last_direction.y):
|
||||||
|
|
@ -66,6 +74,12 @@ func _play_hit_sound() -> void:
|
||||||
func take_damage(amount: int) -> void:
|
func take_damage(amount: int) -> void:
|
||||||
if is_dying:
|
if is_dying:
|
||||||
return
|
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
|
hp -= amount
|
||||||
if hp <= 0:
|
if hp <= 0:
|
||||||
die()
|
die()
|
||||||
|
|
@ -99,6 +113,11 @@ func _chase_witch() -> void:
|
||||||
if direction != Vector2.ZERO:
|
if direction != Vector2.ZERO:
|
||||||
last_direction = direction
|
last_direction = direction
|
||||||
velocity = direction * speed
|
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:
|
if direction == Vector2.ZERO:
|
||||||
animated_sprite_2d.play("idle")
|
animated_sprite_2d.play("idle")
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
extends ProjectileBase
|
extends ProjectileBase
|
||||||
|
|
||||||
var _is_spread_child := false
|
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 := [
|
const DIRS := [
|
||||||
Vector2(1, 0),
|
Vector2(1, 0),
|
||||||
|
|
@ -17,11 +20,29 @@ func _on_body_entered(body: Node2D) -> void:
|
||||||
if body.is_in_group("enemies"):
|
if body.is_in_group("enemies"):
|
||||||
body.take_damage(damage)
|
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:
|
func _ready() -> void:
|
||||||
damage = 6
|
damage = 6
|
||||||
if _is_spread_child:
|
if _is_spread_child:
|
||||||
super()
|
super()
|
||||||
return
|
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
|
var spawn_pos = global_position
|
||||||
for dir in DIRS:
|
for dir in DIRS:
|
||||||
var bullet = duplicate()
|
var bullet = duplicate()
|
||||||
|
|
@ -29,4 +50,15 @@ func _ready() -> void:
|
||||||
get_parent().add_child(bullet)
|
get_parent().add_child(bullet)
|
||||||
bullet.global_position = spawn_pos
|
bullet.global_position = spawn_pos
|
||||||
bullet.launch(spawn_pos + dir * 1000)
|
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")
|
@onready var perk_effects = get_node("/root/Game/PerkEffects")
|
||||||
|
|
||||||
var beam_seg := preload("res://scenes/beam.tscn")
|
var beam_seg := preload("res://scenes/beam.tscn")
|
||||||
|
var shuriken_scene := preload("res://scenes/shuriken.tscn")
|
||||||
var target: Node2D = null
|
var target: Node2D = null
|
||||||
var all_segs: Array = []
|
var all_segs: Array = []
|
||||||
var mid_segs: Array = []
|
var mid_segs: Array = []
|
||||||
|
|
@ -123,6 +124,10 @@ func retarget(new_target: Node2D) -> void:
|
||||||
func do_damage_tick() -> void:
|
func do_damage_tick() -> void:
|
||||||
if is_instance_valid(target) and not target.is_dying:
|
if is_instance_valid(target) and not target.is_dying:
|
||||||
target.take_damage(PRIMARY_TICK_DMG)
|
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 = []
|
var hit: Array = []
|
||||||
for seg in mid_segs:
|
for seg in mid_segs:
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,11 @@ var cauldron
|
||||||
var available_perks: Array[Perk] = []
|
var available_perks: Array[Perk] = []
|
||||||
var spell_modes: Dictionary = {}
|
var spell_modes: Dictionary = {}
|
||||||
var laser_retarget_enabled = false
|
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_enabled = false
|
||||||
var throwing_knife_cooldown: float = 2.0
|
var throwing_knife_cooldown: float = 2.0
|
||||||
var throwing_knife_count: int = 1
|
var throwing_knife_count: int = 1
|
||||||
|
|
@ -24,6 +29,7 @@ var _spellbooks: Array = []
|
||||||
|
|
||||||
var _icon_knife = preload("res://assets/weapons/knvie.png")
|
var _icon_knife = preload("res://assets/weapons/knvie.png")
|
||||||
var _icon_laser: AtlasTexture
|
var _icon_laser: AtlasTexture
|
||||||
|
var _icon_tornado: AtlasTexture
|
||||||
var _icon_book = preload("res://assets/books_set_2/books_pentagram.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_brew = preload("res://assets/books_set_2/books_health_potion.png")
|
||||||
var _icon_shuriken: AtlasTexture
|
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.atlas = preload("res://assets/Fire Pixel Bullet 16x16/All_Fire_Bullet_Pixel_16x16_05.png")
|
||||||
_icon_laser.region = Rect2(96, 16, 16, 16)
|
_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()
|
var lrt = Perk.new()
|
||||||
lrt.name = "Laser Lock-On"
|
lrt.name = "Laser Lock-On"
|
||||||
lrt.description = "Laser retargets to the next highest health enemy on kill"
|
lrt.description = "Laser retargets to the next highest health enemy on kill"
|
||||||
|
|
@ -197,6 +211,52 @@ func _ready() -> void:
|
||||||
bh.effect = battle_hardened
|
bh.effect = battle_hardened
|
||||||
available_perks.append(bh)
|
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()
|
var ss = Perk.new()
|
||||||
ss.name = "Swift Strike"
|
ss.name = "Swift Strike"
|
||||||
ss.description = "Attack more often"
|
ss.description = "Attack more often"
|
||||||
|
|
@ -221,6 +281,21 @@ func _process(delta: float) -> void:
|
||||||
func laser_retarget():
|
func laser_retarget():
|
||||||
laser_retarget_enabled = true
|
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():
|
func double_shuriken():
|
||||||
witch.shuriken_count += 2
|
witch.shuriken_count += 2
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
extends ProjectileBase
|
extends ProjectileBase
|
||||||
|
|
||||||
var enemies_hit = 0
|
var enemies_hit = 0
|
||||||
|
@onready var perk_effects = get_node("/root/Game/PerkEffects")
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
speed = 500
|
speed = 500
|
||||||
|
|
@ -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:
|
if body.is_in_group("enemies") and not body.is_hurt and not body.is_dying:
|
||||||
enemies_hit += 1
|
enemies_hit += 1
|
||||||
body.take_damage(damage)
|
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:
|
if enemies_hit == 20:
|
||||||
queue_free()
|
queue_free()
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ extends Area2D
|
||||||
@onready var explosion_collision: CollisionShape2D = $ExplosionCollision
|
@onready var explosion_collision: CollisionShape2D = $ExplosionCollision
|
||||||
|
|
||||||
var _is_pulling := true
|
var _is_pulling := true
|
||||||
|
@onready var perk_effects = get_node("/root/Game/PerkEffects")
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
tornado_area.disabled = false
|
tornado_area.disabled = false
|
||||||
|
|
@ -19,6 +20,8 @@ func _ready() -> void:
|
||||||
_explode()
|
_explode()
|
||||||
|
|
||||||
func _physics_process(delta: float) -> void:
|
func _physics_process(delta: float) -> void:
|
||||||
|
if perk_effects.tornado_fruit_collect:
|
||||||
|
_collect_nearby_fruits()
|
||||||
if not _is_pulling:
|
if not _is_pulling:
|
||||||
return
|
return
|
||||||
for enemy in get_overlapping_bodies():
|
for enemy in get_overlapping_bodies():
|
||||||
|
|
@ -28,6 +31,15 @@ func _physics_process(delta: float) -> void:
|
||||||
continue
|
continue
|
||||||
enemy.global_position = enemy.global_position.move_toward(global_position, pull_strength * delta)
|
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:
|
func _explode() -> void:
|
||||||
_is_pulling = false
|
_is_pulling = false
|
||||||
var targets = get_overlapping_bodies().filter(func(b): return b.is_in_group("enemies") and not b.is_dying)
|
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():
|
func shoot_tornado():
|
||||||
StatsManager.on_spell_cast("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 target = get_nearest_enemy(global_position)
|
||||||
var tw = tornado.instantiate()
|
var tw = tornado.instantiate()
|
||||||
tw.global_position = target.global_position if target != null else global_position
|
tw.global_position = target.global_position if target != null else global_position
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue