| 
									
										
										
										
											2023-04-09 15:06:59 -04:00
										 |  |  | import csv | 
					
						
							|  |  |  | import enum | 
					
						
							|  |  |  | import math | 
					
						
							|  |  |  | from dataclasses import dataclass, field | 
					
						
							|  |  |  | from random import Random | 
					
						
							| 
									
										
										
										
											2023-10-10 15:30:20 -05:00
										 |  |  | from typing import Dict, List, Set | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from BaseClasses import Item, ItemClassification | 
					
						
							|  |  |  | from . import Options, data | 
					
						
							| 
									
										
										
										
											2023-04-09 15:06:59 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class DLCQuestItem(Item): | 
					
						
							|  |  |  |     game: str = "DLCQuest" | 
					
						
							| 
									
										
										
										
											2023-10-26 00:51:32 +02:00
										 |  |  |     coins: int = 0 | 
					
						
							|  |  |  |     coin_suffix: str = "" | 
					
						
							| 
									
										
										
										
											2023-04-09 15:06:59 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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() | 
					
						
							| 
									
										
										
										
											2024-03-10 17:12:55 -04:00
										 |  |  |     Twice = enum.auto() | 
					
						
							|  |  |  |     Piece = enum.auto() | 
					
						
							|  |  |  |     Deprecated = enum.auto() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-09 15:06:59 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @dataclass(frozen=True) | 
					
						
							|  |  |  | class ItemData: | 
					
						
							|  |  |  |     code_without_offset: offset | 
					
						
							|  |  |  |     name: str | 
					
						
							|  |  |  |     classification: ItemClassification | 
					
						
							| 
									
										
										
										
											2023-04-14 01:09:50 -04:00
										 |  |  |     groups: Set[Group] = field(default_factory=frozenset) | 
					
						
							| 
									
										
										
										
											2023-04-09 15:06:59 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     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 = ItemClassification[item["classification"]] | 
					
						
							|  |  |  |             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() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-10 17:12:55 -04:00
										 |  |  | def create_trap_items(world, world_options: Options.DLCQuestOptions, trap_needed: int, random: Random) -> List[Item]: | 
					
						
							| 
									
										
										
										
											2023-04-09 15:06:59 -04:00
										 |  |  |     traps = [] | 
					
						
							|  |  |  |     for i in range(trap_needed): | 
					
						
							|  |  |  |         trap = random.choice(items_by_group[Group.Trap]) | 
					
						
							| 
									
										
										
										
											2024-03-10 17:12:55 -04:00
										 |  |  |         traps.append(world.create_item(trap, ItemClassification.trap)) | 
					
						
							| 
									
										
										
										
											2023-04-09 15:06:59 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return traps | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-05 08:19:54 -04:00
										 |  |  | def create_items(world, world_options: Options.DLCQuestOptions, locations_count: int, excluded_items: list[str], random: Random): | 
					
						
							| 
									
										
										
										
											2023-04-09 15:06:59 -04:00
										 |  |  |     created_items = [] | 
					
						
							| 
									
										
										
										
											2024-03-10 17:12:55 -04:00
										 |  |  |     if world_options.campaign == Options.Campaign.option_basic or world_options.campaign == Options.Campaign.option_both: | 
					
						
							| 
									
										
										
										
											2025-04-05 08:19:54 -04:00
										 |  |  |         create_items_basic(world_options, created_items, world, excluded_items) | 
					
						
							| 
									
										
										
										
											2024-03-10 17:12:55 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (world_options.campaign == Options.Campaign.option_live_freemium_or_die or | 
					
						
							|  |  |  |             world_options.campaign == Options.Campaign.option_both): | 
					
						
							| 
									
										
										
										
											2025-04-05 08:19:54 -04:00
										 |  |  |         create_items_lfod(world_options, created_items, world, excluded_items) | 
					
						
							| 
									
										
										
										
											2024-03-10 17:12:55 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     trap_items = create_trap_items(world, world_options, locations_count - len(created_items), random) | 
					
						
							|  |  |  |     created_items += trap_items | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return created_items | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-05 08:19:54 -04:00
										 |  |  | def create_items_lfod(world_options, created_items, world, excluded_items): | 
					
						
							| 
									
										
										
										
											2024-03-10 17:12:55 -04:00
										 |  |  |     for item in items_by_group[Group.Freemium]: | 
					
						
							| 
									
										
										
										
											2025-04-05 08:19:54 -04:00
										 |  |  |         if item.name in excluded_items: | 
					
						
							|  |  |  |             excluded_items.remove(item) | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-10 17:12:55 -04:00
										 |  |  |         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): | 
					
						
							| 
									
										
										
										
											2023-04-09 15:06:59 -04:00
										 |  |  |                 created_items.append(world.create_item(item)) | 
					
						
							| 
									
										
										
										
											2024-03-10 17:12:55 -04:00
										 |  |  |     if world_options.coinsanity == Options.CoinSanity.option_coin: | 
					
						
							|  |  |  |         if world_options.coinbundlequantity == -1: | 
					
						
							|  |  |  |             create_coin_piece(created_items, world, 889, 200, Group.Freemium) | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         create_coin(world_options, created_items, world, 889, 200, Group.Freemium) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-05 08:19:54 -04:00
										 |  |  | def create_items_basic(world_options, created_items, world, excluded_items): | 
					
						
							| 
									
										
										
										
											2024-03-10 17:12:55 -04:00
										 |  |  |     for item in items_by_group[Group.DLCQuest]: | 
					
						
							| 
									
										
										
										
											2025-04-05 08:19:54 -04:00
										 |  |  |         if item.name in excluded_items: | 
					
						
							|  |  |  |             excluded_items.remove(item.name) | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-10 17:12:55 -04:00
										 |  |  |         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): | 
					
						
							| 
									
										
										
										
											2023-04-09 15:06:59 -04:00
										 |  |  |                 created_items.append(world.create_item(item)) | 
					
						
							| 
									
										
										
										
											2024-03-10 17:12:55 -04:00
										 |  |  |     if world_options.coinsanity == Options.CoinSanity.option_coin: | 
					
						
							|  |  |  |         if world_options.coinbundlequantity == -1: | 
					
						
							|  |  |  |             create_coin_piece(created_items, world, 825, 250, Group.DLCQuest) | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         create_coin(world_options, created_items, world, 825, 250, Group.DLCQuest) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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): | 
					
						
							| 
									
										
										
										
											2023-04-09 15:06:59 -04:00
										 |  |  |                 created_items.append(world.create_item(item)) | 
					
						
							| 
									
										
										
										
											2024-03-10 17:12:55 -04:00
										 |  |  |             for i in range(coin_bundle_useful): | 
					
						
							|  |  |  |                 created_items.append(world.create_item(item, ItemClassification.useful)) | 
					
						
							| 
									
										
										
										
											2023-04-09 15:06:59 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-10 17:12:55 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 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)) |