from dataclasses import dataclass from typing import Iterable, Union, List, Tuple, Hashable from BaseClasses import CollectionState from .base import BaseStardewRule, CombinableStardewRule from .protocol import StardewRule class TotalReceived(BaseStardewRule): count: int items: Iterable[str] player: int def __init__(self, count: int, items: Union[str, Iterable[str]], player: int): items_list: List[str] if isinstance(items, Iterable): items_list = [*items] else: items_list = [items] self.player = player self.items = items_list self.count = count def __call__(self, state: CollectionState) -> bool: c = 0 for item in self.items: c += state.count(item, self.player) if c >= self.count: return True return False def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRule, bool]: return self, self(state) def __repr__(self): return f"Received {self.count} {self.items}" @dataclass(frozen=True) class Received(CombinableStardewRule): item: str player: int count: int event: bool = False """Helps `explain` to know it can dig into a location with the same name.""" @property def combination_key(self) -> Hashable: return self.item @property def value(self): return self.count def __call__(self, state: CollectionState) -> bool: return state.has(self.item, self.player, self.count) def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRule, bool]: return self, self(state) def __repr__(self): if self.count == 1: return f"Received {'event ' if self.event else ''}{self.item}" return f"Received {'event ' if self.event else ''}{self.count} {self.item}" @dataclass(frozen=True) class Reach(BaseStardewRule): spot: str resolution_hint: str player: int def __call__(self, state: CollectionState) -> bool: if self.resolution_hint == 'Region' and self.spot not in state.multiworld.regions.region_cache[self.player]: return False return state.can_reach(self.spot, self.resolution_hint, self.player) def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRule, bool]: return self, self(state) def __repr__(self): return f"Reach {self.resolution_hint} {self.spot}" @dataclass(frozen=True) class HasProgressionPercent(CombinableStardewRule): player: int percent: int def __post_init__(self): assert self.percent > 0, "HasProgressionPercent rule must be above 0%" assert self.percent <= 100, "HasProgressionPercent rule can't require more than 100% of items" @property def combination_key(self) -> Hashable: return HasProgressionPercent.__name__ @property def value(self): return self.percent def __call__(self, state: CollectionState) -> bool: stardew_world = state.multiworld.worlds[self.player] total_count = stardew_world.total_progression_items needed_count = (total_count * self.percent) // 100 player_state = state.prog_items[self.player] if needed_count <= len(player_state): return True total_count = 0 for item, item_count in player_state.items(): total_count += item_count if total_count >= needed_count: return True return False def evaluate_while_simplifying(self, state: CollectionState) -> Tuple[StardewRule, bool]: return self, self(state) def __repr__(self): return f"Received {self.percent}% progression items"