| 
									
										
										
										
											2022-03-15 08:55:57 -04:00
										 |  |  |  | from typing import Dict, List | 
					
						
							|  |  |  |  | import random | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | import worlds.smz3.TotalSMZ3.Region as Region | 
					
						
							|  |  |  |  | import worlds.smz3.TotalSMZ3.Config as Config | 
					
						
							|  |  |  |  | import worlds.smz3.TotalSMZ3.Item as Item | 
					
						
							|  |  |  |  | import worlds.smz3.TotalSMZ3.Location as Location | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | from worlds.smz3.TotalSMZ3.Regions.Zelda.CastleTower import CastleTower | 
					
						
							|  |  |  |  | from worlds.smz3.TotalSMZ3.Regions.Zelda.EasternPalace import EasternPalace | 
					
						
							|  |  |  |  | from worlds.smz3.TotalSMZ3.Regions.Zelda.DesertPalace import DesertPalace | 
					
						
							|  |  |  |  | from worlds.smz3.TotalSMZ3.Regions.Zelda.TowerOfHera import TowerOfHera | 
					
						
							|  |  |  |  | from worlds.smz3.TotalSMZ3.Regions.Zelda.PalaceOfDarkness import PalaceOfDarkness | 
					
						
							|  |  |  |  | from worlds.smz3.TotalSMZ3.Regions.Zelda.SwampPalace import SwampPalace | 
					
						
							|  |  |  |  | from worlds.smz3.TotalSMZ3.Regions.Zelda.SkullWoods import SkullWoods | 
					
						
							|  |  |  |  | from worlds.smz3.TotalSMZ3.Regions.Zelda.ThievesTown import ThievesTown | 
					
						
							|  |  |  |  | from worlds.smz3.TotalSMZ3.Regions.Zelda.IcePalace import IcePalace | 
					
						
							|  |  |  |  | from worlds.smz3.TotalSMZ3.Regions.Zelda.MiseryMire import MiseryMire | 
					
						
							|  |  |  |  | from worlds.smz3.TotalSMZ3.Regions.Zelda.TurtleRock import TurtleRock | 
					
						
							|  |  |  |  | from worlds.smz3.TotalSMZ3.Regions.Zelda.GanonsTower import GanonsTower | 
					
						
							|  |  |  |  | from worlds.smz3.TotalSMZ3.Regions.Zelda.LightWorld.DeathMountain.West import West as LightWorldDeathMountainWest | 
					
						
							|  |  |  |  | from worlds.smz3.TotalSMZ3.Regions.Zelda.LightWorld.DeathMountain.East import East as LightWorldDeathMountainEast | 
					
						
							|  |  |  |  | from worlds.smz3.TotalSMZ3.Regions.Zelda.LightWorld.NorthWest import NorthWest as LightWorldNorthWest | 
					
						
							|  |  |  |  | from worlds.smz3.TotalSMZ3.Regions.Zelda.LightWorld.NorthEast import NorthEast as LightWorldNorthEast | 
					
						
							|  |  |  |  | from worlds.smz3.TotalSMZ3.Regions.Zelda.LightWorld.South import South as LightWorldSouth | 
					
						
							|  |  |  |  | from worlds.smz3.TotalSMZ3.Regions.Zelda.HyruleCastle import HyruleCastle | 
					
						
							|  |  |  |  | from worlds.smz3.TotalSMZ3.Regions.Zelda.DarkWorld.DeathMountain.West import West as DarkWorldDeathMountainWest | 
					
						
							|  |  |  |  | from worlds.smz3.TotalSMZ3.Regions.Zelda.DarkWorld.DeathMountain.East import East as DarkWorldDeathMountainEast | 
					
						
							|  |  |  |  | from worlds.smz3.TotalSMZ3.Regions.Zelda.DarkWorld.NorthWest import NorthWest as DarkWorldNorthWest | 
					
						
							|  |  |  |  | from worlds.smz3.TotalSMZ3.Regions.Zelda.DarkWorld.NorthEast import NorthEast as DarkWorldNorthEast | 
					
						
							|  |  |  |  | from worlds.smz3.TotalSMZ3.Regions.Zelda.DarkWorld.South import South as DarkWorldSouth | 
					
						
							|  |  |  |  | from worlds.smz3.TotalSMZ3.Regions.Zelda.DarkWorld.Mire import Mire as DarkWorldMire | 
					
						
							|  |  |  |  | from worlds.smz3.TotalSMZ3.Regions.SuperMetroid.Crateria.Central import Central | 
					
						
							|  |  |  |  | from worlds.smz3.TotalSMZ3.Regions.SuperMetroid.Crateria.West import West as CrateriaWest  | 
					
						
							|  |  |  |  | from worlds.smz3.TotalSMZ3.Regions.SuperMetroid.Crateria.East import East as CrateriaEast | 
					
						
							|  |  |  |  | from worlds.smz3.TotalSMZ3.Regions.SuperMetroid.Brinstar.Blue import Blue | 
					
						
							|  |  |  |  | from worlds.smz3.TotalSMZ3.Regions.SuperMetroid.Brinstar.Green import Green | 
					
						
							|  |  |  |  | from worlds.smz3.TotalSMZ3.Regions.SuperMetroid.Brinstar.Kraid import Kraid | 
					
						
							|  |  |  |  | from worlds.smz3.TotalSMZ3.Regions.SuperMetroid.Brinstar.Pink import Pink | 
					
						
							|  |  |  |  | from worlds.smz3.TotalSMZ3.Regions.SuperMetroid.Brinstar.Red import Red | 
					
						
							|  |  |  |  | from worlds.smz3.TotalSMZ3.Regions.SuperMetroid.Maridia.Outer import Outer | 
					
						
							|  |  |  |  | from worlds.smz3.TotalSMZ3.Regions.SuperMetroid.Maridia.Inner import Inner | 
					
						
							|  |  |  |  | from worlds.smz3.TotalSMZ3.Regions.SuperMetroid.NorfairUpper.West import West as NorfairUpperWest | 
					
						
							|  |  |  |  | from worlds.smz3.TotalSMZ3.Regions.SuperMetroid.NorfairUpper.East import East as NorfairUpperEast | 
					
						
							|  |  |  |  | from worlds.smz3.TotalSMZ3.Regions.SuperMetroid.NorfairUpper.Crocomire import Crocomire | 
					
						
							|  |  |  |  | from worlds.smz3.TotalSMZ3.Regions.SuperMetroid.NorfairLower.West import West as NorfairLowerWest | 
					
						
							|  |  |  |  | from worlds.smz3.TotalSMZ3.Regions.SuperMetroid.NorfairLower.East import East as NorfairLowerEast | 
					
						
							|  |  |  |  | from worlds.smz3.TotalSMZ3.Regions.SuperMetroid.WreckedShip import WreckedShip | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | class World: | 
					
						
							|  |  |  |  |     Locations: List[Location.Location] | 
					
						
							|  |  |  |  |     Regions: List[Region.Region] | 
					
						
							|  |  |  |  |     Config: Config.Config | 
					
						
							|  |  |  |  |     Player: str | 
					
						
							|  |  |  |  |     Guid: str | 
					
						
							|  |  |  |  |     Id: int | 
					
						
							| 
									
										
										
										
											2022-08-15 10:48:13 -04:00
										 |  |  |  |     WorldState = None | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     @property | 
					
						
							|  |  |  |  |     def TowerCrystals(self): | 
					
						
							|  |  |  |  |         return 7 if self.WorldState is None else self.WorldState.TowerCrystals | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     @property | 
					
						
							|  |  |  |  |     def GanonCrystals(self): | 
					
						
							|  |  |  |  |         return  7 if self.WorldState is None else self.WorldState.GanonCrystals | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     @property | 
					
						
							|  |  |  |  |     def TourianBossTokens(self): | 
					
						
							|  |  |  |  |         return 4 if self.WorldState is None else self.WorldState.TourianBossTokens | 
					
						
							| 
									
										
										
										
											2022-03-15 08:55:57 -04:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |     def Items(self): | 
					
						
							|  |  |  |  |         return [l.Item for l in self.Locations if l.Item != None] | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-15 10:48:13 -04:00
										 |  |  |  |     ForwardSearch: bool = False | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     rewardLookup: Dict[int, List[Region.IReward]] | 
					
						
							| 
									
										
										
										
											2022-03-15 08:55:57 -04:00
										 |  |  |  |     locationLookup: Dict[str, Location.Location] | 
					
						
							|  |  |  |  |     regionLookup: Dict[str, Region.Region] | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     def GetLocation(self, name:str): return self.locationLookup[name] | 
					
						
							|  |  |  |  |     def GetRegion(self, name:str): return self.regionLookup[name] | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     def __init__(self, config: Config, player: str, id: int, guid: str): | 
					
						
							|  |  |  |  |         self.Config = config | 
					
						
							|  |  |  |  |         self.Player = player | 
					
						
							|  |  |  |  |         self.Id = id | 
					
						
							|  |  |  |  |         self.Guid = guid | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         self.Regions = [ | 
					
						
							|  |  |  |  |             CastleTower(self, self.Config), | 
					
						
							|  |  |  |  |             EasternPalace(self, self.Config), | 
					
						
							|  |  |  |  |             DesertPalace(self, self.Config), | 
					
						
							|  |  |  |  |             TowerOfHera(self, self.Config), | 
					
						
							|  |  |  |  |             PalaceOfDarkness(self, self.Config), | 
					
						
							|  |  |  |  |             SwampPalace(self, self.Config), | 
					
						
							|  |  |  |  |             SkullWoods(self, self.Config), | 
					
						
							|  |  |  |  |             ThievesTown(self, self.Config), | 
					
						
							|  |  |  |  |             IcePalace(self, self.Config), | 
					
						
							|  |  |  |  |             MiseryMire(self, self.Config), | 
					
						
							|  |  |  |  |             TurtleRock(self, self.Config), | 
					
						
							|  |  |  |  |             GanonsTower(self, self.Config), | 
					
						
							|  |  |  |  |             LightWorldDeathMountainWest(self, self.Config), | 
					
						
							|  |  |  |  |             LightWorldDeathMountainEast(self, self.Config), | 
					
						
							|  |  |  |  |             LightWorldNorthWest(self, self.Config), | 
					
						
							|  |  |  |  |             LightWorldNorthEast(self, self.Config), | 
					
						
							|  |  |  |  |             LightWorldSouth(self, self.Config), | 
					
						
							|  |  |  |  |             HyruleCastle(self, self.Config), | 
					
						
							|  |  |  |  |             DarkWorldDeathMountainWest(self, self.Config), | 
					
						
							|  |  |  |  |             DarkWorldDeathMountainEast(self, self.Config), | 
					
						
							|  |  |  |  |             DarkWorldNorthWest(self, self.Config), | 
					
						
							|  |  |  |  |             DarkWorldNorthEast(self, self.Config), | 
					
						
							|  |  |  |  |             DarkWorldSouth(self, self.Config), | 
					
						
							|  |  |  |  |             DarkWorldMire(self, self.Config), | 
					
						
							|  |  |  |  |             CrateriaWest(self, self.Config), | 
					
						
							| 
									
										
										
										
											2022-08-15 10:48:13 -04:00
										 |  |  |  |             Central(self, self.Config), | 
					
						
							| 
									
										
										
										
											2022-03-15 08:55:57 -04:00
										 |  |  |  |             CrateriaEast(self, self.Config), | 
					
						
							|  |  |  |  |             Blue(self, self.Config), | 
					
						
							|  |  |  |  |             Green(self, self.Config), | 
					
						
							|  |  |  |  |             Pink(self, self.Config), | 
					
						
							|  |  |  |  |             Red(self, self.Config), | 
					
						
							| 
									
										
										
										
											2022-08-15 10:48:13 -04:00
										 |  |  |  |             Kraid(self, self.Config), | 
					
						
							|  |  |  |  |             WreckedShip(self, self.Config), | 
					
						
							| 
									
										
										
										
											2022-03-15 08:55:57 -04:00
										 |  |  |  |             Outer(self, self.Config), | 
					
						
							|  |  |  |  |             Inner(self, self.Config), | 
					
						
							|  |  |  |  |             NorfairUpperWest(self, self.Config), | 
					
						
							|  |  |  |  |             NorfairUpperEast(self, self.Config), | 
					
						
							|  |  |  |  |             Crocomire(self, self.Config), | 
					
						
							|  |  |  |  |             NorfairLowerWest(self, self.Config), | 
					
						
							| 
									
										
										
										
											2022-08-15 10:48:13 -04:00
										 |  |  |  |             NorfairLowerEast(self, self.Config) | 
					
						
							| 
									
										
										
										
											2022-03-15 08:55:57 -04:00
										 |  |  |  |         ] | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         self.Locations = [] | 
					
						
							|  |  |  |  |         for r in self.Regions: | 
					
						
							|  |  |  |  |             self.Locations = self.Locations + r.Locations | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         self.regionLookup = {r.Name:r for r in self.Regions} | 
					
						
							|  |  |  |  |         self.locationLookup = {loc.Name:loc for loc in self.Locations} | 
					
						
							|  |  |  |  |          | 
					
						
							|  |  |  |  |         for region in self.Regions: | 
					
						
							|  |  |  |  |             region.GenerateLocationLookup() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     def CanEnter(self, regionName: str, items: Item.Progression): | 
					
						
							|  |  |  |  |         region = self.regionLookup[regionName] | 
					
						
							|  |  |  |  |         if (region == None): | 
					
						
							|  |  |  |  |             raise Exception(f"World.CanEnter: Invalid region name {regionName}", f'{regionName=}'.partition('=')[0]) | 
					
						
							|  |  |  |  |         return region.CanEnter(items) | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-15 10:48:13 -04:00
										 |  |  |  |     def CanAcquire(self, items: Item.Progression, reward: Region.RewardType): | 
					
						
							| 
									
										
										
										
											2022-03-15 08:55:57 -04:00
										 |  |  |  |         return next(iter([region for region in self.Regions if isinstance(region, Region.IReward) and region.Reward == reward])).CanComplete(items) | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-15 10:48:13 -04:00
										 |  |  |  |     def CanAcquireAll(self, items: Item.Progression, rewardsMask: Region.RewardType): | 
					
						
							|  |  |  |  |         return all(region.CanComplete(items) for region in self.rewardLookup[rewardsMask.value]) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     def CanAcquireAtLeast(self, amount, items: Item.Progression, rewardsMask: Region.RewardType): | 
					
						
							|  |  |  |  |             return len([region for region in self.rewardLookup[rewardsMask.value] if region.CanComplete(items)]) >= amount | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     def Setup(self, state): | 
					
						
							|  |  |  |  |         self.WorldState = state | 
					
						
							|  |  |  |  |         self.SetMedallions(state.Medallions) | 
					
						
							|  |  |  |  |         self.SetRewards(state.Rewards) | 
					
						
							|  |  |  |  |         self.SetRewardLookup() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     def SetRewards(self, rewards: List): | 
					
						
							|  |  |  |  |         regions = [region for region in self.Regions if isinstance(region, Region.IReward) and region.Reward == Region.RewardType.Null] | 
					
						
							|  |  |  |  |         for (region, reward) in zip(regions, rewards): | 
					
						
							|  |  |  |  |             region.Reward = reward | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     def SetMedallions(self, medallions: List): | 
					
						
							|  |  |  |  |         self.GetRegion("Misery Mire").Medallion = medallions[0] | 
					
						
							|  |  |  |  |         self.GetRegion("Turtle Rock").Medallion = medallions[1] | 
					
						
							| 
									
										
										
										
											2022-03-15 08:55:57 -04:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-15 10:48:13 -04:00
										 |  |  |  |     def SetRewardLookup(self): | 
					
						
							|  |  |  |  |         #/* Generate a lookup of all possible regions for any given reward combination for faster lookup later */ | 
					
						
							|  |  |  |  |         self.rewardLookup: Dict[int, Region.IReward] = {} | 
					
						
							|  |  |  |  |         for i in range(0, 512): | 
					
						
							|  |  |  |  |             self.rewardLookup[i] = [region for region in self.Regions if isinstance(region, Region.IReward) and (region.Reward.value & i) != 0] |