"""Visual effects: floating damage numbers, attack lines, ink splash.""" import math import random import pygame from card_game.config import INK_BLACK, ZHU_HONG, TENG_HUANG class FloatingText: def __init__(self, x, y, text, color=ZHU_HONG, duration=60): self.x = x self.y = y self.text = text self.color = color self.timer = duration self.max_timer = duration def update(self): self.y -= 0.5 self.timer -= 1 return self.timer > 0 def draw(self, surface, font): alpha = min(255, int(255 * self.timer / self.max_timer)) text_surf = font.render(self.text, True, self.color) alpha_surf = pygame.Surface(text_surf.get_size(), pygame.SRCALPHA) alpha_surf.fill((255, 255, 255, alpha)) text_surf.blit(alpha_surf, (0, 0), special_flags=pygame.BLEND_RGBA_MULT) surface.blit(text_surf, (self.x - text_surf.get_width() // 2, int(self.y))) class AttackLine: def __init__(self, x1, y1, x2, y2, duration=20): self.x1, self.y1 = x1, y1 self.x2, self.y2 = x2, y2 self.timer = duration self.max_timer = duration def update(self): self.timer -= 1 return self.timer > 0 def draw(self, surface): progress = 1 - self.timer / self.max_timer cx = self.x1 + (self.x2 - self.x1) * min(progress * 2, 1) cy = self.y1 + (self.y2 - self.y1) * min(progress * 2, 1) from card_game.ink_style import draw_brush_stroke draw_brush_stroke(surface, (int(self.x1), int(self.y1)), (int(cx), int(cy)), 3, TENG_HUANG, alpha=200) class InkSplash: def __init__(self, x, y, duration=30): self.x = x self.y = y self.timer = duration self.max_timer = duration rng = random.Random(int(x * 100 + y)) self.particles = [] for _ in range(8): angle = rng.uniform(0, 2 * math.pi) speed = rng.uniform(1, 4) size = rng.randint(3, 8) self.particles.append((angle, speed, size)) def update(self): self.timer -= 1 return self.timer > 0 def draw(self, surface): progress = 1 - self.timer / self.max_timer alpha = max(0, int(200 * (1 - progress))) for angle, speed, size in self.particles: dist = speed * progress * 30 px = int(self.x + dist * math.cos(angle)) py = int(self.y + dist * math.sin(angle)) current_size = max(1, int(size * (1 - progress * 0.5))) s = pygame.Surface((current_size * 2, current_size * 2), pygame.SRCALPHA) pygame.draw.circle(s, (*INK_BLACK[:3], alpha), (current_size, current_size), current_size) surface.blit(s, (px - current_size, py - current_size)) class EffectManager: def __init__(self): self.texts = [] self.lines = [] self.splashes = [] def add_damage(self, x, y, amount): self.texts.append(FloatingText(x, y, f"-{amount}", ZHU_HONG)) def add_heal(self, x, y, amount): self.texts.append(FloatingText(x, y, f"+{amount}", (70, 140, 80))) def add_attack_line(self, x1, y1, x2, y2): self.lines.append(AttackLine(x1, y1, x2, y2)) def add_ink_splash(self, x, y): self.splashes.append(InkSplash(x, y)) def update(self): self.texts = [t for t in self.texts if t.update()] self.lines = [l for l in self.lines if l.update()] self.splashes = [s for s in self.splashes if s.update()] def draw(self, surface, font): for line in self.lines: line.draw(surface) for splash in self.splashes: splash.draw(surface) for text in self.texts: text.draw(surface, font)