144 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
		
		
			
		
	
	
			144 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
|   | import csv | ||
|  | import enum | ||
|  | from dataclasses import dataclass, field | ||
|  | from functools import reduce | ||
|  | from pathlib import Path | ||
|  | from typing import Dict, List, Protocol, Union, Set, Optional | ||
|  | 
 | ||
|  | from BaseClasses import Item, ItemClassification | ||
|  | from .. import data | ||
|  | from ..logic.logic_event import all_events | ||
|  | 
 | ||
|  | ITEM_CODE_OFFSET = 717000 | ||
|  | 
 | ||
|  | world_folder = Path(__file__).parent | ||
|  | 
 | ||
|  | 
 | ||
|  | class Group(enum.Enum): | ||
|  |     RESOURCE_PACK = enum.auto() | ||
|  |     FRIENDSHIP_PACK = enum.auto() | ||
|  |     COMMUNITY_REWARD = enum.auto() | ||
|  |     TRASH = enum.auto() | ||
|  |     FOOTWEAR = enum.auto() | ||
|  |     HATS = enum.auto() | ||
|  |     RING = enum.auto() | ||
|  |     WEAPON = enum.auto() | ||
|  |     WEAPON_GENERIC = enum.auto() | ||
|  |     WEAPON_SWORD = enum.auto() | ||
|  |     WEAPON_CLUB = enum.auto() | ||
|  |     WEAPON_DAGGER = enum.auto() | ||
|  |     WEAPON_SLINGSHOT = enum.auto() | ||
|  |     PROGRESSIVE_TOOLS = enum.auto() | ||
|  |     SKILL_LEVEL_UP = enum.auto() | ||
|  |     SKILL_MASTERY = enum.auto() | ||
|  |     BUILDING = enum.auto() | ||
|  |     WIZARD_BUILDING = enum.auto() | ||
|  |     ARCADE_MACHINE_BUFFS = enum.auto() | ||
|  |     BASE_RESOURCE = enum.auto() | ||
|  |     WARP_TOTEM = enum.auto() | ||
|  |     GEODE = enum.auto() | ||
|  |     ORE = enum.auto() | ||
|  |     FERTILIZER = enum.auto() | ||
|  |     SEED = enum.auto() | ||
|  |     CROPSANITY = enum.auto() | ||
|  |     FISHING_RESOURCE = enum.auto() | ||
|  |     SEASON = enum.auto() | ||
|  |     TRAVELING_MERCHANT_DAY = enum.auto() | ||
|  |     MUSEUM = enum.auto() | ||
|  |     FRIENDSANITY = enum.auto() | ||
|  |     FESTIVAL = enum.auto() | ||
|  |     RARECROW = enum.auto() | ||
|  |     TRAP = enum.auto() | ||
|  |     BONUS = enum.auto() | ||
|  |     MAXIMUM_ONE = enum.auto() | ||
|  |     AT_LEAST_TWO = enum.auto() | ||
|  |     DEPRECATED = enum.auto() | ||
|  |     RESOURCE_PACK_USEFUL = enum.auto() | ||
|  |     SPECIAL_ORDER_BOARD = enum.auto() | ||
|  |     SPECIAL_ORDER_QI = enum.auto() | ||
|  |     BABY = enum.auto() | ||
|  |     GINGER_ISLAND = enum.auto() | ||
|  |     WALNUT_PURCHASE = enum.auto() | ||
|  |     TV_CHANNEL = enum.auto() | ||
|  |     QI_CRAFTING_RECIPE = enum.auto() | ||
|  |     CHEFSANITY = enum.auto() | ||
|  |     CHEFSANITY_STARTER = enum.auto() | ||
|  |     CHEFSANITY_QOS = enum.auto() | ||
|  |     CHEFSANITY_PURCHASE = enum.auto() | ||
|  |     CHEFSANITY_FRIENDSHIP = enum.auto() | ||
|  |     CHEFSANITY_SKILL = enum.auto() | ||
|  |     CRAFTSANITY = enum.auto() | ||
|  |     BOOK_POWER = enum.auto() | ||
|  |     LOST_BOOK = enum.auto() | ||
|  |     PLAYER_BUFF = enum.auto() | ||
|  |     # Mods | ||
|  |     MAGIC_SPELL = enum.auto() | ||
|  |     MOD_WARP = enum.auto() | ||
|  | 
 | ||
|  | 
 | ||
|  | @dataclass(frozen=True) | ||
|  | class ItemData: | ||
|  |     code_without_offset: Optional[int] | ||
|  |     name: str | ||
|  |     classification: ItemClassification | ||
|  |     mod_name: Optional[str] = None | ||
|  |     groups: Set[Group] = field(default_factory=frozenset) | ||
|  | 
 | ||
|  |     def __post_init__(self): | ||
|  |         if not isinstance(self.groups, frozenset): | ||
|  |             super().__setattr__("groups", frozenset(self.groups)) | ||
|  | 
 | ||
|  |     @property | ||
|  |     def code(self): | ||
|  |         return ITEM_CODE_OFFSET + self.code_without_offset if self.code_without_offset is not None else None | ||
|  | 
 | ||
|  |     def has_any_group(self, *group: Group) -> bool: | ||
|  |         groups = set(group) | ||
|  |         return bool(groups.intersection(self.groups)) | ||
|  | 
 | ||
|  | 
 | ||
|  | class StardewItemFactory(Protocol): | ||
|  |     def __call__(self, name: Union[str, ItemData], override_classification: ItemClassification = None) -> Item: | ||
|  |         raise NotImplementedError | ||
|  | 
 | ||
|  | 
 | ||
|  | def load_item_csv(): | ||
|  |     from importlib.resources import files | ||
|  | 
 | ||
|  |     items = [] | ||
|  |     with files(data).joinpath("items.csv").open() as file: | ||
|  |         item_reader = csv.DictReader(file) | ||
|  |         for item in item_reader: | ||
|  |             id = int(item["id"]) if item["id"] else None | ||
|  |             classification = reduce((lambda a, b: a | b), {ItemClassification[str_classification] for str_classification in item["classification"].split(",")}) | ||
|  |             groups = {Group[group] for group in item["groups"].split(",") if group} | ||
|  |             mod_name = str(item["mod_name"]) if item["mod_name"] else None | ||
|  |             items.append(ItemData(id, item["name"], classification, mod_name, groups)) | ||
|  |     return items | ||
|  | 
 | ||
|  | 
 | ||
|  | events = [ | ||
|  |     ItemData(None, e, ItemClassification.progression) | ||
|  |     for e in sorted(all_events) | ||
|  | ] | ||
|  | 
 | ||
|  | all_items: List[ItemData] = load_item_csv() + events | ||
|  | item_table: Dict[str, ItemData] = {} | ||
|  | items_by_group: Dict[Group, List[ItemData]] = {} | ||
|  | 
 | ||
|  | 
 | ||
|  | def initialize_groups(): | ||
|  |     for item in all_items: | ||
|  |         for group in item.groups: | ||
|  |             item_group = items_by_group.get(group, list()) | ||
|  |             item_group.append(item) | ||
|  |             items_by_group[group] = item_group | ||
|  | 
 | ||
|  | 
 | ||
|  | def initialize_item_table(): | ||
|  |     item_table.update({item.name: item for item in all_items}) | ||
|  | 
 | ||
|  | 
 | ||
|  | initialize_item_table() | ||
|  | initialize_groups() |