"""In-game state detection for D2R. Detects health/mana, location, enemies, items on ground, etc. """ from typing import Optional, List, Tuple import logging import numpy as np from engine.vision.color import ColorAnalyzer from engine.vision.detector import ElementDetector, Detection from games.d2r.config import D2RConfig logger = logging.getLogger(__name__) class InGameDetector: """Detects in-game state from screen captures.""" def __init__(self, config: D2RConfig): self.config = config self.color = ColorAnalyzer() self.detector = ElementDetector() def is_in_game(self, screen: np.ndarray) -> bool: """Check if we're in an active game (health/mana orbs visible).""" health = self.get_health_percentage(screen) return health > 0 def get_health_percentage(self, screen: np.ndarray) -> float: """Read current health from the health orb.""" return self.color.read_bar_percentage( screen, self.config.regions.health_orb, self.config.colors.health_filled, ) def get_mana_percentage(self, screen: np.ndarray) -> float: """Read current mana from the mana orb.""" return self.color.read_bar_percentage( screen, self.config.regions.mana_orb, self.config.colors.mana_filled, ) def is_dead(self, screen: np.ndarray) -> bool: """Check if character is dead.""" # Health at 0 + death screen elements return self.get_health_percentage(screen) == 0 def should_use_health_potion(self, screen: np.ndarray) -> bool: """Check if health is below potion threshold.""" return self.get_health_percentage(screen) < self.config.health_potion_threshold def should_chicken(self, screen: np.ndarray) -> bool: """Check if health is critically low (exit game).""" return self.get_health_percentage(screen) < self.config.chicken_threshold def find_items_on_ground(self, screen: np.ndarray) -> List[Detection]: """Detect item labels on the ground.""" items = [] if self.config.pickup_uniques: items.extend(self.detector.find_by_color( screen, *self.config.colors.item_unique, min_area=50, label="unique", )) if self.config.pickup_sets: items.extend(self.detector.find_by_color( screen, *self.config.colors.item_set, min_area=50, label="set", )) return items def find_portal(self, screen: np.ndarray) -> Optional[Detection]: """Detect a town portal on screen.""" portals = self.detector.find_by_color( screen, *self.config.colors.portal_blue, min_area=200, label="portal", ) return portals[0] if portals else None def is_inventory_open(self, screen: np.ndarray) -> bool: """Check if the inventory panel is open.""" # TODO: Template match inventory panel return False