| 
									
										
										
										
											2023-05-20 19:57:48 +02:00
										 |  |  | from __future__ import annotations | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-13 23:02:18 +01:00
										 |  |  | import typing | 
					
						
							| 
									
										
										
										
											2023-05-20 19:57:48 +02:00
										 |  |  | from typing import List, Optional | 
					
						
							| 
									
										
										
										
											2022-02-13 23:02:18 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-20 19:57:48 +02:00
										 |  |  | from BaseClasses import CollectionState, Region, MultiWorld | 
					
						
							| 
									
										
										
										
											2017-10-15 15:35:45 -04:00
										 |  |  | from Fill import fill_restrictive | 
					
						
							| 
									
										
										
										
											2023-04-26 10:48:08 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-20 19:57:48 +02:00
										 |  |  | from .Bosses import BossFactory, Boss | 
					
						
							| 
									
										
										
										
											2023-04-26 10:48:08 +02:00
										 |  |  | from .Items import ItemFactory | 
					
						
							| 
									
										
										
										
											2023-09-26 23:24:10 -04:00
										 |  |  | from .Regions import lookup_boss_drops, key_drop_data | 
					
						
							| 
									
										
										
										
											2024-02-19 19:07:49 -05:00
										 |  |  | from .Options import small_key_shuffle | 
					
						
							| 
									
										
										
										
											2017-05-15 20:28:04 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-20 17:10:12 +01:00
										 |  |  | if typing.TYPE_CHECKING: | 
					
						
							| 
									
										
										
										
											2023-05-20 19:57:48 +02:00
										 |  |  |     from .SubClasses import ALttPLocation, ALttPItem | 
					
						
							|  |  |  |     from . import ALTTPWorld | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Dungeon: | 
					
						
							|  |  |  |     def __init__(self, name: str, regions: List[Region], big_key: ALttPItem, small_keys: List[ALttPItem], | 
					
						
							|  |  |  |                  dungeon_items: List[ALttPItem], player: int): | 
					
						
							|  |  |  |         self.name = name | 
					
						
							|  |  |  |         self.regions = regions | 
					
						
							|  |  |  |         self.big_key = big_key | 
					
						
							|  |  |  |         self.small_keys = small_keys | 
					
						
							|  |  |  |         self.dungeon_items = dungeon_items | 
					
						
							|  |  |  |         self.bosses = dict() | 
					
						
							|  |  |  |         self.player = player | 
					
						
							|  |  |  |         self.multiworld = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @property | 
					
						
							|  |  |  |     def boss(self) -> Optional[Boss]: | 
					
						
							|  |  |  |         return self.bosses.get(None, None) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @boss.setter | 
					
						
							|  |  |  |     def boss(self, value: Optional[Boss]): | 
					
						
							|  |  |  |         self.bosses[None] = value | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @property | 
					
						
							|  |  |  |     def keys(self) -> List[ALttPItem]: | 
					
						
							|  |  |  |         return self.small_keys + ([self.big_key] if self.big_key else []) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @property | 
					
						
							|  |  |  |     def all_items(self) -> List[ALttPItem]: | 
					
						
							|  |  |  |         return self.dungeon_items + self.keys | 
					
						
							| 
									
										
										
										
											2017-05-15 20:28:04 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-20 19:57:48 +02:00
										 |  |  |     def is_dungeon_item(self, item: ALttPItem) -> bool: | 
					
						
							|  |  |  |         return item.player == self.player and item.name in (dungeon_item.name for dungeon_item in self.all_items) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __eq__(self, other: Dungeon) -> bool: | 
					
						
							|  |  |  |         if not other: | 
					
						
							|  |  |  |             return False | 
					
						
							|  |  |  |         return self.name == other.name and self.player == other.player | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __repr__(self): | 
					
						
							|  |  |  |         return self.__str__() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __str__(self): | 
					
						
							|  |  |  |         return self.multiworld.get_name_string_for_object(self) if self.multiworld \ | 
					
						
							|  |  |  |             else f'{self.name} (Player {self.player})' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def create_dungeons(world: "ALTTPWorld"): | 
					
						
							|  |  |  |     multiworld = world.multiworld | 
					
						
							|  |  |  |     player = world.player | 
					
						
							| 
									
										
										
										
											2023-04-26 10:48:08 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-26 13:12:20 -04:00
										 |  |  |     def make_dungeon(name, default_boss, dungeon_regions, big_key, small_keys, dungeon_items): | 
					
						
							| 
									
										
										
										
											2021-08-30 16:31:56 +02:00
										 |  |  |         dungeon = Dungeon(name, dungeon_regions, big_key, | 
					
						
							| 
									
										
										
										
											2024-02-19 19:07:49 -05:00
										 |  |  |                           [] if multiworld.small_key_shuffle[player] == small_key_shuffle.option_universal else small_keys, | 
					
						
							| 
									
										
										
										
											2020-08-20 20:13:00 +02:00
										 |  |  |                           dungeon_items, player) | 
					
						
							| 
									
										
										
										
											2021-08-30 16:31:56 +02:00
										 |  |  |         for item in dungeon.all_items: | 
					
						
							|  |  |  |             item.dungeon = dungeon | 
					
						
							| 
									
										
										
										
											2020-12-31 13:23:32 +01:00
										 |  |  |         dungeon.boss = BossFactory(default_boss, player) if default_boss else None | 
					
						
							| 
									
										
										
										
											2023-05-20 19:57:48 +02:00
										 |  |  |         regions = [] | 
					
						
							|  |  |  |         for region_name in dungeon.regions: | 
					
						
							|  |  |  |             region = multiworld.get_region(region_name, player) | 
					
						
							|  |  |  |             region.dungeon = dungeon | 
					
						
							|  |  |  |             regions.append(region) | 
					
						
							|  |  |  |             dungeon.multiworld = multiworld | 
					
						
							|  |  |  |         dungeon.regions = regions | 
					
						
							| 
									
										
										
										
											2017-10-15 12:16:07 -04:00
										 |  |  |         return dungeon | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-24 16:22:49 +02:00
										 |  |  |     ES = make_dungeon('Hyrule Castle', None, ['Hyrule Castle', 'Sewers', 'Sewer Drop', 'Sewers (Dark)', 'Sanctuary'], | 
					
						
							| 
									
										
										
										
											2023-09-26 23:24:10 -04:00
										 |  |  |                       ItemFactory('Big Key (Hyrule Castle)', player), | 
					
						
							|  |  |  |                       ItemFactory(['Small Key (Hyrule Castle)'] * 4, player), | 
					
						
							| 
									
										
										
										
											2020-06-24 16:22:49 +02:00
										 |  |  |                       [ItemFactory('Map (Hyrule Castle)', player)]) | 
					
						
							|  |  |  |     EP = make_dungeon('Eastern Palace', 'Armos Knights', ['Eastern Palace'], | 
					
						
							| 
									
										
										
										
											2023-09-26 23:24:10 -04:00
										 |  |  |                       ItemFactory('Big Key (Eastern Palace)', player), | 
					
						
							|  |  |  |                       ItemFactory(['Small Key (Eastern Palace)'] * 2, player), | 
					
						
							| 
									
										
										
										
											2020-06-24 16:22:49 +02:00
										 |  |  |                       ItemFactory(['Map (Eastern Palace)', 'Compass (Eastern Palace)'], player)) | 
					
						
							| 
									
										
										
										
											2021-08-30 16:31:56 +02:00
										 |  |  |     DP = make_dungeon('Desert Palace', 'Lanmolas', | 
					
						
							|  |  |  |                       ['Desert Palace North', 'Desert Palace Main (Inner)', 'Desert Palace Main (Outer)', | 
					
						
							|  |  |  |                        'Desert Palace East'], ItemFactory('Big Key (Desert Palace)', player), | 
					
						
							| 
									
										
										
										
											2023-09-26 23:24:10 -04:00
										 |  |  |                       ItemFactory(['Small Key (Desert Palace)'] * 4, player), | 
					
						
							| 
									
										
										
										
											2021-08-30 16:31:56 +02:00
										 |  |  |                       ItemFactory(['Map (Desert Palace)', 'Compass (Desert Palace)'], player)) | 
					
						
							|  |  |  |     ToH = make_dungeon('Tower of Hera', 'Moldorm', | 
					
						
							|  |  |  |                        ['Tower of Hera (Bottom)', 'Tower of Hera (Basement)', 'Tower of Hera (Top)'], | 
					
						
							|  |  |  |                        ItemFactory('Big Key (Tower of Hera)', player), | 
					
						
							|  |  |  |                        [ItemFactory('Small Key (Tower of Hera)', player)], | 
					
						
							|  |  |  |                        ItemFactory(['Map (Tower of Hera)', 'Compass (Tower of Hera)'], player)) | 
					
						
							|  |  |  |     PoD = make_dungeon('Palace of Darkness', 'Helmasaur King', | 
					
						
							|  |  |  |                        ['Palace of Darkness (Entrance)', 'Palace of Darkness (Center)', | 
					
						
							|  |  |  |                         'Palace of Darkness (Big Key Chest)', 'Palace of Darkness (Bonk Section)', | 
					
						
							|  |  |  |                         'Palace of Darkness (North)', 'Palace of Darkness (Maze)', | 
					
						
							|  |  |  |                         'Palace of Darkness (Harmless Hellway)', 'Palace of Darkness (Final Section)'], | 
					
						
							|  |  |  |                        ItemFactory('Big Key (Palace of Darkness)', player), | 
					
						
							|  |  |  |                        ItemFactory(['Small Key (Palace of Darkness)'] * 6, player), | 
					
						
							|  |  |  |                        ItemFactory(['Map (Palace of Darkness)', 'Compass (Palace of Darkness)'], player)) | 
					
						
							|  |  |  |     TT = make_dungeon('Thieves Town', 'Blind', ['Thieves Town (Entrance)', 'Thieves Town (Deep)', 'Blind Fight'], | 
					
						
							| 
									
										
										
										
											2023-09-26 23:24:10 -04:00
										 |  |  |                       ItemFactory('Big Key (Thieves Town)', player), | 
					
						
							|  |  |  |                       ItemFactory(['Small Key (Thieves Town)'] * 3, player), | 
					
						
							| 
									
										
										
										
											2021-08-30 16:31:56 +02:00
										 |  |  |                       ItemFactory(['Map (Thieves Town)', 'Compass (Thieves Town)'], player)) | 
					
						
							|  |  |  |     SW = make_dungeon('Skull Woods', 'Mothula', ['Skull Woods Final Section (Entrance)', 'Skull Woods First Section', | 
					
						
							|  |  |  |                                                  'Skull Woods Second Section', 'Skull Woods Second Section (Drop)', | 
					
						
							|  |  |  |                                                  'Skull Woods Final Section (Mothula)', | 
					
						
							|  |  |  |                                                  'Skull Woods First Section (Right)', | 
					
						
							|  |  |  |                                                  'Skull Woods First Section (Left)', 'Skull Woods First Section (Top)'], | 
					
						
							|  |  |  |                       ItemFactory('Big Key (Skull Woods)', player), | 
					
						
							| 
									
										
										
										
											2023-09-26 23:24:10 -04:00
										 |  |  |                       ItemFactory(['Small Key (Skull Woods)'] * 5, player), | 
					
						
							| 
									
										
										
										
											2021-08-30 16:31:56 +02:00
										 |  |  |                       ItemFactory(['Map (Skull Woods)', 'Compass (Skull Woods)'], player)) | 
					
						
							|  |  |  |     SP = make_dungeon('Swamp Palace', 'Arrghus', | 
					
						
							|  |  |  |                       ['Swamp Palace (Entrance)', 'Swamp Palace (First Room)', 'Swamp Palace (Starting Area)', | 
					
						
							| 
									
										
										
										
											2023-09-26 23:24:10 -04:00
										 |  |  |                        'Swamp Palace (West)', 'Swamp Palace (Center)', 'Swamp Palace (North)'], | 
					
						
							|  |  |  |                       ItemFactory('Big Key (Swamp Palace)', player), | 
					
						
							|  |  |  |                       ItemFactory(['Small Key (Swamp Palace)'] * 6, player), | 
					
						
							| 
									
										
										
										
											2021-08-30 16:31:56 +02:00
										 |  |  |                       ItemFactory(['Map (Swamp Palace)', 'Compass (Swamp Palace)'], player)) | 
					
						
							|  |  |  |     IP = make_dungeon('Ice Palace', 'Kholdstare', | 
					
						
							| 
									
										
										
										
											2023-09-26 23:24:10 -04:00
										 |  |  |                       ['Ice Palace (Entrance)', 'Ice Palace (Second Section)', 'Ice Palace (Main)', 'Ice Palace (East)', | 
					
						
							|  |  |  |                        'Ice Palace (East Top)', 'Ice Palace (Kholdstare)'], ItemFactory('Big Key (Ice Palace)', player), | 
					
						
							|  |  |  |                       ItemFactory(['Small Key (Ice Palace)'] * 6, player), | 
					
						
							| 
									
										
										
										
											2021-08-30 16:31:56 +02:00
										 |  |  |                       ItemFactory(['Map (Ice Palace)', 'Compass (Ice Palace)'], player)) | 
					
						
							|  |  |  |     MM = make_dungeon('Misery Mire', 'Vitreous', | 
					
						
							|  |  |  |                       ['Misery Mire (Entrance)', 'Misery Mire (Main)', 'Misery Mire (West)', 'Misery Mire (Final Area)', | 
					
						
							|  |  |  |                        'Misery Mire (Vitreous)'], ItemFactory('Big Key (Misery Mire)', player), | 
					
						
							| 
									
										
										
										
											2023-09-26 23:24:10 -04:00
										 |  |  |                       ItemFactory(['Small Key (Misery Mire)'] * 6, player), | 
					
						
							| 
									
										
										
										
											2021-08-30 16:31:56 +02:00
										 |  |  |                       ItemFactory(['Map (Misery Mire)', 'Compass (Misery Mire)'], player)) | 
					
						
							|  |  |  |     TR = make_dungeon('Turtle Rock', 'Trinexx', | 
					
						
							|  |  |  |                       ['Turtle Rock (Entrance)', 'Turtle Rock (First Section)', 'Turtle Rock (Chain Chomp Room)', | 
					
						
							| 
									
										
										
										
											2023-09-26 23:24:10 -04:00
										 |  |  |                        'Turtle Rock (Pokey Room)', | 
					
						
							| 
									
										
										
										
											2021-08-30 16:31:56 +02:00
										 |  |  |                        'Turtle Rock (Second Section)', 'Turtle Rock (Big Chest)', 'Turtle Rock (Crystaroller Room)', | 
					
						
							|  |  |  |                        'Turtle Rock (Dark Room)', 'Turtle Rock (Eye Bridge)', 'Turtle Rock (Trinexx)'], | 
					
						
							|  |  |  |                       ItemFactory('Big Key (Turtle Rock)', player), | 
					
						
							| 
									
										
										
										
											2023-09-26 23:24:10 -04:00
										 |  |  |                       ItemFactory(['Small Key (Turtle Rock)'] * 6, player), | 
					
						
							| 
									
										
										
										
											2021-08-30 16:31:56 +02:00
										 |  |  |                       ItemFactory(['Map (Turtle Rock)', 'Compass (Turtle Rock)'], player)) | 
					
						
							| 
									
										
										
										
											2019-07-27 09:13:13 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-20 19:57:48 +02:00
										 |  |  |     if multiworld.mode[player] != 'inverted': | 
					
						
							| 
									
										
										
										
											2021-08-30 16:31:56 +02:00
										 |  |  |         AT = make_dungeon('Agahnims Tower', 'Agahnim', ['Agahnims Tower', 'Agahnim 1'], None, | 
					
						
							| 
									
										
										
										
											2023-09-26 23:24:10 -04:00
										 |  |  |                           ItemFactory(['Small Key (Agahnims Tower)'] * 4, player), []) | 
					
						
							| 
									
										
										
										
											2021-08-30 16:31:56 +02:00
										 |  |  |         GT = make_dungeon('Ganons Tower', 'Agahnim2', | 
					
						
							|  |  |  |                           ['Ganons Tower (Entrance)', 'Ganons Tower (Tile Room)', 'Ganons Tower (Compass Room)', | 
					
						
							|  |  |  |                            'Ganons Tower (Hookshot Room)', 'Ganons Tower (Map Room)', 'Ganons Tower (Firesnake Room)', | 
					
						
							|  |  |  |                            'Ganons Tower (Teleport Room)', 'Ganons Tower (Bottom)', 'Ganons Tower (Top)', | 
					
						
							|  |  |  |                            'Ganons Tower (Before Moldorm)', 'Ganons Tower (Moldorm)', 'Agahnim 2'], | 
					
						
							|  |  |  |                           ItemFactory('Big Key (Ganons Tower)', player), | 
					
						
							| 
									
										
										
										
											2023-09-26 23:24:10 -04:00
										 |  |  |                           ItemFactory(['Small Key (Ganons Tower)'] * 8, player), | 
					
						
							| 
									
										
										
										
											2021-08-30 16:31:56 +02:00
										 |  |  |                           ItemFactory(['Map (Ganons Tower)', 'Compass (Ganons Tower)'], player)) | 
					
						
							| 
									
										
										
										
											2019-07-27 09:13:13 -04:00
										 |  |  |     else: | 
					
						
							| 
									
										
										
										
											2021-08-30 16:31:56 +02:00
										 |  |  |         AT = make_dungeon('Inverted Agahnims Tower', 'Agahnim', ['Inverted Agahnims Tower', 'Agahnim 1'], None, | 
					
						
							| 
									
										
										
										
											2023-09-26 23:24:10 -04:00
										 |  |  |                           ItemFactory(['Small Key (Agahnims Tower)'] * 4, player), []) | 
					
						
							| 
									
										
										
										
											2021-08-30 16:31:56 +02:00
										 |  |  |         GT = make_dungeon('Inverted Ganons Tower', 'Agahnim2', | 
					
						
							|  |  |  |                           ['Inverted Ganons Tower (Entrance)', 'Ganons Tower (Tile Room)', | 
					
						
							|  |  |  |                            'Ganons Tower (Compass Room)', 'Ganons Tower (Hookshot Room)', 'Ganons Tower (Map Room)', | 
					
						
							|  |  |  |                            'Ganons Tower (Firesnake Room)', 'Ganons Tower (Teleport Room)', 'Ganons Tower (Bottom)', | 
					
						
							|  |  |  |                            'Ganons Tower (Top)', 'Ganons Tower (Before Moldorm)', 'Ganons Tower (Moldorm)', | 
					
						
							|  |  |  |                            'Agahnim 2'], ItemFactory('Big Key (Ganons Tower)', player), | 
					
						
							| 
									
										
										
										
											2023-09-26 23:24:10 -04:00
										 |  |  |                           ItemFactory(['Small Key (Ganons Tower)'] * 8, player), | 
					
						
							| 
									
										
										
										
											2021-08-30 16:31:56 +02:00
										 |  |  |                           ItemFactory(['Map (Ganons Tower)', 'Compass (Ganons Tower)'], player)) | 
					
						
							| 
									
										
										
										
											2019-04-18 11:23:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     GT.bosses['bottom'] = BossFactory('Armos Knights', player) | 
					
						
							|  |  |  |     GT.bosses['middle'] = BossFactory('Lanmolas', player) | 
					
						
							|  |  |  |     GT.bosses['top'] = BossFactory('Moldorm', player) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-29 16:02:28 +02:00
										 |  |  |     for dungeon in [ES, EP, DP, ToH, AT, PoD, TT, SW, SP, IP, MM, TR, GT]: | 
					
						
							| 
									
										
										
										
											2023-05-20 19:57:48 +02:00
										 |  |  |         world.dungeons[dungeon.name] = dungeon | 
					
						
							| 
									
										
										
										
											2017-10-15 12:16:07 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-25 17:47:15 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-20 19:57:48 +02:00
										 |  |  | def get_dungeon_item_pool(multiworld: MultiWorld) -> typing.List[ALttPItem]: | 
					
						
							|  |  |  |     return [item | 
					
						
							|  |  |  |             for world in multiworld.get_game_worlds("A Link to the Past") | 
					
						
							|  |  |  |             for item in get_dungeon_item_pool_player(world)] | 
					
						
							| 
									
										
										
										
											2017-05-25 17:47:15 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-09 06:50:11 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-20 19:57:48 +02:00
										 |  |  | def get_dungeon_item_pool_player(world) -> typing.List[ALttPItem]: | 
					
						
							|  |  |  |     return [item | 
					
						
							|  |  |  |             for dungeon in world.dungeons.values() | 
					
						
							|  |  |  |             for item in dungeon.all_items] | 
					
						
							| 
									
										
										
										
											2021-08-30 16:31:56 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-20 19:57:48 +02:00
										 |  |  | def get_unfilled_dungeon_locations(multiworld: MultiWorld) -> typing.List[ALttPLocation]: | 
					
						
							|  |  |  |     return [location | 
					
						
							|  |  |  |             for world in multiworld.get_game_worlds("A Link to the Past") | 
					
						
							|  |  |  |             for dungeon in world.dungeons.values() | 
					
						
							|  |  |  |             for region in dungeon.regions | 
					
						
							|  |  |  |             for location in region.locations if not location.item] | 
					
						
							| 
									
										
										
										
											2022-11-20 20:50:32 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-20 19:57:48 +02:00
										 |  |  | def fill_dungeons_restrictive(multiworld: MultiWorld): | 
					
						
							| 
									
										
										
										
											2020-10-07 19:51:46 +02:00
										 |  |  |     """Places dungeon-native items into their dungeons, places nothing if everything is shuffled outside.""" | 
					
						
							| 
									
										
										
										
											2021-08-30 16:31:56 +02:00
										 |  |  |     localized: set = set() | 
					
						
							|  |  |  |     dungeon_specific: set = set() | 
					
						
							| 
									
										
										
										
											2023-05-20 19:57:48 +02:00
										 |  |  |     for subworld in multiworld.get_game_worlds("A Link to the Past"): | 
					
						
							| 
									
										
										
										
											2021-08-30 16:31:56 +02:00
										 |  |  |         player = subworld.player | 
					
						
							| 
									
										
										
										
											2023-09-26 23:24:10 -04:00
										 |  |  |         if player not in multiworld.groups: | 
					
						
							|  |  |  |             localized |= {(player, item_name) for item_name in | 
					
						
							|  |  |  |                           subworld.dungeon_local_item_names} | 
					
						
							|  |  |  |             dungeon_specific |= {(player, item_name) for item_name in | 
					
						
							|  |  |  |                                  subworld.dungeon_specific_item_names} | 
					
						
							| 
									
										
										
										
											2021-08-30 16:31:56 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if localized: | 
					
						
							| 
									
										
										
										
											2023-05-20 19:57:48 +02:00
										 |  |  |         in_dungeon_items = [item for item in get_dungeon_item_pool(multiworld) if (item.player, item.name) in localized] | 
					
						
							| 
									
										
										
										
											2021-08-30 16:31:56 +02:00
										 |  |  |         if in_dungeon_items: | 
					
						
							| 
									
										
										
										
											2023-05-20 19:57:48 +02:00
										 |  |  |             restricted_players = {player for player, restricted in multiworld.restrict_dungeon_item_on_boss.items() if | 
					
						
							| 
									
										
										
										
											2021-08-30 16:31:56 +02:00
										 |  |  |                                   restricted} | 
					
						
							| 
									
										
										
										
											2023-03-20 17:10:12 +01:00
										 |  |  |             locations: typing.List["ALttPLocation"] = [ | 
					
						
							| 
									
										
										
										
											2023-05-20 19:57:48 +02:00
										 |  |  |                 location for location in get_unfilled_dungeon_locations(multiworld) | 
					
						
							| 
									
										
										
										
											2023-03-20 17:10:12 +01:00
										 |  |  |                 # filter boss | 
					
						
							|  |  |  |                 if not (location.player in restricted_players and location.name in lookup_boss_drops)] | 
					
						
							| 
									
										
										
										
											2021-08-30 16:31:56 +02:00
										 |  |  |             if dungeon_specific: | 
					
						
							|  |  |  |                 for location in locations: | 
					
						
							|  |  |  |                     dungeon = location.parent_region.dungeon | 
					
						
							|  |  |  |                     orig_rule = location.item_rule | 
					
						
							| 
									
										
										
										
											2021-08-30 16:47:34 +02:00
										 |  |  |                     location.item_rule = lambda item, dungeon=dungeon, orig_rule=orig_rule: \ | 
					
						
							| 
									
										
										
										
											2021-08-30 23:52:40 +02:00
										 |  |  |                         (not (item.player, item.name) in dungeon_specific or item.dungeon is dungeon) and orig_rule(item) | 
					
						
							| 
									
										
										
										
											2021-08-30 16:31:56 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-20 19:57:48 +02:00
										 |  |  |             multiworld.random.shuffle(locations) | 
					
						
							| 
									
										
										
										
											2021-08-30 16:31:56 +02:00
										 |  |  |             # Dungeon-locked items have to be placed first, to not run out of spaces for dungeon-locked items | 
					
						
							|  |  |  |             # subsort in the order Big Key, Small Key, Other before placing dungeon items | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             sort_order = {"BigKey": 3, "SmallKey": 2} | 
					
						
							|  |  |  |             in_dungeon_items.sort( | 
					
						
							|  |  |  |                 key=lambda item: sort_order.get(item.type, 1) + | 
					
						
							|  |  |  |                                  (5 if (item.player, item.name) in dungeon_specific else 0)) | 
					
						
							| 
									
										
										
										
											2023-05-18 07:31:12 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-20 19:57:48 +02:00
										 |  |  |             # Construct a partial all_state which contains only the items from get_pre_fill_items, | 
					
						
							|  |  |  |             # which aren't in_dungeon | 
					
						
							| 
									
										
										
										
											2023-05-18 07:31:12 -06:00
										 |  |  |             in_dungeon_player_ids = {item.player for item in in_dungeon_items} | 
					
						
							| 
									
										
										
										
											2023-05-20 19:57:48 +02:00
										 |  |  |             all_state_base = CollectionState(multiworld) | 
					
						
							|  |  |  |             for item in multiworld.itempool: | 
					
						
							|  |  |  |                 multiworld.worlds[item.player].collect(all_state_base, item) | 
					
						
							| 
									
										
										
										
											2023-05-18 07:31:12 -06:00
										 |  |  |             pre_fill_items = [] | 
					
						
							|  |  |  |             for player in in_dungeon_player_ids: | 
					
						
							| 
									
										
										
										
											2023-05-20 19:57:48 +02:00
										 |  |  |                 pre_fill_items += multiworld.worlds[player].get_pre_fill_items() | 
					
						
							| 
									
										
										
										
											2021-08-31 19:19:26 -05:00
										 |  |  |             for item in in_dungeon_items: | 
					
						
							| 
									
										
										
										
											2023-05-18 07:31:12 -06:00
										 |  |  |                 try: | 
					
						
							|  |  |  |                     pre_fill_items.remove(item) | 
					
						
							|  |  |  |                 except ValueError: | 
					
						
							|  |  |  |                     # pre_fill_items should be a subset of in_dungeon_items, but just in case | 
					
						
							|  |  |  |                     pass | 
					
						
							|  |  |  |             for item in pre_fill_items: | 
					
						
							| 
									
										
										
										
											2023-05-20 19:57:48 +02:00
										 |  |  |                 multiworld.worlds[item.player].collect(all_state_base, item) | 
					
						
							| 
									
										
										
										
											2023-05-18 07:31:12 -06:00
										 |  |  |             all_state_base.sweep_for_events() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-10 05:06:25 -06:00
										 |  |  |             # Remove completion condition so that minimal-accessibility worlds place keys properly | 
					
						
							|  |  |  |             for player in {item.player for item in in_dungeon_items}: | 
					
						
							|  |  |  |                 if all_state_base.has("Triforce", player): | 
					
						
							| 
									
										
										
										
											2023-05-20 19:57:48 +02:00
										 |  |  |                     all_state_base.remove(multiworld.worlds[player].create_item("Triforce")) | 
					
						
							| 
									
										
										
										
											2023-05-10 05:06:25 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-29 14:23:46 -04:00
										 |  |  |             for (player, key_drop_shuffle) in multiworld.key_drop_shuffle.items(): | 
					
						
							| 
									
										
										
										
											2023-09-26 23:24:10 -04:00
										 |  |  |                 if not key_drop_shuffle and player not in multiworld.groups: | 
					
						
							|  |  |  |                     for key_loc in key_drop_data: | 
					
						
							|  |  |  |                         key_data = key_drop_data[key_loc] | 
					
						
							|  |  |  |                         all_state_base.remove(ItemFactory(key_data[3], player)) | 
					
						
							|  |  |  |                         loc = multiworld.get_location(key_loc, player) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         if loc in all_state_base.events: | 
					
						
							|  |  |  |                             all_state_base.events.remove(loc) | 
					
						
							| 
									
										
										
										
											2023-12-15 14:39:09 -05:00
										 |  |  |             fill_restrictive(multiworld, all_state_base, locations, in_dungeon_items, True, True, allow_excluded=True, | 
					
						
							| 
									
										
										
										
											2023-10-30 01:22:00 +01:00
										 |  |  |                              name="LttP Dungeon Items") | 
					
						
							| 
									
										
										
										
											2017-10-15 13:52:42 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-28 23:42:35 -04:00
										 |  |  | dungeon_music_addresses = {'Eastern Palace - Prize': [0x1559A], | 
					
						
							|  |  |  |                            'Desert Palace - Prize': [0x1559B, 0x1559C, 0x1559D, 0x1559E], | 
					
						
							| 
									
										
										
										
											2017-11-08 19:23:21 -05:00
										 |  |  |                            'Tower of Hera - Prize': [0x155C5, 0x1107A, 0x10B8C], | 
					
						
							| 
									
										
										
										
											2017-10-28 23:42:35 -04:00
										 |  |  |                            'Palace of Darkness - Prize': [0x155B8], | 
					
						
							|  |  |  |                            'Swamp Palace - Prize': [0x155B7], | 
					
						
							| 
									
										
										
										
											2018-09-26 17:34:15 -04:00
										 |  |  |                            'Thieves\' Town - Prize': [0x155C6], | 
					
						
							| 
									
										
										
										
											2021-08-30 16:31:56 +02:00
										 |  |  |                            'Skull Woods - Prize': [0x155BA, 0x155BB, 0x155BC, 0x155BD, 0x15608, 0x15609, 0x1560A, | 
					
						
							|  |  |  |                                                    0x1560B], | 
					
						
							| 
									
										
										
										
											2017-10-28 23:42:35 -04:00
										 |  |  |                            'Ice Palace - Prize': [0x155BF], | 
					
						
							|  |  |  |                            'Misery Mire - Prize': [0x155B9], | 
					
						
							|  |  |  |                            'Turtle Rock - Prize': [0x155C7, 0x155A7, 0x155AA, 0x155AB]} | 
					
						
							| 
									
										
										
										
											2023-05-20 19:57:48 +02:00
										 |  |  | 
 |