import pygame import math from game.config import COLOR_WHITE, COLOR_ORANGE, COLOR_CYAN, COLOR_DARK_GREEN, COLOR_BRIGHT_PURPLE from game.utils import distance class Projectile: def __init__(self, x, y, target, damage, proj_type="arrow", splash=0, slow_factor=0, slow_duration=0, poison_dps=0, poison_duration=0, chain_count=0, chain_range=0, chain_decay=0): self.x = x self.y = y self.target = target self.damage = damage self.proj_type = proj_type self.splash = splash self.slow_factor = slow_factor self.slow_duration = slow_duration self.poison_dps = poison_dps self.poison_duration = poison_duration self.chain_count = chain_count self.chain_range = chain_range self.chain_decay = chain_decay self.speed = 400 self.alive = True def update(self, dt, enemies): if not self.alive: return if not self.target or not self.target.alive: self.alive = False return tx, ty = self.target.x, self.target.y dx = tx - self.x dy = ty - self.y dist = math.hypot(dx, dy) move = self.speed * dt if dist <= move: self._hit(enemies) else: self.x += dx / dist * move self.y += dy / dist * move def _hit(self, enemies): self.alive = False if self.proj_type == "cannon" and self.splash > 0: for e in enemies: if e.alive and distance(self.target.x, self.target.y, e.x, e.y) <= self.splash: e.take_damage(self.damage) else: self.target.take_damage(self.damage) if self.proj_type == "slow" and self.target.alive: self.target.apply_slow(self.slow_factor, self.slow_duration) if self.proj_type == "poison" and self.target.alive: self.target.apply_poison(self.poison_dps, self.poison_duration) if self.proj_type == "lightning" and self.chain_count > 0: self._chain_lightning(enemies, self.target, self.damage, self.chain_count) def _chain_lightning(self, enemies, source, damage, chains_left): if chains_left <= 0: return hit = [self.target, source] current = source current_damage = damage for _ in range(chains_left): current_damage *= self.chain_decay best = None best_dist = self.chain_range for e in enemies: if e.alive and e not in hit: d = distance(current.x, current.y, e.x, e.y) if d < best_dist: best_dist = d best = e if best: best.take_damage(current_damage) hit.append(best) current = best def draw(self, surface): if not self.alive: return ix, iy = int(self.x), int(self.y) if self.proj_type == "arrow": pygame.draw.circle(surface, COLOR_WHITE, (ix, iy), 3) elif self.proj_type == "cannon": pygame.draw.circle(surface, COLOR_ORANGE, (ix, iy), 5) elif self.proj_type == "slow": pygame.draw.circle(surface, COLOR_CYAN, (ix, iy), 4) elif self.proj_type == "sniper": pygame.draw.circle(surface, (150, 180, 255), (ix, iy), 4) pygame.draw.circle(surface, COLOR_WHITE, (ix, iy), 2) elif self.proj_type == "poison": pygame.draw.circle(surface, COLOR_DARK_GREEN, (ix, iy), 5) pygame.draw.circle(surface, (100, 255, 100), (ix, iy), 3) elif self.proj_type == "lightning": pygame.draw.circle(surface, COLOR_BRIGHT_PURPLE, (ix, iy), 5) pygame.draw.circle(surface, (255, 255, 255), (ix, iy), 2)