import enum import sys from abc import ABC from dataclasses import dataclass, field from types import MappingProxyType from typing import List, Iterable, Set, ClassVar, Tuple, Mapping, Callable, Any from ..stardew_rule.protocol import StardewRule if sys.version_info >= (3, 10): kw_only = {"kw_only": True} else: kw_only = {} DEFAULT_REQUIREMENT_TAGS = MappingProxyType({}) @dataclass(frozen=True) class Requirement(ABC): ... class ItemTag(enum.Enum): CROPSANITY_SEED = enum.auto() CROPSANITY = enum.auto() FISH = enum.auto() FRUIT = enum.auto() VEGETABLE = enum.auto() EDIBLE_MUSHROOM = enum.auto() BOOK = enum.auto() BOOK_POWER = enum.auto() BOOK_SKILL = enum.auto() @dataclass(frozen=True) class ItemSource(ABC): add_tags: ClassVar[Tuple[ItemTag]] = () @property def requirement_tags(self) -> Mapping[str, Tuple[ItemTag, ...]]: return DEFAULT_REQUIREMENT_TAGS # FIXME this should just be an optional field, but kw_only requires python 3.10... @property def other_requirements(self) -> Iterable[Requirement]: return () @dataclass(frozen=True, **kw_only) class GenericSource(ItemSource): regions: Tuple[str, ...] = () """No region means it's available everywhere.""" other_requirements: Tuple[Requirement, ...] = () @dataclass(frozen=True) class CustomRuleSource(ItemSource): """Hopefully once everything is migrated to sources, we won't need these custom logic anymore.""" create_rule: Callable[[Any], StardewRule] class Tag(ItemSource): """Not a real source, just a way to add tags to an item. Will be removed from the item sources during unpacking.""" tag: Tuple[ItemTag, ...] def __init__(self, *tag: ItemTag): self.tag = tag # noqa @property def add_tags(self): return self.tag @dataclass(frozen=True) class GameItem: name: str sources: List[ItemSource] = field(default_factory=list) tags: Set[ItemTag] = field(default_factory=set) def add_sources(self, sources: Iterable[ItemSource]): self.sources.extend(source for source in sources if type(source) is not Tag) for source in sources: self.add_tags(source.add_tags) def add_tags(self, tags: Iterable[ItemTag]): self.tags.update(tags)