def GetLevelStaircaseRoomNumberList(self, level_num: LevelNum) -> List[RoomNum]: assert level_num in Range.VALID_LEVEL_NUMBERS offset = level_num * self.LEVEL_METADATA_OFFSET + self.STAIRCASE_LIST_OFFSET tbr: List[RoomNum] = [] for offset in range(0, 9): tbr.append(RoomNum(self.level_metadata[offset])) return tbr
def __init__(self, rom_data: Optional[List[int]] = None) -> None: if not rom_data: rom_data = [0x26, 0x26, 0x00, 0x00, 0x17, 0x00] if rom_data[4] & 0x1F == 0x03: stuff_not_to_change = rom_data[4] & 0xE0 rom_data[4] = stuff_not_to_change + 0x0E self.rom_data = rom_data self.marked_as_visited = False # -1 is used as a sentinal value indicating a lack of stairway room self.stairs_destination = RoomNum(-1)
def _ReadItemsAndLocationsRecursively( self, level_num: LevelNum, room_num: RoomNum, entrance_direction: Direction) -> None: print("Reading room %x" % room_num) if room_num not in Range.VALID_ROOM_NUMBERS: return # No escaping back into the overworld! :) room = self.data_table.GetRoom(level_num, room_num) if room.IsMarkedAsVisited(): return room.MarkAsVisited() item = room.GetItem() if item.IsMajorItem() or item == Item.TRIFORCE: self.item_shuffler.AddLocationAndItem( Location.LevelRoom(level_num, room_num), item) # Staircase cases (bad pun intended) if room.IsItemStaircase(): return # Dead end, no need to traverse further. if room.IsTransportStairway(): for upstairs_room in [ room.GetStairwayRoomLeftExit(), room.GetStairwayRoomRightExit() ]: self._ReadItemsAndLocationsRecursively(level_num, upstairs_room, Direction.STAIRCASE) return # Regular (non-staircase) room case. Check all four cardinal directions, plus "down". for direction in (Direction.WEST, Direction.NORTH, Direction.EAST, Direction.SOUTH): if direction == entrance_direction: continue if room.GetWallType(direction) != WallType.SOLID_WALL: self._ReadItemsAndLocationsRecursively( level_num, RoomNum(room_num + direction), direction.Reverse()) if room.HasStairs(): self._ReadItemsAndLocationsRecursively(level_num, room.GetStairsDestination(), Direction.STAIRCASE)
def GetLevelStartRoomNumber(self, level_num: LevelNum) -> RoomNum: assert level_num in Range.VALID_LEVEL_NUMBERS return RoomNum( self.level_metadata[level_num * self.LEVEL_METADATA_OFFSET + self.START_ROOM_OFFSET])
def ClearStairsDestination(self) -> None: self.stairs_destination = RoomNum(-1)
def HasStairs(self) -> bool: # -1 is used as a sentinal value indicating a lack of stairs room return self.stairs_destination != RoomNum(-1)
def GetStairwayRoomRightExit(self) -> RoomNum: assert self.IsStairwayRoom() return RoomNum(self._ReadRomBits(1, 0x7F))
def _RecursivelyTraverseLevel(self, level_num: LevelNum, room_num: RoomNum, entry_direction: Direction) -> None: log.debug("Visiting level %d room %x" % (level_num, room_num)) if not room_num in Range.VALID_ROOM_NUMBERS: return room = self.data_table.GetRoom(level_num, room_num) if room.IsMarkedAsVisited(): return room.MarkAsVisited() current_location = Location.LevelRoom(level_num, room_num) # An item staircase room is a dead-end, so no need to recurse after picking up the item. if room.IsItemStaircase(): self.inventory.AddItem(room.GetItem(), current_location) return # For a transport staircase, we don't know whether we came in through the left or right. # So try to leave both ways; the one that we came from will have already been marked as # visited and just return. if room.IsTransportStaircase(): for room_num_to_visit in [ room.GetStairwayRoomLeftExit(), room.GetStairwayRoomRightExit() ]: self._RecursivelyTraverseLevel(level_num, room_num_to_visit, Direction.STAIRCASE) return if self._CanGetRoomItem(entry_direction, room) and room.HasItem(): self.inventory.AddItem(room.GetItem(), current_location) if room.GetEnemy() == Enemy.THE_BEAST: if self.inventory.HasBowSilverArrowsAndSword( ) and self.inventory.Has(Item.LADDER): # TODO: Doesn't address the case where ladder isn't obtained log.info("Got the triforce of power!") self.inventory.AddItem(Item.TRIFORCE_OF_POWER, current_location) if room.GetEnemy() == Enemy.THE_KIDNAPPED: log.info("Found the kidnapped") if self.inventory.Has(Item.TRIFORCE_OF_POWER): log.info("And rescued the kidnapped! :)") self.inventory.AddItem(Item.RESCUED_KIDNAPPED_VIRTUAL_ITEM, current_location) for direction in (Direction.WEST, Direction.NORTH, Direction.EAST, Direction.SOUTH): if direction == entry_direction: continue if not self.inventory.HasReusableWeapon() and room.GetEnemy( ).HasHardCombatEnemies(): continue if self._CanMove(entry_direction, direction, level_num, room_num, room): self._RecursivelyTraverseLevel(level_num, RoomNum(room_num + direction), direction.Reverse()) if room.GetRoomType().HasUnobstructedStairs() or ( room.HasStairs() and self._CanDefeatEnemies(room)): if entry_direction != Direction.STAIRCASE: self._RecursivelyTraverseLevel(level_num, room.GetStairsDestination(), Direction.STAIRCASE)
def GetRoomNum(self) -> RoomNum: assert self.IsLevelRoom() return RoomNum(self.sub_id)