import csv import enum import math from dataclasses import dataclass, field from functools import reduce from random import Random from typing import Dict, List, Set from BaseClasses import Item, ItemClassification from . import Options, data class DLCQuestItem(Item): game: str = "DLCQuest" coins: int = 0 coin_suffix: str = "" offset = 120_000 class Group(enum.Enum): DLC = enum.auto() DLCQuest = enum.auto() Freemium = enum.auto() Item = enum.auto() Coin = enum.auto() Trap = enum.auto() Twice = enum.auto() Piece = enum.auto() Deprecated = enum.auto() @dataclass(frozen=True) class ItemData: code_without_offset: offset name: str classification: ItemClassification 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 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)) def load_item_csv(): try: from importlib.resources import files except ImportError: from importlib_resources import files # noqa 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} items.append(ItemData(id, item["name"], classification, groups)) return items all_items: List[ItemData] = load_item_csv() item_table: Dict[str, ItemData] = {} items_by_group: Dict[Group, List[ItemData]] = {} def initialize_item_table(): item_table.update({item.name: item for item in all_items}) 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 initialize_item_table() initialize_groups() def create_trap_items(world, world_options: Options.DLCQuestOptions, trap_needed: int, random: Random) -> List[Item]: traps = [] for i in range(trap_needed): trap = random.choice(items_by_group[Group.Trap]) traps.append(world.create_item(trap, ItemClassification.trap)) return traps def create_items(world, world_options: Options.DLCQuestOptions, locations_count: int, excluded_items: list[str], random: Random): created_items = [] if world_options.campaign == Options.Campaign.option_basic or world_options.campaign == Options.Campaign.option_both: create_items_campaign(world_options, created_items, world, excluded_items, Group.DLCQuest, 825, 250) if (world_options.campaign == Options.Campaign.option_live_freemium_or_die or world_options.campaign == Options.Campaign.option_both): create_items_campaign(world_options, created_items, world, excluded_items, Group.Freemium, 889, 200) trap_items = create_trap_items(world, world_options, locations_count - len(created_items), random) created_items += trap_items return created_items def create_items_campaign(world_options: Options.DLCQuestOptions, created_items: list[DLCQuestItem], world, excluded_items: list[str], group: Group, total_coins: int, required_coins: int): for item in items_by_group[group]: if item.name in excluded_items: excluded_items.remove(item.name) continue if item.has_any_group(Group.DLC): created_items.append(world.create_item(item)) if item.has_any_group(Group.Item) and world_options.item_shuffle == Options.ItemShuffle.option_shuffled: created_items.append(world.create_item(item)) if item.has_any_group(Group.Twice): created_items.append(world.create_item(item)) if world_options.coinsanity == Options.CoinSanity.option_coin: if world_options.coinbundlequantity == -1: create_coin_piece(created_items, world, total_coins, required_coins, group) return create_coin(world_options, created_items, world, total_coins, required_coins, group) def create_coin(world_options, created_items, world, total_coins, required_coins, group): coin_bundle_required = math.ceil(required_coins / world_options.coinbundlequantity) coin_bundle_useful = math.ceil( (total_coins - coin_bundle_required * world_options.coinbundlequantity) / world_options.coinbundlequantity) for item in items_by_group[group]: if item.has_any_group(Group.Coin): for i in range(coin_bundle_required): created_items.append(world.create_item(item)) for i in range(coin_bundle_useful): created_items.append(world.create_item(item, ItemClassification.useful)) def create_coin_piece(created_items, world, total_coins, required_coins, group): for item in items_by_group[group]: if item.has_any_group(Group.Piece): for i in range(required_coins * 10): created_items.append(world.create_item(item)) for i in range((total_coins - required_coins) * 10): created_items.append(world.create_item(item, ItemClassification.useful))