Archipelago/worlds/smz3/TotalSMZ3/World.py

178 lines
7.8 KiB
Python

from typing import Dict, List
import random
from . import Region
from . import Config
from . import Item
from . import Location
from .Regions.Zelda.CastleTower import CastleTower
from .Regions.Zelda.EasternPalace import EasternPalace
from .Regions.Zelda.DesertPalace import DesertPalace
from .Regions.Zelda.TowerOfHera import TowerOfHera
from .Regions.Zelda.PalaceOfDarkness import PalaceOfDarkness
from .Regions.Zelda.SwampPalace import SwampPalace
from .Regions.Zelda.SkullWoods import SkullWoods
from .Regions.Zelda.ThievesTown import ThievesTown
from .Regions.Zelda.IcePalace import IcePalace
from .Regions.Zelda.MiseryMire import MiseryMire
from .Regions.Zelda.TurtleRock import TurtleRock
from .Regions.Zelda.GanonsTower import GanonsTower
from .Regions.Zelda.LightWorld.DeathMountain.West import West as LightWorldDeathMountainWest
from .Regions.Zelda.LightWorld.DeathMountain.East import East as LightWorldDeathMountainEast
from .Regions.Zelda.LightWorld.NorthWest import NorthWest as LightWorldNorthWest
from .Regions.Zelda.LightWorld.NorthEast import NorthEast as LightWorldNorthEast
from .Regions.Zelda.LightWorld.South import South as LightWorldSouth
from .Regions.Zelda.HyruleCastle import HyruleCastle
from .Regions.Zelda.DarkWorld.DeathMountain.West import West as DarkWorldDeathMountainWest
from .Regions.Zelda.DarkWorld.DeathMountain.East import East as DarkWorldDeathMountainEast
from .Regions.Zelda.DarkWorld.NorthWest import NorthWest as DarkWorldNorthWest
from .Regions.Zelda.DarkWorld.NorthEast import NorthEast as DarkWorldNorthEast
from .Regions.Zelda.DarkWorld.South import South as DarkWorldSouth
from .Regions.Zelda.DarkWorld.Mire import Mire as DarkWorldMire
from .Regions.SuperMetroid.Crateria.Central import Central
from .Regions.SuperMetroid.Crateria.West import West as CrateriaWest
from .Regions.SuperMetroid.Crateria.East import East as CrateriaEast
from .Regions.SuperMetroid.Brinstar.Blue import Blue
from .Regions.SuperMetroid.Brinstar.Green import Green
from .Regions.SuperMetroid.Brinstar.Kraid import Kraid
from .Regions.SuperMetroid.Brinstar.Pink import Pink
from .Regions.SuperMetroid.Brinstar.Red import Red
from .Regions.SuperMetroid.Maridia.Outer import Outer
from .Regions.SuperMetroid.Maridia.Inner import Inner
from .Regions.SuperMetroid.NorfairUpper.West import West as NorfairUpperWest
from .Regions.SuperMetroid.NorfairUpper.East import East as NorfairUpperEast
from .Regions.SuperMetroid.NorfairUpper.Crocomire import Crocomire
from .Regions.SuperMetroid.NorfairLower.West import West as NorfairLowerWest
from .Regions.SuperMetroid.NorfairLower.East import East as NorfairLowerEast
from .Regions.SuperMetroid.WreckedShip import WreckedShip
class World:
Locations: List[Location.Location]
Regions: List[Region.Region]
Config: Config.Config
Player: str
Guid: str
Id: int
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
def Items(self):
return [l.Item for l in self.Locations if l.Item != None]
ForwardSearch: bool = False
rewardLookup: Dict[int, List[Region.IReward]]
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),
Central(self, self.Config),
CrateriaEast(self, self.Config),
Blue(self, self.Config),
Green(self, self.Config),
Pink(self, self.Config),
Red(self, self.Config),
Kraid(self, self.Config),
WreckedShip(self, self.Config),
Outer(self, self.Config),
Inner(self, self.Config),
NorfairUpperWest(self, self.Config),
NorfairUpperEast(self, self.Config),
Crocomire(self, self.Config),
NorfairLowerWest(self, self.Config),
NorfairLowerEast(self, self.Config)
]
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)
def CanAcquire(self, items: Item.Progression, reward: Region.RewardType):
return next(iter([region for region in self.Regions if isinstance(region, Region.IReward) and region.Reward == reward])).CanComplete(items)
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]
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]