| 
									
										
										
										
											2021-11-12 08:00:11 -05:00
										 |  |  | import random | 
					
						
							|  |  |  | import copy | 
					
						
							|  |  |  | from logic.smbool import SMBool | 
					
						
							|  |  |  | from rom.rom_patches import RomPatches | 
					
						
							|  |  |  | import utils.log, logging | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | LOG = utils.log.get('DoorsManager') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | colorsList = ['red', 'green', 'yellow', 'wave', 'spazer', 'plasma', 'ice'] | 
					
						
							|  |  |  | # 1/15 chance to have the door set to grey | 
					
						
							|  |  |  | colorsListGrey = colorsList * 2 + ['grey'] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Facing: | 
					
						
							|  |  |  |     Left = 0 | 
					
						
							|  |  |  |     Right = 1 | 
					
						
							|  |  |  |     Top = 2 | 
					
						
							|  |  |  |     Bottom = 3 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # door facing left - right - top   - bottom | 
					
						
							|  |  |  | plmRed    = [0xc88a, 0xc890, 0xc896, 0xc89c] | 
					
						
							|  |  |  | plmGreen  = [0xc872, 0xc878, 0xc87e, 0xc884] | 
					
						
							|  |  |  | plmYellow = [0xc85a, 0xc860, 0xc866, 0xc86c] | 
					
						
							|  |  |  | plmGrey   = [0xc842, 0xc848, 0xc84e, 0xc854] | 
					
						
							|  |  |  | plmWave   = [0xf763, 0xf769, 0xf70f, 0xf715] | 
					
						
							|  |  |  | plmSpazer = [0xf733, 0xf739, 0xf73f, 0xf745] | 
					
						
							|  |  |  | plmPlasma = [0xf74b, 0xf751, 0xf757, 0xf75d] | 
					
						
							|  |  |  | plmIce    = [0xf71b, 0xf721, 0xf727, 0xf72d] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | colors2plm = { | 
					
						
							|  |  |  |     'red': plmRed, | 
					
						
							|  |  |  |     'green': plmGreen, | 
					
						
							|  |  |  |     'yellow': plmYellow, | 
					
						
							|  |  |  |     'grey': plmGrey, | 
					
						
							|  |  |  |     'wave': plmWave, | 
					
						
							|  |  |  |     'spazer': plmSpazer, | 
					
						
							|  |  |  |     'plasma': plmPlasma, | 
					
						
							|  |  |  |     'ice': plmIce | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Door(object): | 
					
						
							|  |  |  |     __slots__ = ('name', 'address', 'vanillaColor', 'color', 'forced', 'facing', 'hidden', 'id', 'canGrey', 'forbiddenColors') | 
					
						
							|  |  |  |     def __init__(self, name, address, vanillaColor, facing, id=None, canGrey=False, forbiddenColors=None): | 
					
						
							|  |  |  |         self.name = name | 
					
						
							|  |  |  |         self.address = address | 
					
						
							|  |  |  |         self.vanillaColor = vanillaColor | 
					
						
							|  |  |  |         self.setColor(vanillaColor) | 
					
						
							|  |  |  |         self.forced = False | 
					
						
							|  |  |  |         self.facing = facing | 
					
						
							|  |  |  |         self.hidden = False | 
					
						
							|  |  |  |         self.canGrey = canGrey | 
					
						
							|  |  |  |         self.id = id | 
					
						
							|  |  |  |         # list of forbidden colors | 
					
						
							|  |  |  |         self.forbiddenColors = forbiddenColors | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def forceBlue(self): | 
					
						
							|  |  |  |         # custom start location, area, patches can force doors to blue | 
					
						
							|  |  |  |         self.setColor('blue') | 
					
						
							|  |  |  |         self.forced = True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def setColor(self, color): | 
					
						
							|  |  |  |         self.color = color | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def getColor(self): | 
					
						
							|  |  |  |         if self.hidden: | 
					
						
							|  |  |  |             return 'grey' | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             return self.color | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def isRandom(self): | 
					
						
							|  |  |  |         return self.color != self.vanillaColor and not self.isBlue() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def isBlue(self): | 
					
						
							|  |  |  |         return self.color == 'blue' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def canRandomize(self): | 
					
						
							|  |  |  |         return not self.forced and self.id is None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def filterColorList(self, colorsList): | 
					
						
							|  |  |  |         if self.forbiddenColors is None: | 
					
						
							|  |  |  |             return colorsList | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             return [color for color in colorsList if color not in self.forbiddenColors] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def randomize(self, allowGreyDoors): | 
					
						
							|  |  |  |         if self.canRandomize(): | 
					
						
							|  |  |  |             if self.canGrey and allowGreyDoors: | 
					
						
							|  |  |  |                 self.setColor(random.choice(self.filterColorList(colorsListGrey))) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 self.setColor(random.choice(self.filterColorList(colorsList))) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def traverse(self, smbm): | 
					
						
							|  |  |  |         if self.hidden or self.color == 'grey': | 
					
						
							|  |  |  |             return SMBool(False) | 
					
						
							|  |  |  |         elif self.color == 'red': | 
					
						
							|  |  |  |             return smbm.canOpenRedDoors() | 
					
						
							|  |  |  |         elif self.color == 'green': | 
					
						
							|  |  |  |             return smbm.canOpenGreenDoors() | 
					
						
							|  |  |  |         elif self.color == 'yellow': | 
					
						
							|  |  |  |             return smbm.canOpenYellowDoors() | 
					
						
							|  |  |  |         elif self.color == 'wave': | 
					
						
							|  |  |  |             return smbm.haveItem('Wave') | 
					
						
							|  |  |  |         elif self.color == 'spazer': | 
					
						
							|  |  |  |             return smbm.haveItem('Spazer') | 
					
						
							|  |  |  |         elif self.color == 'plasma': | 
					
						
							|  |  |  |             return smbm.haveItem('Plasma') | 
					
						
							|  |  |  |         elif self.color == 'ice': | 
					
						
							|  |  |  |             return smbm.haveItem('Ice') | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             return SMBool(True) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __repr__(self): | 
					
						
							|  |  |  |         return "Door({}, {})".format(self.name, self.color) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def isRefillSave(self): | 
					
						
							|  |  |  |         return self.address is None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def writeColor(self, rom): | 
					
						
							|  |  |  |         if self.isBlue() or self.isRefillSave(): | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         rom.writeWord(colors2plm[self.color][self.facing], self.address) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # also set plm args high byte to never opened, even during escape | 
					
						
							|  |  |  |         if self.color == 'grey': | 
					
						
							|  |  |  |             rom.writeByte(0x90, self.address+5) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def readColor(self, rom): | 
					
						
							|  |  |  |         if self.forced or self.isRefillSave(): | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         plm = rom.readWord(self.address) | 
					
						
							|  |  |  |         if plm in plmRed: | 
					
						
							|  |  |  |             self.setColor('red') | 
					
						
							|  |  |  |         elif plm in plmGreen: | 
					
						
							|  |  |  |             self.setColor('green') | 
					
						
							|  |  |  |         elif plm in plmYellow: | 
					
						
							|  |  |  |             self.setColor('yellow') | 
					
						
							|  |  |  |         elif plm in plmGrey: | 
					
						
							|  |  |  |             self.setColor('grey') | 
					
						
							|  |  |  |         elif plm in plmWave: | 
					
						
							|  |  |  |             self.setColor('wave') | 
					
						
							|  |  |  |         elif plm in plmSpazer: | 
					
						
							|  |  |  |             self.setColor('spazer') | 
					
						
							|  |  |  |         elif plm in plmPlasma: | 
					
						
							|  |  |  |             self.setColor('plasma') | 
					
						
							|  |  |  |         elif plm in plmIce: | 
					
						
							|  |  |  |             self.setColor('ice') | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             raise Exception("Unknown color {} for {}".format(hex(plm), self.name)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # for tracker | 
					
						
							|  |  |  |     def canHide(self): | 
					
						
							|  |  |  |         return self.color != 'blue' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def hide(self): | 
					
						
							|  |  |  |         if self.canHide(): | 
					
						
							|  |  |  |             self.hidden = True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def reveal(self): | 
					
						
							|  |  |  |         self.hidden = False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def switch(self): | 
					
						
							|  |  |  |         if self.hidden: | 
					
						
							|  |  |  |             self.reveal() | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             self.hide() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # to send/receive state to tracker/plando | 
					
						
							|  |  |  |     def serialize(self): | 
					
						
							|  |  |  |         return (self.color, self.facing, self.hidden) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def unserialize(self, data): | 
					
						
							|  |  |  |         self.setColor(data[0]) | 
					
						
							|  |  |  |         self.facing = data[1] | 
					
						
							|  |  |  |         self.hidden = data[2] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class DoorsManager(): | 
					
						
							|  |  |  |     doorsDict = {} | 
					
						
							|  |  |  |     doors = { | 
					
						
							|  |  |  |         # crateria | 
					
						
							|  |  |  |         'LandingSiteRight': Door('LandingSiteRight', 0x78018, 'green', Facing.Left, canGrey=True), | 
					
						
							|  |  |  |         'LandingSiteTopRight': Door('LandingSiteTopRight', 0x07801e, 'yellow', Facing.Left), | 
					
						
							|  |  |  |         'KihunterBottom': Door('KihunterBottom', 0x78228, 'yellow', Facing.Top, canGrey=True), | 
					
						
							|  |  |  |         'KihunterRight': Door('KihunterRight', 0x78222, 'yellow', Facing.Left, canGrey=True), | 
					
						
							|  |  |  |         'FlywayRight': Door('FlywayRight', 0x78420, 'red', Facing.Left), | 
					
						
							|  |  |  |         'GreenPiratesShaftBottomRight': Door('GreenPiratesShaftBottomRight', 0x78470, 'red', Facing.Left, canGrey=True), | 
					
						
							|  |  |  |         'RedBrinstarElevatorTop': Door('RedBrinstarElevatorTop', 0x78256, 'yellow', Facing.Bottom), | 
					
						
							|  |  |  |         'ClimbRight': Door('ClimbRight', 0x78304, 'yellow', Facing.Left), | 
					
						
							|  |  |  |         # blue brinstar | 
					
						
							|  |  |  |         'ConstructionZoneRight': Door('ConstructionZoneRight', 0x78784, 'red', Facing.Left), | 
					
						
							|  |  |  |         # green brinstar | 
					
						
							|  |  |  |         'GreenHillZoneTopRight': Door('GreenHillZoneTopRight', 0x78670, 'yellow', Facing.Left, canGrey=True), | 
					
						
							|  |  |  |         'NoobBridgeRight': Door('NoobBridgeRight', 0x787a6, 'green', Facing.Left, canGrey=True), | 
					
						
							|  |  |  |         'MainShaftRight': Door('MainShaftRight', 0x784be, 'red', Facing.Left), | 
					
						
							|  |  |  |         'MainShaftBottomRight': Door('MainShaftBottomRight', 0x784c4, 'red', Facing.Left, canGrey=True), | 
					
						
							|  |  |  |         'EarlySupersRight': Door('EarlySupersRight', 0x78512, 'red', Facing.Left), | 
					
						
							|  |  |  |         'EtecoonEnergyTankLeft': Door('EtecoonEnergyTankLeft', 0x787c8, 'green', Facing.Right), | 
					
						
							|  |  |  |         # pink brinstar | 
					
						
							|  |  |  |         'BigPinkTopRight': Door('BigPinkTopRight', 0x78626, 'red', Facing.Left), | 
					
						
							|  |  |  |         'BigPinkRight': Door('BigPinkRight', 0x7861a, 'yellow', Facing.Left), | 
					
						
							|  |  |  |         'BigPinkBottomRight': Door('BigPinkBottomRight', 0x78620, 'green', Facing.Left, canGrey=True), | 
					
						
							|  |  |  |         'BigPinkBottomLeft': Door('BigPinkBottomLeft', 0x7862c, 'red', Facing.Right), | 
					
						
							|  |  |  |         # red brinstar | 
					
						
							|  |  |  |         'RedTowerLeft': Door('RedTowerLeft', 0x78866, 'yellow', Facing.Right), | 
					
						
							|  |  |  |         'RedBrinstarFirefleaLeft': Door('RedBrinstarFirefleaLeft', 0x7886e, 'red', Facing.Right), | 
					
						
							|  |  |  |         'RedTowerElevatorTopLeft': Door('RedTowerElevatorTopLeft', 0x788aa, 'green', Facing.Right), | 
					
						
							|  |  |  |         'RedTowerElevatorLeft': Door('RedTowerElevatorLeft', 0x788b0, 'yellow', Facing.Right), | 
					
						
							|  |  |  |         'RedTowerElevatorBottomLeft': Door('RedTowerElevatorBottomLeft', 0x788b6, 'green', Facing.Right), | 
					
						
							|  |  |  |         'BelowSpazerTopRight': Door('BelowSpazerTopRight', 0x78966, 'green', Facing.Left), | 
					
						
							|  |  |  |         # Wrecked ship | 
					
						
							|  |  |  |         'WestOceanRight': Door('WestOceanRight', 0x781e2, 'green', Facing.Left, canGrey=True), | 
					
						
							|  |  |  |         'LeCoudeBottom': Door('LeCoudeBottom', 0x7823e, 'yellow', Facing.Top, canGrey=True), | 
					
						
							|  |  |  |         'WreckedShipMainShaftBottom': Door('WreckedShipMainShaftBottom', 0x7c277, 'green', Facing.Top), | 
					
						
							|  |  |  |         'ElectricDeathRoomTopLeft': Door('ElectricDeathRoomTopLeft', 0x7c32f, 'red', Facing.Right), | 
					
						
							|  |  |  |         # Upper Norfair | 
					
						
							|  |  |  |         'BusinessCenterTopLeft': Door('BusinessCenterTopLeft', 0x78b00, 'green', Facing.Right), | 
					
						
							|  |  |  |         'BusinessCenterBottomLeft': Door('BusinessCenterBottomLeft', 0x78b0c, 'red', Facing.Right), | 
					
						
							|  |  |  |         'CathedralEntranceRight': Door('CathedralEntranceRight', 0x78af2, 'red', Facing.Left, canGrey=True), | 
					
						
							|  |  |  |         'CathedralRight': Door('CathedralRight', 0x78aea, 'green', Facing.Left), | 
					
						
							|  |  |  |         'BubbleMountainTopRight': Door('BubbleMountainTopRight', 0x78c60, 'green', Facing.Left), | 
					
						
							|  |  |  |         'BubbleMountainTopLeft': Door('BubbleMountainTopLeft', 0x78c5a, 'green', Facing.Right), | 
					
						
							|  |  |  |         'SpeedBoosterHallRight': Door('SpeedBoosterHallRight', 0x78c7a, 'red', Facing.Left), | 
					
						
							|  |  |  |         'SingleChamberRight': Door('SingleChamberRight', 0x78ca8, 'red', Facing.Left), | 
					
						
							|  |  |  |         'DoubleChamberRight': Door('DoubleChamberRight', 0x78cc2, 'red', Facing.Left), | 
					
						
							|  |  |  |         'KronicBoostBottomLeft': Door('KronicBoostBottomLeft', 0x78d4e, 'yellow', Facing.Right, canGrey=True), | 
					
						
							|  |  |  |         'CrocomireSpeedwayBottom': Door('CrocomireSpeedwayBottom', 0x78b96, 'green', Facing.Top, canGrey=True), | 
					
						
							|  |  |  |         # Crocomire | 
					
						
							|  |  |  |         'PostCrocomireUpperLeft': Door('PostCrocomireUpperLeft', 0x78bf4, 'red', Facing.Right), | 
					
						
							|  |  |  |         'PostCrocomireShaftRight': Door('PostCrocomireShaftRight', 0x78c0c, 'red', Facing.Left), | 
					
						
							|  |  |  |         # Lower Norfair | 
					
						
							|  |  |  |         'RedKihunterShaftBottom': Door('RedKihunterShaftBottom', 0x7902e, 'yellow', Facing.Top), | 
					
						
							|  |  |  |         'WastelandLeft': Door('WastelandLeft', 0x790ba, 'green', Facing.Right, forbiddenColors=['yellow']), | 
					
						
							|  |  |  |         # Maridia | 
					
						
							|  |  |  |         'MainStreetBottomRight': Door('MainStreetBottomRight', 0x7c431, 'red', Facing.Left), | 
					
						
							|  |  |  |         'FishTankRight': Door('FishTankRight', 0x7c475, 'red', Facing.Left), | 
					
						
							|  |  |  |         'CrabShaftRight': Door('CrabShaftRight', 0x7c4fb, 'green', Facing.Left), | 
					
						
							|  |  |  |         'ColosseumBottomRight': Door('ColosseumBottomRight', 0x7c6fb, 'green', Facing.Left), | 
					
						
							|  |  |  |         'PlasmaSparkBottom': Door('PlasmaSparkBottom', 0x7c577, 'green', Facing.Top), | 
					
						
							|  |  |  |         'OasisTop': Door('OasisTop', 0x7c5d3, 'green', Facing.Bottom), | 
					
						
							|  |  |  |         # refill/save | 
					
						
							|  |  |  |         'GreenBrinstarSaveStation': Door('GreenBrinstarSaveStation', None, 'red', Facing.Right, id=0x1f), | 
					
						
							|  |  |  |         'MaridiaBottomSaveStation': Door('MaridiaBottomSaveStation', None, 'red', Facing.Left, id=0x8c), | 
					
						
							|  |  |  |         'MaridiaAqueductSaveStation': Door('MaridiaAqueductSaveStation', None, 'red', Facing.Right, id=0x96), | 
					
						
							|  |  |  |         'ForgottenHighwaySaveStation': Door('ForgottenHighwaySaveStation', None, 'red', Facing.Left, id=0x92), | 
					
						
							|  |  |  |         'DraygonSaveRefillStation': Door('DraygonSaveRefillStation', None, 'red', Facing.Left, id=0x98), | 
					
						
							|  |  |  |         'KraidRefillStation': Door('KraidRefillStation', None, 'green', Facing.Left, id=0x44), | 
					
						
							|  |  |  |         'RedBrinstarEnergyRefill': Door('RedBrinstarEnergyRefill', None, 'green', Facing.Right, id=0x38), | 
					
						
							|  |  |  |         'GreenBrinstarMissileRefill': Door('GreenBrinstarMissileRefill', None, 'red', Facing.Right, id=0x23) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # call from logic | 
					
						
							|  |  |  |     def traverse(self, smbm, doorName): | 
					
						
							|  |  |  |         return DoorsManager.doorsDict[smbm.player][doorName].traverse(smbm) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @staticmethod | 
					
						
							|  |  |  |     def setDoorsColor(player=0): | 
					
						
							| 
									
										
										
										
											2022-05-15 10:29:56 -04:00
										 |  |  |         DoorsManager.doorsDict[player] = copy.deepcopy(DoorsManager.doors) | 
					
						
							| 
									
										
										
										
											2021-11-12 08:00:11 -05:00
										 |  |  |         currentDoors = DoorsManager.doorsDict[player] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # depending on loaded patches, force some doors to blue, excluding them from randomization | 
					
						
							|  |  |  |         if RomPatches.has(player, RomPatches.BlueBrinstarBlueDoor): | 
					
						
							|  |  |  |             currentDoors['ConstructionZoneRight'].forceBlue() | 
					
						
							|  |  |  |         if RomPatches.has(player, RomPatches.BrinReserveBlueDoors): | 
					
						
							|  |  |  |             currentDoors['MainShaftRight'].forceBlue() | 
					
						
							|  |  |  |             currentDoors['EarlySupersRight'].forceBlue() | 
					
						
							|  |  |  |         if RomPatches.has(player, RomPatches.EtecoonSupersBlueDoor): | 
					
						
							|  |  |  |             currentDoors['EtecoonEnergyTankLeft'].forceBlue() | 
					
						
							|  |  |  |         #if RomPatches.has(player, RomPatches.SpongeBathBlueDoor): | 
					
						
							|  |  |  |         #    currentDoors[''].forceBlue() | 
					
						
							|  |  |  |         if RomPatches.has(player, RomPatches.HiJumpAreaBlueDoor): | 
					
						
							|  |  |  |             currentDoors['BusinessCenterBottomLeft'].forceBlue() | 
					
						
							|  |  |  |         if RomPatches.has(player, RomPatches.SpeedAreaBlueDoors): | 
					
						
							|  |  |  |             currentDoors['BubbleMountainTopRight'].forceBlue() | 
					
						
							|  |  |  |             currentDoors['SpeedBoosterHallRight'].forceBlue() | 
					
						
							|  |  |  |         if RomPatches.has(player, RomPatches.MamaTurtleBlueDoor): | 
					
						
							|  |  |  |             currentDoors['FishTankRight'].forceBlue() | 
					
						
							|  |  |  |         if RomPatches.has(player, RomPatches.HellwayBlueDoor): | 
					
						
							|  |  |  |             currentDoors['RedTowerElevatorLeft'].forceBlue() | 
					
						
							|  |  |  |         if RomPatches.has(player, RomPatches.RedTowerBlueDoors): | 
					
						
							|  |  |  |             currentDoors['RedBrinstarElevatorTop'].forceBlue() | 
					
						
							|  |  |  |         if RomPatches.has(player, RomPatches.AreaRandoBlueDoors): | 
					
						
							|  |  |  |             currentDoors['GreenHillZoneTopRight'].forceBlue() | 
					
						
							|  |  |  |             currentDoors['NoobBridgeRight'].forceBlue() | 
					
						
							|  |  |  |             currentDoors['LeCoudeBottom'].forceBlue() | 
					
						
							|  |  |  |             currentDoors['KronicBoostBottomLeft'].forceBlue() | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             # no area rando, prevent some doors to be in the grey doors pool | 
					
						
							|  |  |  |             currentDoors['GreenPiratesShaftBottomRight'].canGrey = False | 
					
						
							|  |  |  |             currentDoors['CrocomireSpeedwayBottom'].canGrey = False | 
					
						
							|  |  |  |             currentDoors['KronicBoostBottomLeft'].canGrey = False | 
					
						
							|  |  |  |         if RomPatches.has(player, RomPatches.AreaRandoMoreBlueDoors): | 
					
						
							|  |  |  |             currentDoors['KihunterBottom'].forceBlue() | 
					
						
							|  |  |  |             currentDoors['GreenPiratesShaftBottomRight'].forceBlue() | 
					
						
							|  |  |  |         if RomPatches.has(player, RomPatches.CrocBlueDoors): | 
					
						
							|  |  |  |             currentDoors['CrocomireSpeedwayBottom'].forceBlue() | 
					
						
							|  |  |  |         if RomPatches.has(player, RomPatches.CrabShaftBlueDoor): | 
					
						
							|  |  |  |             currentDoors['CrabShaftRight'].forceBlue() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @staticmethod | 
					
						
							|  |  |  |     def randomize(allowGreyDoors, player): | 
					
						
							|  |  |  |         for door in DoorsManager.doorsDict[player].values(): | 
					
						
							|  |  |  |             door.randomize(allowGreyDoors) | 
					
						
							|  |  |  |         # set both ends of toilet to the same color to avoid soft locking in area rando | 
					
						
							|  |  |  |         toiletTop = DoorsManager.doorsDict[player]['PlasmaSparkBottom'] | 
					
						
							|  |  |  |         toiletBottom = DoorsManager.doorsDict[player]['OasisTop'] | 
					
						
							|  |  |  |         if toiletTop.color != toiletBottom.color: | 
					
						
							|  |  |  |             toiletBottom.setColor(toiletTop.color) | 
					
						
							|  |  |  |         DoorsManager.debugDoorsColor() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # call from rom loader | 
					
						
							|  |  |  |     @staticmethod | 
					
						
							|  |  |  |     def loadDoorsColor(rom): | 
					
						
							|  |  |  |         # force to blue some doors depending on patches | 
					
						
							|  |  |  |         DoorsManager.setDoorsColor() | 
					
						
							|  |  |  |         # for each door store it's color | 
					
						
							|  |  |  |         for door in DoorsManager.doors.values(): | 
					
						
							|  |  |  |             door.readColor(rom) | 
					
						
							|  |  |  |         DoorsManager.debugDoorsColor() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # tell that we have randomized doors | 
					
						
							|  |  |  |         isRandom = DoorsManager.isRandom() | 
					
						
							|  |  |  |         if isRandom: | 
					
						
							|  |  |  |             DoorsManager.setRefillSaveToBlue() | 
					
						
							|  |  |  |         return isRandom | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @staticmethod | 
					
						
							|  |  |  |     def isRandom(player): | 
					
						
							|  |  |  |         return any(door.isRandom() for door in DoorsManager.doorsDict[player].values()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @staticmethod | 
					
						
							|  |  |  |     def setRefillSaveToBlue(player): | 
					
						
							|  |  |  |         for door in DoorsManager.doorsDict[player].values(): | 
					
						
							|  |  |  |             if door.id is not None: | 
					
						
							|  |  |  |                 door.forceBlue() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @staticmethod | 
					
						
							|  |  |  |     def debugDoorsColor(): | 
					
						
							|  |  |  |         if LOG.getEffectiveLevel() == logging.DEBUG: | 
					
						
							|  |  |  |             for door in DoorsManager.doors.values(): | 
					
						
							|  |  |  |                 LOG.debug("{:>32}: {:>6}".format(door.name, door.color)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # call from rom patcher | 
					
						
							|  |  |  |     @staticmethod | 
					
						
							|  |  |  |     def writeDoorsColor(rom, doors, player): | 
					
						
							|  |  |  |         for door in DoorsManager.doorsDict[player].values(): | 
					
						
							|  |  |  |             door.writeColor(rom) | 
					
						
							|  |  |  |             # also set save/refill doors to blue | 
					
						
							|  |  |  |             if door.id is not None: | 
					
						
							|  |  |  |                 doors.append(door.id) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # call from web | 
					
						
							|  |  |  |     @staticmethod | 
					
						
							|  |  |  |     def getAddressesToRead(): | 
					
						
							|  |  |  |         return [door.address for door in DoorsManager.doors.values() if door.address is not None] + [door.address+1 for door in DoorsManager.doors.values() if door.address is not None] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # for isolver state | 
					
						
							|  |  |  |     @staticmethod | 
					
						
							|  |  |  |     def serialize(): | 
					
						
							|  |  |  |         return {door.name: door.serialize() for door in DoorsManager.doors.values()} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @staticmethod | 
					
						
							|  |  |  |     def unserialize(state): | 
					
						
							|  |  |  |         for name, data in state.items(): | 
					
						
							|  |  |  |             DoorsManager.doors[name].unserialize(data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @staticmethod | 
					
						
							|  |  |  |     def allDoorsRevealed(): | 
					
						
							|  |  |  |         for door in DoorsManager.doors.values(): | 
					
						
							|  |  |  |             if door.hidden: | 
					
						
							|  |  |  |                 return False | 
					
						
							|  |  |  |         return True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # when using the tracker, first set all colored doors to grey until the user clicks on it | 
					
						
							|  |  |  |     @staticmethod | 
					
						
							|  |  |  |     def initTracker(): | 
					
						
							|  |  |  |         for door in DoorsManager.doors.values(): | 
					
						
							|  |  |  |             door.hide() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # when the user clicks on a door in the tracker | 
					
						
							|  |  |  |     @staticmethod | 
					
						
							|  |  |  |     def switchVisibility(name): | 
					
						
							|  |  |  |         DoorsManager.doors[name].switch() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # when the user clicks on a door in the race tracker or the plando | 
					
						
							|  |  |  |     @staticmethod | 
					
						
							|  |  |  |     def setColor(name, color): | 
					
						
							|  |  |  |         # in race mode the doors are hidden | 
					
						
							|  |  |  |         DoorsManager.doors[name].reveal() | 
					
						
							|  |  |  |         DoorsManager.doors[name].setColor(color) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # in autotracker we need the current doors state | 
					
						
							|  |  |  |     @staticmethod | 
					
						
							|  |  |  |     def getDoorsState(): | 
					
						
							|  |  |  |         hiddenDoors = set([door.name for door in DoorsManager.doors.values() if door.hidden]) | 
					
						
							|  |  |  |         revealedDoor = set([door.name for door in DoorsManager.doors.values() if (not door.hidden) and door.canHide()]) | 
					
						
							|  |  |  |         return (hiddenDoors, revealedDoor) |