diff --git a/scripts/perk_effects.gd b/scripts/perk_effects.gd index f0041a0..b7bcaa8 100644 --- a/scripts/perk_effects.gd +++ b/scripts/perk_effects.gd @@ -102,6 +102,26 @@ func _ready() -> void: ftor.effect = fireball_set_impact_tornado available_perks.append(ftor) + var fsg = Perk.new() + fsg.name = "Fireball: Shotgun" + fsg.description = "Fireball fires a spread of pellets in front of you instead of homing shots" + fsg.stats = _stat_toggle("Shotgun") + fsg.spell = SpellLibrary.FIREBALL + fsg.icon = _icon_fireball + fsg.archetype_slot = "fireball.cast" + fsg.effect = fireball_set_cast_shotgun + available_perks.append(fsg) + + var fmg = Perk.new() + fmg.name = "Fireball: Minigun" + fmg.description = "Fireball rapid-fires at the nearest enemy instead of one burst" + fmg.stats = _stat_toggle("Minigun") + fmg.spell = SpellLibrary.FIREBALL + fmg.icon = _icon_fireball + fmg.archetype_slot = "fireball.cast" + fmg.effect = fireball_set_cast_minigun + available_perks.append(fmg) + var fsp = Perk.new() fsp.name = "Fireball Spread" fsp.description = "Fireballs target more enemies" @@ -189,6 +209,12 @@ func fireball_set_impact_explosion() -> void: func fireball_set_impact_tornado() -> void: set_mode("fireball.impact", "spawn_tornado") +func fireball_set_cast_shotgun() -> void: + set_mode("fireball.cast", "shotgun") + +func fireball_set_cast_minigun() -> void: + set_mode("fireball.cast", "minigun") + func fireball_spread(): witch.fireball_max_targets = witch.fireball_max_targets * 1.5 var fsp = Perk.new() diff --git a/scripts/witch.gd b/scripts/witch.gd index 8c4f914..37e49eb 100644 --- a/scripts/witch.gd +++ b/scripts/witch.gd @@ -4,6 +4,7 @@ signal health_changed(current_hp: int, max_hp: int) signal died(attacker) var camera +@onready var perk_effects = get_node("/root/Game/PerkEffects") var is_casting = false var fireball = preload("res://scenes/fireball.tscn") var shuriken = preload("res://scenes/shuriken.tscn") @@ -19,6 +20,9 @@ var max_hp: int = 50 var current_hp: int = 50 var is_invincible: bool = false var fireball_max_targets: int = 5 +var fireball_pellet_count: int = 6 +var fireball_minigun_shots: int = 6 +var fireball_minigun_interval: float = 0.08 const HP_BAR_WIDTH = 20 const HP_BAR_HEIGHT = 3 @@ -55,6 +59,15 @@ func _on_collect(DropsBase): func shoot_fireballs(): + match perk_effects.get_mode("fireball.cast"): + "shotgun": + await _cast_fireball_shotgun() + "minigun": + await _cast_fireball_minigun() + _: + await _cast_fireball_base() + +func _cast_fireball_base() -> void: var enemies = get_tree().get_nodes_in_group("enemies") enemies = enemies.filter(func(e): return is_instance_valid(e)) enemies.sort_custom(func(a, b): return global_position.distance_to(a.global_position) < global_position.distance_to(b.global_position)) @@ -64,15 +77,46 @@ func shoot_fireballs(): continue var dir = global_position.direction_to(enemy.global_position) _face_direction(dir) - var fb = fireball.instantiate() - fb.global_position = global_position - get_parent().add_child(fb) - fb.launch(enemy.global_position) + _spawn_fireball_toward(enemy.global_position) _play_fire_sfx() camera.shake(0.15, 0.5) await get_tree().create_timer(0.12).timeout $AnimatedSprite2D.play("south") +func _cast_fireball_shotgun() -> void: + var target = get_nearest_enemy(global_position) + var aim_pos = target.global_position if target != null else global_position + Vector2.DOWN * 100.0 + var base_dir = global_position.direction_to(aim_pos) + _face_direction(base_dir) + var spread_deg = 40.0 + for i in range(fireball_pellet_count): + var t = float(i) / float(max(1, fireball_pellet_count - 1)) + var angle_offset = deg_to_rad(lerp(-spread_deg / 2.0, spread_deg / 2.0, t)) + var dir = base_dir.rotated(angle_offset) + _spawn_fireball_toward(global_position + dir * 300.0) + _play_fire_sfx() + camera.shake(0.2, 0.6) + $AnimatedSprite2D.play("south") + +func _cast_fireball_minigun() -> void: + for i in range(fireball_minigun_shots): + var target = get_nearest_enemy(global_position) + if target == null: + break + var dir = global_position.direction_to(target.global_position) + _face_direction(dir) + _spawn_fireball_toward(target.global_position) + _play_fire_sfx() + camera.shake(0.08, 0.3) + await get_tree().create_timer(fireball_minigun_interval).timeout + $AnimatedSprite2D.play("south") + +func _spawn_fireball_toward(target_pos: Vector2) -> void: + var fb = fireball.instantiate() + fb.global_position = global_position + get_parent().add_child(fb) + fb.launch(target_pos) + func _face_direction(dir: Vector2) -> void: if abs(dir.x) >= abs(dir.y): $AnimatedSprite2D.play("east" if dir.x > 0 else "west")