80 lines
2.8 KiB
Python
80 lines
2.8 KiB
Python
"""Heal and flame spells: wrappers that spawn particle effects + damage hits."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from simvx.core import Node2D, Vec2
|
|
|
|
from .particles import ParticleEffect
|
|
|
|
|
|
class FlameProjectile(Node2D):
|
|
"""Linear-flying flame; damages the first enemy whose AABB it overlaps.
|
|
|
|
Self-destructs on hit or after ``lifetime`` seconds.
|
|
"""
|
|
|
|
def __init__(self, position: Vec2, direction: Vec2, frames: list[str], strength: float, **kwargs):
|
|
super().__init__(position=position, **kwargs)
|
|
self.direction = direction
|
|
self.speed = 460.0
|
|
self.strength = strength
|
|
self.lifetime = 0.9
|
|
self._frames = frames
|
|
self._consumed = False
|
|
|
|
def on_ready(self):
|
|
self.add_child(ParticleEffect(self._frames, Vec2(0.0, 0.0), fps=14.0, size=42))
|
|
# Looping flame: re-spawn the effect when it finishes
|
|
self._respawn_timer = 0.18
|
|
|
|
def on_update(self, dt: float):
|
|
if self._consumed:
|
|
return
|
|
self.lifetime -= dt
|
|
if self.lifetime <= 0:
|
|
self.destroy()
|
|
return
|
|
self.position += self.direction * (self.speed * dt)
|
|
# Periodically spawn a new flame puff for the looping effect
|
|
self._respawn_timer -= dt
|
|
if self._respawn_timer <= 0:
|
|
self.add_child(ParticleEffect(self._frames, Vec2(0.0, 0.0), fps=14.0, size=42))
|
|
self._respawn_timer = 0.18
|
|
|
|
def consume(self):
|
|
self._consumed = True
|
|
self.destroy()
|
|
|
|
|
|
class MagicPlayer:
|
|
"""Helper bound to the level: keeps spell logic out of the level body."""
|
|
|
|
def __init__(self, animation_library):
|
|
self._anims = animation_library
|
|
|
|
def heal(self, player, strength: float, cost: int, parent: Node2D) -> None:
|
|
if player.energy < cost:
|
|
return
|
|
if player.hp >= player.max_hp:
|
|
return
|
|
player.energy = max(0.0, player.energy - cost)
|
|
player.hp = min(player.max_hp, player.hp + strength)
|
|
parent.add_child(
|
|
ParticleEffect(self._anims.get("heal"), Vec2(player.position.x, player.position.y - 60), fps=14.0, size=72)
|
|
)
|
|
parent.add_child(
|
|
ParticleEffect(self._anims.get("aura"), Vec2(player.position.x, player.position.y), fps=14.0, size=80)
|
|
)
|
|
|
|
def flame(self, player, strength: float, cost: int, parent: Node2D) -> FlameProjectile | None:
|
|
if player.energy < cost:
|
|
return None
|
|
player.energy = max(0.0, player.energy - cost)
|
|
face = player.facing_vector()
|
|
if face.x == 0 and face.y == 0:
|
|
face = Vec2(0.0, 1.0)
|
|
spawn = Vec2(player.position.x + face.x * 30, player.position.y + face.y * 30)
|
|
proj = FlameProjectile(spawn, face, self._anims.get("flame"), strength)
|
|
parent.add_child(proj)
|
|
return proj
|