Archipelago/worlds/smz3/TotalSMZ3/Location.py

112 lines
3.7 KiB
Python

from enum import Enum
from typing import List, Callable
from .Item import Progression
from . import Region
from . import World
class LocationType(Enum):
Regular = 0
HeraStandingKey = 1
Pedestal = 2
Ether = 3
Bombos = 4
NotInDungeon = 5
Visible = 6
Chozo = 7
Hidden = 8
# delegate bool Requirement(Progression items);
# delegate bool Verification(Item item, Progression items);
class Location:
Id: int
Name: str
Type: LocationType
Address: int
Region: Region
def Weight(self): return self.weight if self.weight != None else self.Region.Weight
canAccess: Callable = lambda items: True
alwaysAllow: Callable = lambda item, items: True
allow: Callable = lambda item, items: True
weight: int
def ItemIs(self, type, world: World):
item = self.APLocation.item.item if self.APLocation.item is not None and self.APLocation.item.game == "SMZ3" else None
return item.Is(type, world) if item != None else False
def ItemIsNot(self, type, world: World): return not self.ItemIs(type, world)
def __init__(self, region: Region, id: int, address: int, type: LocationType, name: str, access: Callable = lambda items : True):
self.Region = region
self.Id = id
self.Name = name
self.Type = type
self.Item = None
self.Address = address
self.canAccess = access
self.alwaysAllow = lambda item, items: False
self.allow = lambda item, items: True
def Weighted(self, weight: int):
self.weight = weight
return self
def AlwaysAllow(self, allow: Callable):
self.alwaysAllow = allow
return self
def Allow(self, allow: Callable):
self.allow = allow
return self
def Available(self, items: Progression):
return self.Region.CanEnter(items) and self.canAccess(items)
def CanFill(self, item, items: Progression):
oldItem = self.Item
self.Item = item
fillable = self.alwaysAllow(item, items) or (self.Region.CanFill(item) and self.allow(item, items) and self.Available(items))
self.Item = oldItem
return fillable
@staticmethod
def Get(locations, name: str):
loc = next((l for l in locations if l.Name == name), None)
if (loc == None):
raise Exception(f"Could not find location name {name}")
return loc
@staticmethod
def Empty(locations):
return [l for l in locations if l.Item == None]
@staticmethod
def Filled(locations):
return [l for l in locations if l.Item != None]
@staticmethod
def AvailableWithinWorld(locations, items):
result = []
worldList = []
[worldList.append(l.Region.World) for l in locations if l.Region.World not in worldList]
for world in worldList:
result += Location.AvailableGlobal([l for l in locations if l.Region.World == world], [i for i in items if i.World == world])
return result
@staticmethod
def AvailableGlobal(locations, items):
progression = Progression(items)
return [l for l in locations if l.Available(progression)]
@staticmethod
def CanFillWithinWorld(locations, item, items):
itemWorldProgression = Progression([i for i in items if i.World == item.World].append(item))
worldList = []
[worldList.append(l.Region.World) for l in locations if l.Region.World not in worldList]
worldProgression = {world.Id : Progression([i for i in items if i.World == world]) for world in worldList}
return [l for l in locations if l.CanFill(item, worldProgression[l.Region.World.Id] and next(ll for ll in item.World.Locations if ll.Id == l.Id).Available(itemWorldProgression))]
# Start of AP integration
locations_start_id = 85000