from __future__ import annotations import random from typing import Dict, Tuple import pygame from config import constants from src.items import Item, random_metal_drop class Asteroid(pygame.sprite.Sprite): """Simple asteroid obstacle with HP and contact damage.""" def __init__(self, variant: str, spawn_pos: Tuple[float, float], speed: float = 120.0, sprite: pygame.Surface | None = None): super().__init__() data: Dict[str, float] = constants.ASTEROID_TYPES[variant] self.variant = variant self.hp = data["hp"] self.damage = data["damage"] self.speed = speed if sprite is None: sprite = pygame.Surface((32, 24), pygame.SRCALPHA) color = (120, 120, 120) if variant == "small" else (140, 110, 110) if variant == "wreck_fragment": color = (90, 90, 130) sprite.fill(color) self.image = sprite self.rect = self.image.get_rect(center=spawn_pos) self.pos = pygame.Vector2(spawn_pos) self.vel = pygame.Vector2(-self.speed, random.uniform(-40, 40)) def update(self, dt: float): self.pos += self.vel * dt self.rect.center = (int(self.pos.x), int(self.pos.y)) def take_damage(self, amount: float): self.hp -= amount def is_dead(self) -> bool: return self.hp <= 0 def drop_loot(self) -> list[Item]: data: Dict[str, float] = constants.ASTEROID_TYPES[self.variant] drop_min, drop_max = data["drop_range"] drops = [] for _ in range(random.randint(drop_min, drop_max)): drops.append(Item(random_metal_drop(), self.rect.center)) return drops def choose_variant() -> str: variants = list(constants.ASTEROID_TYPES.keys()) weights = [constants.ASTEROID_TYPES[v]["spawn_weight"] for v in variants] total = sum(weights) r = random.uniform(0, total) cumulative = 0.0 for variant, w in zip(variants, weights): cumulative += w if r <= cumulative: return variant return variants[-1]