iso-bot/games/d2r/screens/ingame.py

89 lines
3 KiB
Python

"""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