Merged in DR v1.4.1.6

This commit is contained in:
codemann8
2024-02-10 18:48:05 -06:00
76 changed files with 12756 additions and 1695 deletions

View File

@@ -110,7 +110,8 @@ class CustomSettings(object):
args.pottery[p] = get_setting(settings['pottery'], args.pottery[p])
if get_setting(settings['keydropshuffle'], args.keydropshuffle[p]):
args.dropshuffle[p] = True
if args.dropshuffle[p] == 'none':
args.dropshuffle[p] = 'keys'
if args.pottery[p] == 'none':
args.pottery[p] = 'keys'
@@ -153,6 +154,7 @@ class CustomSettings(object):
args.shuffleenemies[p] = get_setting(settings['enemy_shuffle'], get_setting(settings['shuffleenemies'], args.shuffleenemies[p]))
args.enemy_health[p] = get_setting(settings['enemy_health'], args.enemy_health[p])
args.enemy_damage[p] = get_setting(settings['enemy_damage'], args.enemy_damage[p])
args.any_enemy_logic[p] = get_setting(settings['any_enemy_logic'], args.any_enemy_logic[p])
args.shufflepots[p] = get_setting(settings['shufflepots'], args.shufflepots[p])
args.bombbag[p] = get_setting(settings['bombbag'], args.bombbag[p])
args.shufflelinks[p] = get_setting(settings['shufflelinks'], args.shufflelinks[p])
@@ -260,6 +262,11 @@ class CustomSettings(object):
return self.file_source['drops']
return None
def get_enemies(self):
if 'enemies' in self.file_source:
return self.file_source['enemies']
return None
def create_from_world(self, world, settings):
self.player_range = range(1, world.players + 1)
settings_dict, meta_dict = {}, {}
@@ -319,6 +326,7 @@ class CustomSettings(object):
settings_dict[p]['enemy_shuffle'] = world.enemy_shuffle[p]
settings_dict[p]['enemy_health'] = world.enemy_health[p]
settings_dict[p]['enemy_damage'] = world.enemy_damage[p]
settings_dict[p]['any_enemy_logic'] = world.any_enemy_logic[p]
settings_dict[p]['shufflepots'] = world.potshuffle[p]
settings_dict[p]['bombbag'] = world.bombbag[p]
settings_dict[p]['shufflelinks'] = world.shufflelinks[p]

View File

@@ -127,7 +127,8 @@ SETTINGSTOPROCESS = {
"enemyshuffle": "shuffleenemies",
"bossshuffle": "shufflebosses",
"enemydamage": "enemy_damage",
"enemyhealth": "enemy_health"
"enemyhealth": "enemy_health",
"enemylogic": "any_enemy_logic"
},
"gameoptions": {
"nobgm": "disablemusic",

2676
source/dungeon/EnemyList.py Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,266 @@
Ganon = 0x0
HC_NorthCorridor = 0x1
HC_SwitchRoom = 0x2
HoulihanRoom = 0x3
TR_CrystalRollerRoom = 0x4
Swamp_Arrghus = 0x6
Hera_Moldorm = 0x7
Cave_HealingFairy = 0x8
PalaceofDarkness0x09 = 0x9
PoD_StalfosTrapRoom = 0xa
PoD_TurtleRoom = 0xb
GT_EntranceRoom = 0xc
GT_Agahnim2 = 0xd
Ice_EntranceRoom = 0xe
GanonEvacuationRoute = 0x10
HC_BombableStockRoom = 0x11
Sanctuary = 0x12
TR_Hokku_BokkuKeyRoom2 = 0x13
TR_BigKeyRoom = 0x14
TurtleRock0x15 = 0x15
Swamp_SwimmingTreadmill = 0x16
Hera_MoldormFallRoom = 0x17
Cave0x18_BigFairyDropEntrance = 0x18
PoD_DarkMaze = 0x19
PoD_BigChestRoom = 0x1a
PoD_Mimics_MovingWallRoom = 0x1b
GT_IceArmos = 0x1c
GT_FinalHallway = 0x1d
Ice_BombFloor_BariRoom = 0x1e
Ice_Pengator_BigKeyRoom = 0x1f
Tower_Agahnim = 0x20
HC_KeyRatRoom = 0x21
HC_SewerTextTriggerRoom = 0x22
TR_WestExittoBalcony = 0x23
TR_DoubleHokku_Bokku_BigchestRoom = 0x24
Swamp_StatueRoom = 0x26
Hera_BigChest = 0x27
Swamp_EntranceRoom = 0x28
Skull_Mothula = 0x29
PoD_BigHubRoom = 0x2a
PoD_MapChest_FairyRoom = 0x2b
Cave0x2C_HookshotCaveBackdoor = 0x2c
Ice_CompassRoom = 0x2e
Cave_KakarikoWellHP = 0x2f
Tower_MaidenSacrificeChamber = 0x30
Hera_HardhatBeetlesRoom = 0x31
HC_SewerKeyChestRoom = 0x32
Desert_Lanmolas = 0x33
Swamp_PushBlockPuzzle_Pre_BigKeyRoom = 0x34
Swamp_BigKey_BSRoom = 0x35
Swamp_BigChestRoom = 0x36
Swamp_MapChest_WaterFillRoom = 0x37
Swamp_KeyPotRoom = 0x38
Skull_GibdoKey_MothulaHoleRoom = 0x39
PoD_BombableFloorRoom = 0x3a
PoD_SpikeBlock_ConveyorRoom = 0x3b
Cave0x3C_HookshotCave = 0x3c
GT_TorchRoom2 = 0x3d
Ice_StalfosKnights_ConveyorHellway = 0x3e
Ice_MapChestRoom = 0x3f
Tower_FinalBridgeRoom = 0x40
HC_FirstDarkRoom = 0x41
HC_6RopesRoom = 0x42
Desert_TorchPuzzle_MovingWallRoom = 0x43
TT_BigChestRoom = 0x44
TT_JailCellsRoom = 0x45
Swamp_CompassChestRoom = 0x46
Skull_GibdoTorchPuzzleRoom = 0x49
PoD_EntranceRoom = 0x4a
PoD_Warps_SouthMimicsRoom = 0x4b
GT_Mini_HelmasaurConveyorRoom = 0x4c
GT_MoldormRoom = 0x4d
Ice_Bomb_JumpRoom = 0x4e
IcePalaceCloneRoom_FairyRoom = 0x4f
HC_WestCorridor = 0x50
HC_ThroneRoom = 0x51
HC_EastCorridor = 0x52
Desert_Popos2_BeamosHellwayRoom = 0x53
Swamp_UpstairsPitsRoom = 0x54
CastleSecretEntrance_UncleDeathRoom = 0x55
Skull_KeyPot_TrapRoom = 0x56
Skull_BigKeyRoom = 0x57
Skull_BigChestRoom = 0x58
Skull_FinalSectionEntranceRoom = 0x59
PoD_HelmasaurKing = 0x5a
GT_SpikePitRoom = 0x5b
GT_Ganon_BallZ = 0x5c
GT_Gauntlet1_2_3 = 0x5d
Ice_LonelyFirebar = 0x5e
Ice_HiddenChest_SpikeFloorRoom = 0x5f
HC_WestEntranceRoom = 0x60
HC_MainEntranceRoom = 0x61
HC_EastEntranceRoom = 0x62
Desert_FinalSectionEntranceRoom = 0x63
TT_WestAtticRoom = 0x64
TT_EastAtticRoom = 0x65
Swamp_HiddenChest_HiddenDoorRoom = 0x66
Skull_CompassChestRoom = 0x67
Skull_KeyChest_TrapRoom = 0x68
PoD_RupeeRoom = 0x6a
GT_MimicsRooms = 0x6b
GT_LanmolasRoom = 0x6c
GT_Gauntlet4_5 = 0x6d
Ice_PengatorsRoom = 0x6e
HC_SmallCorridortoJailCells = 0x70
HC_BoomerangChestRoom = 0x71
HC_MapChestRoom = 0x72
Desert_BigChestRoom = 0x73
Desert_MapChestRoom = 0x74
Desert_BigKeyChestRoom = 0x75
Swamp_WaterDrainRoom = 0x76
Hera_EntranceRoom = 0x77
GanonsTower = 0x7b
GT_EastSideCollapsingBridge_ExplodingWallRoom = 0x7c
GT_Winder_WarpMazeRoom = 0x7d
Ice_HiddenChest_BombableFloorRoom = 0x7e
Ice_BigSpikeTrapsRoom = 0x7f
HC_JailCellRoom = 0x80
HC_NextToChasmRoom = 0x81
HC_BasementChasmRoom = 0x82
Desert_WestEntranceRoom = 0x83
Desert_MainEntranceRoom = 0x84
Desert_EastEntranceRoom = 0x85
Hera_TileRoom = 0x87
Eastern_FairyRoom = 0x89
GT_BlockPuzzle_SpikeSkip_MapChestRoom = 0x8b
GT_EastandWestDownstairs_BigChestRoom = 0x8c
GT_Tile_TorchPuzzleRoom = 0x8d
IcePalace0x8E = 0x8e
Mire_Vitreous = 0x90
Mire_FinalSwitchRoom = 0x91
Mire_DarkBombWall_SwitchesRoom = 0x92
Mire_DarkCaneFloorSwitchPuzzleRoom = 0x93
GT_FinalCollapsingBridgeRoom = 0x95
GT_Torches1Room = 0x96
Mire_TorchPuzzle_MovingWallRoom = 0x97
Mire_EntranceRoom = 0x98
Eastern_EyegoreKeyRoom = 0x99
GT_ManySpikes_WarpMazeRoom = 0x9b
GT_InvisibleFloorMazeRoom = 0x9c
GT_CompassChest_InvisibleFloorRoom = 0x9d
Ice_BigChestRoom = 0x9e
IcePalace0x9F = 0x9f
Mire_Pre_VitreousRoom = 0xa0
Mire_FishRoom = 0xa1
Mire_BridgeKeyChestRoom = 0xa2
MiseryMire0xA3 = 0xa3
TR_Trinexx = 0xa4
GT_WizzrobesRooms = 0xa5
GT_MoldormFallRoom = 0xa6
Hera_FairyRoom = 0xa7
Eastern_StalfosSpawnRoom = 0xa8
Eastern_BigChestRoom = 0xa9
Eastern_MapChestRoom = 0xaa
TT_MovingSpikes_KeyPotRoom = 0xab
TT_BlindTheThief = 0xac
IcePalace0xAE = 0xae
Ice_IceBridgeRoom = 0xaf
Tower_CircleofPots = 0xb0
Mire_HourglassRoom = 0xb1
Mire_SlugRoom = 0xb2
Mire_SpikeKeyChestRoom = 0xb3
TR_Pre_TrinexxRoom = 0xb4
TR_DarkMaze = 0xb5
TR_ChainChompsRoom = 0xb6
TR_MapChest_KeyChest_RollerRoom = 0xb7
Eastern_BigKeyRoom = 0xb8
Eastern_LobbyCannonballsRoom = 0xb9
Eastern_DarkAntifairy_KeyPotRoom = 0xba
TT_Hellway = 0xbb
TT_ConveyorToilet = 0xbc
Ice_BlockPuzzleRoom = 0xbe
IcePalaceCloneRoom_SwitchRoom = 0xbf
Tower_DarkBridgeRoom = 0xc0
Mire_CompassChest_TileRoom = 0xc1
Mire_BigHubRoom = 0xc2
Mire_BigChestRoom = 0xc3
TR_FinalCrystalSwitchPuzzleRoom = 0xc4
TR_LaserBridge = 0xc5
TurtleRock0xC6 = 0xc6
TR_TorchPuzzle = 0xc7
Eastern_ArmosKnights = 0xc8
Eastern_EntranceRoom = 0xc9
UnknownRoom = 0xca
TT_NorthWestEntranceRoom = 0xcb
TT_NorthEastEntranceRoom = 0xcc
Ice_HoletoKholdstareRoom = 0xce
Tower_DarkMaze = 0xd0
Mire_ConveyorSlug_BigKeyRoom = 0xd1
Mire_Mire02_WizzrobesRoom = 0xd2
TR_LaserKeyRoom = 0xd5
TR_EntranceRoom = 0xd6
Eastern_PreArmosKnightsRoom = 0xd8
Eastern_CanonballRoom = 0xd9
EasternPalace = 0xda
TT_Main_SouthWestEntranceRoom = 0xdb
TT_SouthEastEntranceRoom = 0xdc
Ice_Kholdstare = 0xde
Cave_BackwardsDeathMountainTopFloor = 0xdf
Tower_EntranceRoom = 0xe0
Cave_LostWoodsHP = 0xe1
Cave_LumberjacksTreeHP = 0xe2
Cave_HalfMagic = 0xe3
Cave_LostOldManFinalCave = 0xe4
Cave_LostOldManFinalCave2 = 0xe5
Cave0xE6 = 0xe6
Cave0xE7 = 0xe7
Cave0xE8 = 0xe8
Cave_SpectacleRockHP = 0xea
Cave0xEB = 0xeb
Cave0xED = 0xed
Cave_SpiralCave = 0xee
Cave_CrystalSwitch_5ChestsRoom = 0xef
Cave_LostOldManStartingCave = 0xf0
Cave_LostOldManStartingCave2 = 0xf1
House = 0xf2
House_OldWoman = 0xf3
House_AngryBrothers = 0xf4
House_AngryBrothers2 = 0xf5
Cave0xF8 = 0xf8
Cave0xF9 = 0xf9
Cave0xFA = 0xfa
Cave0xFB = 0xfb
Cave0xFD = 0xfd
Cave0xFE = 0xfe
Cave0xFF = 0xff
ShopInLostWoods0x100 = 0x100
ScaredLadyHouses = 0x101
SickKid = 0x102
Inn_BushHouse = 0x103
LinksHouse = 0x104
ShabadooHouse = 0x105
ChestGame_BombHouse = 0x106
Library_BombFarmRoom = 0x107
ChickenHouse = 0x108
WitchHut = 0x109
Aginah = 0x10a
SwampFloodwayRoom = 0x10b
MimicCave = 0x10c
CaveOutsideMiseryMire = 0x10d
Cave0x10E = 0x10e
Shop0x10F = 0x10f
Shop0x110 = 0x110
ArcherGame = 0x111
CaveShop0x112 = 0x112
KingsTomb = 0x113
WishingWell_Cave0x114 = 0x114
WishingWell_BigFairy = 0x115
FatFairy = 0x116
SpikeCave = 0x117
Shop0x118 = 0x118
BlindsHouse = 0x119
Mutant = 0x11a
MirrorCaveGroveAndTomb = 0x11b
BombShop = 0x11c
BlindsBasement = 0x11d
HypeCave = 0x11e
Shop0x11F = 0x11f
IceRodCave = 0x120
SmithHouse = 0x121
FortuneTellers = 0x122
MiniMoldormCave = 0x123
UnknownCave_BonkCave = 0x124
Cave0x125 = 0x125
CheckerBoardCave = 0x126
HammerPegCave = 0x127

View File

@@ -0,0 +1,331 @@
vanilla_headers = {
0x0000: [0x41, 0x21, 0x13, 0x22, 0x07, 0x3D, 0x00, 0x00, 0x00, 0x10, 0xC0, 0x00, 0x00, 0x04],
0x0001: [0xC0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x00, 0x50, 0x52],
0x0002: [0xC0, 0x1D, 0x04, 0x06, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x18, 0x0D],
0x0003: [0xC0, 0x07, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x02, 0x12, 0x00, 0x00, 0x00],
0x0004: [0x00, 0x18, 0x0D, 0x26, 0x00, 0x26, 0x14, 0x00, 0x00, 0x00, 0xB5, 0x00, 0x08, 0x08],
0x0005: [0x00, 0x08, 0x08, 0x14, 0x00, 0x25, 0x00, 0x20, 0x06, 0x05, 0x0C, 0x00, 0x25, 0x00],
0x0006: [0x00, 0x08, 0x08, 0x14, 0x00, 0x25, 0x00, 0x20, 0x06, 0x05, 0x0C, 0x00, 0x25, 0x00],
0x0007: [0x20, 0x06, 0x05, 0x0C, 0x00, 0x25, 0x00, 0x00, 0x00, 0x17, 0x17, 0xC0, 0x07, 0x06],
0x0008: [0xC0, 0x07, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x07, 0x19, 0x00, 0x27, 0x00],
0x0009: [0x00, 0x0F, 0x07, 0x19, 0x00, 0x27, 0x00, 0x00, 0x00, 0x4B, 0x4A, 0x4A, 0x00, 0x0F],
0x000A: [0x00, 0x0F, 0x07, 0x19, 0x00, 0x27, 0x00, 0x00, 0x00, 0x09, 0x3A, 0x01, 0x0F, 0x07],
0x000B: [0x01, 0x0F, 0x07, 0x19, 0x00, 0x03, 0x00, 0x00, 0x00, 0x6A, 0x1B, 0xC0, 0x28, 0x0E],
0x000C: [0xC0, 0x28, 0x0E, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6B, 0x8C, 0x8C, 0x40],
0x000D: [0x40, 0x1B, 0x0E, 0x18, 0x05, 0x38, 0x00, 0x00, 0x13, 0x0B, 0x1C, 0x00, 0x08, 0x00],
0x000E: [0x00, 0x13, 0x0B, 0x1C, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x21, 0x13],
0x000F: [0x00, 0x21, 0x13, 0x22, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00],
0x0010: [0x00, 0x21, 0x13, 0x22, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00],
0x0011: [0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x02, 0xC0, 0x1D, 0x04],
0x0012: [0xC0, 0x1D, 0x04, 0x06, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0D, 0x26, 0x00, 0x00, 0x00],
0x0013: [0x00, 0x18, 0x0D, 0x26, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0D, 0x1E, 0x00, 0x00, 0x00],
0x0014: [0x20, 0x18, 0x0D, 0x26, 0x00, 0x00, 0x00, 0xC0, 0x18, 0x0D, 0x26, 0x00, 0x00, 0x00],
0x0015: [0xC0, 0x18, 0x0D, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB6, 0x90, 0x08, 0x08],
0x0016: [0x90, 0x08, 0x08, 0x11, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x20, 0x06, 0x05],
0x0017: [0x20, 0x06, 0x05, 0x19, 0x00, 0x35, 0x00, 0x00, 0x00, 0x27, 0x07, 0x27, 0x01, 0x0F],
0x0018: [0x00, 0x07, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, 0x22, 0x12, 0x07, 0x00, 0x00, 0x00],
0x0019: [0x01, 0x0F, 0x07, 0x19, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x07, 0x19, 0x00, 0x16, 0x00],
0x001A: [0x00, 0x0F, 0x07, 0x19, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x6A, 0x6A, 0x68, 0x0F],
0x001B: [0x68, 0x0F, 0x07, 0x08, 0x00, 0x03, 0x1C, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x1A, 0x0E],
0x001C: [0x00, 0x1A, 0x0E, 0x09, 0x00, 0x04, 0x3F, 0x00, 0x00, 0x00, 0x8C, 0x00, 0x1B, 0x0E],
0x001D: [0x00, 0x1B, 0x0E, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4C, 0x20, 0x13, 0x0B],
0x001E: [0x20, 0x13, 0x0B, 0x1C, 0x00, 0x17, 0x00, 0x00, 0x00, 0x3E, 0x0E, 0x00, 0x13, 0x0B],
0x001F: [0x00, 0x13, 0x0B, 0x29, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x20, 0x0C, 0x02],
0x0020: [0x20, 0x0C, 0x02, 0x12, 0x00, 0x15, 0x25, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00],
0x0021: [0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0D, 0x26, 0x00, 0x01, 0x00],
0x0022: [0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0D, 0x26, 0x00, 0x01, 0x00],
0x0023: [0x00, 0x18, 0x0D, 0x26, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0D, 0x1E, 0x00, 0x00, 0x00],
0x0024: [0x00, 0x18, 0x0D, 0x26, 0x00, 0x01, 0x00, 0x00, 0x0A, 0x08, 0x11, 0x00, 0x16, 0x00],
0x0025: [0x00, 0x0A, 0x08, 0x11, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x76, 0x76, 0x76, 0x20],
0x0026: [0x00, 0x0A, 0x08, 0x11, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x76, 0x76, 0x76, 0x20],
0x0027: [0x20, 0x06, 0x05, 0x19, 0x00, 0x36, 0x00, 0x00, 0x00, 0x31, 0x17, 0x31, 0x80, 0x0A],
0x0028: [0x80, 0x0A, 0x08, 0x11, 0x00, 0x32, 0x1B, 0x00, 0x00, 0x00, 0x38, 0xCC, 0x0E, 0x09],
0x0029: [0xCC, 0x0E, 0x09, 0x1A, 0x02, 0x25, 0x00, 0x00, 0x0F, 0x07, 0x19, 0x00, 0x00, 0x00],
0x002A: [0x00, 0x0F, 0x07, 0x19, 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x07, 0x2B, 0x00, 0x16, 0x00],
0x002B: [0xC0, 0x0F, 0x07, 0x2B, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x13, 0x0B],
0x002C: [0x00, 0x07, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, 0x22, 0x12, 0x07, 0x00, 0x00, 0x00],
0x002D: [0x00, 0x13, 0x0B, 0x1C, 0x00, 0x2A, 0x00, 0xC0, 0x07, 0x06, 0x19, 0x00, 0x00, 0x00],
0x002E: [0x00, 0x13, 0x0B, 0x1C, 0x00, 0x2A, 0x00, 0xC0, 0x07, 0x06, 0x19, 0x00, 0x00, 0x00],
0x002F: [0xC0, 0x07, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x02, 0x12, 0x00, 0x00, 0x00],
0x0030: [0x00, 0x0C, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x20, 0x06, 0x05],
0x0031: [0x20, 0x06, 0x05, 0x19, 0x00, 0x37, 0x04, 0x22, 0x00, 0x77, 0x27, 0x77, 0x01, 0x01],
0x0032: [0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x04, 0x05],
0x0033: [0x00, 0x04, 0x05, 0x0B, 0x00, 0x15, 0x25, 0x80, 0x0A, 0x08, 0x11, 0x00, 0x00, 0x00],
0x0034: [0x80, 0x0A, 0x08, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x80, 0x0A, 0x08],
0x0035: [0x80, 0x0A, 0x08, 0x11, 0x00, 0x00, 0x19, 0x80, 0x0A, 0x08, 0x11, 0x00, 0x00, 0x00],
0x0036: [0x80, 0x0A, 0x08, 0x11, 0x00, 0x00, 0x00, 0x80, 0x0A, 0x08, 0x11, 0x00, 0x00, 0x00],
0x0037: [0x80, 0x0A, 0x08, 0x11, 0x00, 0x00, 0x19, 0x80, 0x0A, 0x08, 0x11, 0x00, 0x00, 0x00],
0x0038: [0x80, 0x0A, 0x08, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x20, 0x0D, 0x09],
0x0039: [0x20, 0x0D, 0x09, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x20, 0x0F, 0x07, 0x19],
0x003A: [0x20, 0x0F, 0x07, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x0A, 0x00, 0x0F, 0x07],
0x003B: [0x00, 0x0F, 0x07, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x07, 0x06],
0x003C: [0x00, 0x07, 0x06, 0x13, 0x00, 0x00, 0x00, 0x20, 0x1A, 0x0E, 0x0C, 0x00, 0x33, 0x00],
0x003D: [0x20, 0x1A, 0x0E, 0x0C, 0x00, 0x33, 0x00, 0x00, 0x00, 0x96, 0x96, 0xCC, 0x13, 0x0B],
0x003E: [0xCC, 0x13, 0x0B, 0x29, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x13, 0x0B],
0x003F: [0x00, 0x13, 0x0B, 0x29, 0x00, 0x27, 0x14, 0x00, 0x00, 0x00, 0x1F, 0x5F, 0xC0, 0x00],
0x0040: [0xC0, 0x00, 0x02, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xB0, 0x01, 0x00],
0x0041: [0x01, 0x00, 0x00, 0x02, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x42, 0x01, 0x01, 0x01],
0x0042: [0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x32, 0x68, 0x04],
0x0043: [0x68, 0x04, 0x05, 0x0A, 0x00, 0x00, 0x1D, 0x00, 0x17, 0x0A, 0x1B, 0x00, 0x01, 0x00],
0x0044: [0x00, 0x17, 0x0A, 0x1B, 0x00, 0x01, 0x00, 0x60, 0x17, 0x0A, 0x1B, 0x00, 0x01, 0x00],
0x0045: [0x60, 0x17, 0x0A, 0x1B, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xBC, 0x00, 0x0A, 0x08],
0x0046: [0x00, 0x0A, 0x08, 0x11, 0x00, 0x3C, 0x00, 0x00, 0x0D, 0x09, 0x13, 0x00, 0x33, 0x34],
0x0047: [0x00, 0x0D, 0x09, 0x13, 0x00, 0x33, 0x34, 0x00, 0x0F, 0x07, 0x19, 0x00, 0x17, 0x00],
0x0048: [0x00, 0x0D, 0x09, 0x13, 0x00, 0x33, 0x34, 0x00, 0x0F, 0x07, 0x19, 0x00, 0x17, 0x00],
0x0049: [0x00, 0x0D, 0x09, 0x13, 0x00, 0x33, 0x34, 0x00, 0x0F, 0x07, 0x19, 0x00, 0x17, 0x00],
0x004A: [0x00, 0x0F, 0x07, 0x19, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x09, 0x09, 0x00, 0x0F],
0x004B: [0x00, 0x0F, 0x07, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x09, 0x00, 0x1A, 0x0E, 0x0C],
0x004C: [0x00, 0x1A, 0x0E, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0x20, 0x1A, 0x0E],
0x004D: [0x20, 0x1A, 0x0E, 0x0C, 0x00, 0x32, 0x3F, 0x00, 0x00, 0xA6, 0xA6, 0x00, 0x13, 0x0B],
0x004E: [0x00, 0x13, 0x0B, 0x29, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x6E, 0x00, 0x13, 0x0B],
0x004F: [0x00, 0x13, 0x0B, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBE, 0xC0, 0x00, 0x00, 0x04],
0x0050: [0xC0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01],
0x0051: [0xC0, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0xC0, 0x00, 0x00],
0x0052: [0xC0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01],
0x0053: [0xC0, 0x04, 0x05, 0x0A, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x63, 0x20, 0x0A, 0x08],
0x0054: [0x20, 0x0A, 0x08, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x34, 0x01, 0x01, 0x10],
0x0055: [0x01, 0x01, 0x10, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x09, 0x13, 0x00, 0x23, 0x00],
0x0056: [0x00, 0x0D, 0x09, 0x13, 0x00, 0x23, 0x00, 0x00, 0x0D, 0x09, 0x13, 0x00, 0x16, 0x00],
0x0057: [0x00, 0x0D, 0x09, 0x13, 0x00, 0x16, 0x00, 0x00, 0x0D, 0x09, 0x13, 0x00, 0x21, 0x28],
0x0058: [0x00, 0x0D, 0x09, 0x13, 0x00, 0x21, 0x28, 0xC0, 0x0D, 0x09, 0x13, 0x00, 0x00, 0x00],
0x0059: [0xC0, 0x0D, 0x09, 0x13, 0x00, 0x00, 0x00, 0x00, 0x10, 0x07, 0x15, 0x00, 0x25, 0x00],
0x005A: [0x00, 0x10, 0x07, 0x15, 0x00, 0x25, 0x00, 0xC0, 0x1B, 0x0E, 0x0A, 0x00, 0x17, 0x00],
0x005B: [0xC0, 0x1B, 0x0E, 0x0A, 0x00, 0x17, 0x00, 0x00, 0x1B, 0x0E, 0x0A, 0x00, 0x00, 0x00],
0x005C: [0x00, 0x1B, 0x0E, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5D, 0x00, 0x24, 0x0E],
0x005D: [0x00, 0x24, 0x0E, 0x23, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x5C, 0x20, 0x13, 0x0B],
0x005E: [0x20, 0x13, 0x0B, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x00, 0x13, 0x0B],
0x005F: [0x00, 0x13, 0x0B, 0x1C, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x7F, 0xC0, 0x00],
0x0060: [0xC0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00],
0x0061: [0xC0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x51, 0x00, 0x09, 0x05],
0x0062: [0xC0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00],
0x0063: [0x00, 0x09, 0x05, 0x0A, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x53, 0xE0, 0x23, 0x0A],
0x0064: [0xE0, 0x23, 0x0A, 0x21, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0xAB, 0xE0, 0x23, 0x0A],
0x0065: [0xE0, 0x23, 0x0A, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAC, 0xC0, 0x0A, 0x08, 0x11],
0x0066: [0xC0, 0x0A, 0x08, 0x11, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x0D, 0x09],
0x0067: [0x00, 0x0D, 0x09, 0x13, 0x00, 0x22, 0x00, 0x00, 0x0D, 0x09, 0x13, 0x00, 0x00, 0x00],
0x0068: [0x00, 0x0D, 0x09, 0x13, 0x00, 0x00, 0x00, 0x01, 0x0F, 0x07, 0x19, 0x00, 0x00, 0x00],
0x0069: [0x01, 0x0F, 0x07, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1A, 0x1A, 0x00, 0x1B],
0x006A: [0x01, 0x0F, 0x07, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1A, 0x1A, 0x00, 0x1B],
0x006B: [0x00, 0x1B, 0x0E, 0x0A, 0x00, 0x08, 0x0B, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x24, 0x0E],
0x006C: [0x00, 0x24, 0x0E, 0x23, 0x00, 0x03, 0x3F, 0x00, 0x00, 0x00, 0xA5, 0x00, 0x24, 0x0E],
0x006D: [0x00, 0x24, 0x0E, 0x23, 0x00, 0x05, 0x00, 0x00, 0x13, 0x0B, 0x1C, 0x00, 0x02, 0x00],
0x006E: [0x00, 0x13, 0x0B, 0x1C, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x4E, 0x00, 0x01, 0x01],
0x006F: [0x00, 0x01, 0x01, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x71, 0x80, 0xC0, 0x01],
0x0070: [0x00, 0x01, 0x01, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x71, 0x80, 0xC0, 0x01],
0x0071: [0xC0, 0x01, 0x01, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x70, 0xC0, 0x01, 0x01],
0x0072: [0xC0, 0x01, 0x01, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x09, 0x05],
0x0073: [0x00, 0x09, 0x05, 0x0A, 0x00, 0x17, 0x00, 0x00, 0x09, 0x05, 0x0A, 0x00, 0x27, 0x00],
0x0074: [0x00, 0x09, 0x05, 0x0A, 0x00, 0x27, 0x00, 0x00, 0x09, 0x05, 0x0A, 0x00, 0x01, 0x00],
0x0075: [0x00, 0x09, 0x05, 0x0A, 0x00, 0x01, 0x00, 0x80, 0x0A, 0x08, 0x11, 0x00, 0x00, 0x18],
0x0076: [0x80, 0x0A, 0x08, 0x11, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x26, 0x26, 0x26, 0xC0],
0x0077: [0xC0, 0x06, 0x05, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA7, 0x31, 0x87, 0x87, 0x00],
0x0078: [0x00, 0x28, 0x0E, 0x13, 0x00, 0x03, 0x39, 0x00, 0x00, 0x9D, 0x00, 0x28, 0x0E, 0x13],
0x0079: [0x00, 0x28, 0x0E, 0x13, 0x00, 0x03, 0x39, 0x00, 0x00, 0x9D, 0x00, 0x28, 0x0E, 0x13],
0x007A: [0x00, 0x28, 0x0E, 0x13, 0x00, 0x03, 0x39, 0x00, 0x00, 0x9D, 0x00, 0x28, 0x0E, 0x13],
0x007B: [0x00, 0x28, 0x0E, 0x13, 0x00, 0x03, 0x39, 0x00, 0x00, 0x9D, 0x00, 0x28, 0x0E, 0x13],
0x007C: [0x00, 0x28, 0x0E, 0x13, 0x00, 0x20, 0x00, 0x00, 0x28, 0x0E, 0x13, 0x00, 0x04, 0x3C],
0x007D: [0x00, 0x28, 0x0E, 0x13, 0x00, 0x04, 0x3C, 0x00, 0x00, 0x9B, 0x20, 0x13, 0x0B, 0x1C],
0x007E: [0x20, 0x13, 0x0B, 0x1C, 0x00, 0x2B, 0x17, 0x00, 0x00, 0x9E, 0x5E, 0x00, 0x13, 0x0B],
0x007F: [0x00, 0x13, 0x0B, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5F, 0x60, 0x01, 0x01],
0x0080: [0x60, 0x01, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xC0, 0x01, 0x01],
0x0081: [0xC0, 0x01, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x05, 0x0A, 0x00, 0x0D, 0x00],
0x0082: [0xC0, 0x01, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x05, 0x0A, 0x00, 0x0D, 0x00],
0x0083: [0x00, 0x09, 0x05, 0x0A, 0x00, 0x0D, 0x00, 0x00, 0x09, 0x05, 0x0A, 0x00, 0x00, 0x00],
0x0084: [0x00, 0x09, 0x05, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x09, 0x05, 0x0A, 0x00, 0x02, 0x00],
0x0085: [0x00, 0x09, 0x05, 0x0A, 0x00, 0x02, 0x00, 0x00, 0x06, 0x05, 0x19, 0x00, 0x3E, 0x01],
0x0086: [0x00, 0x06, 0x05, 0x19, 0x00, 0x3E, 0x01, 0x28, 0x00, 0x00, 0x77, 0x77, 0x00, 0x0B],
0x0087: [0x00, 0x06, 0x05, 0x19, 0x00, 0x3E, 0x01, 0x28, 0x00, 0x00, 0x77, 0x77, 0x00, 0x0B],
0x0088: [0x00, 0x0B, 0x05, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0xA9, 0x00, 0x28, 0x0E, 0x13],
0x0089: [0x00, 0x0B, 0x05, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0xA9, 0x00, 0x28, 0x0E, 0x13],
0x008A: [0x00, 0x28, 0x0E, 0x13, 0x00, 0x3A, 0x0C, 0x20, 0x28, 0x0E, 0x13, 0x00, 0x16, 0x00],
0x008B: [0x00, 0x28, 0x0E, 0x13, 0x00, 0x3A, 0x0C, 0x20, 0x28, 0x0E, 0x13, 0x00, 0x16, 0x00],
0x008C: [0x20, 0x28, 0x0E, 0x13, 0x00, 0x16, 0x00, 0x28, 0x00, 0x1C, 0x0C, 0x0C, 0x1C, 0x00],
0x008D: [0x00, 0x28, 0x0E, 0x13, 0x00, 0x33, 0x29, 0x00, 0x13, 0x0B, 0x1C, 0x00, 0x00, 0x00],
0x008E: [0x00, 0x13, 0x0B, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAE, 0x80, 0x12, 0x0C],
0x008F: [0x80, 0x12, 0x0C, 0x16, 0x00, 0x25, 0x00, 0x00, 0x11, 0x0C, 0x1C, 0x00, 0x00, 0x00],
0x0090: [0x80, 0x12, 0x0C, 0x16, 0x00, 0x25, 0x00, 0x00, 0x11, 0x0C, 0x1C, 0x00, 0x00, 0x00],
0x0091: [0x00, 0x11, 0x0C, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x01, 0x11, 0x0C],
0x0092: [0x01, 0x11, 0x0C, 0x1C, 0x00, 0x00, 0x00, 0x01, 0x11, 0x0C, 0x1C, 0x00, 0x16, 0x00],
0x0093: [0x01, 0x11, 0x0C, 0x1C, 0x00, 0x16, 0x00, 0x08, 0x00, 0x00, 0xA2, 0x00, 0x25, 0x0E],
0x0094: [0x00, 0x25, 0x0E, 0x24, 0x00, 0x00, 0x00, 0x00, 0x25, 0x0E, 0x24, 0x00, 0x33, 0x00],
0x0095: [0x00, 0x25, 0x0E, 0x24, 0x00, 0x00, 0x00, 0x00, 0x25, 0x0E, 0x24, 0x00, 0x33, 0x00],
0x0096: [0x00, 0x25, 0x0E, 0x24, 0x00, 0x33, 0x00, 0x00, 0x00, 0x00, 0x3D, 0x68, 0x11, 0x0C],
0x0097: [0x68, 0x11, 0x0C, 0x1D, 0x00, 0x1C, 0x00, 0x00, 0x00, 0xD1, 0xD1, 0x00, 0x11, 0x0C],
0x0098: [0x00, 0x11, 0x0C, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD2, 0x01, 0x0B, 0x05],
0x0099: [0x01, 0x0B, 0x05, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDA, 0x00, 0x28, 0x0E],
0x009A: [0x00, 0x28, 0x0E, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7D, 0x00, 0x28, 0x0E, 0x13],
0x009B: [0x00, 0x28, 0x0E, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7D, 0x00, 0x28, 0x0E, 0x13],
0x009C: [0x00, 0x28, 0x0E, 0x13, 0x06, 0x00, 0x00, 0x00, 0x28, 0x0E, 0x13, 0x06, 0x00, 0x3B],
0x009D: [0x00, 0x28, 0x0E, 0x13, 0x06, 0x00, 0x3B, 0x00, 0x00, 0x7B, 0x20, 0x13, 0x0B, 0x1C],
0x009E: [0x20, 0x13, 0x0B, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBE, 0xBE, 0x00, 0x13, 0x0B],
0x009F: [0x00, 0x13, 0x0B, 0x1C, 0x00, 0x17, 0x00, 0x00, 0x12, 0x0C, 0x1D, 0x00, 0x00, 0x00],
0x00A0: [0x00, 0x12, 0x0C, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x00, 0x11, 0x0C],
0x00A1: [0x00, 0x11, 0x0C, 0x1D, 0x00, 0x00, 0x00, 0xC0, 0x11, 0x0C, 0x1D, 0x00, 0x00, 0x00],
0x00A2: [0xC0, 0x11, 0x0C, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x93, 0x60, 0x19, 0x0D],
0x00A3: [0x00, 0x11, 0x0C, 0x1D, 0x00, 0x00, 0x00, 0xC0, 0x11, 0x0C, 0x1D, 0x00, 0x00, 0x00],
0x00A4: [0x60, 0x19, 0x0D, 0x17, 0x04, 0x25, 0x00, 0x00, 0x25, 0x0E, 0x24, 0x00, 0x07, 0x00],
0x00A5: [0x00, 0x25, 0x0E, 0x24, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x25, 0x0E],
0x00A6: [0x00, 0x25, 0x0E, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4D, 0x00, 0x06, 0x05],
0x00A7: [0x00, 0x06, 0x05, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xC0, 0x0B, 0x05, 0x08],
0x00A8: [0xC0, 0x0B, 0x05, 0x08, 0x00, 0x03, 0x00, 0xC0, 0x0B, 0x05, 0x08, 0x00, 0x17, 0x00],
0x00A9: [0xC0, 0x0B, 0x05, 0x08, 0x00, 0x17, 0x00, 0x00, 0x00, 0x89, 0xC0, 0x0B, 0x05, 0x08],
0x00AA: [0xC0, 0x0B, 0x05, 0x08, 0x00, 0x17, 0x00, 0x00, 0x17, 0x0A, 0x1B, 0x00, 0x00, 0x00],
0x00AB: [0x00, 0x17, 0x0A, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xE0, 0x17, 0x0A],
0x00AC: [0xE0, 0x17, 0x0A, 0x20, 0x00, 0x25, 0x00, 0x00, 0x13, 0x0B, 0x1C, 0x00, 0x27, 0x00],
0x00AD: [0x00, 0x13, 0x0B, 0x1C, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x8E, 0x00, 0x13, 0x0B],
0x00AE: [0x00, 0x13, 0x0B, 0x1C, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x8E, 0x00, 0x13, 0x0B],
0x00AF: [0x00, 0x13, 0x0B, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x26, 0x02, 0x21, 0x00, 0x05, 0x02],
0x00B0: [0x00, 0x26, 0x02, 0x21, 0x00, 0x05, 0x02, 0x08, 0x00, 0x00, 0x40, 0xC0, 0x00, 0x11],
0x00B1: [0x00, 0x11, 0x0C, 0x1D, 0x00, 0x00, 0x00, 0x02, 0x00, 0xB2, 0xC0, 0x11, 0x0C, 0x1D],
0x00B2: [0xC0, 0x11, 0x0C, 0x1D, 0x00, 0x03, 0x0E, 0xC0, 0x11, 0x0C, 0x1D, 0x00, 0x27, 0x00],
0x00B3: [0xC0, 0x11, 0x0C, 0x1D, 0x00, 0x27, 0x00, 0x00, 0x19, 0x0D, 0x17, 0x00, 0x00, 0x00],
0x00B4: [0x00, 0x19, 0x0D, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC4, 0x01, 0x18, 0x0D],
0x00B5: [0x01, 0x18, 0x0D, 0x25, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x18, 0x0D],
0x00B6: [0x00, 0x18, 0x0D, 0x1E, 0x00, 0x04, 0x3C, 0x00, 0x00, 0x00, 0x15, 0x00, 0x0B, 0x05],
0x00B7: [0x00, 0x18, 0x0D, 0x1E, 0x00, 0x00, 0x00, 0x20, 0x18, 0x0D, 0x26, 0x00, 0x00, 0x00],
0x00B8: [0x00, 0x0B, 0x05, 0x08, 0x00, 0x27, 0x00, 0xC0, 0x0B, 0x05, 0x08, 0x00, 0x00, 0x00],
0x00B9: [0xC0, 0x0B, 0x05, 0x08, 0x00, 0x00, 0x00, 0x01, 0x0B, 0x05, 0x08, 0x00, 0x17, 0x00],
0x00BA: [0x01, 0x0B, 0x05, 0x08, 0x00, 0x17, 0x00, 0x40, 0x17, 0x0A, 0x1B, 0x00, 0x00, 0x00],
0x00BB: [0x40, 0x17, 0x0A, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x17, 0x0A, 0x1B, 0x00, 0x17, 0x00],
0x00BC: [0x00, 0x17, 0x0A, 0x1B, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x45, 0x00, 0x13, 0x0B],
0x00BD: [0x00, 0x13, 0x0B, 0x29, 0x00, 0x16, 0x00, 0x00, 0x00, 0x4F, 0x9E, 0x00, 0x13, 0x0B],
0x00BE: [0x00, 0x13, 0x0B, 0x29, 0x00, 0x16, 0x00, 0x00, 0x00, 0x4F, 0x9E, 0x00, 0x13, 0x0B],
0x00BF: [0x00, 0x13, 0x0B, 0x29, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x27, 0x00, 0x02, 0x0F],
0x00C0: [0x01, 0x00, 0x02, 0x27, 0x00, 0x02, 0x0F, 0x00, 0x00, 0x00, 0xB0, 0xD0, 0x00, 0x11],
0x00C1: [0x00, 0x11, 0x0C, 0x1D, 0x00, 0x33, 0x00, 0xC0, 0x11, 0x0C, 0x1D, 0x00, 0x27, 0x00],
0x00C2: [0xC0, 0x11, 0x0C, 0x1D, 0x00, 0x27, 0x00, 0xC0, 0x11, 0x0C, 0x1D, 0x00, 0x00, 0x00],
0x00C3: [0xC0, 0x11, 0x0C, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0D, 0x25, 0x00, 0x00, 0x00],
0x00C4: [0x00, 0x18, 0x0D, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB4, 0x00, 0x18, 0x0D],
0x00C5: [0x00, 0x18, 0x0D, 0x25, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0D, 0x1E, 0x00, 0x33, 0x00],
0x00C6: [0x00, 0x18, 0x0D, 0x1E, 0x00, 0x00, 0x00, 0x20, 0x18, 0x0D, 0x26, 0x00, 0x00, 0x00],
0x00C7: [0x00, 0x18, 0x0D, 0x1E, 0x00, 0x33, 0x00, 0x00, 0x0B, 0x05, 0x09, 0x00, 0x15, 0x25],
0x00C8: [0x00, 0x0B, 0x05, 0x09, 0x00, 0x15, 0x25, 0x00, 0x0B, 0x05, 0x08, 0x00, 0x17, 0x00],
0x00C9: [0x00, 0x0B, 0x05, 0x08, 0x00, 0x17, 0x00, 0xC0, 0x17, 0x0A, 0x1B, 0x00, 0x00, 0x00],
0x00CA: [0xC0, 0x17, 0x0A, 0x1B, 0x00, 0x00, 0x00, 0x20, 0x13, 0x0B, 0x29, 0x00, 0x14, 0x00],
0x00CB: [0xC0, 0x17, 0x0A, 0x1B, 0x00, 0x00, 0x00, 0x20, 0x13, 0x0B, 0x29, 0x00, 0x14, 0x00],
0x00CC: [0xC0, 0x17, 0x0A, 0x1B, 0x00, 0x00, 0x00, 0x20, 0x13, 0x0B, 0x29, 0x00, 0x14, 0x00],
0x00CD: [0x20, 0x13, 0x0B, 0x29, 0x00, 0x14, 0x00, 0x00, 0x00, 0xDE, 0x01, 0x00, 0x02, 0x21],
0x00CE: [0x20, 0x13, 0x0B, 0x29, 0x00, 0x14, 0x00, 0x00, 0x00, 0xDE, 0x01, 0x00, 0x02, 0x21],
0x00CF: [0x01, 0x00, 0x02, 0x21, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xE0, 0x00, 0x11],
0x00D0: [0x01, 0x00, 0x02, 0x21, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xE0, 0x00, 0x11],
0x00D1: [0x00, 0x11, 0x0C, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB1, 0x97, 0x00, 0x11, 0x0C],
0x00D2: [0x00, 0x11, 0x0C, 0x1D, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0x0B, 0x05],
0x00D3: [0x00, 0x0B, 0x05, 0x08, 0x00, 0x06, 0x00, 0x00, 0x0B, 0x05, 0x08, 0x00, 0x17, 0x00],
0x00D4: [0x00, 0x0B, 0x05, 0x08, 0x00, 0x06, 0x00, 0x00, 0x0B, 0x05, 0x08, 0x00, 0x17, 0x00],
0x00D5: [0x00, 0x18, 0x0D, 0x25, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0D, 0x1E, 0x00, 0x33, 0x00],
0x00D6: [0x00, 0x18, 0x0D, 0x1E, 0x00, 0x00, 0x00, 0x20, 0x18, 0x0D, 0x26, 0x00, 0x00, 0x00],
0x00D7: [0x00, 0x0B, 0x05, 0x08, 0x00, 0x06, 0x00, 0x00, 0x0B, 0x05, 0x08, 0x00, 0x17, 0x00],
0x00D8: [0x00, 0x0B, 0x05, 0x08, 0x00, 0x06, 0x00, 0x00, 0x0B, 0x05, 0x08, 0x00, 0x17, 0x00],
0x00D9: [0x00, 0x0B, 0x05, 0x08, 0x00, 0x17, 0x00, 0x00, 0x0B, 0x05, 0x08, 0x00, 0x17, 0x00],
0x00DA: [0x00, 0x0B, 0x05, 0x08, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x99, 0xE0, 0x14, 0x0B],
0x00DB: [0xC0, 0x17, 0x0A, 0x1B, 0x00, 0x00, 0x00, 0x20, 0x13, 0x0B, 0x29, 0x00, 0x14, 0x00],
0x00DC: [0xC0, 0x17, 0x0A, 0x1B, 0x00, 0x00, 0x00, 0x20, 0x13, 0x0B, 0x29, 0x00, 0x14, 0x00],
0x00DD: [0xE0, 0x14, 0x0B, 0x16, 0x00, 0x25, 0x00, 0xC0, 0x20, 0x06, 0x13, 0x00, 0x00, 0x00],
0x00DE: [0xE0, 0x14, 0x0B, 0x16, 0x00, 0x25, 0x00, 0xC0, 0x20, 0x06, 0x13, 0x00, 0x00, 0x00],
0x00DF: [0xC0, 0x20, 0x06, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEF, 0x00, 0x26, 0x02],
0x00E0: [0x00, 0x26, 0x02, 0x21, 0x00, 0x01, 0x2A, 0x00, 0x00, 0x00, 0xD0, 0xC0, 0x07, 0x06],
0x00E1: [0xC0, 0x07, 0x06, 0x28, 0x00, 0x00, 0x00, 0x00, 0x20, 0x06, 0x13, 0x00, 0x00, 0x00],
0x00E2: [0x00, 0x20, 0x06, 0x13, 0x00, 0x00, 0x00, 0xC0, 0x20, 0x06, 0x09, 0x00, 0x00, 0x00],
0x00E3: [0xC0, 0x20, 0x06, 0x09, 0x00, 0x00, 0x00, 0x01, 0x07, 0x14, 0x01, 0x00, 0x00, 0x00],
0x00E4: [0x01, 0x07, 0x14, 0x01, 0x00, 0x00, 0x00, 0x01, 0x07, 0x06, 0x01, 0x00, 0x00, 0x00],
0x00E5: [0x01, 0x07, 0x14, 0x01, 0x00, 0x00, 0x00, 0x01, 0x07, 0x06, 0x01, 0x00, 0x00, 0x00],
0x00E6: [0x01, 0x07, 0x06, 0x01, 0x00, 0x00, 0x00, 0x20, 0x07, 0x06, 0x13, 0x00, 0x00, 0x00],
0x00E7: [0x01, 0x07, 0x06, 0x01, 0x00, 0x00, 0x00, 0x20, 0x07, 0x06, 0x13, 0x00, 0x00, 0x00],
0x00E8: [0x20, 0x07, 0x06, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8],
0x00E9: [0x20, 0x20, 0x06, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFA, 0xFA, 0x20, 0x07, 0x06],
0x00EA: [0x20, 0x20, 0x06, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFA, 0xFA, 0x20, 0x07, 0x06],
0x00EB: [0x20, 0x07, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFB, 0xFB, 0x20, 0x20, 0x06],
0x00EC: [0x20, 0x20, 0x06, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xFD, 0xFD, 0x20, 0x20],
0x00ED: [0x20, 0x20, 0x06, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xFD, 0xFD, 0x20, 0x20],
0x00EE: [0x20, 0x20, 0x06, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x20, 0x20, 0x06, 0x13],
0x00EF: [0x20, 0x20, 0x06, 0x13, 0x00, 0x02, 0x00, 0x08, 0x00, 0xFF, 0xDF, 0xFF, 0x00, 0x02],
0x00F0: [0x01, 0x07, 0x06, 0x01, 0x00, 0x00, 0x00, 0x20, 0x07, 0x06, 0x13, 0x00, 0x00, 0x00],
0x00F1: [0x01, 0x07, 0x06, 0x01, 0x00, 0x00, 0x00, 0x20, 0x07, 0x06, 0x13, 0x00, 0x00, 0x00],
0x00F2: [0x00, 0x02, 0x03, 0x05, 0x00, 0x00, 0x02, 0x03, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x07],
0x00F3: [0x00, 0x02, 0x03, 0x05, 0x00, 0x00, 0x02, 0x03, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x07],
0x00F4: [0x00, 0x02, 0x03, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x07, 0x06, 0x13, 0x00, 0x00, 0x00],
0x00F5: [0x00, 0x02, 0x03, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x07, 0x06, 0x13, 0x00, 0x00, 0x00],
0x00F6: [0x00, 0x07, 0x06, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE8, 0xE8, 0xE8, 0xE8],
0x00F7: [0x00, 0x07, 0x06, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE8, 0xE8, 0xE8, 0xE8],
0x00F8: [0x00, 0x07, 0x06, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE8, 0xE8, 0xE8, 0xE8],
0x00F9: [0x00, 0x20, 0x06, 0x13, 0x00, 0x00, 0x00, 0xC0, 0x20, 0x06, 0x13, 0x00, 0x00, 0x00],
0x00FA: [0xC0, 0x20, 0x06, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEA, 0x00, 0x07, 0x06],
0x00FB: [0x00, 0x07, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEB, 0x00, 0x20, 0x06],
0x00FC: [0x00, 0x20, 0x06, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xED, 0xED, 0x00, 0x07],
0x00FD: [0x00, 0x20, 0x06, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xED, 0xED, 0x00, 0x07],
0x00FE: [0x00, 0x20, 0x06, 0x13, 0x00, 0x00, 0x00, 0xC0, 0x20, 0x06, 0x13, 0x00, 0x00, 0x00],
0x00FF: [0x00, 0x07, 0x06, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEF, 0x00, 0x05, 0x03],
0x0100: [0x00, 0x05, 0x03, 0x28, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x03, 0x05, 0x00, 0x00, 0x00],
0x0101: [0x00, 0x02, 0x03, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x15, 0x03, 0x0D, 0x00, 0x00, 0x00],
0x0102: [0x00, 0x15, 0x03, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x05, 0x03, 0x0F, 0x00, 0x00, 0x00],
0x0103: [0x00, 0x05, 0x03, 0x0F, 0x00, 0x00, 0x00, 0x01, 0x15, 0x03, 0x0D, 0x00, 0x00, 0x00],
0x0104: [0x01, 0x15, 0x03, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x0F, 0x10, 0x00, 0x00, 0x00],
0x0105: [0x00, 0x1C, 0x0F, 0x10, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x03, 0x0F, 0x00, 0x00, 0x00],
0x0106: [0x00, 0x1F, 0x03, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x01, 0x00, 0x00, 0x00],
0x0107: [0x00, 0x02, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x0E, 0x00, 0x00, 0x00],
0x0108: [0x00, 0x02, 0x03, 0x0E, 0x00, 0x00, 0x00, 0x01, 0x05, 0x03, 0x05, 0x00, 0x00, 0x00],
0x0109: [0x01, 0x05, 0x03, 0x05, 0x00, 0x00, 0x00, 0x01, 0x07, 0x06, 0x10, 0x00, 0x00, 0x00],
0x010A: [0x01, 0x07, 0x06, 0x10, 0x00, 0x00, 0x00, 0x80, 0x0A, 0x08, 0x08, 0x00, 0x00, 0x1A],
0x010B: [0x80, 0x0A, 0x08, 0x08, 0x00, 0x00, 0x1A, 0x00, 0x27, 0x06, 0x08, 0x00, 0x03, 0x00],
0x010C: [0x00, 0x27, 0x06, 0x08, 0x00, 0x03, 0x00, 0x00, 0x0A, 0x08, 0x11, 0x00, 0x00, 0x00],
0x010D: [0x00, 0x0A, 0x08, 0x11, 0x00, 0x00, 0x00, 0x00, 0x07, 0x14, 0x05, 0x00, 0x00, 0x00],
0x010E: [0x00, 0x07, 0x14, 0x05, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x11, 0x05, 0x00, 0x00, 0x00],
0x010F: [0x00, 0x1F, 0x03, 0x05, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x0F, 0x00, 0x00, 0x00],
0x0110: [0x00, 0x1F, 0x03, 0x05, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x0F, 0x00, 0x00, 0x00],
0x0111: [0x00, 0x1E, 0x11, 0x05, 0x00, 0x00, 0x00, 0x00, 0x07, 0x14, 0x05, 0x00, 0x00, 0x00],
0x0112: [0x00, 0x07, 0x14, 0x05, 0x00, 0x00, 0x00, 0x00, 0x03, 0x10, 0x08, 0x00, 0x00, 0x00],
0x0113: [0x00, 0x03, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x07, 0x06, 0x07, 0x00, 0x00, 0x00],
0x0114: [0x00, 0x07, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, 0x22, 0x12, 0x07, 0x00, 0x00, 0x00],
0x0115: [0x00, 0x07, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, 0x22, 0x12, 0x07, 0x00, 0x00, 0x00],
0x0116: [0x00, 0x22, 0x12, 0x07, 0x00, 0x00, 0x00, 0x00, 0x20, 0x14, 0x05, 0x00, 0x00, 0x00],
0x0117: [0x00, 0x20, 0x14, 0x05, 0x00, 0x00, 0x00, 0xE0, 0x23, 0x0A, 0x0F, 0x00, 0x00, 0x00],
0x0118: [0x00, 0x05, 0x03, 0x0F, 0x00, 0x00, 0x00, 0x01, 0x15, 0x03, 0x0D, 0x00, 0x00, 0x00],
0x0119: [0xE0, 0x23, 0x0A, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x1C, 0x0F],
0x011A: [0x00, 0x1C, 0x0F, 0x05, 0x00, 0x00, 0x00, 0xC0, 0x07, 0x06, 0x08, 0x00, 0x00, 0x00],
0x011B: [0xC0, 0x07, 0x06, 0x08, 0x00, 0x00, 0x00, 0x00, 0x23, 0x0A, 0x0F, 0x00, 0x00, 0x00],
0x011C: [0x00, 0x1F, 0x03, 0x05, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x0F, 0x00, 0x00, 0x00],
0x011D: [0x00, 0x23, 0x0A, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x20, 0x06],
0x011E: [0x00, 0x20, 0x06, 0x2A, 0x00, 0x00, 0x00, 0x00, 0x05, 0x03, 0x05, 0x00, 0x00, 0x00],
0x011F: [0x00, 0x05, 0x03, 0x05, 0x00, 0x00, 0x00, 0x00, 0x13, 0x06, 0x13, 0x00, 0x00, 0x00],
0x0120: [0x00, 0x13, 0x06, 0x13, 0x00, 0x00, 0x00, 0x00, 0x07, 0x06, 0x28, 0x00, 0x03, 0x00],
0x0121: [0x00, 0x1E, 0x11, 0x05, 0x00, 0x00, 0x00, 0x00, 0x07, 0x14, 0x05, 0x00, 0x00, 0x00],
0x0122: [0x00, 0x1E, 0x11, 0x05, 0x00, 0x00, 0x00, 0x00, 0x07, 0x14, 0x05, 0x00, 0x00, 0x00],
0x0123: [0x00, 0x07, 0x06, 0x28, 0x00, 0x03, 0x00, 0x00, 0x07, 0x06, 0x28, 0x00, 0x00, 0x00],
0x0124: [0x00, 0x07, 0x06, 0x28, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
0x0125: [0x00, 0x07, 0x06, 0x28, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
0x0126: [0x00, 0x07, 0x06, 0x28, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
0x0127: [0x00, 0x20, 0x06, 0x2A, 0x00, 0x00, 0x00, 0x00, 0x05, 0x03, 0x05, 0x00, 0x00, 0x00],
0x0128: [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
0x0129: [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
0x012A: [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
0x012B: [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
0x012C: [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
0x012D: [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
0x012E: [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]
}
class RoomHeader:
def __init__(self, room_id, byte_array):
self.room_id = room_id
# todo: the rest of the header
self.byte_0 = byte_array[0] # bg2, collision, lights out
self.sprite_sheet = byte_array[3] # sprite gfx #
self.effect = byte_array[4]
def write_to_rom(self, rom, base_address):
room_offest = self.room_id*14
rom.write_byte(base_address + room_offest + 0, self.byte_0)
rom.write_byte(base_address + room_offest + 3, self.sprite_sheet)
rom.write_byte(base_address + room_offest + 4, self.effect)
def init_room_headers():
header_table = {}
for room_id, header_bytes in vanilla_headers.items():
header_table[room_id] = RoomHeader(room_id, header_bytes)
return header_table

View File

@@ -1,34 +1,505 @@
try:
from fast_enum import FastEnum
except ImportError:
from enum import IntFlag as FastEnum
from RoomData import DoorKind, Position
from source.dungeon.RoomObject import RoomObject, DoorObject
class Room:
def __init__(self, layout, layer1, layer2, doors):
def __init__(self, layout, layer1, layer2, doors, layer3=None):
self.layout = layout
self.layer1 = layer1
self.layer2 = layer2
self.layer3 = layer3
self.doors = doors
def write_to_rom(self, address, rom):
offset = 0
rom.write_bytes(address, self.layout)
address += 2
offset += 2
for obj in self.layer1:
rom.write_bytes(address, obj.data)
address += 3
rom.write_bytes(address, [0xFF, 0xFF])
address += 2
rom.write_bytes(address + offset, obj.data)
offset += 3
rom.write_bytes(address + offset, [0xFF, 0xFF])
offset += 2
for obj in self.layer2:
rom.write_bytes(address, obj.data)
address += 3
rom.write_bytes(address, [0xFF, 0xFF, 0xF0, 0xFF])
address += 4
rom.write_bytes(address + offset, obj.data)
offset += 3
rom.write_bytes(address + offset, [0xFF, 0xFF])
offset += 2
if self.layer3:
for obj in self.layer3:
rom.write_bytes(address + offset, obj.data)
offset += 3
rom.write_bytes(address + offset, [0xF0, 0xFF])
offset += 2
door_start = offset
for door in self.doors:
rom.write_bytes(address, door.get_bytes())
address += 2
rom.write_bytes(address, [0xFF, 0xFF])
return address + 2 # where the data ended
rom.write_bytes(address + offset, door.get_bytes())
offset += 2
rom.write_bytes(address + offset, [0xFF, 0xFF])
return door_start, offset + 2 # how many bytes were written
def find_all_pots(self):
pots = []
pots.extend([x for x in self.layer1 if x.data[2] in {0xFA, 0xFB} and not x.dummy])
pots.extend([x for x in self.layer2 if x.data[2] in {0xFA, 0xFB} and not x.dummy])
if self.layer3:
pots.extend([x for x in self.layer3 if x.data[2] in {0xFA, 0xFB} and not x.dummy])
return pots
Room0006 = Room([0xE1, 0x00],
[RoomObject(0x1FA15C, [0x1B, 0xA3, 0xC8]),
RoomObject(0x1FA15F, [0x58, 0xA3, 0xC8]),
RoomObject(0x1FA162, [0x1B, 0xD8, 0xC8]),
RoomObject(0x1FA165, [0x58, 0xD8, 0xC8]),
RoomObject(0x1FA168, [0x17, 0x9F, 0x3F]),
RoomObject(0x1FA16B, [0x54, 0x9F, 0x3F]),
RoomObject(0x1FA16E, [0x17, 0xA3, 0x79]),
RoomObject(0x1FA171, [0x14, 0xE1, 0x79]),
RoomObject(0x1FA174, [0x17, 0xEB, 0x40]),
RoomObject(0x1FA177, [0x54, 0xEB, 0x40]),
RoomObject(0x1FA17A, [0x6B, 0xA3, 0x7A]),
RoomObject(0x1FA17D, [0x68, 0xE1, 0x7A]),
RoomObject(0x1FA180, [0x21, 0x90, 0xF8]),
RoomObject(0x1FA183, [0x51, 0x90, 0xF8]),
RoomObject(0x1FA186, [0x0C, 0xA5, 0x7F]),
RoomObject(0x1FA189, [0x6C, 0xA5, 0x80])],
[], [DoorObject(Position.SouthW, DoorKind.Trap)])
Room0007 = Room([0x81, 0x1C],
[RoomObject(0x1FCAF0, [0x0A, 0x4E, 0x0D]),
RoomObject(0x1FCAF3, [0x0A, 0xAA, 0x0E]),
RoomObject(0x1FCAF6, [0x0B, 0x51, 0x61]),
RoomObject(0x1FCAF9, [0xC0, 0x2C, 0xA2]),
RoomObject(0x1FCAFC, [0xB0, 0x20, 0x0F]),
RoomObject(0x1FCAFF, [0xB0, 0x22, 0x62]),
RoomObject(0x1FCB02, [0xFE, 0xC1, 0x02]),
RoomObject(0x1FCB05, [0xC9, 0x38, 0x01]),
RoomObject(0x1FCB08, [0xFF, 0xA3, 0x82]),
RoomObject(0x1FCB0B, [0xBA, 0xE6, 0x10]),
RoomObject(0x1FCB0E, [0xE8, 0xAA, 0x62]),
RoomObject(0x1FCB11, [0xFF, 0x43, 0xB9]),
RoomObject(0x1FCB14, [0x53, 0x53, 0xE0]),
RoomObject(0x1FCB17, [0x91, 0x53, 0xE0]),
RoomObject(0x1FCB1A, [0x53, 0x91, 0xE0]),
RoomObject(0x1FCB1D, [0x91, 0x91, 0xE0]),
RoomObject(0x1FCB20, [0x3C, 0x6B, 0xC2]),
RoomObject(0x1FCB23, [0x3D, 0x9B, 0xC3]),
RoomObject(0x1FCB26, [0x54, 0xA6, 0xC3]),
RoomObject(0x1FCB29, [0x5C, 0xAA, 0xC3]),
RoomObject(0x1FCB2C, [0x68, 0xB1, 0xC3]),
RoomObject(0x1FCB2F, [0x75, 0xB0, 0xC3]),
RoomObject(0x1FCB32, [0x8F, 0xB1, 0xC3]),
RoomObject(0x1FCB35, [0x9B, 0xAA, 0xC3]),
RoomObject(0x1FCB38, [0xA6, 0xA0, 0xC3]),
RoomObject(0x1FCB3B, [0xAD, 0x98, 0xC3]),
RoomObject(0x1FCB3E, [0xB4, 0x6A, 0xC2]),
RoomObject(0x1FCB41, [0x51, 0x3D, 0xC3]),
RoomObject(0x1FCB44, [0x45, 0x49, 0xC3]),
RoomObject(0x1FCB47, [0x3D, 0x51, 0xC3]),
RoomObject(0x1FCB4A, [0x9C, 0x39, 0xC2]),
RoomObject(0x1FCB4D, [0xA1, 0x49, 0xC3]),
RoomObject(0x1FCB50, [0xAD, 0x51, 0xC3]),
RoomObject(0x1FCB53, [0x3A, 0x50, 0x8A]),
RoomObject(0x1FCB56, [0x38, 0x50, 0x22]),
RoomObject(0x1FCB59, [0x44, 0x44, 0x69]),
RoomObject(0x1FCB5C, [0x44, 0x44, 0x22]),
RoomObject(0x1FCB5F, [0x58, 0x13, 0x05]),
RoomObject(0x1FCB62, [0x60, 0x15, 0x55]),
RoomObject(0x1FCB65, [0x78, 0x10, 0x3A]),
RoomObject(0x1FCB68, [0x08, 0x5B, 0x65]),
RoomObject(0x1FCB6B, [0x0C, 0x61, 0x7F]),
RoomObject(0x1FCB6E, [0xC8, 0x39, 0x05]),
RoomObject(0x1FCB71, [0xE8, 0x5B, 0x66]),
RoomObject(0x1FCB74, [0xEC, 0x4A, 0x80]),
RoomObject(0x1FCB77, [0x58, 0xEB, 0x06]),
RoomObject(0x1FCB7A, [0x60, 0xED, 0x56]),
RoomObject(0x1FCB7D, [0x78, 0xEC, 0x3B]),
RoomObject(0x1FCB80, [0x50, 0x38, 0x69]),
RoomObject(0x1FCB83, [0x50, 0x38, 0x5F]),
RoomObject(0x1FCB86, [0xA8, 0x38, 0x69]),
RoomObject(0x1FCB89, [0xA8, 0x44, 0x22]),
RoomObject(0x1FCB8C, [0xB4, 0x44, 0x69]),
RoomObject(0x1FCB8F, [0xB4, 0x51, 0x22]),
RoomObject(0x1FCB92, [0xC6, 0x50, 0x8A]),
RoomObject(0x1FCB95, [0x3B, 0xC8, 0x22]),
RoomObject(0x1FCB98, [0x8B, 0xC8, 0x22]),
RoomObject(0x1FCB9B, [0x74, 0xBC, 0x69]),
RoomObject(0x1FCB9E, [0x88, 0xBC, 0x69]),
RoomObject(0x1FCBA1, [0x63, 0x3C, 0xC2]),
RoomObject(0x1FCBA4, [0x66, 0x4F, 0x29]),
RoomObject(0x1FCBA7, [0x64, 0x50, 0x6B]),
RoomObject(0x1FCBAA, [0x5C, 0x54, 0x2B]),
RoomObject(0x1FCBAD, [0x5C, 0x58, 0x6B]),
RoomObject(0x1FCBB0, [0x54, 0x5C, 0x2B]),
RoomObject(0x1FCBB3, [0x54, 0x60, 0x6B]),
RoomObject(0x1FCBB6, [0x4C, 0x64, 0x2B]),
RoomObject(0x1FCBB9, [0x4E, 0x6B, 0x6B]),
RoomObject(0x1FCBBC, [0x4C, 0x98, 0x2D]),
RoomObject(0x1FCBBF, [0x54, 0x9C, 0x6B]),
RoomObject(0x1FCBC2, [0x54, 0xA0, 0x2D]),
RoomObject(0x1FCBC5, [0x5C, 0xA4, 0x6B]),
RoomObject(0x1FCBC8, [0x5C, 0xA8, 0x2D]),
RoomObject(0x1FCBCB, [0x64, 0xAC, 0x6B]),
RoomObject(0x1FCBCE, [0x66, 0xB3, 0x2A]),
RoomObject(0x1FCBD1, [0x98, 0xAC, 0x6A]),
RoomObject(0x1FCBD4, [0x98, 0xA8, 0x2E]),
RoomObject(0x1FCBD7, [0xA0, 0xA4, 0x6A]),
RoomObject(0x1FCBDA, [0xA0, 0xA0, 0x2E]),
RoomObject(0x1FCBDD, [0xA8, 0x9C, 0x6A]),
RoomObject(0x1FCBE0, [0xA8, 0x98, 0x2E]),
RoomObject(0x1FCBE3, [0xB2, 0x6B, 0x6A]),
RoomObject(0x1FCBE6, [0xA8, 0x64, 0x2C]),
RoomObject(0x1FCBE9, [0xA8, 0x60, 0x6A]),
RoomObject(0x1FCBEC, [0xA0, 0x5C, 0x2C]),
RoomObject(0x1FCBEF, [0xA0, 0x58, 0x6A]),
RoomObject(0x1FCBF2, [0x98, 0x54, 0x2C]),
RoomObject(0x1FCBF5, [0x98, 0x50, 0x6A]),
RoomObject(0x1FCBF8, [0x68, 0x74, 0xC2]),
RoomObject(0x1FCBFB, [0x68, 0x71, 0x27]),
RoomObject(0x1FCBFE, [0x68, 0x77, 0x6A]),
RoomObject(0x1FCC01, [0x74, 0x77, 0x6B]),
RoomObject(0x1FCC04, [0x68, 0x85, 0x28]),
RoomObject(0x1FCC07, [0xFC, 0x31, 0x72]),
RoomObject(0x1FCC0A, [0x74, 0xAE, 0x04]),
RoomObject(0x1FCC0D, [0x71, 0xA0, 0xE0]),
RoomObject(0x1FCC10, [0x0A, 0x13, 0xA0]),
RoomObject(0x1FCC13, [0x0A, 0xBF, 0xA1]),
RoomObject(0x1FCC16, [0xBE, 0xF7, 0xA3]),
RoomObject(0x1FCC19, [0xC3, 0x11, 0xC0]),
RoomObject(0x1FCC1C, [0xD1, 0x31, 0x00])],
[], [])
Room001C = Room([0xE1, 0x00],
[RoomObject(0x1FF74B, [0x2D, 0x32, 0xA4]),
RoomObject(0x1FF74E, [0xA9, 0x1E, 0xDC]),
RoomObject(0x1FF751, [0xA8, 0x91, 0x3A]),
RoomObject(0x1FF754, [0x88, 0xAD, 0x76]),
RoomObject(0x1FF757, [0xEC, 0xAD, 0x77]),
RoomObject(0x1FF75A, [0xA8, 0x50, 0x3D]),
RoomObject(0x1FF75D, [0xD0, 0x50, 0x3D]),
RoomObject(0x1FF760, [0x30, 0xA9, 0x3D]),
RoomObject(0x1FF763, [0x30, 0xC1, 0x3D]),
RoomObject(0x1FF766, [0xFC, 0x69, 0x38]),
RoomObject(0x1FF769, [0x97, 0x9F, 0xD1]),
RoomObject(0x1FF76C, [0xCD, 0x9F, 0xD1]),
RoomObject(0x1FF76F, [0x97, 0xDC, 0xD1]),
RoomObject(0x1FF772, [0xCD, 0xDC, 0xD1]),
RoomObject(0x1FF775, [0xBD, 0x32, 0xF9]),
RoomObject(0x1FF778, [0xB1, 0x22, 0xF9]),
RoomObject(0x1FF77B, [0xC9, 0x22, 0xF9]),], [],
[DoorObject(Position.InteriorE, DoorKind.TrapTriggerable),
DoorObject(Position.InteriorS, DoorKind.Trap), DoorObject(Position.InteriorW, DoorKind.Dashable)])
Room0029 = Room([0xE5, 0x00],
[RoomObject(0x1FC188, [0x97, 0x9C, 0xDE]),
RoomObject(0x1FC18B, [0xB7, 0x9C, 0xDE]),
RoomObject(0x1FC18E, [0xD6, 0x9C, 0xDE]),
RoomObject(0x1FC191, [0x97, 0xE4, 0xDE]),
RoomObject(0x1FC194, [0xB7, 0xE4, 0xDE]),
RoomObject(0x1FC197, [0xD6, 0xE4, 0xDE]),
RoomObject(0x1FC19A, [0x94, 0xA7, 0xDE]),
RoomObject(0x1FC19D, [0x94, 0xC7, 0xDE]),
RoomObject(0x1FC1A0, [0xE4, 0xA7, 0xDE]),
RoomObject(0x1FC1A3, [0xE4, 0xC7, 0xDE])],
[RoomObject(0x1FC1A8, [0x03, 0x03, 0xCA]),
RoomObject(0x1FC1AB, [0x43, 0x03, 0xCA]),
RoomObject(0x1FC1AE, [0x83, 0x03, 0xCA]),
RoomObject(0x1FC1B1, [0xC3, 0x03, 0xCA]),
RoomObject(0x1FC1B4, [0x03, 0x43, 0xCA]),
RoomObject(0x1FC1B7, [0x43, 0x43, 0xCA]),
RoomObject(0x1FC1BA, [0x83, 0x43, 0xCA]),
RoomObject(0x1FC1BD, [0xC3, 0x43, 0xCA]),
RoomObject(0x1FC1C0, [0x03, 0x83, 0xCA]),
RoomObject(0x1FC1C3, [0x43, 0x83, 0xCA]),
RoomObject(0x1FC1C6, [0x83, 0x83, 0xCA]),
RoomObject(0x1FC1C9, [0xC3, 0x83, 0xCA]),
RoomObject(0x1FC1CC, [0x03, 0xC3, 0xCA]),
RoomObject(0x1FC1CF, [0x43, 0xC3, 0xCA]),
RoomObject(0x1FC1D2, [0x83, 0xC3, 0xCA]),
RoomObject(0x1FC1D5, [0xC3, 0xC3, 0xCA])],
[], layer3=[RoomObject(0x1FC1DA, [0x9F, 0xA7, 0xC6]),
RoomObject(0x1FC1DD, [0xD4, 0xA7, 0xC6]),
RoomObject(0x1FC1E0, [0xFE, 0xF9, 0xF4]),
RoomObject(0x1FC1E3, [0xFF, 0x1E, 0x74]),
RoomObject(0x1FC1E6, [0xFE, 0x5C, 0x74]),
RoomObject(0x1FC1E9, [0xFF, 0x9C, 0x74])])
Room0033 = Room([0xE9, 0x00], [], [], [DoorObject(Position.SouthW, DoorKind.Trap)])
Room004D = Room([0x82, 0x1C],
[RoomObject(0x1FFD43, [0x09, 0x34, 0x0D]),
RoomObject(0x1FFD46, [0x08, 0x3A, 0x61]),
RoomObject(0x1FFD49, [0x09, 0xC0, 0x0E]),
RoomObject(0x1FFD4C, [0x08, 0xC2, 0x61]),
RoomObject(0x1FFD4F, [0xD1, 0x10, 0x0F]),
RoomObject(0x1FFD52, [0xE8, 0x3A, 0x62]),
RoomObject(0x1FFD55, [0x5E, 0x1C, 0x03]),
RoomObject(0x1FFD58, [0x17, 0x49, 0x63]),
RoomObject(0x1FFD5B, [0xDF, 0x4B, 0x64]),
RoomObject(0x1FFD5E, [0xDC, 0xCA, 0x64]),
RoomObject(0x1FFD61, [0xFF, 0x7D, 0xCB]),
RoomObject(0x1FFD64, [0x9D, 0xDF, 0x04]),
RoomObject(0x1FFD67, [0x3B, 0x5B, 0xE0]),
RoomObject(0x1FFD6A, [0x7B, 0x5B, 0xE0]),
RoomObject(0x1FFD6D, [0xB8, 0x5B, 0xE0]),
RoomObject(0x1FFD70, [0x6A, 0xB1, 0xE0]),
RoomObject(0x1FFD73, [0x78, 0x54, 0xC2]),
RoomObject(0x1FFD76, [0x5B, 0x2A, 0xC2]),
RoomObject(0x1FFD79, [0x98, 0x2A, 0xC2]),
RoomObject(0x1FFD7C, [0x21, 0x4B, 0xC3]),
RoomObject(0x1FFD7F, [0x21, 0x7B, 0xC3]),
RoomObject(0x1FFD82, [0x21, 0xA1, 0xC3]),
RoomObject(0x1FFD85, [0x38, 0x7B, 0xC2]),
RoomObject(0x1FFD88, [0x48, 0x8A, 0xC2]),
RoomObject(0x1FFD8B, [0x3A, 0xAA, 0xC2]),
RoomObject(0x1FFD8E, [0x5B, 0x9C, 0xC2]),
RoomObject(0x1FFD91, [0xC9, 0x4B, 0xC3]),
RoomObject(0x1FFD94, [0xC9, 0x7B, 0xC3]),
RoomObject(0x1FFD97, [0xB8, 0x79, 0xC2]),
RoomObject(0x1FFD9A, [0xA8, 0x88, 0xC2]),
RoomObject(0x1FFD9D, [0x9B, 0x9B, 0xC2]),
RoomObject(0x1FFDA0, [0x9B, 0xD0, 0xC2]),
RoomObject(0x1FFDA3, [0xD0, 0xA3, 0xC2]),
RoomObject(0x1FFDA6, [0x78, 0x8C, 0xC2]),
RoomObject(0x1FFDA9, [0x15, 0x45, 0x22]),
RoomObject(0x1FFDAC, [0x59, 0x1F, 0x69]),
RoomObject(0x1FFDAF, [0xA5, 0x1F, 0x69]),
RoomObject(0x1FFDB2, [0xC9, 0x45, 0x22]),
RoomObject(0x1FFDB5, [0x68, 0xE4, 0x5E]),
RoomObject(0x1FFDB8, [0x15, 0xB9, 0x22]),
RoomObject(0x1FFDBB, [0x35, 0xB9, 0x69]),
RoomObject(0x1FFDBE, [0x37, 0xD9, 0x22]),
RoomObject(0x1FFDC1, [0x88, 0xD9, 0x22]),
RoomObject(0x1FFDC4, [0x98, 0xD9, 0x69]),
RoomObject(0x1FFDC7, [0x66, 0xCB, 0x2A]),
RoomObject(0x1FFDCA, [0x69, 0xC9, 0x04]),
RoomObject(0x1FFDCD, [0x79, 0xCB, 0xF9]),
RoomObject(0x1FFDD0, [0x8D, 0xBA, 0xF9]),
RoomObject(0x1FFDD3, [0x37, 0x57, 0x29]),
RoomObject(0x1FFDD6, [0x87, 0x57, 0x29]),
RoomObject(0x1FFDD9, [0x78, 0x5A, 0x6A]),
RoomObject(0x1FFDDC, [0x84, 0x5A, 0x6B]),
RoomObject(0x1FFDDF, [0x78, 0x65, 0x28]),
RoomObject(0x1FFDE2, [0x35, 0x5B, 0x6B]),
RoomObject(0x1FFDE5, [0x34, 0x7A, 0x2D]),
RoomObject(0x1FFDE8, [0x44, 0x7E, 0x6B]),
RoomObject(0x1FFDEB, [0x44, 0x8A, 0x2D]),
RoomObject(0x1FFDEE, [0x54, 0x8E, 0x6B]),
RoomObject(0x1FFDF1, [0x55, 0x9B, 0x2A]),
RoomObject(0x1FFDF4, [0x78, 0x8E, 0x6A]),
RoomObject(0x1FFDF7, [0x78, 0x89, 0x27]),
RoomObject(0x1FFDFA, [0x84, 0x8E, 0x6B]),
RoomObject(0x1FFDFD, [0x85, 0x9B, 0x2A]),
RoomObject(0x1FFE00, [0xA8, 0x8E, 0x6A]),
RoomObject(0x1FFE03, [0xA8, 0x8A, 0x2E]),
RoomObject(0x1FFE06, [0xB8, 0x7E, 0x6A]),
RoomObject(0x1FFE09, [0xB8, 0x7A, 0x2E]),
RoomObject(0x1FFE0C, [0xC9, 0x5B, 0x6A]),
RoomObject(0x1FFE0F, [0x66, 0xAF, 0x29]),
RoomObject(0x1FFE12, [0x65, 0xB1, 0x6B]),
RoomObject(0x1FFE15, [0x99, 0xB1, 0x6A]),
RoomObject(0x1FFE18, [0x38, 0x4B, 0x03]),
RoomObject(0x1FFE1B, [0xA8, 0x4B, 0x03]),
RoomObject(0x1FFE1E, [0x48, 0x13, 0x3A]),
RoomObject(0x1FFE21, [0x0C, 0x4A, 0x7F]),
RoomObject(0x1FFE24, [0xEC, 0x4A, 0x80]),
RoomObject(0x1FFE27, [0xFE, 0xE1, 0x39]),
RoomObject(0x1FFE2A, [0x09, 0x11, 0xA0]),
RoomObject(0x1FFE2D, [0xD5, 0x11, 0xA2]),
RoomObject(0x1FFE30, [0x09, 0xD5, 0xA1])],
[RoomObject(0x1FFE35, [0x5B, 0x19, 0xDB]),
RoomObject(0x1FFE38, [0x98, 0x19, 0xDB]),
RoomObject(0x1FFE3B, [0x11, 0x4B, 0xDB]),
RoomObject(0x1FFE3E, [0x11, 0x8A, 0xDB]),
RoomObject(0x1FFE41, [0x39, 0x48, 0xDB]),
RoomObject(0x1FFE44, [0xA9, 0x48, 0xDB]),
RoomObject(0x1FFE47, [0xD9, 0x4B, 0xDB]),
RoomObject(0x1FFE4A, [0xD9, 0x8B, 0xDB]),
RoomObject(0x1FFE4D, [0x6A, 0xC8, 0xDB]),
RoomObject(0x1FFE50, [0x9B, 0xCA, 0xDB]),
RoomObject(0x1FFE53, [0xD9, 0xCA, 0xDB])],
[DoorObject(Position.NorthW, DoorKind.SmallKey), DoorObject(Position.WestS, DoorKind.Normal)])
Room005A = Room([0xE9, 0x00],
[RoomObject(0x1FA7CD, [0xA8, 0xA8, 0xDE]),
RoomObject(0x1FA7D0, [0xB0, 0xA0, 0xDE]),
RoomObject(0x1FA7D3, [0xB8, 0xA8, 0xDE]),
RoomObject(0x1FA7D6, [0xC0, 0xA0, 0xDE]),
RoomObject(0x1FA7D9, [0xC8, 0xA8, 0xDE]),
RoomObject(0x1FA7DC, [0xD0, 0xA0, 0xDE])],
[], [DoorObject(Position.SouthE, DoorKind.Trap)])
Room006C = Room([0xE2, 0x00],
[RoomObject(0x1FFA58, [0x17, 0x9F, 0xE8]),
RoomObject(0x1FFA5B, [0x4D, 0x9F, 0xE8]),
RoomObject(0x1FFA5E, [0x17, 0xDC, 0xE8]),
RoomObject(0x1FFA61, [0x4D, 0xDC, 0xE8]),
RoomObject(0x1FFA64, [0x18, 0xE1, 0xFE]),
RoomObject(0x1FFA67, [0x88, 0xAD, 0x76]),
RoomObject(0x1FFA6A, [0x99, 0xBC, 0x33]),
RoomObject(0x1FFA6D, [0x9B, 0xBB, 0x34]),
RoomObject(0x1FFA70, [0x9B, 0xCF, 0x34]),
RoomObject(0x1FFA73, [0xD8, 0xB8, 0x34]),
RoomObject(0x1FFA76, [0xD8, 0xCC, 0x34]),
RoomObject(0x1FFA79, [0xAF, 0xAA, 0xFE]),
RoomObject(0x1FFA7C, [0xC7, 0xAA, 0xFE]),
RoomObject(0x1FFA7F, [0xAF, 0xD2, 0xFE]),
RoomObject(0x1FFA82, [0xC7, 0xD2, 0xFE]),
RoomObject(0x1FFA85, [0x28, 0x11, 0x3A]),
RoomObject(0x1FFA88, [0x28, 0x91, 0x3A]),
RoomObject(0x1FFA8B, [0xFC, 0xE1, 0x38]),
RoomObject(0x1FFA8E, [0x2B, 0x33, 0xFA]),
RoomObject(0x1FFA91, [0x53, 0x33, 0xFA]),
RoomObject(0x1FFA94, [0x2B, 0x53, 0xFA]),
RoomObject(0x1FFA97, [0x53, 0x53, 0xFA])], [],
[DoorObject(Position.InteriorS, DoorKind.Trap2), DoorObject(Position.InteriorW, DoorKind.Trap),
DoorObject(Position.EastS, DoorKind.Normal)])
Room0090 = Room([0xE1, 0x00],
[RoomObject(0x1FBAA0, [0x28, 0xEC, 0x56]),
RoomObject(0x1FBAA3, [0x48, 0xEC, 0x56]),
RoomObject(0x1FBAA6, [0x1B, 0xA2, 0xFF])],
[RoomObject(0x1FBAAB, [0x16, 0x9C, 0xFE])], [DoorObject(Position.SouthW, DoorKind.Trap)])
Room00A4 = Room([0xE1, 0x00],
[RoomObject(0x1FE702, [0xFC, 0x08, 0x00]),
RoomObject(0x1FE705, [0x13, 0x80, 0x01]),
RoomObject(0x1FE708, [0xFD, 0xC8, 0x02]),
RoomObject(0x1FE70B, [0x02, 0x93, 0x61]),
RoomObject(0x1FE70E, [0xFC, 0x0E, 0x81]),
RoomObject(0x1FE711, [0x13, 0xE8, 0x02]),
RoomObject(0x1FE714, [0xFD, 0xCE, 0x83]),
RoomObject(0x1FE717, [0x72, 0x93, 0x62]),
RoomObject(0x1FE71A, [0x13, 0x93, 0xC4]),
RoomObject(0x1FE71D, [0x51, 0x93, 0xC4]),
RoomObject(0x1FE720, [0x51, 0xC9, 0xC4]),
RoomObject(0x1FE723, [0x10, 0xC9, 0xC4]),
RoomObject(0x1FE726, [0x0E, 0x8D, 0xDE]),
RoomObject(0x1FE729, [0x0D, 0x9C, 0xDE]),
RoomObject(0x1FE72C, [0x0C, 0xA5, 0xDE]),
RoomObject(0x1FE72F, [0x5E, 0x8C, 0xDE]),
RoomObject(0x1FE732, [0x65, 0x94, 0xDE]),
RoomObject(0x1FE735, [0x6C, 0x9C, 0xDE])],
[RoomObject(0x1FE73A, [0x2E, 0x98, 0xFF])], [DoorObject(Position.SouthW, DoorKind.Trap)])
Room00AC = Room([0xE9, 0x00],
[RoomObject(0x1FD9B1, [0x88, 0xA4, 0x0D]),
RoomObject(0x1FD9B4, [0x88, 0xD0, 0x0E]),
RoomObject(0x1FD9B7, [0xE0, 0x90, 0x0F]),
RoomObject(0x1FD9BA, [0xE0, 0xE4, 0x10]),
RoomObject(0x1FD9BD, [0x89, 0xAB, 0x61]),
RoomObject(0x1FD9C0, [0xE9, 0xAB, 0x62]),
RoomObject(0x1FD9C3, [0x88, 0x91, 0xA0]),
RoomObject(0x1FD9C6, [0x88, 0xE5, 0xA1]),
RoomObject(0x1FD9C9, [0xE4, 0x91, 0xA2]),
RoomObject(0x1FD9CC, [0xE4, 0xF5, 0xA3])],
[RoomObject(0x1FD9D1, [0xB1, 0xA8, 0xFF])], [DoorObject(Position.SouthE, DoorKind.Trap)])
Room00C8 = Room([0xE1, 0x00],
[RoomObject(0x0A9587, [0x98, 0x92, 0x3A]),
RoomObject(0x0A958A, [0x88, 0xAA, 0x65]),
RoomObject(0x0A958D, [0xE8, 0xAA, 0x66])], [], [DoorObject(Position.SouthE, DoorKind.Trap)])
Room00DE = Room([0xE4, 0x00], [], [RoomObject(0x1FCAE5, [0xAD, 0x21, 0xF9])], [])
Room010C = Room([0xE0, 0x08],
[RoomObject(0x03F25D, [0xFC, 0x62, 0x00]),
RoomObject(0x03F260, [0x19, 0x33, 0x61]),
RoomObject(0x03F263, [0xFC, 0x66, 0x81]),
RoomObject(0x03F266, [0x29, 0x22, 0x01]),
RoomObject(0x03F269, [0xFD, 0x62, 0x02]),
RoomObject(0x03F26C, [0x59, 0x33, 0x62]),
RoomObject(0x03F26F, [0xFD, 0x66, 0x83]),
RoomObject(0x03F272, [0xFC, 0x89, 0x00]),
RoomObject(0x03F275, [0x22, 0xA1, 0x61]),
RoomObject(0x03F278, [0xFC, 0x8E, 0x81]),
RoomObject(0x03F27B, [0x90, 0xCA, 0x0E]),
RoomObject(0x03F27E, [0xD0, 0xE6, 0x10]),
RoomObject(0x03F281, [0xFE, 0x41, 0x00]),
RoomObject(0x03F284, [0x93, 0x23, 0x61]),
RoomObject(0x03F287, [0x92, 0x98, 0x61]),
RoomObject(0x03F28A, [0xFF, 0x81, 0x02]),
RoomObject(0x03F28D, [0xE3, 0x23, 0x62]),
RoomObject(0x03F290, [0xE2, 0x98, 0x62]),
RoomObject(0x03F293, [0xFE, 0x71, 0xC8]),
RoomObject(0x03F296, [0xAD, 0x1C, 0x03]),
RoomObject(0x03F299, [0xFF, 0x51, 0xCA]),
RoomObject(0x03F29C, [0x9D, 0x2D, 0x63]),
RoomObject(0x03F29F, [0xFE, 0x75, 0x89]),
RoomObject(0x03F2A2, [0xAD, 0x58, 0x04]),
RoomObject(0x03F2A5, [0xD5, 0x2D, 0x64]),
RoomObject(0x03F2A8, [0xFF, 0x55, 0x8B]),
RoomObject(0x03F2AB, [0xFE, 0x78, 0x08]),
RoomObject(0x03F2AE, [0xAD, 0x80, 0x03]),
RoomObject(0x03F2B1, [0xFF, 0x58, 0x0A]),
RoomObject(0x03F2B4, [0x9C, 0x91, 0x63]),
RoomObject(0x03F2B7, [0xFE, 0x7A, 0x09]),
RoomObject(0x03F2BA, [0xAD, 0xA0, 0x04]),
RoomObject(0x03F2BD, [0xFF, 0x5A, 0x0B]),
RoomObject(0x03F2C0, [0xD4, 0x91, 0x64]),
RoomObject(0x03F2C3, [0x2C, 0x2E, 0xDC]),
RoomObject(0x03F2C6, [0x3D, 0x3E, 0xF9]),
RoomObject(0x03F2C9, [0x32, 0xA9, 0xF9]),
RoomObject(0x03F2CC, [0x3A, 0xA9, 0xF9]),
RoomObject(0x03F2CF, [0x42, 0xA9, 0xF9]),
RoomObject(0x03F2D2, [0x4A, 0xA9, 0xF9]),
RoomObject(0x03F2D5, [0x57, 0x9E, 0x69]),
RoomObject(0x03F2D8, [0x54, 0xDC, 0x69]),
RoomObject(0x03F2DB, [0x38, 0xC8, 0x89]),
RoomObject(0x03F2DE, [0x58, 0x9C, 0x89]),
RoomObject(0x03F2E1, [0x58, 0xA8, 0x89]),
RoomObject(0x03F2E4, [0x58, 0xB4, 0x89]),
RoomObject(0x03F2E7, [0x58, 0xC0, 0x89]),
RoomObject(0x03F2EA, [0x58, 0xCC, 0x89]),
RoomObject(0x03F2ED, [0x58, 0xD8, 0x89]),
RoomObject(0x03F2F0, [0x58, 0xE4, 0x89]),
RoomObject(0x03F2F3, [0xAA, 0x2E, 0xC8]),
RoomObject(0x03F2F6, [0xAA, 0x29, 0x3F]),
RoomObject(0x03F2F9, [0xAA, 0x2E, 0x79]),
RoomObject(0x03F2FC, [0xAA, 0x59, 0x40]),
RoomObject(0x03F2FF, [0xD6, 0x2E, 0x7A]),
RoomObject(0x03F302, [0xAA, 0x90, 0xC8]),
RoomObject(0x03F305, [0xAA, 0x8D, 0x3F]),
RoomObject(0x03F308, [0xA8, 0x93, 0x79]),
RoomObject(0x03F30B, [0xAA, 0xA1, 0x40]),
RoomObject(0x03F30E, [0xD4, 0x93, 0x7A]),
RoomObject(0x03F311, [0xB9, 0x5B, 0xF9]),
RoomObject(0x03F314, [0xB9, 0xA3, 0xF9]),
RoomObject(0x03F317, [0x9C, 0x68, 0x22]),
RoomObject(0x03F31A, [0x9C, 0x6A, 0x69]),
RoomObject(0x03F31D, [0x9C, 0x7C, 0x22]),
RoomObject(0x03F320, [0xD4, 0x7C, 0x22]),
RoomObject(0x03F323, [0x9C, 0xB0, 0x22]),
RoomObject(0x03F326, [0xD4, 0xB0, 0x22]),
RoomObject(0x03F329, [0xB3, 0x73, 0xFA]),
RoomObject(0x03F32C, [0xCD, 0x68, 0xDD]),
RoomObject(0x03F32F, [0xB8, 0xC0, 0xDD]),
RoomObject(0x03F332, [0x08, 0x00, 0x60]),
RoomObject(0x03F335, [0x10, 0x00, 0x60]),
RoomObject(0x03F338, [0x1B, 0x10, 0xC0]),
RoomObject(0x03F33B, [0x59, 0x10, 0xC0]),
RoomObject(0x03F33E, [0x68, 0x23, 0xC0]),
RoomObject(0x03F341, [0x68, 0x61, 0xC0]),
RoomObject(0x03F344, [0x1B, 0x91, 0x60]),
RoomObject(0x03F347, [0x88, 0x10, 0x60]),
RoomObject(0x03F34A, [0xF0, 0x10, 0x60]),
RoomObject(0x03F34D, [0x90, 0xDF, 0xA1]),
RoomObject(0x03F350, [0xD4, 0xF7, 0xA3])], [],
[DoorObject(Position.InteriorW, DoorKind.TrapTriggerable),
DoorObject(Position.SouthW, DoorKind.CaveEntrance), DoorObject(Position.SouthE, DoorKind.CaveEntrance)]
)
Room0127 = Room([0xE1, 0x00],
[RoomObject(0x0AB600, [0xFE, 0x89, 0x00]),
@@ -44,15 +515,35 @@ Room0127 = Room([0xE1, 0x00],
RoomObject(0x0AB61E, [0x43, 0xCB, 0xFA]),
RoomObject(0x0AB621, [0x4B, 0xCB, 0xFA]),
RoomObject(0x0AB624, [0xBF, 0x94, 0xF9]),
RoomObject(0x0AB627, [0xB3, 0xB3, 0xFA]),
RoomObject(0x0AB62A, [0xCB, 0xB3, 0xFA]),
RoomObject(0x0AB627, [0xB3, 0xB3, 0xFA], True),
RoomObject(0x0AB62A, [0xCB, 0xB3, 0xFA], True),
RoomObject(0x0AB62D, [0xAD, 0xC8, 0xDF]),
RoomObject(0x0AB630, [0xC4, 0xC8, 0xDF]),
RoomObject(0x0AB633, [0xB3, 0xE3, 0xFA]),
RoomObject(0x0AB636, [0xCB, 0xE3, 0xFA]),
RoomObject(0x0AB633, [0xB3, 0xE3, 0xFA], True),
RoomObject(0x0AB636, [0xCB, 0xE3, 0xFA], True),
RoomObject(0x0AB639, [0x81, 0x93, 0xC0]),
RoomObject(0x0AB63C, [0x81, 0xD2, 0xC0]),
RoomObject(0x0AB63F, [0xE1, 0x93, 0xC0]),
RoomObject(0x0AB642, [0xE1, 0xD2, 0xC0])],
[], [DoorObject(Position.SouthW, DoorKind.CaveEntrance),
DoorObject(Position.SouthE, DoorKind.CaveEntrance)])
# boss room id, room data, shell x, shell y, clear layer 2
boss_rooms = {
'Eastern Palace': (0xc8, Room00C8, 0x2B, 0x28, False),
'Desert Palace': (0x33, Room0033, 0x0B, 0x28, False),
'Tower of Hera': (7, Room0007, 0x18, 0x16, False),
'Palace of Darkness': (0x5A, Room005A, 0x2B, 0x28, False),
'Swamp Palace': (6, Room0006, 0x0B, 0x28, False),
'Skull Woods': (0x29, Room0029, 0x2B, 0x28, False),
'Thieves Town': (0xac, Room00AC, 0x2B, 0x28, True),
'Ice Palace': (0xde, Room00DE, 0x2B, 0x08, True),
'Misery Mire': (0x90, Room0090, 0x0B, 0x28, True),
'Turtle Rock': (0xa4, Room00A4, 0x0B, 0x28, True),
}
gt_boss_room = {
'bottom': (0x1C, Room001C, 0x2B, 0x28, False),
'middle': (0x6C, Room006C, 0x0B, 0x28, False),
'top': (0x4D, Room004D, 0x18, 0x16, False),
}

View File

@@ -8,9 +8,10 @@ Shuffled_Pot = (0xFB, 0, 0) # formerly weird pot, or black diagonal thing
class RoomObject:
def __init__(self, address, data):
def __init__(self, address, data, dummy=False):
self.address = address
self.data = data
self.dummy = dummy # some room objects are dummies, unreachable
def change_type(self, new_type):
type_id, datum_a, datum_b = new_type
@@ -22,6 +23,17 @@ class RoomObject:
def write_to_rom(self, rom):
rom.write_bytes(snes_to_pc(self.address), self.data)
# subtype 3 only?
def matches_oid(self, oid):
my_oid = (self.data[2] << 4) | ((self.data[1] & 3) << 2) | (self.data[0] & 3)
return my_oid == oid
@staticmethod
def subtype3_factory(x, y, type_id):
return RoomObject(None, [((x << 2) & 0xFC) | (type_id & 0x3),
((y << 2) & 0xFC) | ((type_id >> 2) & 0x3),
0xF0 | ((type_id >> 4) & 0xF)])
class DoorObject:

View File

@@ -0,0 +1 @@
# do nothing, just exist to make "source" package

View File

@@ -0,0 +1,222 @@
import RaceRandom as random
from Utils import snes_to_pc
from source.dungeon.EnemyList import EnemySprite, SpriteType, Sprite
from source.dungeon.RoomList import boss_rooms, gt_boss_room, Room0006
from source.dungeon.RoomObject import RoomObject
from source.enemizer.SpriteSheets import required_boss_sheets
def get_dungeon_boss_room(dungeon_name, level):
if level is None:
return boss_rooms[dungeon_name]
return gt_boss_room[level]
def get_dungeon_boss_default(dungeon_name, level):
if level is None:
return boss_defaults[dungeon_name]
return gt_boss_defaults[level]
def add_shell_to_boss_room(data_tables, dungeon_name, level, shell_id):
room_id, room, shell_x, shell_y, clear_layer_2 = get_dungeon_boss_room(dungeon_name, level)
if room_id in data_tables.room_list:
room = data_tables.room_list[room_id]
else:
data_tables.room_list[room_id] = room
room.layout[0] = 0xF0
if clear_layer_2:
room.layer2.clear()
y_offset = 0 if shell_id == 0xF95 else -2
room.layer2.append(RoomObject.subtype3_factory(shell_x, shell_y + y_offset, shell_id))
def remove_shell_from_boss_room(data_tables, dungeon_name, level, shell_id):
room_id, room, shell_x, shell_y, clear_layer_2 = get_dungeon_boss_room(dungeon_name, level)
if room_id in data_tables.room_list:
room = data_tables.room_list[room_id]
else:
data_tables.room_list[room_id] = room
room.layer2[:] = [obj for obj in room.layer2 if not obj.matches_oid(shell_id)]
def remove_water_tiles(data_tables):
room = Room0006
if 0x6 in data_tables.room_list:
room = data_tables.room_list[0x6]
else:
data_tables.room_list[0x6] = room
room.layer1.clear()
def create_sprite(super_tile, kind, sub_type, layer, tile_x, tile_y):
return Sprite(super_tile, kind, sub_type, layer, tile_x, tile_y, None, False, None)
def add_armos_to_list(sprite_list, room_id):
sprite_list.insert(0, create_sprite(room_id, EnemySprite.ArmosKnight, 0x00, 0, 0x04, 0x05))
sprite_list.insert(1, create_sprite(room_id, EnemySprite.ArmosKnight, 0x00, 0, 0x07, 0x05))
sprite_list.insert(2, create_sprite(room_id, EnemySprite.ArmosKnight, 0x00, 0, 0x0a, 0x05))
sprite_list.insert(3, create_sprite(room_id, EnemySprite.ArmosKnight, 0x00, 0, 0x0a, 0x08))
sprite_list.insert(4, create_sprite(room_id, EnemySprite.ArmosKnight, 0x00, 0, 0x07, 0x08))
sprite_list.insert(5, create_sprite(room_id, EnemySprite.ArmosKnight, 0x00, 0, 0x04, 0x08))
sprite_list.insert(6, create_sprite(room_id, 0x19, SpriteType.Overlord, 0, 0x07, 0x08))
def add_lanmolas_to_list(sprite_list, room_id):
sprite_list.insert(0, create_sprite(room_id, EnemySprite.Lanmolas, 0x00, 0, 0x06, 0x07))
sprite_list.insert(1, create_sprite(room_id, EnemySprite.Lanmolas, 0x00, 0, 0x09, 0x07))
sprite_list.insert(2, create_sprite(room_id, EnemySprite.Lanmolas, 0x00, 0, 0x07, 0x09))
def add_moldorm_to_list(sprite_list, room_id):
sprite_list.insert(0, create_sprite(room_id, EnemySprite.Moldorm, 0x00, 0, 0x09, 0x09))
def add_helmasaur_king_to_list(sprite_list, room_id):
sprite_list.insert(0, create_sprite(room_id, EnemySprite.HelmasaurKing, 0x00, 0, 0x07, 0x06))
def add_arrghus_to_list(sprite_list, room_id):
sprite_list.insert(0, create_sprite(room_id, EnemySprite.Arrghus, 0x00, 0, 0x07, 0x07))
sprite_list.insert(1, create_sprite(room_id, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07))
sprite_list.insert(2, create_sprite(room_id, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07))
sprite_list.insert(3, create_sprite(room_id, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07))
sprite_list.insert(4, create_sprite(room_id, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07))
sprite_list.insert(5, create_sprite(room_id, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07))
sprite_list.insert(6, create_sprite(room_id, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07))
sprite_list.insert(7, create_sprite(room_id, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07))
sprite_list.insert(8, create_sprite(room_id, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07))
sprite_list.insert(9, create_sprite(room_id, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07))
sprite_list.insert(10, create_sprite(room_id, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07))
sprite_list.insert(11, create_sprite(room_id, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07))
sprite_list.insert(12, create_sprite(room_id, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07))
sprite_list.insert(13, create_sprite(room_id, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07))
def add_mothula_to_list(sprite_list, room_id):
sprite_list.insert(0, create_sprite(room_id, EnemySprite.Mothula, 0x00, 0, 0x08, 0x06))
def add_blind_to_list(sprite_list, room_id):
sprite_list.insert(0, create_sprite(room_id, EnemySprite.Blind, 0x00, 0, 0x09, 0x05))
def add_kholdstare_to_list(sprite_list, room_id):
sprite_list.insert(0, create_sprite(room_id, EnemySprite.KholdstareShell, 0x00, 0, 0x07, 0x05))
sprite_list.insert(1, create_sprite(room_id, EnemySprite.FallingIce, 0x00, 0, 0x07, 0x05))
sprite_list.insert(2, create_sprite(room_id, EnemySprite.Kholdstare, 0x00, 0, 0x07, 0x05))
def add_vitreous_to_list(sprite_list, room_id):
sprite_list.clear() # vitreous does not play nice which other sprites on the tile, just kill them
sprite_list.append(create_sprite(room_id, EnemySprite.Vitreous, 0x00, 0, 0x07, 0x05))
def add_trinexx_to_list(sprite_list, room_id):
sprite_list.insert(0, create_sprite(room_id, EnemySprite.TrinexxRockHead, 0x00, 0, 0x07, 0x05))
sprite_list.insert(1, create_sprite(room_id, EnemySprite.TrinexxFireHead, 0x00, 0, 0x07, 0x05))
sprite_list.insert(2, create_sprite(room_id, EnemySprite.TrinexxIceHead, 0x00, 0, 0x07, 0x05))
def boss_adjust(world, player):
data_tables = world.data_tables[player]
for dungeon in world.get_dungeons(player):
for level, boss in dungeon.bosses.items():
if not boss or boss.name in ['Agahnim', 'Agahnim2']:
continue
default_boss = get_dungeon_boss_default(dungeon.name, level)
room_data = get_dungeon_boss_room(dungeon.name, level)
room_id = room_data[0]
if default_boss != boss.name:
sprite_list = data_tables.uw_enemy_table.room_map[room_id]
data = boss_room_remove_data[room_id]
del sprite_list[:data]
add_func, sprite_type = boss_addition_table[boss.name]
add_func(sprite_list, room_id)
if len(sprite_list) > 15:
del sprite_list[15:]
data_tables.room_headers[room_id].sprite_sheet = required_boss_sheets[sprite_type]
def boss_writes(world, player, rom):
rom.write_byte(snes_to_pc(0x368107), 1) # centralize drops
eye_number = random.randint(0, 8) # randomize moldorm eyes (var + 1)
rom.write_byte(snes_to_pc(0x368102), eye_number) # enemizer flag
rom.write_byte(snes_to_pc(0x1DDBB3), eye_number) # loop variable
data_tables = world.data_tables[player]
arrghus_can_swim = True
water_tiles_on = True
for dungeon in world.get_dungeons(player):
for level, boss in dungeon.bosses.items():
if not boss or boss.name in ['Agahnim', 'Agahnim2']:
continue
room_data = get_dungeon_boss_room(dungeon.name, level)
room_id = room_data[0]
# room changes
if boss.name == 'Arrghus' and (dungeon.name != 'Swamp Palace' or level is not None):
rom.write_byte(snes_to_pc(0x0DB6BE), 0) # arrghus can stand on ground
arrghus_can_swim = False
if boss.name != 'Arrghus' and dungeon.name == 'Swamp Palace' and level is None:
remove_water_tiles(data_tables)
water_tiles_on = False
if boss.name == 'Trinexx' and (dungeon.name != 'Turtle Rock' or level is not None):
add_shell_to_boss_room(data_tables, dungeon.name, level, 0xFF2)
data_tables.room_headers[room_id].byte_0 = 0x60
data_tables.room_headers[room_id].effect = 4
# $2E, $98, $FF (original shell)
if boss.name == 'Kholdstare' and (dungeon.name != 'Ice Palace' or level is not None):
add_shell_to_boss_room(data_tables, dungeon.name, level, 0xF95)
data_tables.room_headers[room_id].byte_0 = 0xE0
data_tables.room_headers[room_id].effect = 1
if boss.name != 'Trinexx' and dungeon.name == 'Turtle Rock' and level is None:
remove_shell_from_boss_room(data_tables, dungeon.name, level, 0xFF2)
# disable trinexx ice breath with No-ops
rom.write_bytes(snes_to_pc(0x09B37E), [0xEA, 0xEA, 0xEA, 0xEA])
if boss.name != 'Kholdstare' and dungeon.name == 'Ice Palace' and level is None:
remove_shell_from_boss_room(data_tables, dungeon.name, level, 0xF95)
if boss.name != 'Blind' and dungeon.name == 'Thieves Town' and level is None:
rom.write_byte(snes_to_pc(0x368101), 1) # set blind boss door flag
# maiden is deleted
del data_tables.uw_enemy_table.room_map[0x45][0]
if not arrghus_can_swim and water_tiles_on:
remove_water_tiles(data_tables)
boss_defaults = {
'Eastern Palace': 'Armos Knights',
'Desert Palace': 'Lanmolas',
'Tower of Hera': 'Moldorm',
'Palace of Darkness': 'Helmasaur King',
'Swamp Palace': 'Arrghus',
'Skull Woods': 'Mothula',
'Thieves Town': 'Blind',
'Ice Palace': 'Kholdstare',
'Misery Mire': 'Vitreous',
'Turtle Rock': 'Trinexx',
}
gt_boss_defaults = {
'bottom': 'Armos Knights',
'middle': 'Lanmolas',
'top': 'Moldorm',
}
boss_room_remove_data = {
6: 14, 7: 1, 0x1c: 7, 0x29: 1, 0x33: 3, 0x4d: 1, 0x5a: 1,
0x6c: 3, 0x90: 1, 0xa4: 2, 0xac: 1, 0xc8: 7, 0xde: 3
}
boss_addition_table = {
'Armos Knights': (add_armos_to_list, EnemySprite.ArmosKnight),
'Lanmolas': (add_lanmolas_to_list, EnemySprite.Lanmolas),
'Moldorm': (add_moldorm_to_list, EnemySprite.Moldorm),
'Helmasaur King': (add_helmasaur_king_to_list, EnemySprite.HelmasaurKing),
'Arrghus': (add_arrghus_to_list, EnemySprite.Arrghus),
'Mothula': (add_mothula_to_list, EnemySprite.Mothula),
'Blind': (add_blind_to_list, EnemySprite.Blind),
'Kholdstare': (add_kholdstare_to_list, EnemySprite.Kholdstare),
'Vitreous': (add_vitreous_to_list, EnemySprite.Vitreous),
'Trinexx': (add_trinexx_to_list, EnemySprite.TrinexxRockHead)
}

View File

@@ -0,0 +1,8 @@
from Utils import load_cached_yaml
class DamageTable:
def __init__(self):
self.damage_table = load_cached_yaml(['source', 'enemizer', 'damage_table.yaml'])
self.enemy_damage = load_cached_yaml(['source', 'enemizer', 'enemy_damage_table.yaml'])

539
source/enemizer/Enemizer.py Normal file
View File

@@ -0,0 +1,539 @@
import RaceRandom as random
from Utils import snes_to_pc
from source.dungeon.EnemyList import SpriteType, EnemySprite, sprite_translation
from source.dungeon.RoomList import Room010C
from source.enemizer.SpriteSheets import sub_group_choices
from source.enemizer.SpriteSheets import randomize_underworld_sprite_sheets, randomize_overworld_sprite_sheets
from source.enemizer.TilePattern import tile_patterns
shutter_sprites = {
0xb8: {0, 1, 2, 3, 4, 5}, 0xb: {4, 5, 6, 7, 8, 9}, 0x1b: {3, 4, 5}, 0x4b: {0, 3, 4}, 0x4: {9, 13, 14},
0x24: {3, 4, 5, 6}, # not sure about 6 - bunny beam under pot
0x28: {0, 1, 2, 3, 4}, 0xe: {0, 1, 2, 3}, 0x2e: {0, 1, 2, 3, 4, 5}, 0x3e: {1, 2}, 0x6e: {0, 1, 2, 3, 4},
0x31: {7, 8, 10}, 0x44: {2, 3, 5}, 0x45: {1, 2, 3}, 0x53: {5, 6, 8, 9, 10}, 0x75: {0, 2, 3, 4, 5},
0x85: {2, 3, 4, 5}, 0x5d: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}, 0x6b: {5, 6, 7, 8, 9, 10, 11, 12, 13},
0x6d: {0, 1, 2, 3, 4, 5, 6, 7, 8}, 0x7b: {2, 3, 4, 5, 8, 9, 10}, 0x7d: {4, 5, 6, 7, 8, 10}, 0x8d: {0, 1, 2, 3, 4},
0xa5: {0, 1, 2, 3, 4, 5, 6, 7}, 0x71: {0, 1}, 0xd8: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
0xb0: {0, 1, 2, 3, 4, 5, 7, 8, 9, 10}, 0xc0: {0, 1, 2}, 0xe0: {0, 1, 2, 3}, 0xb2: {5, 6, 7, 10, 11},
0xd2: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 0xef: {0, 1, 2}, 0x10c: {4, 5, 6, 7}, 0x123: {0, 1, 2, 3},
0xee: {0, 1, 2, 3, 4} # low health traversal
}
def setup_specific_requirements(data_tables):
requirements = data_tables.sprite_requirements
water_groups = set()
water_sub_groups = {0: set(), 1: set(), 2: set(), 3: set()}
killable_groups = set()
killable_sub_groups = {0: set(), 1: set(), 2: set(), 3: set()}
key_groups = set()
key_sub_groups = {0: set(), 1: set(), 2: set(), 3: set()}
for sid, requirement in requirements.items():
if isinstance(requirement, dict):
continue
if requirement.good_for_uw_water():
water_groups.update(requirement.groups)
for i in range(0, 4):
limited = [x for x in requirement.sub_groups[i] if x in sub_group_choices[i]]
water_sub_groups[i].update(limited)
if requirement.good_for_shutter([]):
killable_groups.update(requirement.groups)
for i in range(0, 4):
killable_sub_groups[i].update(requirement.sub_groups[i])
if requirement.can_drop:
key_groups.update(requirement.groups)
for i in range(0, 4):
key_sub_groups[i].update(requirement.sub_groups[i])
return water_groups, water_sub_groups, killable_groups, killable_sub_groups, key_groups, key_sub_groups
def get_possible_sheets(room_id, data_tables, specific, all_sheets, uw_sheets):
# forced sprites for room
requirements = data_tables.sprite_requirements
water_groups, water_sub_groups, killable_groups, killable_sub_groups, key_groups, key_sub_groups = specific
# forced_req = set()
key_needed = False
killable_needed = room_id in shutter_sprites
for sheet in all_sheets:
if room_id in sheet.room_set:
return [sheet]
match_all_room_groups = set()
match_all_sub_groups = {0: set(), 1: set(), 2: set(), 3: set()}
# match_all_sub_groups = {0: set(uw_sub_group_choices[0] + [70, 72]), 1: set(uw_sub_group_choices[1] + [13, 73]),
# 2: set(uw_sub_group_choices[2] + [19]), 3: set(uw_sub_group_choices[3] + [25, 68])}
for sprite in data_tables.uw_enemy_table.room_map[room_id]:
sprite_secondary = 0 if sprite.sub_type != SpriteType.Overlord else sprite.sub_type
key = (sprite.kind, sprite_secondary)
if key not in requirements:
continue
req = requirements[key]
if isinstance(req, dict):
req = req[room_id]
if req.static or not req.can_randomize or sprite.static:
if req.groups:
match_all_room_groups.intersection_update(req.groups)
if not match_all_room_groups:
match_all_room_groups = set(req.groups)
for i in range(0, 4):
if req.sub_groups[i]:
match_all_sub_groups[i].intersection_update(req.sub_groups[i])
if not match_all_sub_groups[i]:
match_all_sub_groups[i] = set(req.sub_groups[i])
# forced_req.add(req)
if sprite.drops_item:
key_needed = True
match_any_room_groups = set()
match_any_sub_groups = {0: set(), 1: set(), 2: set(), 3: set()}
exclude_all_groups = set()
exclude_all_sub_groups = {0: set(), 1: set(), 2: set(), 3: set()}
if room_id in data_tables.room_requirements:
required_groups = data_tables.room_requirements[room_id]
for idx, grp in enumerate(required_groups):
if grp is not None:
if isinstance(grp, tuple):
match_any_sub_groups[idx].update(grp)
else:
match_all_sub_groups[idx] = {grp}
if key_needed:
if key_groups:
match_any_room_groups.update(key_groups)
for i in range(0, 4):
if key_sub_groups[i]:
match_any_sub_groups[i].update(key_sub_groups[i])
elif killable_needed:
if killable_groups:
match_any_room_groups.update(killable_groups)
for i in range(0, 4):
if killable_sub_groups[i]:
match_any_sub_groups[i].update(killable_sub_groups[i])
possible_sheets = []
for sheet in uw_sheets:
if match_all_room_groups and sheet.id not in match_all_room_groups:
continue
if any(match_all_sub_groups[i] and sheet.sub_groups[i] not in match_all_sub_groups[i] for i in range(0, 4)):
continue
if exclude_all_groups and sheet.id in exclude_all_groups:
continue
if any(exclude_all_sub_groups[i] and sheet.sub_groups[i] in exclude_all_sub_groups[i] for i in range(0, 4)):
continue
if match_any_room_groups and sheet.id not in match_any_sub_groups:
continue
test_subs = [i for i in range(0, 4) if match_any_sub_groups[i]]
if test_subs and all(sheet.sub_groups[i] not in match_any_sub_groups[i] for i in test_subs):
continue
possible_sheets.append(sheet)
return possible_sheets
def get_possible_ow_sheets(area_id, all_sheets, ow_sheets, data_tables):
requirements = data_tables.sprite_requirements
for sheet in all_sheets:
if area_id in sheet.room_set:
return [sheet]
match_all_room_groups = set()
match_all_sub_groups = {0: set(), 1: set(), 2: set(), 3: set()}
for sprite in data_tables.ow_enemy_table[area_id]:
sprite_secondary = 0 if sprite.sub_type != SpriteType.Overlord else sprite.sub_type
key = (sprite.kind, sprite_secondary)
if key not in requirements:
continue
req = requirements[key]
if isinstance(req, dict):
req = req[area_id]
if req.static or not req.can_randomize:
if req.groups:
match_all_room_groups.intersection_update(req.groups)
if not match_all_room_groups:
match_all_room_groups = set(req.groups)
for i in range(0, 4):
if req.sub_groups[i]:
match_all_sub_groups[i].intersection_update(req.sub_groups[i])
if not match_all_sub_groups[i]:
match_all_sub_groups[i] = set(req.sub_groups[i])
possible_sheets = []
for sheet in ow_sheets:
if match_all_room_groups and sheet.id not in match_all_room_groups:
continue
if any(match_all_sub_groups[i] and sheet.sub_groups[i] not in match_all_sub_groups[i] for i in range(0, 4)):
continue
possible_sheets.append(sheet)
return possible_sheets
ignore_sheets_uw = {65, 69, 71, 78, 79, 82, 88, 98}
ignore_sheets_ow = {6}
def find_candidate_sprites(data_tables, sheet_range, uw=True):
requirements = data_tables.sprite_requirements
sprite_candidates = []
sheet_candidates = []
all_sheets = []
candidate_groups = set()
candidate_sub_groups = {0: set(), 1: set(), 2: set(), 3: set()}
for k, r in requirements.items():
if isinstance(r, dict):
continue
valid_flag = (uw and r.uw_valid) or (not uw and r.ow_valid)
if not r.static and valid_flag and not r.dont_use:
candidate_groups.update(r.groups)
for i in range(0, 4):
candidate_sub_groups[i].update(r.sub_groups[i])
sprite_candidates.append(k)
for num in sheet_range:
sheet = data_tables.sprite_sheets[num]
all_sheets.append(sheet)
if (uw and num in ignore_sheets_uw) or (not uw and num in ignore_sheets_ow):
continue
if candidate_groups and sheet not in candidate_groups:
continue
test_subs = [i for i in range(0, 4) if candidate_sub_groups[i]]
if test_subs and all(sheet.sub_groups[i] not in candidate_sub_groups[i] for i in test_subs):
continue
sheet_candidates.append(sheet)
return sprite_candidates, sheet_candidates, all_sheets
def get_possible_enemy_sprites(room_id, sheet, uw_sprites, data_tables):
ret = []
for sprite in uw_sprites:
requirement = data_tables.sprite_requirements[sprite]
if isinstance(requirement, dict):
requirement = requirement[room_id]
if sheet.valid_sprite(requirement) and requirement.can_spawn_in_room(room_id):
ret.append(requirement)
return ret
def get_possible_enemy_sprites_ow(sheet, sprites, data_tables):
ret = []
for sprite in sprites:
requirement = data_tables.sprite_requirements[sprite]
if isinstance(requirement, dict):
continue
if sheet.valid_sprite(requirement) and requirement.ow_valid:
ret.append(requirement)
return ret
def get_randomize_able_sprites(room_id, data_tables):
sprite_table = {}
for idx, sprite in enumerate(data_tables.uw_enemy_table.room_map[room_id]):
sprite_secondary = 0 if sprite.sub_type != SpriteType.Overlord else sprite.sub_type
key = (sprite.kind, sprite_secondary)
if key not in data_tables.sprite_requirements:
continue
req = data_tables.sprite_requirements[key]
if isinstance(req, dict):
continue
if not req.static and req.can_randomize and not sprite.static:
sprite_table[idx] = sprite
return sprite_table
def get_randomize_able_sprites_ow(area_id, data_tables):
sprite_table = {}
for idx, sprite in enumerate(data_tables.ow_enemy_table[area_id]):
sprite_secondary = 0 if sprite.sub_type != SpriteType.Overlord else sprite.sub_type
key = (sprite.kind, sprite_secondary)
if key not in data_tables.sprite_requirements:
continue
req = data_tables.sprite_requirements[key]
if isinstance(req, dict):
continue
if not req.static and req.can_randomize:
sprite_table[idx] = sprite
return sprite_table
sprite_limiter = {
EnemySprite.Debirando: 2,
EnemySprite.DebirandoPit: 2,
EnemySprite.Hinox: 2,
EnemySprite.Sluggula: 2,
EnemySprite.BombGuard: 2,
EnemySprite.Beamos: 2,
EnemySprite.Gibo: 2,
# EnemySprite.CannonTrooper: 2, ??
EnemySprite.WallCannonHorzTop: 2,
EnemySprite.WallCannonHorzBottom: 2,
EnemySprite.WallCannonVertLeft: 2,
EnemySprite.WallCannonVertRight: 2,
EnemySprite.BlueArcher: 2,
EnemySprite.BlueGuard: 2,
EnemySprite.GreenGuard: 2,
EnemySprite.RedSpearGuard: 2,
EnemySprite.RedJavelinGuard: 2,
EnemySprite.AntiFairyCircle: 4
}
def exceeds_sprite_limit(limit, sprite):
return sprite_limiter[sprite.sprite]-1+limit > 15 if sprite.sprite in sprite_limiter else False
def randomize_underworld_rooms(data_tables, world, player, custom_uw):
any_enemy_logic = world.any_enemy_logic[player]
enemy_drops_active = world.dropshuffle[player] in ['underworld']
specific = setup_specific_requirements(data_tables)
uw_candidates, uw_sheets, all_sheets = find_candidate_sprites(data_tables, range(65, 124))
for room_id in range(0, 0x128):
if room_id in {0, 1, 3, 6, 7, 0xd, 0x14, 0x20, 0x29, 0x30, 0x33,
0x4d, 0x5a, 0x90, 0xa4, 0xac, 0xc8, 0xde}:
continue
current_sprites = data_tables.uw_enemy_table.room_map[room_id]
sprite_limit = sum(sprite_limiter[x.kind] if x.kind in sprite_limiter else 1 for x in current_sprites)
if room_id in {0x3f, 0x44, 0x45, 0x93, 0xce, 0x117}:
sprite_limit += 1 # for liftable blocks see PotFlags.Block in PotShuffle
randomizeable_sprites = get_randomize_able_sprites(room_id, data_tables)
if not randomizeable_sprites:
candidate_sheets = get_possible_sheets(room_id, data_tables, specific, all_sheets, uw_sheets)
chosen_sheet = random.choice(candidate_sheets)
data_tables.room_headers[room_id].sprite_sheet = chosen_sheet.id - 0x40
if randomizeable_sprites:
candidate_sheets = get_possible_sheets(room_id, data_tables, specific, all_sheets, uw_sheets)
done = False
while not done:
chosen_sheet = random.choice(candidate_sheets)
data_tables.room_headers[room_id].sprite_sheet = chosen_sheet.id - 0x40
candidate_sprites = get_possible_enemy_sprites(room_id, chosen_sheet, uw_candidates, data_tables)
randomized = True
# wallmaster in hera basement throws off hera basement key code
wallmaster_chosen = room_id in {0x0039, 0x0049, 0x0056, 0x0057, 0x0068, 0x0087, 0x008d}
for i, sprite in randomizeable_sprites.items():
if room_id in custom_uw and i in custom_uw[room_id]:
sprite.kind = sprite_translation[custom_uw[room_id][i]]
else:
# filter out water if necessary
candidate_sprites = [x for x in candidate_sprites if not x.water_only or sprite.water]
# filter out wallmaster if already on tile
if wallmaster_chosen:
candidate_sprites = [x for x in candidate_sprites if x.sprite != EnemySprite.Wallmaster]
candidate_sprites = [x for x in candidate_sprites if not exceeds_sprite_limit(sprite_limit, x)]
if sprite.drops_item:
forbidden = determine_forbidden(any_enemy_logic == 'none', room_id, True)
choice_list = [x for x in candidate_sprites if x.good_for_key_drop(forbidden)]
# terrorpin, deadrock, buzzblob, lynel, redmimic/eyegore
elif room_id in shutter_sprites and i in shutter_sprites[room_id]:
forbidden = determine_forbidden(any_enemy_logic != 'allow_all', room_id)
choice_list = [x for x in candidate_sprites if x.good_for_shutter(forbidden)]
else:
choice_list = [x for x in candidate_sprites if not x.water_only]
choice_list = filter_choices(choice_list, room_id, i, data_tables.uw_enemy_denials)
if enemy_drops_active:
choice_list = filter_choices(choice_list, room_id, i, data_tables.uw_enemy_drop_denials)
if len(choice_list) == 0:
randomized = False
break
weight = [data_tables.uw_weights[r.sprite] for r in choice_list]
chosen = random.choices(choice_list, weight, k=1)[0]
sprite.kind = chosen.sprite
if sprite.kind in sprite_limiter:
sprite_limit += sprite_limiter[sprite.kind]-1
if sprite.kind == EnemySprite.Wallmaster:
wallmaster_chosen = True
sprite.kind = 0x09
sprite.sub_type = SpriteType.Overlord
done = randomized
# done with sprites
# done with rooms
def determine_forbidden(forbid, room_id, drop_flag=False):
forbidden_set = set()
if forbid:
forbidden_set.update({EnemySprite.Terrorpin, EnemySprite.Deadrock, EnemySprite.Buzzblob,
EnemySprite.Lynel})
if drop_flag:
forbidden_set.add(EnemySprite.RedBari) # requires FireRod to Drop
# else: Not yet able to protect triggers, would change default GT tile room behavior
# forbidden_set.add(EnemySprite.AntiFairy) # can't drop anyway
if room_id not in {0x6b, 0x4b, 0x1b, 0xd8}: # mimics/eyegore are allowed in vanilla rooms
forbidden_set.add(EnemySprite.RedEyegoreMimic)
forbidden_set.add(EnemySprite.RedMimic)
return forbidden_set
def filter_choices(options, room_id, sprite_idx, denials):
key = room_id, sprite_idx
return [x for x in options if key not in denials or x.sprite not in denials[key]]
def filter_water_phobic(options, sprite):
return [x for x in options if not x.water_phobic or not sprite.water]
def randomize_overworld_enemies(data_tables, custom_ow):
ow_candidates, ow_sheets, all_sheets = find_candidate_sprites(data_tables, range(1, 64), False)
areas_to_randomize = [0, 2, 3, 5, 7, 0xA, 0xF, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
0x1a, 0x1b, 0x1d, 0x1e, 0x22, 0x25, 0x28, 0x29, 0x2A, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x30, 0x32, 0x33, 0x34, 0x35, 0x37, 0x3a, 0x3b, 0x3c, 0x3f]
area_list = areas_to_randomize + [x + 0x40 for x in areas_to_randomize] # light world + dark world
area_list += [0x80, 0x81] + [x + 0x90 for x in areas_to_randomize] # specials + post aga LW
for area_id in area_list:
randomizeable_sprites = get_randomize_able_sprites_ow(area_id, data_tables)
if not randomizeable_sprites:
candidate_sheets = get_possible_ow_sheets(area_id, all_sheets, ow_sheets, data_tables)
chosen_sheet = random.choice(candidate_sheets)
data_tables.overworld_sprite_sheets[area_id] = chosen_sheet
candidate_sprites = get_possible_enemy_sprites_ow(chosen_sheet, ow_candidates, data_tables)
else:
candidate_sheets = get_possible_ow_sheets(area_id, all_sheets, ow_sheets, data_tables)
chosen_sheet = random.choice(candidate_sheets)
data_tables.overworld_sprite_sheets[area_id] = chosen_sheet
candidate_sprites = get_possible_enemy_sprites_ow(chosen_sheet, ow_candidates, data_tables)
for i, sprite in randomizeable_sprites.items():
if area_id in custom_ow and i in custom_ow[area_id]:
sprite.kind = sprite_translation[custom_ow[area_id][i]]
else:
candidate_sprites = filter_choices(candidate_sprites, area_id, i, data_tables.ow_enemy_denials)
candidate_sprites = filter_water_phobic(candidate_sprites, sprite)
weight = [data_tables.ow_weights[r.sprite] for r in candidate_sprites]
chosen = random.choices(candidate_sprites, weight, k=1)[0]
sprite.kind = chosen.sprite
# randomize the bush sprite per area
weight = [data_tables.ow_weights[r.sprite] for r in candidate_sprites]
bush_sprite_choice = random.choices(candidate_sprites, weight, k=1)[0]
data_tables.bush_sprite_table[area_id] = bush_sprite_choice
# damage and health tables only go to F2
skip_sprites = {
EnemySprite.ArmosKnight, EnemySprite.Lanmolas, EnemySprite.Moldorm, EnemySprite.Mothula, EnemySprite.Arrghus,
EnemySprite.HelmasaurKing, EnemySprite.Vitreous, EnemySprite.TrinexxRockHead, EnemySprite.TrinexxFireHead,
EnemySprite.TrinexxIceHead, EnemySprite.Blind, EnemySprite.Kholdstare, EnemySprite.KholdstareShell,
EnemySprite.FallingIce, EnemySprite.Arrghi, EnemySprite.Agahnim, EnemySprite.Ganon,
EnemySprite.PositionTarget, EnemySprite.Boulders
}
def randomize_enemies(world, player):
if world.enemy_shuffle[player] != 'none':
data_tables = world.data_tables[player]
custom_uw, custom_ow = {}, {}
enemy_map = world.customizer.get_enemies() if world.customizer else None
if enemy_map and player in enemy_map:
if 'Underworld' in enemy_map[player]:
custom_uw = enemy_map[player]['Underworld']
if 'Overworld' in enemy_map[player]:
custom_ow = enemy_map[player]['Overworld']
randomize_underworld_sprite_sheets(data_tables.sprite_sheets, data_tables, custom_uw)
randomize_underworld_rooms(data_tables, world, player, custom_uw)
randomize_overworld_sprite_sheets(data_tables.sprite_sheets, data_tables, custom_ow)
randomize_overworld_enemies(data_tables, custom_ow)
# fix thief stats
# subclass_table = world.damage_table[player].damage_table['SubClassTable']
# subclass_table[EnemySprite.Thief] = subclass_table[EnemySprite.GreenEyegoreMimic]
# data_tables.enemy_stats[EnemySprite.Thief].health = 4
# could turn droppable on here if we wanted for killable theives
# health shuffle
if world.enemy_health[player] != 'default':
stats = world.data_tables[player].enemy_stats
min_health = {'easy': 1, 'normal': 2, 'hard': 2, 'expert': 4}
max_health = {'easy': 4, 'normal': 15, 'hard': 25, 'expert': 50}
min_h = min_health[world.enemy_health[player]]
max_h = max_health[world.enemy_health[player]]
for sprite, stat in stats.items():
if sprite == EnemySprite.Octorok4Way:
stat.health = stats[EnemySprite.Octorok].health # these guys share data
elif sprite == EnemySprite.GreenMimic:
stat.health = stats[EnemySprite.GreenEyegoreMimic].health # these share data
elif sprite == EnemySprite.RedMimic:
stat.health = stats[EnemySprite.RedEyegoreMimic].health # these share data
elif sprite not in skip_sprites:
if isinstance(stat.health, tuple):
stat.health = random.randint(min_h, max_h), random.randint(min_h, max_h)
else:
stat.health = random.randint(min_h, max_h)
if world.enemy_damage[player] != 'default':
stats = world.data_tables[player].enemy_stats
# randomize damage groupings
for sprite, stat in stats.items():
if sprite == EnemySprite.Octorok4Way:
stat.damage = stats[EnemySprite.Octorok].damage # these guys share data
elif sprite == EnemySprite.GreenMimic:
stat.damage = stats[EnemySprite.GreenEyegoreMimic].damage # these share data
elif sprite == EnemySprite.RedMimic:
stat.damage = stats[EnemySprite.RedEyegoreMimic].damage # these share data
elif sprite == EnemySprite.Thief: # always group 0 for 0 damage
stat.damage = 0
elif sprite not in skip_sprites:
if isinstance(stat.damage, tuple):
stat.damage = random.randint(0, 8), random.randint(0, 8)
else:
stat.damage = random.randint(0, 8)
# randomize bump table
original_table = [
(0x02, 0x01, 0x01),
(0x04, 0x04, 0x04),
(0x00, 0x00, 0x00),
(0x08, 0x04, 0x02),
(0x08, 0x08, 0x08),
(0x10, 0x08, 0x04),
(0x20, 0x10, 0x08),
(0x20, 0x18, 0x10),
(0x18, 0x10, 0x08),
(0x40, 0x30, 0x18)]
for i in range(0, 10):
if i == 0: # group 0 will always be 0 for thieves
green_mail, blue_mail, red_mail = 0, 0, 0
del original_table[2]
else:
if world.enemy_damage[player] == 'random':
green_mail = random.randint(0, 64)
if world.enemy_damage[player] == 'random':
blue_mail = random.randint(0, 64)
red_mail = random.randint(0, 64)
else:
idx = random.randint(0, len(original_table)-1)
green_mail, blue_mail, red_mail = original_table[idx]
del original_table[idx]
world.data_tables[player].enemy_damage[i] = [green_mail, blue_mail, red_mail]
def write_enemy_shuffle_settings(world, player, rom):
if world.dropshuffle[player] in ['underworld']:
rom.write_byte(snes_to_pc(0x368109), 0x01)
if world.enemy_shuffle[player] != 'none':
# enable new mimics
rom.write_byte(snes_to_pc(0x368105), 0x01)
# killable thief
# rom.write_byte(snes_to_pc(0x368108), 0xc4)
# rom.write_byte(snes_to_pc(0x0DB237), 4) # health value - randomize it if killable, maybe
# mimic room barriers
data_tables = world.data_tables[player]
mimic_room = data_tables.room_list[0x10c] = Room010C
mimic_room.layer1[40].data[0] = 0x54 # rail adjust
mimic_room.layer1[40].data[1] = 0x9C
mimic_room.layer1[45].data[1] = 0xB0 # block adjust 1
mimic_room.layer1[47].data[1] = 0xD0 # block adjust 2
# random tile pattern
pattern_name, tile_pattern = random.choice(tile_patterns)
rom.write_byte(snes_to_pc(0x9BA1D), len(tile_pattern))
for idx, pair in enumerate(tile_pattern):
rom.write_byte(snes_to_pc(0x09BA2A + idx), (pair[0] + 3) * 16)
rom.write_byte(snes_to_pc(0x09BA40 + idx), (pair[1] + 4) * 16)
if world.enemy_shuffle[player] == 'random':
rom.write_byte(snes_to_pc(0x368100), 1) # randomize bushes

View File

@@ -0,0 +1,185 @@
from types import SimpleNamespace
from collections import Counter, defaultdict
from source.dungeon.EnemyList import enemy_names, SpriteType
from source.enemizer.Enemizer import randomize_underworld_rooms, randomize_overworld_enemies
from source.enemizer.SpriteSheets import randomize_underworld_sprite_sheets, randomize_overworld_sprite_sheets
from source.rom.DataTables import init_data_tables
from source.enemizer.DamageTables import DamageTable
import RaceRandom as random
def calculate_odds():
ctr_uw = Counter()
ctr_ow = Counter()
for trial in range(0, 100):
world = SimpleNamespace(pottery={1: 'none'}, damage_table={1: DamageTable()})
data_tables = init_data_tables(world, 1)
randomize_underworld_sprite_sheets(data_tables.sprite_sheets, data_tables)
randomize_overworld_sprite_sheets(data_tables.sprite_sheets)
for num in range(65, 124):
sheet = data_tables.sprite_sheets[num]
ret = []
for req in data_tables.sprite_requirements.values():
if not isinstance(req, dict) and sheet.valid_sprite(req) and not req.overlord and not req.static:
ret.append(enemy_names[req.sprite])
for x in ret:
ctr_uw[x] += 1
for num in range(1, 64):
sheet = data_tables.sprite_sheets[num]
ret = []
for req in data_tables.sprite_requirements.values():
if not isinstance(req, dict) and sheet.valid_sprite(req) and not req.overlord and not req.static:
ret.append(enemy_names[req.sprite])
for x in ret:
ctr_ow[x] += 1
ttl = sum(ctr_uw.values())
print(f'UW: # Total {ttl}')
for k, v in ctr_uw.items():
weight = round(.01 * ttl * 100 / v)
print(f' {k}: {weight} # {v*100/ttl:.5f}% raw:{v}')
ttl = sum(ctr_ow.values())
print(f'OW: # Total {ttl}')
for k, v in ctr_ow.items():
weight = round(.01 * ttl * 100 / v)
print(f' {k}: {weight} # {v*100/ttl:.5f}% raw:{v}')
if __name__ == '__main__':
# calculate_odds()
random.seed(42)
#
frequency = Counter()
sheet_ctr = Counter()
ctr_uw = Counter()
ctr_ow = Counter()
sheet_thing = Counter()
sheet_sub_groups = defaultdict(set)
for trial in range(0, 100):
world = SimpleNamespace(pottery={1: 'none'}, damage_table={1: DamageTable()}, any_enemy_logic={1: 'allow_all'},
dropshuffle={1: 'none'})
data_tables = init_data_tables(world, 1)
stats = data_tables.enemy_stats
def randomize_able_sprite(sprite, stats):
if sprite.static:
return False
if sprite.sub_type == 0x7 and sprite.kind != 0x9:
return False
if sprite.sub_type == 0x7 and sprite.kind == 0x9:
return True
return sprite.kind not in stats or not stats[sprite.kind].static
if trial == 0:
print(f' Underworld:')
for room_id, enemy_list in data_tables.uw_enemy_table.room_map.items():
print(f' {hex(room_id)}:')
for i, sprite in enumerate(enemy_list):
if randomize_able_sprite(sprite, stats):
print(f' {i}: {str(sprite)}')
print(f' Overworld:')
for area, enemy_list in data_tables.ow_enemy_table.items():
print(f' {hex(area)}:')
for i, sprite in enumerate(enemy_list):
if randomize_able_sprite(sprite, stats):
print(f' {i}: {str(sprite)}')
randomize_underworld_sprite_sheets(data_tables.sprite_sheets, data_tables, {})
randomize_underworld_rooms(data_tables, world, 1)
randomize_overworld_sprite_sheets(data_tables.sprite_sheets, data_tables, {})
randomize_overworld_enemies(data_tables)
for room_id, enemy_list in data_tables.uw_enemy_table.room_map.items():
# print(f'Room {hex(room_id)}:')
for i, sprite in enumerate(enemy_list):
if randomize_able_sprite(sprite, stats):
result = str(sprite)
frequency[result] += 1
for area, enemy_list in data_tables.ow_enemy_table.items():
for i, sprite in enumerate(enemy_list):
if randomize_able_sprite(sprite, stats):
result = str(sprite)
frequency[result] += 1
for num in range(65, 124):
if num in {65, 69, 71, 78, 79, 82, 88, 98}:
continue
sheet = data_tables.sprite_sheets[num]
ret = []
for req in data_tables.sprite_requirements.values():
if not isinstance(req, dict) and sheet.valid_sprite(req) and not req.overlord and not req.static:
ret.append(enemy_names[req.sprite])
for x in ret:
ctr_uw[x] += 1
sheet_ctr[x] += 1
key = tuple(sorted(ret))
sheet_thing[key] += 1
sheet_sub_groups[key].add(tuple(sheet.sub_groups))
for num in range(1, 64):
if num == 6:
continue
sheet = data_tables.sprite_sheets[num]
ret = []
for req in data_tables.sprite_requirements.values():
if not isinstance(req, dict) and sheet.valid_sprite(req) and not req.overlord and not req.static:
ret.append(enemy_names[req.sprite])
for x in ret:
ctr_ow[x] += 1
sheet_ctr[x] += 1
key = tuple(sorted(ret))
sheet_thing[key] += 1
sheet_sub_groups[key].add(tuple(sheet.sub_groups))
total_sheets = sum(sheet_thing.values())
ttl = sum(ctr_uw.values())
print(f'UW: # Total {ttl}')
for k in sorted(list(ctr_uw.keys())):
v = ctr_uw[k]
weight = round(.01 * ttl * 100 / v)
print(f' {k}: {weight} # {v*100/ttl:.5f}% raw:{v} {v*100/total_sheets:.5f}%')
ttl = sum(ctr_ow.values())
print(f'OW: # Total {ttl}')
for k in sorted(list(ctr_ow.keys())):
v = ctr_ow[k]
weight = round(.01 * ttl * 100 / v)
print(f' {k}: {weight} # {v*100/ttl:.5f}% raw:{v} {v*100/total_sheets:.5f}%')
ttl = sum(sheet_ctr.values())
print(f'Sheet: # Total {ttl}')
for k, v in sheet_ctr.items():
print(f' {k} {v*100/ttl:.5f}% raw:{v} {v*100/total_sheets:.5f}%')
ttl = sum(frequency.values())
print(f'Total: {ttl}')
for enemy, freq in frequency.items():
print(f'{enemy} {freq*100/ttl:.5f}% raw:{freq}')
ttl = sum(sheet_thing.values())
print(f'Total Sheets?: {ttl}')
def rejoin(list_of_things):
return f'[{",".join([str(i) for i in list_of_things])}]'
for items, cnt in sheet_thing.items():
print(f'{",".join(items)} {cnt} {cnt*100/ttl:.5f}% {",".join([rejoin(x) for x in sheet_sub_groups[items]])}')
# if result not in column_headers:
# column_headers[result] = None
# stats[(room_id, i)][result] += 1
# with open('result.csv', 'w') as result_file:
# result_file.write('room_id,slot,')
# result_file.write(','.join(column_headers.keys()))
# result_file.write('\n')
#
# for key, counter in stats.items():
# rid, slot = key
# result_file.write(f'{rid},{slot}')
# for result_item in column_headers.keys():
# result_file.write(f',{counter[result_item]}')
# result_file.write('\n')

View File

@@ -0,0 +1,525 @@
import math
from collections import defaultdict
import RaceRandom as random
from source.logic.Rule import RuleFactory
from source.dungeon.EnemyList import EnemySprite
# these are for drops only
def defeat_rule_single(world, player, enemy_sprite, region):
if enemy_sprite.kind == EnemySprite.Terrorpin:
# must be flipped
return has('Hammer', player)
elif enemy_sprite.kind == EnemySprite.RedBari:
# must be burned to drop
return or_rule(has('Fire Rod', player), and_rule(has_sword(player), has('Bombos', player)))
vln = enemy_vulnerability(world, player, enemy_sprite, region)
rules = []
if vln['Blunt'] != 0:
rules.append(has_blunt_weapon(player))
if vln['Stun'] != 0:
rules.append(buzzblob_rule(player))
if vln['Somaria'] != 0:
rules.append(somaria_rule(world, player, vln['Somaria']))
if vln['Byrna'] != 0:
rules.append(byrna_rule(world, player, vln['Byrna']))
if vln['Master'] != 0:
rules.append(has_class_2_weapon(player))
if vln['Bow'] != 0:
rules.append(bow_rule(world, player, vln['Bow']))
if vln['Silvers'] != 0:
rules.append(silvers_rule(world, player, vln['Silvers']))
if vln['Bomb'] != 0:
rules.append(bombs_rule(world, player, vln['Bomb']))
if vln['Hookshot'] != 0:
rules.append(has('Hookshot', player))
if vln['IceRod'] != 0:
rules.append(ice_rod_rule(world, player, vln['IceRod']))
if vln['FireRod'] != 0:
rules.append(fire_rod_rule(world, player, vln['FireRod']))
if vln['Boomerang'] != 0:
rules.append(has_boomerang(player))
if vln['Powder'] not in [0, -3]: # fairy doesn't make it drop
rules.append(magic_powder_rule(world, player, vln['Powder']))
# skip medallions if vln to Blunt?
if vln['Bombos'] != 0 and vln['Blunt'] == 0:
rules.append(medallion_rule(world, player, 'Bombos', vln['Bombos']))
if vln['Ether'] != 0 and vln['Blunt'] == 0:
rules.append(medallion_rule(world, player, 'Ether', vln['Ether']))
if vln['Quake'] != 0 and vln['Blunt'] == 0:
rules.append(medallion_rule(world, player, 'Quake', vln['Quake']))
if enemy_sprite.kind == EnemySprite.StalfosKnight:
# must be bombed once made vulnerable
return and_rule(can_use_bombs(world, player), or_rule(*rules))
return or_rule(*rules)
damage_cost = {
'Bomb': 1, 'Bow': 1, 'Silvers': 1,
'Powder': .5, 'Somaria': .5, 'Byrna': 1.125,
'FireRod': 1, 'IceRod': 1,
'Bombos': 2, 'Ether': 2, 'Quake': 2
}
# damage_set = ['Blunt', 'Stun', 'Master', 'Tempered', 'Boomerang', 'Hookshot', 'Bomb', 'Silvers', 'Bow',
# 'Somaria', 'Powder', 'FireRod', 'IceRod', 'Byrna', 'Bombos', 'Ether', 'Quake']
# these are for "challenge" rooms
def defeat_rule_multiple(world, player, enemy_sprite_region_pairs):
vln_list = {}
for sprite, region in enemy_sprite_region_pairs:
vln_list[(sprite, region)] = enemy_vulnerability(world, player, sprite, region)
# damage_accounting = {x: list(y) for x, y in damage_types.items()}
used_resources = {'Bomb': 0, 'Arrow': 0, 'Magic': 0}
required_rules = []
picky_enemies = []
hammer_required = False
bombs_required = False
for key, vln in vln_list.items():
if key[0].kind == EnemySprite.Terrorpin:
if not hammer_required:
required_rules.append(has('Hammer', player))
hammer_required = True
picky_enemies.append(key)
continue
if key[0].kind == EnemySprite.StalfosKnight:
if not bombs_required:
required_rules.append(bombs_rule(world, player, 1))
bombs_required = True
used_resources['Bomb'] += 1
picky_enemies.append(key)
continue
vln_types = [k for k in vln.keys() if vln[k] != 0]
if len(vln_types) == 1:
d_type = vln_types[0]
required_rules.append(defeat_rule_single(world, player, key[0], key[1]))
picky_enemies.append(key)
if d_type in damage_cost:
cost = damage_cost[d_type]
if d_type == 'Bomb':
used_resources['Bomb'] += cost
elif d_type in ['Bow', 'Silvers']:
used_resources['Arrow'] += cost
else:
used_resources['Magic'] += cost
vln_list = {k: v for k, v in vln_list.items() if k not in picky_enemies}
while len(vln_list) > 0:
optional_clears = find_possible_rules(vln_list, used_resources, world, player)
if len(optional_clears) == 0:
raise Exception('Kill rules seems to be insufficient for this enemy set, please report:'
+ ', '.join([str(x) for x, y in enemy_sprite_region_pairs]))
# find rules which kill the most
# idea: this could be multiple criteria: most-constrained then which method kills the most
best_rules = {}
best_size = 0
for vln_option in optional_clears.keys():
if len(vln_option) > best_size:
best_size = len(vln_option)
best_rules.clear()
best_rules[vln_option] = optional_clears[vln_option]
elif len(vln_option) == best_size: # assumes vln_option is different from prior options
best_rules[vln_option] = optional_clears[vln_option]
if len(best_rules) == 1:
vln_option, rule_pair_list = next(iter(best_rules.items()))
else:
vln_option, rule_pair_list = random.choice(list(best_rules.items()))
if best_size == 0:
raise Exception('Invulnerable enemy? rules seems to be insufficient for this enemy set, please report:'
+ ', '.join([str(x) for x, y in enemy_sprite_region_pairs]))
new_vln_list = {vln_kv[0]: vln_kv[1] for idx, vln_kv in enumerate(vln_list.items()) if idx not in vln_option}
rules_to_add = [rule for rule, resources in rule_pair_list]
resources_to_use = [resources for rule, resources in rule_pair_list]
required_rules.append(or_rule(*rules_to_add))
for r in resources_to_use:
for k, v in r.items():
used_resources[k] += v
vln_list = new_vln_list
return and_rule(*required_rules)
def find_possible_rules(vln_list, used_resources, world, player):
optional_clears = defaultdict(list)
blunt_marker = defaultdict(bool)
for damage_type in ['Blunt', 'Stun', 'Master', 'Boomerang', 'Hookshot']:
# all_vln = all(vln[damage_type] != 0 for vln in vln_list.values())
vln_sub_list = frozenset({idx for idx, vln in enumerate(vln_list.values()) if vln[damage_type] != 0})
if vln_sub_list:
if damage_type == 'Blunt':
optional_clears[vln_sub_list].append((has_blunt_weapon(player), {}))
blunt_marker[vln_sub_list] = True
if damage_type == 'Stun':
optional_clears[vln_sub_list].append((buzzblob_rule(player), {}))
if damage_type == 'Master' and not blunt_marker[vln_sub_list]:
optional_clears[vln_sub_list].append((has_class_2_weapon(player), {}))
if damage_type == 'Boomerang':
optional_clears[vln_sub_list].append((has('Hookshot', player), {}))
elif damage_type == 'Hookshot':
optional_clears[vln_sub_list].append((has_boomerang(player), {}))
damage_type = 'Bomb'
vln_sub_list = frozenset({idx for idx, vln in enumerate(vln_list.values()) if vln[damage_type] != 0})
if vln_sub_list:
hits = needed_resources(damage_type, vln_list)
if hits + used_resources['Bomb'] <= 8:
optional_clears[vln_sub_list].append(
(bombs_rule(world, player, hits + used_resources['Bomb']), {'Bomb': hits}))
for damage_type in ['Bow', 'Silvers']:
vln_sub_list = frozenset({idx for idx, vln in enumerate(vln_list.values()) if vln[damage_type] != 0})
if vln_sub_list:
hits = needed_resources(damage_type, vln_list)
resources = {'Arrow': hits}
if damage_type == 'Bow' and hits + used_resources['Arrow'] <= 25:
optional_clears[vln_sub_list].append(
(bow_rule(world, player, hits + used_resources['Arrow']), resources))
if damage_type == 'Silvers' and hits + used_resources['Arrow'] <= 25:
optional_clears[vln_sub_list].append(
(silvers_rule(world, player, hits + used_resources['Arrow']), resources))
for damage_type in ['Powder', 'Somaria', 'Byrna', 'FireRod', 'IceRod', 'Bombos', 'Ether', 'Quake']:
vln_sub_list = frozenset({idx for idx, vln in enumerate(vln_list.values()) if vln[damage_type] != 0})
if vln_sub_list:
hits = needed_resources(damage_type, vln_list)
resources = {'Magic': damage_cost[damage_type] * hits}
if damage_type == 'Powder' and math.ceil(hits / 16) * 8 + used_resources['Magic'] <= 160:
flag = min(vln[damage_type] for vln in vln_list.values())
flag = flag if flag < 0 else (hits + used_resources['Magic'] * 2)
optional_clears[vln_sub_list].append((magic_powder_rule(world, player, flag), resources))
elif damage_type == 'Somaria' and math.ceil(hits / 64) * 8 + used_resources['Magic'] <= 160:
flag = min(vln[damage_type] for vln in vln_list.values())
flag = flag if flag < 0 else (hits + used_resources['Magic'] * 8)
optional_clears[vln_sub_list].append((somaria_rule(world, player, flag), resources))
elif damage_type == 'Byrna' and math.ceil(hits / 7) * 8 + used_resources['Magic'] <= 160:
flag = min(vln[damage_type] for vln in vln_list.values())
flag = flag if flag < 0 else (hits + used_resources['Magic'] * 7 / 8)
optional_clears[vln_sub_list].append((byrna_rule(world, player, flag), resources))
elif damage_type == 'FireRod' and hits + used_resources['Magic'] <= 160:
flag = min(vln[damage_type] for vln in vln_list.values())
flag = flag if flag < 0 else (hits + used_resources['Magic'])
optional_clears[vln_sub_list].append((fire_rod_rule(world, player, flag), resources))
elif damage_type == 'IceRod' and hits + used_resources['Magic'] <= 160:
flag = min(vln[damage_type] for vln in vln_list.values())
flag = flag if flag < 0 else (hits + used_resources['Magic'])
optional_clears[vln_sub_list].append((ice_rod_rule(world, player, flag), resources))
elif hits * 2 + used_resources['Magic'] <= 160 and not blunt_marker[vln_sub_list]:
flag = min(vln[damage_type] for vln in vln_list.values())
flag = flag if flag < 0 else (hits + used_resources['Magic'] / 2)
optional_clears[vln_sub_list].append((medallion_rule(world, player, damage_type, flag), resources))
return optional_clears
def needed_resources(damage_type, vln_list):
return sum(vln[damage_type] if vln[damage_type] >= 0 else 1 for vln in vln_list.values() if vln[damage_type] != 0)
special_rules_check = {
'Swamp Waterway': None,
'Hera Back': [5, 6],
'GT Petting Zoo': [5, 8, 9, 11],
'Mimic Cave': [4, 5, 6, 7],
'Ice Hookshot Ledge': None,
'TR Hub Ledges': [3, 4, 5, 6, 7],
'TR Dark Ride': [1, 2, 3],
'GT Speed Torch': [11, 13],
'Old Man Cave (West)': None,
'Old Man Cave (East)': None,
'Old Man House': [1, 3],
'Old Man House Back': [4, 5, 6],
'Death Mountain Return Cave (left)': None,
'Death Mountain Return Cave (right)': [1, 2, 3, 6, 7], # 2, 5, 6 are considered embedded
'Hookshot Fairy': [0, 1, 2, 3]
}
def special_rules_for_region(world, player, region_name, location, original_rule):
if region_name == 'Swamp Waterway':
return or_rule(medallion_rule(world, player, 'Quake', 1),
medallion_rule(world, player, 'Ether', 1),
medallion_rule(world, player, 'Bombos', 1))
elif region_name in ['Hera Back', 'GT Petting Zoo', 'Mimic Cave']:
enemy_number = int(location.name.split('#')[1])
if region_name == 'Mimic Cave':
if enemy_number in [4, 5]: # these are behind hammer blocks potentially
return and_rule(original_rule, has('Hammer', player))
elif enemy_number in special_rules_check[region_name]: # these are behind rails
return and_rule(original_rule, has_boomerang(player))
if enemy_number in special_rules_check[region_name]:
return and_rule(original_rule, has_boomerang(player))
else:
return original_rule
elif region_name in ['TR Hub Ledges', 'Ice Hookshot Ledge', 'TR Dark Ride']:
enemy_number = int(location.name.split('#')[1])
if special_rules_check[region_name] is None or enemy_number in special_rules_check[region_name]:
return and_rule(original_rule, or_rule(has_boomerang(player), has('Hookshot', player)))
else:
return original_rule
elif region_name in ['Old Man Cave (West)', 'Old Man Cave (East)', 'Old Man House Back', 'Old Man House',
'Death Mountain Return Cave (left)', 'Death Mountain Return Cave (right)',
'Hookshot Fairy']:
enemy_number = int(location.name.split('#')[1])
if region_name == 'Death Mountain Return Cave (left)':
if enemy_number in [1, 5]:
return and_rule(original_rule, or_rule(has_boomerang(player), has('Hookshot', player)))
else:
return and_rule(original_rule, has('Hookshot', player))
if special_rules_check[region_name] is None or enemy_number in special_rules_check[region_name]:
return and_rule(original_rule, has('Hookshot', player))
else:
return original_rule
return original_rule
def has_blunt_weapon(player):
return or_rule(has_sword(player), has('Hammer', player))
# Bombs, Arrows, Bombos, FireRod, Somaria, Byrna should be handled by the damage table logic
# Powder doesn't work (also handled by damage table)
def buzzblob_rule(player):
return or_rule(has('Golden Sword', player),
and_rule(has_blunt_weapon(player),
or_rule(has_boomerang(player), has('Hookshot', player), has('Ice Rod', player))),
and_rule(has('Ether', player), has_sword(player)),
and_rule(has('Quake', player), has_sword(player)))
def has_class_2_weapon(player):
return or_rule(has_beam_sword(player), has('Hammer', player))
def somaria_rule(world, player, somaria_hits):
if somaria_hits == -1:
return has('Cane of Somaria', player) # insta-kill somaria? - not in vanilla
else:
magic_needed = math.ceil(somaria_hits / 64) * 8 # 64 hits per magic bar - 80 max?
if magic_needed > 8:
return and_rule(has('Cane of Somaria', player), can_extend_magic(world, player, magic_needed))
else:
return has('Cane of Somaria', player)
def byrna_rule(world, player, byrna_hits):
if byrna_hits == -1:
return has('Cane of Byrna', player) # insta-kill byrna? - not in vanilla
else:
magic_needed = math.ceil(byrna_hits / 7) * 8 # 7 hits per magic bar - generous?
if magic_needed > 8:
return and_rule(has('Cane of Byrna', player), can_extend_magic(world, player, magic_needed))
else:
return has('Cane of Byrna', player)
def bow_rule(world, player, arrows):
if arrows == -1 or 0 < arrows <= 25:
return can_shoot_normal_arrows(world, player)
return RuleFactory.static_rule(False)
def silvers_rule(world, player, arrows):
if arrows == -1 or 0 < arrows <= 25:
return can_shoot_silver_arrows(world, player)
return RuleFactory.static_rule(False)
def bombs_rule(world, player, bombs):
if bombs == -1 or 0 < bombs <= 8:
return can_use_bombs(world, player)
return RuleFactory.static_rule(False)
def ice_rod_rule(world, player, shots):
if shots == -1:
return has('Ice Rod', player)
if shots > 8:
return and_rule(has('Ice Rod', player), can_extend_magic(world, player, shots))
else:
return has('Ice Rod', player)
def fire_rod_rule(world, player, shots):
if shots == -1:
return has('Fire Rod', player)
if shots > 8:
return and_rule(has('Fire Rod', player), can_extend_magic(world, player, shots))
else:
return has('Fire Rod', player)
def magic_powder_rule(world, player, shots):
if shots == -1:
return has('Magic Powder', player)
if shots == -2:
# todo: other resources possible I guess - harder to keep track of though
return and_rule(has('Magic Powder', player), or_rule(has_blunt_weapon(player), has('Hookshot', player)))
magic_needed = math.ceil(shots / 16) * 8 # 16 tries per magic bar, that could be tight...
if magic_needed > 8:
return and_rule(has('Magic Powder', player), can_extend_magic(world, player, shots))
else:
return has('Magic Powder', player)
def medallion_rule(world, player, medallion, shots):
if shots == -1:
return and_rule(has(medallion, player), has_sword(player))
if shots == -2:
return and_rule(has(medallion, player), has_sword(player))
magic_needed = shots * 2
if magic_needed > 8:
return and_rule(has(medallion, player), has_sword(player), can_extend_magic(world, player, shots))
else:
return and_rule(has(medallion, player), has_sword(player))
def or_rule(*rules):
return RuleFactory.disj(rules)
def and_rule(*rules):
return RuleFactory.conj(rules)
def has(item, player, count=1):
return RuleFactory.item(item, player, count)
def has_sword(player):
return or_rule(
has('Fighter Sword', player), has('Master Sword', player),
has('Tempered Sword', player), has('Golden Sword', player)
)
def has_beam_sword(player):
return or_rule(
has('Master Sword', player), has('Tempered Sword', player), has('Golden Sword', player)
)
def has_class_3_sword(player):
return or_rule(
has('Tempered Sword', player), has('Golden Sword', player)
)
def can_extend_magic(world, player, magic, flag_t=False):
potion_shops = (find_shops_that_sell('Blue Potion', world, player) |
find_shops_that_sell('Green Potion', world, player))
return RuleFactory.extend_magic(player, magic, world.difficulty_adjustments[player], potion_shops, flag_t)
# class 0 damage (subtypes 1 and 2)
def has_boomerang(player):
return or_rule(has('Blue Boomerang', player), has('Red_Boomerang', player))
def find_shops_that_sell(item, world, player):
return {shop.region for shop in world.shops[player] if shop.has_unlimited(item) and shop.region.player == player}
def can_shoot_normal_arrows(world, player):
if world.bow_mode[player].startswith('retro'):
shops = find_shops_that_sell('Single Arrow', world, player)
# retro+shopsanity, shops may not sell the Single Arrow at all
if world.bow_mode[player] == 'retro_silvers':
# non-progressive silvers grant wooden arrows, so shop may not be needed
return and_rule(has('Bow', player), or_rule(RuleFactory.unlimited('Single Arrow', player, shops),
has('Single Arrow', player), has('Silver Arrows', player)))
else:
return and_rule(has('Bow', player), or_rule(RuleFactory.unlimited('Single Arrow', player, shops),
has('Single Arrow', player)))
return has('Bow', player)
def can_shoot_silver_arrows(world, player):
# retro_silver requires the silver arrows item which is sufficient for the quiver
if world.bow_mode[player] == 'retro':
shops = find_shops_that_sell('Single Arrow', world, player)
# retro+shopsanity, shops may not sell the Single Arrow at all
return and_rule(has('Silver Arrows', player), or_rule(RuleFactory.unlimited('Single Arrow', player, shops),
has('Single Arrow', player)))
return and_rule(has('Bow', player), has('Silver Arrows', player))
def can_use_bombs(world, player):
return or_rule(RuleFactory.static_rule(not world.bombbag[player]), has('Bomb Upgrade (+10)', player))
def enemy_vulnerability(world, player, enemy_sprite, region):
damage_table = world.damage_table[player].damage_table
stats = world.data_tables[player].enemy_stats
damage_src = damage_table['DamageSource']
sub_class_table = damage_table['SubClassTable']
enemy_sub_class = sub_class_table[enemy_sprite.kind]
vulnerability = defaultdict(int)
c1 = number_of_hits('Sword1', damage_src, enemy_sub_class, stats, enemy_sprite, region)
if c1 != 0:
if enemy_sprite.kind == EnemySprite.Buzzblob:
vulnerability['Stun'] = -1
else:
vulnerability['Blunt'] = -1
vulnerability['Master'] = -1
vulnerability['Somaria'] = c1
vulnerability['Byrna'] = c1
else:
c2 = number_of_hits('Sword3', damage_src, enemy_sub_class, stats, enemy_sprite, region)
if c2 != 0:
vulnerability['Master'] = -1 # currently Lynels are only vulnerable to only master spins or above
hits = number_of_hits('Arrow', damage_src, enemy_sub_class, stats, enemy_sprite, region)
if hits != 0:
vulnerability['Bow'] = hits
hits = number_of_hits('SilverArrow', damage_src, enemy_sub_class, stats, enemy_sprite, region)
if hits != 0:
vulnerability['Silvers'] = hits
for method in ['Bomb', 'Hookshot', 'FireRod', 'IceRod', 'Boomerang', 'Powder', 'Bombos', 'Ether', 'Quake']:
hits = number_of_hits(method, damage_src, enemy_sub_class, stats, enemy_sprite, region)
if hits == -3:
if enemy_sprite.kind != EnemySprite.Buzzblob: # buzzblobs are special and don't die
vulnerability[method] = -1
elif hits != 0:
vulnerability[method] = hits
return vulnerability
def number_of_hits(source_name, damage_src, enemy_sub_class, stats, enemy_sprite, region):
damage_class = damage_src[source_name]['class']
sub_class = enemy_sub_class[damage_class]
damage_amount = damage_src[source_name]['subclass'][sub_class]
if damage_amount == 0:
return 0
elif damage_amount <= 0x64:
health = stats[enemy_sprite.kind].health
if isinstance(health, tuple):
if enemy_sprite.kind in [EnemySprite.Tektite, EnemySprite.HardhatBeetle]:
idx = enemy_sprite.tile_x & 0x1
health = health[idx]
elif region.is_light_world and region.is_dark_world:
health = min(health)
elif region.is_light_world:
health = health[0]
elif region.is_dark_world:
health = health[1]
else:
health = max(health)
return math.ceil(health / damage_amount)
elif damage_amount in [0xF9, 0xFA, 0xFD]:
# -1 incinerated; -2 blobbed, -3 fairy-ed (depends on enemy if "killed" or not)
# F9: fairy, defeated, but doesn't drop anything: -3
# FA: blobbed - can you kill a blob? = -2
# FD: incinerated
return special_classes[damage_amount]
else:
return 0
special_classes = {0xF9: -3, 0xFA: -2, 0xFD: -1}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,788 @@
import logging
from collections import defaultdict
import RaceRandom as random
from source.dungeon.EnemyList import EnemySprite, SpriteType, enemy_names, sprite_translation, overlord_names
from source.dungeon.RoomConstants import *
class SpriteRequirement:
def __init__(self, sprite, overlord=0):
self.sprite = sprite
self.overlord = overlord
self.boss = False
self.static = False # npcs and do not randomize
self.killable = True
self.can_drop = True
self.water_only = False
self.dont_use = False
self.ow_valid = True
self.uw_valid = True
self.can_randomize = True
self.water_phobic = False
self.groups = []
self.sub_groups = defaultdict(list)
self.excluded_rooms = set()
self.allowed_rooms = set()
def can_spawn_in_room(self, room_id):
return room_id not in self.excluded_rooms and (self.sprite != EnemySprite.Wallmaster or room_id < 0x100)
def no_drop(self):
self.can_drop = False
return self
def sub_group(self, key, subs):
if isinstance(subs, list):
self.sub_groups[key].extend(subs)
else:
self.sub_groups[key].append(subs)
return self
def group(self, group_id):
self.groups.append(group_id)
return self
def exclude(self, exclusions):
self.excluded_rooms.update(exclusions)
return self
def allow(self, allowed):
self.allowed_rooms.update(allowed)
return self
def affix(self):
self.static = True
self.killable = False
self.can_drop = False
return self
def stasis(self):
self.can_randomize = False
return self
def exalt(self):
self.boss = True
self.static = True # not randomized by sprite sheet
return self
def immune(self):
self.killable = False
self.can_drop = False
return self
def immerse(self):
self.water_only = True
return self
def aquaphobia(self):
self.water_phobic = True
return self
def skip(self):
self.dont_use = True
return self
def ow_skip(self):
self.ow_valid = False
return self
def uw_skip(self):
self.uw_valid = False
return self
def good_for_uw_water(self):
return self.water_only and not self.static and not self.dont_use and self.uw_valid
def good_for_shutter(self, forbidden):
if self.sprite in forbidden:
return False
return self.killable and not self.static and not self.dont_use and self.uw_valid
def good_for_key_drop(self, forbidden):
return self.good_for_shutter(forbidden) and self.can_drop
def __str__(self):
return f'Req for {enemy_names[self.sprite] if self.overlord != 0x7 else overlord_names[self.sprite]}'
NoFlyingRooms = {0xd2, 0x10c} # Mire 2, Mimic Cave
NoBeamosOrTrapRooms = {0xb, 0x16, 0x19, 0x1e, 0x26, 0x27, 0x36, 0x3f, 0x40, 0x42, 0x46, 0x49, 0x4b, 0x4e, 0x55, 0x57,
0x5f, 0x65, 0x6a, 0x74, 0x76, 0x7d, 0x7f, 0x83, 0x84, 0x85, 0x8c, 0x8d, 0x92, 0x95, 0x98, 0x9b,
0x9c, 0x9d, 0x9e, 0xa0, 0xaa, 0xaf, 0xb3, 0xba, 0xbb, 0xbc, 0xc6, 0xcb, 0xce, 0xd0, 0xd2, 0xd5,
0xd8, 0xdc, 0xdf, 0xe4, 0xe7, 0xee, 0xf9, 0xfd, 0x10c}
LenientTrapsForTesting = {0x16, 0x26, 0x3f, 0x40, 0x42, 0x46, 0x49, 0x4e, 0x57,
0x65, 0x6a, 0x74, 0x76, 0x7d, 0x98,
0x9e, 0xaf, 0xba, 0xc6, 0xcb, 0xce, 0xd2, 0xd5,
0xd8, 0xdf, 0xe4, 0xe7, 0xee, 0xfd, 0x10c}
# this will have to be dynamic if cave rooms are allowed in dungeons
WallmasterValidRooms = {
HC_NorthCorridor, HC_SwitchRoom, HoulihanRoom, TR_CrystalRollerRoom,
PalaceofDarkness0x09, PoD_StalfosTrapRoom, PoD_TurtleRoom, GT_EntranceRoom, Ice_EntranceRoom,
GanonEvacuationRoute, HC_BombableStockRoom, Sanctuary, TR_Hokku_BokkuKeyRoom2, TR_BigKeyRoom, TurtleRock0x15,
Swamp_SwimmingTreadmill, Hera_MoldormFallRoom, PoD_DarkMaze, PoD_BigChestRoom, PoD_Mimics_MovingWallRoom,
GT_IceArmos, GT_FinalHallway, Ice_BombFloor_BariRoom, Ice_Pengator_BigKeyRoom, Tower_Agahnim, HC_KeyRatRoom,
HC_SewerTextTriggerRoom, TR_WestExittoBalcony, TR_DoubleHokku_Bokku_BigchestRoom, Swamp_StatueRoom, Hera_BigChest,
Swamp_EntranceRoom, Skull_Mothula, PoD_BigHubRoom, PoD_MapChest_FairyRoom, Ice_CompassRoom, Hera_HardhatBeetlesRoom,
HC_SewerKeyChestRoom, Desert_Lanmolas, Swamp_PushBlockPuzzle_Pre_BigKeyRoom, Swamp_BigKey_BSRoom,
Swamp_BigChestRoom, Swamp_MapChest_WaterFillRoom, Swamp_KeyPotRoom, Skull_GibdoKey_MothulaHoleRoom,
PoD_BombableFloorRoom, PoD_SpikeBlock_ConveyorRoom, GT_TorchRoom2, Ice_StalfosKnights_ConveyorHellway,
Ice_MapChestRoom, Tower_FinalBridgeRoom, HC_FirstDarkRoom, HC_6RopesRoom, Desert_TorchPuzzle_MovingWallRoom,
TT_BigChestRoom, TT_JailCellsRoom, Swamp_CompassChestRoom, Skull_GibdoTorchPuzzleRoom, PoD_EntranceRoom,
PoD_Warps_SouthMimicsRoom, GT_Mini_HelmasaurConveyorRoom, GT_MoldormRoom, Ice_Bomb_JumpRoom,
IcePalaceCloneRoom_FairyRoom, HC_WestCorridor, HC_ThroneRoom, HC_EastCorridor, Desert_Popos2_BeamosHellwayRoom,
Swamp_UpstairsPitsRoom, CastleSecretEntrance_UncleDeathRoom, Skull_KeyPot_TrapRoom, Skull_BigKeyRoom,
Skull_BigChestRoom, Skull_FinalSectionEntranceRoom, PoD_HelmasaurKing, GT_SpikePitRoom, GT_Ganon_BallZ,
GT_Gauntlet1_2_3, Ice_LonelyFirebar, Ice_HiddenChest_SpikeFloorRoom, HC_WestEntranceRoom, HC_MainEntranceRoom,
HC_EastEntranceRoom, Desert_FinalSectionEntranceRoom, TT_WestAtticRoom, TT_EastAtticRoom,
Swamp_HiddenChest_HiddenDoorRoom, Skull_CompassChestRoom, Skull_KeyChest_TrapRoom, PoD_RupeeRoom, GT_MimicsRooms,
GT_LanmolasRoom, GT_Gauntlet4_5, Ice_PengatorsRoom, HC_SmallCorridortoJailCells, HC_BoomerangChestRoom,
HC_MapChestRoom, Desert_BigChestRoom, Desert_MapChestRoom, Desert_BigKeyChestRoom, Swamp_WaterDrainRoom,
Hera_EntranceRoom, GanonsTower, GT_EastSideCollapsingBridge_ExplodingWallRoom, GT_Winder_WarpMazeRoom,
Ice_HiddenChest_BombableFloorRoom, Ice_BigSpikeTrapsRoom, HC_JailCellRoom, HC_NextToChasmRoom, HC_BasementChasmRoom,
Desert_WestEntranceRoom, Desert_MainEntranceRoom, Desert_EastEntranceRoom, Hera_TileRoom, Eastern_FairyRoom,
GT_BlockPuzzle_SpikeSkip_MapChestRoom, GT_EastandWestDownstairs_BigChestRoom, GT_Tile_TorchPuzzleRoom,
IcePalace0x8E, Mire_Vitreous, Mire_FinalSwitchRoom, Mire_DarkBombWall_SwitchesRoom,
Mire_DarkCaneFloorSwitchPuzzleRoom, GT_FinalCollapsingBridgeRoom, GT_Torches1Room, Mire_TorchPuzzle_MovingWallRoom,
Mire_EntranceRoom, Eastern_EyegoreKeyRoom, GT_ManySpikes_WarpMazeRoom, GT_InvisibleFloorMazeRoom,
GT_CompassChest_InvisibleFloorRoom, Ice_BigChestRoom, IcePalace0x9F, Mire_Pre_VitreousRoom, Mire_FishRoom,
Mire_BridgeKeyChestRoom, MiseryMire0xA3, TR_Trinexx, GT_WizzrobesRooms, GT_MoldormFallRoom, Hera_FairyRoom,
Eastern_StalfosSpawnRoom, Eastern_BigChestRoom, Eastern_MapChestRoom, TT_MovingSpikes_KeyPotRoom, TT_BlindTheThief,
IcePalace0xAE, Ice_IceBridgeRoom, Tower_CircleofPots, Mire_HourglassRoom, Mire_SlugRoom, Mire_SpikeKeyChestRoom,
TR_Pre_TrinexxRoom, TR_DarkMaze, TR_ChainChompsRoom, TR_MapChest_KeyChest_RollerRoom, Eastern_BigKeyRoom,
Eastern_LobbyCannonballsRoom, Eastern_DarkAntifairy_KeyPotRoom, TT_Hellway, TT_ConveyorToilet, Ice_BlockPuzzleRoom,
IcePalaceCloneRoom_SwitchRoom, Tower_DarkBridgeRoom, Mire_CompassChest_TileRoom, Mire_BigHubRoom, Mire_BigChestRoom,
TR_FinalCrystalSwitchPuzzleRoom, TR_LaserBridge, TurtleRock0xC6, TR_TorchPuzzle,
Eastern_EntranceRoom, UnknownRoom, TT_NorthWestEntranceRoom, TT_NorthEastEntranceRoom, Ice_HoletoKholdstareRoom,
Tower_DarkMaze, Mire_ConveyorSlug_BigKeyRoom, Mire_Mire02_WizzrobesRoom, TR_LaserKeyRoom, TR_EntranceRoom,
Eastern_PreArmosKnightsRoom, Eastern_CanonballRoom, EasternPalace, TT_Main_SouthWestEntranceRoom,
TT_SouthEastEntranceRoom, Tower_EntranceRoom
}
def init_sprite_requirements():
reqs = [
SpriteRequirement(EnemySprite.Raven).no_drop().sub_group(3, [0x11, 0x19]).exclude(NoFlyingRooms),
SpriteRequirement(EnemySprite.Vulture).no_drop().sub_group(2, 0x12).exclude(NoFlyingRooms),
SpriteRequirement(EnemySprite.CorrectPullSwitch).affix().sub_group(3, [0x52, 0x53]),
SpriteRequirement(EnemySprite.WrongPullSwitch).affix().sub_group(3, [0x52, 0x53]),
SpriteRequirement(EnemySprite.Octorok).sub_group(2, [0xc, 0x18]),
SpriteRequirement(EnemySprite.Moldorm).exalt().sub_group(2, 0x30),
SpriteRequirement(EnemySprite.Octorok4Way).sub_group(2, 0xc),
SpriteRequirement(EnemySprite.Cucco).immune().sub_group(3, [0x15, 0x50]).exclude(NoFlyingRooms),
SpriteRequirement(EnemySprite.Buzzblob).sub_group(3, 0x11),
SpriteRequirement(EnemySprite.Snapdragon).sub_group(0, 0x16).sub_group(2, 0x17),
SpriteRequirement(EnemySprite.Octoballoon).no_drop().sub_group(2, 0xc).exclude(NoFlyingRooms),
SpriteRequirement(EnemySprite.Hinox).sub_group(0, 0x16),
SpriteRequirement(EnemySprite.Moblin).sub_group(2, 0x17),
SpriteRequirement(EnemySprite.MiniHelmasaur).sub_group(1, 0x1e),
SpriteRequirement(EnemySprite.AntiFairy).no_drop().sub_group(3, [0x52, 0x53])
.exclude(NoFlyingRooms).exclude({0x40}), # no anti-fairies in aga tower bridge room
SpriteRequirement(EnemySprite.Wiseman).affix().sub_group(2, 0x4c),
SpriteRequirement(EnemySprite.Hoarder).sub_group(3, 0x11).exclude({0x10c}),
SpriteRequirement(EnemySprite.MiniMoldorm).sub_group(1, 0x1e),
SpriteRequirement(EnemySprite.Poe).no_drop().sub_group(3, 0x15).exclude(NoFlyingRooms),
SpriteRequirement(EnemySprite.Smithy).affix().sub_group(1, 0x1d).sub_group(3, 0x15),
SpriteRequirement(EnemySprite.Statue).stasis().immune().sub_group(3, [0x52, 0x53]),
SpriteRequirement(EnemySprite.CrystalSwitch).affix().sub_group(3, [0x52, 0x53]),
SpriteRequirement(EnemySprite.SickKid).affix().sub_group(0, 0x51),
SpriteRequirement(EnemySprite.Sluggula).sub_group(2, 0x25),
SpriteRequirement(EnemySprite.WaterSwitch).affix().sub_group(3, 0x53),
SpriteRequirement(EnemySprite.Ropa).sub_group(0, 0x16),
SpriteRequirement(EnemySprite.RedBari).sub_group(0, 0x1f),
SpriteRequirement(EnemySprite.BlueBari).sub_group(0, 0x1f),
SpriteRequirement(EnemySprite.TalkingTree).affix().sub_group(3, [0x15, 0x1B]),
SpriteRequirement(EnemySprite.HardhatBeetle).sub_group(1, 0x1e),
SpriteRequirement(EnemySprite.Deadrock).sub_group(3, 0x10).exclude({0x7f, 0x10c}),
SpriteRequirement(EnemySprite.DarkWorldHintNpc).affix(), # no groups?
SpriteRequirement(EnemySprite.AdultNpc).affix().sub_group(0, [0xe, 0x4f]),
SpriteRequirement(EnemySprite.SweepingLady).affix().group(6), # no sub groups?
SpriteRequirement(EnemySprite.Lumberjacks).affix().sub_group(2, 0x4a),
SpriteRequirement(EnemySprite.RaceGameLady).affix().group(6),
SpriteRequirement(EnemySprite.FortuneTeller).affix().sub_group(0, 0x4b),
SpriteRequirement(EnemySprite.ArgueBros).affix().sub_group(0, 0x4f),
SpriteRequirement(EnemySprite.RupeePull).affix(),
SpriteRequirement(EnemySprite.YoungSnitch).affix().group(6),
SpriteRequirement(EnemySprite.Innkeeper).affix(), # no groups?
SpriteRequirement(EnemySprite.Witch).affix().sub_group(2, 0x7c),
SpriteRequirement(EnemySprite.Waterfall).affix(),
SpriteRequirement(EnemySprite.EyeStatue).affix(),
SpriteRequirement(EnemySprite.Locksmith).affix().sub_group(3, 0x11),
SpriteRequirement(EnemySprite.MagicBat).affix().sub_group(3, 0x1d),
SpriteRequirement(EnemySprite.KidInKak).affix().group(6),
SpriteRequirement(EnemySprite.OldSnitch).affix().group(6),
SpriteRequirement(EnemySprite.Hoarder2).sub_group(3, 0x11).exclude({0x10c}),
SpriteRequirement(EnemySprite.TutorialGuard).affix(),
SpriteRequirement(EnemySprite.LightningGate).affix().sub_group(3, 0x3f),
SpriteRequirement(EnemySprite.BlueGuard).sub_group(1, [0xd, 0x49]),
SpriteRequirement(EnemySprite.GreenGuard).sub_group(1, 0x49),
SpriteRequirement(EnemySprite.RedSpearGuard).sub_group(1, [0xd, 0x49]),
SpriteRequirement(EnemySprite.BluesainBolt).sub_group(0, 0x46).sub_group(1, [0xd, 0x49]),
SpriteRequirement(EnemySprite.UsainBolt).sub_group(1, [0xd, 0x49]),
SpriteRequirement(EnemySprite.BlueArcher).sub_group(0, 0x48).sub_group(1, 0x49),
SpriteRequirement(EnemySprite.GreenBushGuard).sub_group(0, 0x48).sub_group(1, 0x49),
SpriteRequirement(EnemySprite.RedJavelinGuard).sub_group(0, 0x46).sub_group(1, 0x49),
SpriteRequirement(EnemySprite.RedBushGuard).sub_group(0, 0x46).sub_group(1, 0x49),
SpriteRequirement(EnemySprite.BombGuard).sub_group(0, 0x46).sub_group(1, 0x49),
SpriteRequirement(EnemySprite.GreenKnifeGuard).sub_group(1, 0x49).sub_group(2, 0x13),
SpriteRequirement(EnemySprite.Geldman).sub_group(2, 0x12).exclude({0x10c}),
SpriteRequirement(EnemySprite.Toppo).immune().sub_group(3, 0x11),
SpriteRequirement(EnemySprite.Popo).sub_group(1, 0x2c),
SpriteRequirement(EnemySprite.Popo2).sub_group(1, 0x2c),
SpriteRequirement(EnemySprite.ArmosStatue).sub_group(3, 0x10).exclude({0x10c}),
SpriteRequirement(EnemySprite.KingZora).affix().sub_group(3, 0x44),
SpriteRequirement(EnemySprite.ArmosKnight).exalt().sub_group(3, 0x1d),
SpriteRequirement(EnemySprite.Lanmolas).exalt().sub_group(3, 0x31),
SpriteRequirement(EnemySprite.FireballZora).immerse().no_drop().sub_group(2, [0xc, 0x18]), # .uw_skip() test
SpriteRequirement(EnemySprite.Zora).sub_group(2, 0xc).sub_group(3, 0x44), # .uw_skip() test
SpriteRequirement(EnemySprite.DesertStatue).affix().sub_group(2, 0x12),
SpriteRequirement(EnemySprite.Crab).sub_group(2, 0xc),
SpriteRequirement(EnemySprite.LostWoodsBird).affix().sub_group(2, 0x37).sub_group(3, 0x36),
SpriteRequirement(EnemySprite.LostWoodsSquirrel).affix().sub_group(2, 0x37).sub_group(3, 0x36),
SpriteRequirement(EnemySprite.SparkCW).immune().sub_group(0, 0x1f),
SpriteRequirement(EnemySprite.SparkCCW).immune().sub_group(0, 0x1f),
SpriteRequirement(EnemySprite.RollerVerticalUp).immune().sub_group(2, 0x27).exclude(NoBeamosOrTrapRooms),
SpriteRequirement(EnemySprite.RollerVerticalDown).immune().sub_group(2, 0x27).exclude(NoBeamosOrTrapRooms),
SpriteRequirement(EnemySprite.RollerHorizontalLeft).immune().sub_group(2, 0x27).exclude(NoBeamosOrTrapRooms),
SpriteRequirement(EnemySprite.RollerHorizontalRight).immune().sub_group(2, 0x27).exclude(NoBeamosOrTrapRooms),
SpriteRequirement(EnemySprite.Beamos).no_drop().sub_group(1, 0x2c).exclude(NoBeamosOrTrapRooms),
SpriteRequirement(EnemySprite.MasterSword).affix().sub_group(2, 0x37).sub_group(3, 0x36),
SpriteRequirement(EnemySprite.DebirandoPit).sub_group(0, 0x2f), # skip
SpriteRequirement(EnemySprite.Debirando).sub_group(0, 0x2f), # skip
SpriteRequirement(EnemySprite.ArcheryNpc).affix().sub_group(0, 0x4b),
SpriteRequirement(EnemySprite.WallCannonVertLeft).affix().sub_group(0, 0x2f),
SpriteRequirement(EnemySprite.WallCannonVertRight).affix().sub_group(0, 0x2f),
SpriteRequirement(EnemySprite.WallCannonHorzTop).affix().sub_group(0, 0x2f),
SpriteRequirement(EnemySprite.WallCannonHorzBottom).affix().sub_group(0, 0x2f),
SpriteRequirement(EnemySprite.BallNChain).sub_group(0, 0x46).sub_group(1, 0x49),
SpriteRequirement(EnemySprite.CannonTrooper).sub_group(0, 0x46).sub_group(1, 0x49),
SpriteRequirement(EnemySprite.CricketRat).sub_group(2, [0x1c, 0x24]),
SpriteRequirement(EnemySprite.Snake).sub_group(2, [0x1c, 0x24]),
SpriteRequirement(EnemySprite.Keese).no_drop().sub_group(2, [0x1c, 0x24]),
SpriteRequirement(EnemySprite.Leever).sub_group(0, 0x2f),
SpriteRequirement(EnemySprite.FairyPondTrigger).affix().sub_group(3, 0x36),
SpriteRequirement(EnemySprite.UnclePriest).affix().sub_group(0, [0x47, 0x51]),
SpriteRequirement(EnemySprite.RunningNpc).affix().group(6),
SpriteRequirement(EnemySprite.BottleMerchant).affix().group(6),
SpriteRequirement(EnemySprite.Zelda).affix(),
SpriteRequirement(EnemySprite.Grandma).affix().sub_group(0, 0x4b).sub_group(1, 0x4d).sub_group(2, 0x4a),
SpriteRequirement(EnemySprite.Agahnim).exalt().sub_group(0, 0x55).sub_group(1, [0x1a, 0x3d]).sub_group(2, 0x42)
.sub_group(3, 0x43),
SpriteRequirement(EnemySprite.FloatingSkull).sub_group(0, 0x1f).exclude(NoFlyingRooms),
SpriteRequirement(EnemySprite.BigSpike).sub_group(3, [0x52, 0x53]).no_drop(),
SpriteRequirement(EnemySprite.FirebarCW).immune().sub_group(0, 0x1f),
SpriteRequirement(EnemySprite.FirebarCCW).immune().sub_group(0, 0x1f),
SpriteRequirement(EnemySprite.Firesnake).no_drop().sub_group(0, 0x1f),
SpriteRequirement(EnemySprite.Hover).sub_group(2, 0x22), # .exclude(NoFlyingRooms), might be okay now
SpriteRequirement(EnemySprite.AntiFairyCircle).no_drop().sub_group(3, [0x52, 0x53]),
SpriteRequirement(EnemySprite.GreenEyegoreMimic).sub_group(2, 0x2e),
SpriteRequirement(EnemySprite.RedEyegoreMimic).sub_group(2, 0x2e),
SpriteRequirement(EnemySprite.Kodongo).sub_group(2, 0x2a),
# SpriteRequirement(EnemySprite.YellowStalfos).sub_group(0, 0x1f), # doesn't spawn
SpriteRequirement(EnemySprite.Mothula).exalt().sub_group(2, 0x38).sub_group(3, 0x52),
SpriteRequirement(EnemySprite.SpikeBlock).immune().sub_group(3, [0x52, 0x53]).exclude(NoBeamosOrTrapRooms)
.exclude({0x28}), # why exclude sp entrance?
SpriteRequirement(EnemySprite.Gibdo).sub_group(2, 0x23),
SpriteRequirement(EnemySprite.Arrghus).exalt().sub_group(2, 0x39),
SpriteRequirement(EnemySprite.Arrghi).exalt().sub_group(2, 0x39),
SpriteRequirement(EnemySprite.Terrorpin).sub_group(2, 0x2a).exclude({0x10c}), # probably fine in mimic now
SpriteRequirement(EnemySprite.Blob).sub_group(1, 0x20),
SpriteRequirement(EnemySprite.Wallmaster).immune().ow_skip().sub_group(2, 0x23)
.allow(WallmasterValidRooms),
SpriteRequirement(EnemySprite.StalfosKnight).sub_group(1, 0x20).exclude({0x10c}),
SpriteRequirement(EnemySprite.HelmasaurKing).exalt().sub_group(2, 0x3a).sub_group(3, 0x3e),
SpriteRequirement(EnemySprite.Bumper).immune().aquaphobia().sub_group(3, [0x52, 0x53]),
SpriteRequirement(EnemySprite.LaserEyeLeft).affix().sub_group(3, [0x52, 0x53]),
SpriteRequirement(EnemySprite.LaserEyeRight).affix().sub_group(3, [0x52, 0x53]),
SpriteRequirement(EnemySprite.LaserEyeTop).affix().sub_group(3, [0x52, 0x53]),
SpriteRequirement(EnemySprite.LaserEyeBottom).affix().sub_group(3, [0x52, 0x53]),
SpriteRequirement(EnemySprite.Pengator).sub_group(2, 0x26),
SpriteRequirement(EnemySprite.Kyameron).no_drop().immerse().sub_group(2, 0x22),
SpriteRequirement(EnemySprite.Wizzrobe).sub_group(2, [0x25, 0x29]),
SpriteRequirement(EnemySprite.Zoro).sub_group(1, 0x20),
SpriteRequirement(EnemySprite.Babasu).sub_group(1, 0x20),
SpriteRequirement(EnemySprite.GroveOstritch).affix().sub_group(2, 0x4e),
SpriteRequirement(EnemySprite.GroveRabbit).affix(),
SpriteRequirement(EnemySprite.GroveBird).affix().sub_group(2, 0x4e),
SpriteRequirement(EnemySprite.Freezor).stasis().skip().sub_group(2, 0x26),
SpriteRequirement(EnemySprite.Kholdstare).exalt().sub_group(2, 0x3c),
SpriteRequirement(EnemySprite.KholdstareShell).exalt(),
SpriteRequirement(EnemySprite.FallingIce).exalt().sub_group(2, 0x3c),
SpriteRequirement(EnemySprite.BlueZazak).sub_group(2, 0x28),
SpriteRequirement(EnemySprite.RedZazak).sub_group(2, 0x28),
SpriteRequirement(EnemySprite.Stalfos).sub_group(0, 0x1f),
SpriteRequirement(EnemySprite.GreenZirro).no_drop().sub_group(3, 0x1b).exclude(NoFlyingRooms),
SpriteRequirement(EnemySprite.BlueZirro).no_drop().sub_group(3, 0x1b).exclude(NoFlyingRooms),
SpriteRequirement(EnemySprite.Pikit).sub_group(3, 0x1b),
SpriteRequirement(EnemySprite.CrystalMaiden).affix(),
SpriteRequirement(EnemySprite.OldMan).affix().sub_group(0, 0x46).sub_group(1, 0x49).sub_group(2, 0x1c),
SpriteRequirement(EnemySprite.PipeDown).affix(),
SpriteRequirement(EnemySprite.PipeUp).affix(),
SpriteRequirement(EnemySprite.PipeRight).affix(),
SpriteRequirement(EnemySprite.PipeLeft).affix(),
SpriteRequirement(EnemySprite.GoodBee).affix().sub_group(0, 0x1f),
SpriteRequirement(EnemySprite.PurpleChest).affix().sub_group(3, 0x15),
SpriteRequirement(EnemySprite.BombShopGuy).affix().sub_group(1, 0x4d),
SpriteRequirement(EnemySprite.Kiki).affix().sub_group(3, 0x19),
SpriteRequirement(EnemySprite.BlindMaiden).affix(),
# dialog tester.sub_group(1, 0x2c)
SpriteRequirement(EnemySprite.BullyPinkBall).affix().sub_group(3, 0x14),
# shop keepers in complex thing below
SpriteRequirement(EnemySprite.Drunkard).affix().sub_group(0, 0x4f).sub_group(1, 0x4d).sub_group(2, 0x4a).
sub_group(3, 0x50),
SpriteRequirement(EnemySprite.Vitreous).exalt().sub_group(3, 0x3d),
SpriteRequirement(EnemySprite.Catfish).affix().sub_group(2, 0x18),
SpriteRequirement(EnemySprite.CutsceneAgahnim).affix().sub_group(0, 0x55).sub_group(1, 0x3d)
.sub_group(2, 0x42).sub_group(3, 0x43),
SpriteRequirement(EnemySprite.Boulder).affix().sub_group(3, 0x10),
SpriteRequirement(EnemySprite.Gibo).sub_group(2, 0x28),
SpriteRequirement(EnemySprite.Thief).immune().uw_skip().sub_group(0, [0xe, 0x15]),
SpriteRequirement(EnemySprite.Medusa).affix(),
SpriteRequirement(EnemySprite.FourWayShooter).affix(),
SpriteRequirement(EnemySprite.Pokey).sub_group(2, 0x27),
SpriteRequirement(EnemySprite.BigFairy).affix().sub_group(2, 0x39).sub_group(3, 0x36),
SpriteRequirement(EnemySprite.Tektite).sub_group(3, 0x10),
SpriteRequirement(EnemySprite.Chainchomp).immune().sub_group(2, 0x27),
SpriteRequirement(EnemySprite.TrinexxRockHead).exalt().sub_group(0, 0x40).sub_group(3, 0x3f),
SpriteRequirement(EnemySprite.TrinexxFireHead).exalt().sub_group(0, 0x40).sub_group(3, 0x3f),
SpriteRequirement(EnemySprite.TrinexxIceHead).exalt().sub_group(0, 0x40).sub_group(3, 0x3f),
SpriteRequirement(EnemySprite.Blind).exalt().sub_group(1, 0x2c).sub_group(2, 0x3b),
SpriteRequirement(EnemySprite.Swamola).no_drop().sub_group(3, 0x19),
SpriteRequirement(EnemySprite.Lynel).sub_group(3, 0x14),
SpriteRequirement(EnemySprite.BunnyBeam).no_drop().ow_skip(),
SpriteRequirement(EnemySprite.FloppingFish).uw_skip().immune(),
SpriteRequirement(EnemySprite.Stal),
SpriteRequirement(EnemySprite.Landmine).skip(),
SpriteRequirement(EnemySprite.DiggingGameNPC).affix().sub_group(1, 0x2a),
SpriteRequirement(EnemySprite.Ganon).exalt().sub_group(0, 0x21).sub_group(1, 0x41)
.sub_group(2, 0x45).sub_group(3, 0x33),
SpriteRequirement(EnemySprite.Faerie).immune(),
SpriteRequirement(EnemySprite.FakeMasterSword).immune().sub_group(3, 0x11),
SpriteRequirement(EnemySprite.MagicShopAssistant).affix().sub_group(0, 0x4b).sub_group(3, 0x5a),
SpriteRequirement(EnemySprite.SomariaPlatform).affix().sub_group(2, 0x27),
SpriteRequirement(EnemySprite.CastleMantle).affix().sub_group(0, 0x5d),
SpriteRequirement(EnemySprite.GreenMimic).sub_group(1, 0x2c),
SpriteRequirement(EnemySprite.RedMimic).sub_group(1, 0x2c),
SpriteRequirement(EnemySprite.MedallionTablet).affix().sub_group(2, 0x12),
# overlord requirements - encapsulated mostly in the required sheets
SpriteRequirement(2, 7).affix().sub_group(2, 46),
SpriteRequirement(3, 7).affix().sub_group(2, 46),
SpriteRequirement(5, 7).affix().sub_group(0, 31),
SpriteRequirement(6, 7).affix().sub_group(2, [28, 36]),
SpriteRequirement(7, 7).affix(),
SpriteRequirement(8, 7).affix().sub_group(1, 32),
SpriteRequirement(9, 7).affix().sub_group(2, 35),
SpriteRequirement(0xa, 7).affix().sub_group(3, 82),
SpriteRequirement(0xb, 7).affix().sub_group(3, 82),
SpriteRequirement(0x10, 7).affix().sub_group(2, 34),
SpriteRequirement(0x11, 7).affix().sub_group(2, 34),
SpriteRequirement(0x12, 7).affix().sub_group(2, 34),
SpriteRequirement(0x13, 7).affix().sub_group(2, 34),
SpriteRequirement(0x14, 7).affix(),
SpriteRequirement(0x15, 7).affix().sub_group(2, [37, 41]),
SpriteRequirement(0x16, 7).affix().sub_group(1, 32),
SpriteRequirement(0x17, 7).affix().sub_group(0, 31),
SpriteRequirement(0x18, 7).affix().sub_group(0, 31),
SpriteRequirement(0x19, 7).affix(),
SpriteRequirement(0x1a, 7).affix(),
]
simple = {(r.sprite, r.overlord): r for r in reqs}
shopkeeper = [
SpriteRequirement(EnemySprite.Shopkeeper).affix().sub_group(0, 75).sub_group(2, 74).sub_group(3, 90)
.allow({0xff, 0x112, 0x11f}),
SpriteRequirement(EnemySprite.Shopkeeper).affix().sub_group(0, 75).sub_group(1, 77).sub_group(2, 74)
.sub_group(3, 90).allow({0x10f, 0x110, 0x11f}),
SpriteRequirement(EnemySprite.Shopkeeper).affix().sub_group(0, 79).sub_group(2, 74).sub_group(3, 90)
.allow({0x118}),
SpriteRequirement(EnemySprite.Shopkeeper).affix().sub_group(0, 14).sub_group(2, 74).sub_group(3, 90)
.allow({0x123, 0x124}),
SpriteRequirement(EnemySprite.Shopkeeper).affix().sub_group(0, 14).sub_group(2, 74).sub_group(3, 80)
.allow({0x125, 0x100}),
SpriteRequirement(EnemySprite.Shopkeeper).affix().sub_group(0, 21).allow({0x11e}),
]
complex_r = {}
for req in shopkeeper:
for r in req.allowed_rooms:
complex_r[r] = req
simple[(EnemySprite.Shopkeeper, 0)] = complex_r
return simple
# sheet 1 and 1c have group 4 modified from vanilla for murahdahla
vanilla_sheets = [
(0x00, 0x49, 0x00, 0x00), (0x46, 0x49, 0x0C, 0x3F), (0x48, 0x49, 0x13, 0x3F), (0x46, 0x49, 0x13, 0x0E),
(0x48, 0x49, 0x0C, 0x11), (0x48, 0x49, 0x0C, 0x10), (0x4F, 0x49, 0x4A, 0x50), (0x0E, 0x49, 0x4A, 0x11),
(0x46, 0x49, 0x12, 0x00), (0x00, 0x49, 0x00, 0x50), (0x00, 0x49, 0x00, 0x11), (0x48, 0x49, 0x0C, 0x00),
(0x00, 0x00, 0x37, 0x36), (0x48, 0x49, 0x4C, 0x11), (0x5D, 0x2C, 0x0C, 0x44), (0x00, 0x00, 0x4E, 0x00),
(0x0F, 0x00, 0x12, 0x10), (0x00, 0x00, 0x00, 0x4C), (0x00, 0x0D, 0x17, 0x00), (0x16, 0x0D, 0x17, 0x1B),
(0x16, 0x0D, 0x17, 0x14), (0x15, 0x0D, 0x17, 0x15), (0x16, 0x0D, 0x18, 0x19), (0x16, 0x0D, 0x17, 0x19),
(0x16, 0x0D, 0x00, 0x00), (0x16, 0x0D, 0x18, 0x1B), (0x0F, 0x49, 0x4A, 0x11), (0x4B, 0x2A, 0x5C, 0x15),
(0x16, 0x49, 0x17, 0x3F), (0x00, 0x00, 0x00, 0x15), (0x16, 0x0D, 0x17, 0x10), (0x16, 0x49, 0x12, 0x00),
(0x16, 0x49, 0x0C, 0x11), (0x00, 0x00, 0x12, 0x10), (0x16, 0x0D, 0x00, 0x11), (0x16, 0x49, 0x0C, 0x00),
(0x16, 0x0D, 0x4C, 0x11), (0x0E, 0x0D, 0x4A, 0x11), (0x16, 0x1A, 0x17, 0x1B), (0x4F, 0x34, 0x4A, 0x50),
(0x35, 0x4D, 0x65, 0x36), (0x4A, 0x34, 0x4E, 0x00), (0x0E, 0x34, 0x4A, 0x11), (0x51, 0x34, 0x5D, 0x59),
(0x4B, 0x49, 0x4C, 0x11), (0x2D, 0x00, 0x00, 0x00), (0x5D, 0x00, 0x12, 0x59), (0x00, 0x00, 0x00, 0x00),
(0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00),
(0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00),
(0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00),
(0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00),
(0x47, 0x49, 0x2B, 0x2D), (0x46, 0x49, 0x1C, 0x52), (0x00, 0x49, 0x1C, 0x52), (0x5D, 0x49, 0x00, 0x52),
(0x46, 0x49, 0x13, 0x52), (0x4B, 0x4D, 0x4A, 0x5A), (0x47, 0x49, 0x1C, 0x52), (0x4B, 0x4D, 0x39, 0x36),
(0x1F, 0x2C, 0x2E, 0x52), (0x1F, 0x2C, 0x2E, 0x1D), (0x2F, 0x2C, 0x2E, 0x52), (0x2F, 0x2C, 0x2E, 0x31),
(0x1F, 0x1E, 0x30, 0x52), (0x51, 0x49, 0x13, 0x00), (0x4F, 0x49, 0x13, 0x50), (0x4F, 0x4D, 0x4A, 0x50),
(0x4B, 0x49, 0x4C, 0x2B), (0x1F, 0x20, 0x22, 0x53), (0x55, 0x3D, 0x42, 0x43), (0x1F, 0x1E, 0x23, 0x52),
(0x1F, 0x1E, 0x39, 0x3A), (0x1F, 0x1E, 0x3A, 0x3E), (0x1F, 0x1E, 0x3C, 0x3D), (0x40, 0x1E, 0x27, 0x3F),
(0x55, 0x1A, 0x42, 0x43), (0x1F, 0x1E, 0x2A, 0x52), (0x1F, 0x1E, 0x38, 0x52), (0x1F, 0x20, 0x28, 0x52),
(0x1F, 0x20, 0x26, 0x52), (0x1F, 0x2C, 0x25, 0x52), (0x1F, 0x20, 0x27, 0x52), (0x1F, 0x1E, 0x29, 0x52),
(0x1F, 0x2C, 0x3B, 0x52), (0x46, 0x49, 0x24, 0x52), (0x21, 0x41, 0x45, 0x33), (0x1F, 0x2C, 0x28, 0x31),
(0x1F, 0x0D, 0x29, 0x52), (0x1F, 0x1E, 0x27, 0x52), (0x1F, 0x20, 0x27, 0x53), (0x48, 0x49, 0x13, 0x52),
(0x0E, 0x1E, 0x4A, 0x50), (0x1F, 0x20, 0x26, 0x53), (0x15, 0x00, 0x00, 0x00), (0x1F, 0x00, 0x2A, 0x52),
(0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00),
(0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00),
(0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00),
(0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00),
(0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x08), (0x5D, 0x49, 0x00, 0x52), (0x55, 0x49, 0x42, 0x43),
(0x61, 0x62, 0x63, 0x50), (0x61, 0x62, 0x63, 0x50), (0x61, 0x62, 0x63, 0x50), (0x61, 0x62, 0x63, 0x50),
(0x61, 0x62, 0x63, 0x50), (0x61, 0x62, 0x63, 0x50), (0x61, 0x56, 0x57, 0x50), (0x61, 0x62, 0x63, 0x50),
(0x61, 0x62, 0x63, 0x50), (0x61, 0x56, 0x57, 0x50), (0x61, 0x56, 0x63, 0x50), (0x61, 0x56, 0x57, 0x50),
(0x61, 0x56, 0x33, 0x50), (0x61, 0x56, 0x57, 0x50), (0x61, 0x62, 0x63, 0x50), (0x61, 0x62, 0x63, 0x50)
]
required_boss_sheets = {EnemySprite.ArmosKnight: 9, EnemySprite.Lanmolas: 11, EnemySprite.Moldorm: 12,
EnemySprite.HelmasaurKing: 21, EnemySprite.Arrghus: 20, EnemySprite.Mothula: 26,
EnemySprite.Blind: 32, EnemySprite.Kholdstare: 22, EnemySprite.Vitreous: 22,
EnemySprite.TrinexxRockHead: 23}
class SpriteSheet:
def __init__(self, id, default_sub_groups):
self.id = id
self.sub_groups = list(default_sub_groups)
self.locked = [False] * 4
self.room_set = set()
def dungeon_id(self):
return self.id + 0x40
def valid_sprite(self, requirement):
if requirement.groups and self.id not in requirement.groups:
return False
for idx, sub in enumerate(self.sub_groups):
if requirement.sub_groups[idx] and sub not in requirement.sub_groups[idx]:
return False
return True
def lock_sprite_in(self, sprite):
for i, options in sprite.sub_groups.items():
self.locked[i] = len(options) > 0
def add_sprite_to_sheet(self, groups, rooms=None):
for idx, g in enumerate(groups):
if g is not None:
self.sub_groups[idx] = g
self.locked[idx] = True
if rooms is not None:
self.room_set.update(rooms)
def write_to_rom(self, rom, base_address):
rom.write_bytes(base_address + self.id * 4, self.sub_groups)
def __str__(self):
return f'{self.id} => [{", ".join([str(x) for x in self.sub_groups])}]'
# convert to dungeon id
def did(n):
return n + 0x40
def init_sprite_sheets(requirements):
sheets = {id: SpriteSheet(id, def_sheet) for id, def_sheet in enumerate(vanilla_sheets)}
# wait until bosses are randomized to determine which are randomized
for sprite, sheet_num in required_boss_sheets.items():
sheet = sheets[did(sheet_num)] # convert to dungeon sheet id
boss_sprite = requirements[(sprite, 0)]
sheet.lock_sprite_in(boss_sprite)
return sheets
def setup_required_dungeon_groups(sheets, data_tables):
sheets[did(1)].add_sprite_to_sheet([70, 73, 28, 82], {0xe4, 0xf0}) # old man
# various npcs
sheets[did(5)].add_sprite_to_sheet([75, 77, 74, 90], {0xf3, 0x109, 0x10e, 0x10f, 0x110, 0x111, 0x112,
0x11a, 0x11c, 0x11f, 0x122})
sheets[did(7)].add_sprite_to_sheet([75, 77, 57, 54], {0x8, 0x2c, 0x114, 0x115, 0x116}) # big fairies
sheets[did(13)].add_sprite_to_sheet([81, None, None, None], {0x55, 0x102, 0x104}) # uncle, sick kid
sheets[did(14)].add_sprite_to_sheet([71, 73, 76, 80], {0x12, 0x105, 0x10a}) # wisemen
sheets[did(15)].add_sprite_to_sheet([79, 77, 74, 80], {0xf4, 0xf5, 0x101, 0x103, 0x106, 0x118, 0x119}) # more npcs
sheets[did(18)].add_sprite_to_sheet([85, 61, 66, 67], {0x20, 0x30}) # aga alter, aga1
sheets[did(24)].add_sprite_to_sheet([85, 26, 66, 67], {0xd}) # aga2
sheets[did(34)].add_sprite_to_sheet([33, 65, 69, 51], {0}) # ganon
sheets[did(40)].add_sprite_to_sheet([14, None, 74, 80], {0x124, 0x125, 0x126}) # fairy + rupee npcs
sheets[did(9)].add_sprite_to_sheet([None, None, None, 29], {0xe3}) # magic bat
sheets[did(28)].add_sprite_to_sheet([None, None, 38, 82], {0xe, 0x7e, 0x8e, 0x9e}) # freezors
sheets[did(3)].add_sprite_to_sheet([93, None, None, None], {0x51}) # mantle
sheets[did(42)].add_sprite_to_sheet([21, None, None, None], {0x11e}) # hype cave
sheets[did(10)].add_sprite_to_sheet([47, None, 46, None], {0x5c, 0x75, 0xb9, 0xd9}) # cannonballs
sheets[did(37)].add_sprite_to_sheet([31, None, 39, 82], {0x24, 0xb4, 0xb5, 0xc6, 0xc7, 0xd6}) # somaria platforms
# not sure 31 is needed above
free_sheet_reqs = [
([75, None, None, None], [0xff, 0x11f]), # shopkeepers
([None, 77, None, 21], [0x121]), # smithy
([None, None, None, 80], [0x108]), # chicken house
([14, 30, None, None], [0x123]), # mini moldorm (shutter door)
([None, None, 34, None], [0x36, 0x46, 0x66, 0x76]), # pirogusu spawners
([None, 32, None, None], [0x9f]), # babasu spawners
([31, None, None, None], [0x7f]), # force baris
([None, None, 35, None], [0x39, 0x49]), # wallmasters
# bumpers - why the split - because of other requirements -
([None, None, None, (82, 83)], [0x17, 0x2a, 0x4c, 0x59, 0x67, 0x7e, 0x8b, 0xeb, 0xfb]),
# crystal switches - split for some reason
([None, None, None, (82, 83)], [0xb, 0x13, 0x1b, 0x1e, 0x2a, 0x2b, 0x31, 0x5b, 0x6b, 0x77, 0x8b,
0x91, 0x92, 0x9b, 0x9d, 0xa1, 0xab, 0xbf, 0xc4, 0xef]),
# laser eyes - split for some reason
([None, None, None, (82, 83)], [0x13, 0x23, 0x96, 0xa5, 0xc5, 0xd5]),
# statues - split for some reason
([None, None, None, (82, 83)], [0x26, 0x2b, 0x40, 0x4a, 0x6b, 0x7b]),
([None, None, None, 83], [0x43, 0x63, 0x87]), # tile rooms
# non-optional
([None, None, None, 82], [0x58, 0x8c, 0x10b]), # pull switches
([None, None, (28, 36), 82], [0x2, 0x64]), # pull switches (snakes)
([None, None, None, 82], [0x1a, 0x3d, 0x44, 0x5e, 0x7c, 0x95, 0xc3]), # collapsing bridges
([None, None, None, 83], [0x3f, 0xce]), # pull tongue
([None, None, None, 83], [0x35, 0x37, 0x76]), # swamp drains
([None, None, 34, None], [0x28]), # tektike forced? - spawn chest
([None, None, 37, None], [0x97]), # wizzrobe spawner - in middle of room...
# combined
([None, 32, None, (82, 83)], [0x3e]), # babasu spawners + crystal switch
([None, 32, None, 83], [0x4]), # zoro spawners + crystal switch + pull switch
([None, None, 35, 82], [0x56]), # wallmaster + collasping bridge
([None, None, 35, (82, 83)], [0x57, 0x68]), # wallmaster + statue and wallmaster + bumpers
([None, None, 34, 83], [0x76]), # swamp drain + pirogusu spawners
([None, None, 35, 83], [0x8d]), # wallmaster + tile room
([None, None, None, 83], [0xb6, 0xc1]), # tile room + crystal switch
# allow some sprites / increase odds:
([72, 73, None, None], []), # allow for blue archer + greenbush
([None, 73, 19, None], []), # allow for green knife guard
([None, None, 12, 68], []), # increase odds for zora
([22, None, 23, None], []), # increase odds for snapdragon
]
data_tables.room_requirements = {}
# find home for the free_sheet_reqs
for pair in free_sheet_reqs:
groups, room_list = pair
for room in room_list:
data_tables.room_requirements[room] = groups
find_matching_sheet(groups, sheets, range(65, 124), room_list)
# RandomizeRooms(optionFlags);
# roomCollection.LoadRooms()
# roomCollection.RandomizeRoomSpriteGroups(spriteGroupCollection, optionFlags);
# more stuff
sub_group_choices = {
0: [22, 31, 47, 14],
1: [44, 30, 32], # 73, 13
2: [12, 18, 23, 24, 28, 46, 34, 35, 39, 40, 38, 41, 36, 37, 42],
3: [17, 16, 27, 20, 82, 83, 25] # 25 for Swamola
}
# 70, 72 for guards
# 0: 72 specifically for BlueArcher/GreenBush (but needs combination)
# 0: 70 for guards but needs combination
# 2: 19 for green knife guard, but needs combination
# 3: 68 for Zora, but needs combination
def combine_req(sub_groups, requirement):
for i in range(0, 4):
if requirement.sub_groups[i]:
if len(sub_groups[i]) == 0:
sub_groups[i].update(requirement.sub_groups[i])
else:
if len(sub_groups[i].intersection(requirement.sub_groups[i])) == 0:
raise IncompatibleEnemyException
sub_groups[i].intersection_update(requirement.sub_groups[i])
def setup_custom_enemy_sheets(custom_enemies, sheets, data_tables, sheet_range, uw=True):
requirements = data_tables.sprite_requirements
for room_id, enemy_map in custom_enemies.items():
if uw:
original_list = data_tables.uw_enemy_table.room_map[room_id]
else:
original_list = data_tables.ow_enemy_table[room_id]
sub_groups_choices = [set(), set(), set(), set()]
for idx, sprite in enumerate(original_list):
if idx in enemy_map:
key = (sprite_translation[enemy_map[idx]], 0)
if key not in requirements:
continue
req = requirements[key]
try:
combine_req(sub_groups_choices, req)
except IncompatibleEnemyException:
logging.getLogger('').warning(f'Incompatible enemy: {hex(room_id)}:{idx} {enemy_map[idx]}')
else:
sprite_secondary = 0 if sprite.sub_type != SpriteType.Overlord else sprite.sub_type
key = (sprite.kind, sprite_secondary)
if key not in requirements:
continue
req = requirements[key]
if isinstance(req, dict):
req = req[room_id]
if req.static or not req.can_randomize:
try:
combine_req(sub_groups_choices, req)
except IncompatibleEnemyException:
raise IncompatibleEnemyException(f'Incompatible enemy: {hex(room_id)}:{idx} {str(req)}')
sheet_req = [None if not x else tuple(x) for x in sub_groups_choices]
find_matching_sheet(sheet_req, sheets, sheet_range, [room_id], True)
def randomize_underworld_sprite_sheets(sheets, data_tables, custom_enemies):
setup_required_dungeon_groups(sheets, data_tables)
setup_custom_enemy_sheets(custom_enemies, sheets, data_tables, range(65, 124), True)
for num in range(65, 124): # sheets 0x41 to 0x7B inclusive
sheet = sheets[num]
# if not sheet.locked[1] and num in [65, 66, 67, 68]: # guard stuff, kind of
# sheet.locked[1] = True
# sheet.sub_groups[1] = random.choice([13, 73])
free_slots = [idx for idx in range(0, 4) if not sheet.locked[idx]]
while free_slots:
choices = [c for c in data_tables.sheet_choices if all(slot in free_slots for slot in c.slots)]
weights = [c.weight for c in choices]
choice = random.choices(choices, weights, k=1)[0]
for idx, val in choice.assignments.items():
v = random.choice(val) if isinstance(val, list) else val
sheet.sub_groups[idx] = v
sheet.locked[idx] = True
free_slots = [idx for idx in range(0, 4) if not sheet.locked[idx]]
def setup_required_overworld_groups(sheets):
sheets[7].add_sprite_to_sheet([None, None, 74, None], {0x2}) # lumberjacks
sheets[16].add_sprite_to_sheet([None, None, 18, 16], {0x3, 0x93}) # WDM (pre/post-Aga)
sheets[7].add_sprite_to_sheet([None, None, None, 17], {0xA, 0x9A}) # DM Foothills? (pre/post-Aga)
sheets[4].add_sprite_to_sheet([None, None, None, None], {0xF, 0x9F}) # Waterfall of wishing (pre/post-Aga)
sheets[3].add_sprite_to_sheet([None, None, None, 14], {0x14, 0xA4}) # Graveyard (pre/post-Aga)
sheets[1].add_sprite_to_sheet([None, None, 76, 0x3F], {0x1B, 0xAB}) # Hyrule Castle (pre/post-Aga)
sheets[2].add_sprite_to_sheet([None, None, None, 0x3F], {}) # Hyrule Castle - rain state
# Smithy/Race/Kak (pre/post-Aga)
sheets[6].add_sprite_to_sheet([0x4F, 0x49, 0x4A, 0x50], {0x18, 0x22, 0x28, 0xA8, 0xB2, 0xB8})
sheets[8].add_sprite_to_sheet([None, None, 18, None], {0x30, 0xC0}) # Desert (pre/post-Aga)
sheets[10].add_sprite_to_sheet([None, None, None, 17], {0x3A, 0xCA}) # M-rock (pre/post-Aga)
sheets[22].add_sprite_to_sheet([None, None, 24, None], {0x4F, 0xDF}) # Catfish (pre/post-Aga)
sheets[21].add_sprite_to_sheet([21, None, None, 21], {0x62, 0xF2}) # Smith DW (pre/post-Aga)
sheets[27].add_sprite_to_sheet([None, 42, None, None], {0x68, 0xF8}) # Dig Game (pre/post-Aga)
sheets[13].add_sprite_to_sheet([None, None, 76, None], {0x16, 0xA6}) # Witch hut (pre/post-Aga)
sheets[29].add_sprite_to_sheet([None, 77, None, 21], {0x69, 0xF9}) # VoO South (pre/post-Aga)
sheets[15].add_sprite_to_sheet([None, None, 78, None], {0x2A, 0xBA}) # Haunted Grove (pre/post-Aga)
sheets[17].add_sprite_to_sheet([None, None, None, 76], {0x6A, 0xFA}) # Stumpy (pre/post-Aga)
sheets[12].add_sprite_to_sheet([None, None, 55, 54], {0x80, 0x110}) # Specials (pre/post-Aga)
sheets[14].add_sprite_to_sheet([None, None, 12, 68], {0x81, 0x111}) # Zora's Domain (pre/post-Aga)
sheets[26].add_sprite_to_sheet([15, None, None, None], {0x92}) # Lumberjacks post-Aga
sheets[23].add_sprite_to_sheet([None, None, None, 25], {0x5E, 0xEE}) # PoD pre/post-Aga
free_sheet_reqs = [
[None, None, None, 0x14], # bully+pink ball needs this
[72, 73, None, None], # allow for blue archer + green bush
[None, 73, 19, None], # allow for green knife guard
[22, None, 23, None], # increase odds for snapdragon
[70, 73, None, None], # guards group (ballnchain, redbush, redjav, cannon, bomb, bluesain
[None, None, None, 0x15], # an option for talking trees
[None, None, None, 0x1B], # an option for talking trees
]
for group in free_sheet_reqs:
find_matching_sheet(group, sheets, range(1, 64))
class NoMatchingSheetException(Exception):
pass
class IncompatibleEnemyException(Exception):
pass
def find_matching_sheet(groups, sheets, search_sheets, room_list=None, lock_match=False):
possible_sheets = []
found_match = False
for num in search_sheets:
if num in {6, 65, 69, 71, 78, 79, 82, 88, 98}: # these are not useful sheets for randomization
continue
sheet = sheets[num]
valid = True
match = True
for idx, value in enumerate(groups):
if value is not None and sheet.locked[idx]:
valid = False
if (sheet.sub_groups[idx] not in value if isinstance(value, tuple)
else value != sheet.sub_groups[idx]):
match = False
elif value is not None:
match = False
if match:
found_match = True
if lock_match and room_list is not None:
sheet.room_set.update(room_list)
break
if valid:
possible_sheets.append(sheet)
if not found_match:
if len(possible_sheets) == 0:
raise NoMatchingSheetException
chosen_sheet = random.choice(possible_sheets)
chosen_groups = [(random.choice(g) if isinstance(g, tuple) else g) for g in groups]
chosen_sheet.add_sprite_to_sheet(chosen_groups, room_list)
def randomize_overworld_sprite_sheets(sheets, data_tables, custom_enemies):
setup_required_overworld_groups(sheets)
setup_custom_enemy_sheets(custom_enemies, sheets, data_tables, range(1, 64), False)
for num in range(1, 64): # sheets 0x1 to 0x3F inclusive
sheet = sheets[num]
if num == 6: # skip this group - it is locked for kakariko
continue
free_slots = [idx for idx in range(0, 4) if not sheet.locked[idx]]
while free_slots:
choices = [c for c in data_tables.sheet_choices if all(slot in free_slots for slot in c.slots)]
weights = [c.weight for c in choices]
choice = random.choices(choices, weights, k=1)[0]
for idx, val in choice.assignments.items():
v = random.choice(val) if isinstance(val, list) else val
sheet.sub_groups[idx] = v
sheet.locked[idx] = True
free_slots = [idx for idx in range(0, 4) if not sheet.locked[idx]]
class SheetChoice:
def __init__(self, slots, assignments, weight):
self.slots = slots
self.assignments = assignments
self.weight = weight

View File

@@ -0,0 +1,102 @@
import os
import json
import codecs
if __name__ == '__main__':
directory = './EnemizerCLI.Core/tiles'
for filename in os.listdir(directory):
with codecs.open(directory+'/'+filename, 'r', 'utf-8-sig') as fin:
pattern = json.load(fin)
pairs = [f'({x["x"]}, {x["y"]})' for x in pattern["Items"]]
print(f'(\'{filename}\', [{", ".join(pairs)}]),')
tile_patterns = [
('heart soft', [(3, 1), (5, 2), (4, 7), (2, 5), (7, 1), (7, 5), (8, 4), (1, 2), (2, 1), (1, 4), (5, 7), (6, 1),
(6, 6), (4, 2), (8, 3), (1, 3), (3, 6), (8, 2)]),
('metroid', [(2, 7), (7, 7), (1, 3), (3, 1), (8, 3), (1, 6), (4, 5), (5, 3), (1, 4), (6, 1), (6, 4), (8, 6), (3, 4),
(7, 5), (4, 1), (5, 5), (2, 2), (2, 5), (7, 2), (5, 1), (4, 3), (8, 4)]),
# ('moldorm vertical', [(5, 1), (6, 0), (7, 2), (5, 4), (4, 4), (4, 1), (3, 5), (5, 6), (3, 2), (6, 6), (7, 5),
# (6, 1), (4, 8), (3, 3), (5, 7), (3, 8), (2, 7), (6, 4), (4, 0), (3, 6), (7, 3), (4, 6)]),
# ('scream emoji', [(2, 2), (7, 2), (2, 3), (7, 3), (1, 7), (8, 7), (3, 2), (6, 2), (2, 6), (7, 6), (3, 3), (6, 3),
# (2, 7), (7, 7), (4, 5), (5, 7), (5, 5), (4, 7), (4, 6), (5, 6), (2, 5), (7, 5)]),
('mario mushroom', [(3, 7), (4, 7), (5, 7), (3, 4), (4, 4), (5, 4), (3, 1), (4, 1), (5, 1), (2, 2), (6, 6), (6, 2),
(2, 6), (1, 3), (7, 5), (7, 3), (1, 5), (1, 4), (6, 5), (7, 4), (2, 5)]),
('moldorm', [(1, 3), (2, 5), (3, 6), (5, 5), (7, 5), (7, 2), (5, 3), (3, 2), (2, 4), (1, 5), (5, 4), (6, 2), (7, 4),
(8, 1), (8, 4), (4, 2), (9, 2), (2, 3), (4, 6), (9, 3), (7, 3), (6, 6)]),
# ('thinking emoji', [(5, 6), (6, 4), (4, 3), (3, 1), (2, 6), (5, 3), (6, 6), (6, 1), (3, 0), (4, 7), (2, 4),
# (3, 8), (6, 0), (3, 7), (3, 3)]),
('triangle', [(1, 5), (7, 5), (4, 2), (3, 5), (5, 5), (4, 3), (2, 4), (6, 4), (5, 3), (2, 5), (6, 5), (3, 3),
(4, 5), (5, 4), (3, 4), (4, 4)]),
('heart', [(8, 3), (2, 3), (5, 7), (2, 4), (8, 4), (4, 6), (6, 6), (8, 2), (2, 2), (5, 2), (7, 1), (3, 1), (3, 5),
(6, 1), (7, 5), (4, 1)]),
('arrghus', [(4, 1), (6, 2), (2, 3), (4, 3), (3, 4), (4, 5), (5, 6), (3, 7), (1, 4), (2, 5), (5, 1), (6, 3), (2, 2),
(7, 4), (5, 4), (4, 4), (6, 5), (3, 6), (5, 7), (3, 1), (3, 5), (5, 5)]),
# ('cowboy smile', [(1, 2), (3, 3), (4, 1), (3, 5), (5, 8), (6, 7), (5, 2), (7, 2), (1, 3), (2, 7), (5, 5), (5, 3),
# (3, 2), (4, 3), (7, 3), (2, 3), (4, 2), (3, 8), (4, 8), (6, 3)]),
('clown face happy', [(2, 2), (7, 6), (7, 2), (2, 6), (3, 3), (6, 7), (6, 3), (3, 7), (2, 3), (5, 6), (7, 3),
(4, 6), (2, 5), (6, 6), (7, 5), (3, 6), (4, 5), (5, 7), (5, 5), (4, 7), (3, 2), (6, 2)]),
('generic happy face', [(2, 1), (6, 3), (6, 5), (4, 6), (2, 2), (6, 6), (2, 3), (3, 5), (3, 2), (3, 3), (6, 2),
(5, 5), (1, 2), (3, 6), (7, 5), (7, 1), (4, 5), (8, 2), (5, 6), (2, 5), (7, 3), (7, 2)]),
# ('YMCA', [(1, 2), (2, 3), (5, 2), (7, 2), (6, 3), (7, 4), (2, 4), (5, 4), (6, 2), (3, 2), (5, 3), (7, 3), (7, 6),
# (4, 8), (2, 7), (6, 7), (4, 6), (8, 8), (8, 7), (3, 8), (3, 6), (6, 8)]),
# ('ze', [(5, 7), (6, 7), (7, 7), (1, 3), (2, 3), (3, 3), (5, 5), (6, 5), (7, 5), (1, 7), (2, 7), (3, 7), (5, 3),
# (6, 3), (7, 3), (3, 4), (2, 5), (1, 6), (5, 4), (5, 6)]),
# ('space invader metroid', [(4, 1), (2, 3), (3, 5), (5, 6), (7, 6), (7, 3), (2, 8), (3, 2), (1, 7), (1, 4), (6, 2),
# (8, 5), (7, 8), (4, 6), (8, 7), (5, 1), (2, 6), (8, 4), (1, 5), (6, 5)]),
('screw attack', [(2, 7), (7, 4), (6, 1), (3, 7), (2, 4), (5, 6), (4, 2), (5, 4), (3, 6), (7, 1), (3, 3), (6, 4),
(4, 6), (4, 3), (6, 2), (3, 4), (6, 5), (5, 2), (4, 5), (4, 4), (5, 3), (5, 5)]),
('vanilla wrong order', [(7, 2), (7, 4), (7, 5), (7, 7), (6, 3), (6, 5), (5, 2), (5, 3), (5, 4), (5, 5), (5, 6),
(4, 2), (4, 3), (4, 4), (4, 5), (4, 6), (3, 3), (3, 5), (2, 2), (2, 4), (2, 5), (2, 7)]),
('tile shaped tiles', [(2, 7), (2, 6), (2, 5), (2, 4), (2, 3), (2, 2), (3, 2), (4, 2), (5, 2), (6, 2), (7, 2),
(7, 3), (7, 4), (7, 5), (7, 6), (7, 7), (6, 7), (5, 7), (4, 7), (3, 7), (4, 5), (5, 4)]),
# ('panda shocked emoji', [(7, 3), (7, 4), (3, 3), (3, 4), (5, 5), (5, 6), (5, 7), (4, 6), (4, 7), (6, 7), (6, 6),
# (8, 6), (8, 7), (8, 8), (2, 8), (2, 7), (2, 6), (2, 1), (3, 1), (7, 1), (8, 1), (5, 8)]),
('JK', [(1, 5), (3, 4), (5, 3), (7, 3), (3, 2), (7, 5), (6, 4), (2, 6), (5, 6), (5, 5), (8, 2), (3, 5), (8, 6),
(5, 2), (3, 3), (5, 4)]),
('dollar sign', [(6, 2), (5, 1), (4, 1), (3, 1), (2, 2), (2, 6), (3, 7), (4, 7), (5, 7), (6, 6), (2, 3), (6, 5),
(3, 4), (5, 4), (4, 4), (4, 0), (4, 2), (4, 3), (4, 5), (4, 6), (4, 8)]),
# ('rupee diagonal', [(1, 4), (1, 5), (1, 6), (1, 7), (2, 7), (3, 7), (4, 7), (5, 6), (6, 5), (7, 4), (7, 3),
# (7, 2), (7, 1), (6, 1), (5, 1), (4, 1), (3, 2), (2, 3), (3, 5), (4, 4), (5, 3)]),
# ('sword', [(1, 8), (8, 1), (8, 2), (1, 4), (7, 1), (5, 8), (7, 3), (2, 4), (6, 2), (5, 7), (6, 4), (2, 5), (5, 3),
# (4, 7), (5, 5), (3, 6), (4, 4), (2, 7), (4, 6), (3, 5)]),
('z1 dungeon1', [(4, 6), (6, 4), (2, 4), (3, 7), (4, 3), (5, 7), (3, 2), (5, 4), (3, 5), (5, 5), (4, 2), (6, 3),
(4, 7), (3, 4), (7, 3), (4, 5), (4, 4)]),
# ('z1 dungeon 4', [(4, 8), (3, 6), (4, 4), (5, 2), (3, 1), (4, 3), (6, 2), (4, 1), (3, 3), (5, 4), (3, 5), (4, 7),
# (6, 1), (3, 8), (5, 7), (3, 2), (4, 6), (3, 4), (5, 1)]),
# ('LTTP', [(3, 4), (2, 3), (6, 2), (6, 4), (2, 2), (5, 2), (6, 3), (2, 4), (7, 2), (3, 6), (4, 8), (8, 7), (7, 6),
# (7, 8), (5, 6), (7, 7), (4, 6), (4, 7), (8, 6)]),
('triple triforce', [(4, 2), (3, 3), (4, 3), (5, 3), (6, 5), (5, 6), (6, 6), (7, 6), (3, 6), (2, 6), (2, 5),
(1, 6)]),
# ('TILE', [(2, 2), (5, 4), (3, 2), (2, 4), (5, 2), (2, 3), (1, 2), (5, 3), (3, 6), (6, 6), (7, 8), (8, 6), (6, 7),
# (3, 8), (4, 8), (3, 7), (6, 8), (7, 6), (7, 7), (8, 8)]),
# ('panda thinking emoji', [(2, 1), (3, 1), (6, 2), (7, 2), (6, 3), (3, 2), (3, 3), (3, 5), (4, 5), (5, 5), (2, 6),
# (2, 7), (1, 7), (2, 8), (1, 8), (3, 7), (4, 7), (3, 8)]),
# ('pokata key', [(3, 1), (4, 2), (5, 3), (4, 4), (4, 6), (5, 7), (6, 8), (4, 8), (6, 6), (3, 3), (5, 1), (4, 5),
# (3, 2), (4, 3), (5, 4), (5, 6), (4, 7), (5, 8), (3, 4), (5, 2), (4, 1)]),
('tile shaped tiles randomish', [(4, 2), (2, 2), (7, 5), (5, 4), (3, 2), (4, 5), (4, 7), (7, 7), (2, 7), (2, 4),
(7, 2), (2, 5), (5, 7), (7, 4), (5, 2), (6, 2), (3, 7), (2, 3), (7, 6), (6, 7),
(7, 3), (2, 6)]),
('NO', [(1, 5), (4, 4), (3, 4), (6, 2), (8, 4), (1, 2), (8, 5), (7, 5), (1, 3), (6, 5), (6, 4), (1, 4), (4, 5),
(4, 2), (2, 3), (7, 2), (8, 2), (8, 3), (4, 3), (6, 3)]),
('bomb', [(3, 3), (5, 7), (6, 4), (2, 6), (5, 3), (3, 7), (6, 6), (2, 4), (7, 2), (2, 5), (4, 7), (5, 1), (4, 2),
(6, 5), (6, 1), (4, 3), (8, 2)]),
# ('boot', [(6, 7), (8, 6), (5, 5), (5, 3), (8, 2), (3, 6), (4, 8), (7, 8), (8, 4), (6, 2), (2, 7), (3, 8), (4, 5),
# (5, 4), (7, 2), (8, 7), (8, 8), (8, 3), (5, 8), (2, 8), (5, 2), (8, 5)]),
# ('javalogo', [(5, 8), (4, 8), (3, 8), (2, 8), (1, 7), (5, 6), (4, 6), (3, 6), (2, 6), (1, 5), (7, 7), (8, 6),
# (7, 5), (3, 4), (3, 3), (2, 2), (3, 1), (5, 4), (5, 3), (6, 2)]),
# ('pokata and ender key', [(3, 1), (5, 3), (4, 4), (4, 6), (5, 7), (6, 8), (4, 8), (6, 6), (3, 3), (5, 1), (4, 5),
# (3, 2), (4, 7), (4, 1), (5, 8), (5, 2), (3, 4), (5, 6), (5, 4)]),
('kitty', [(3, 1), (6, 4), (7, 6), (8, 3), (1, 4), (3, 7), (3, 4), (2, 2), (5, 2), (6, 1), (6, 5), (6, 7), (2, 6),
(7, 2), (8, 5), (1, 3), (1, 5), (4, 2), (3, 5), (4, 6), (8, 4), (5, 6)]),
('creeper face', [(3, 7), (4, 5), (5, 4), (5, 6), (3, 3), (2, 2), (3, 2), (7, 3), (6, 7), (4, 6), (6, 3), (7, 2),
(2, 3), (4, 4), (3, 6), (6, 2), (6, 6), (5, 5)]),
('fast', [(7, 7)])
]
banned_tiles = {
# these are pots in tower of hera, only ban if pottery is on?
(1, 8), (1, 7), (3, 8), (5, 8), (7, 8),
# these are crystal barrier tiles
# (8, 3), (8, 4), (8, 5) # should I ban these too? bypasses barrier logic? regex \(8, [345]\)
}

View File

@@ -0,0 +1 @@
# do nothing, just exist to make "source" package

View File

@@ -0,0 +1,304 @@
# From: https://spannerisms.github.io/damage
# There are 16 damage classes, each with 8 subclasses.
# These subclasses determine the damage or effect inflicted on a sprite.
# Subclass data is stored as a table in ROM at $0D:B8F1
# DamageSource and SubClassTable
#_0DB8F1: db $00, $01, $20, $FF, $FC, $FB, $00, $00 ; 0x00 - Boomerang
#_0DB8F9: db $00, $02, $40, $04, $00, $00, $00, $00 ; 0x01 - Sword 1
#_0DB901: db $00, $04, $40, $02, $03, $00, $00, $00 ; 0x02 - Sword 2
#_0DB909: db $00, $08, $40, $04, $00, $00, $00, $00 ; 0x03 - Sword 3
#_0DB911: db $00, $10, $40, $08, $00, $00, $00, $00 ; 0x04 - Sword 4
#_0DB919: db $00, $10, $40, $08, $00, $00, $00, $00 ; 0x05 - Sword 5
#_0DB921: db $00, $04, $40, $10, $00, $00, $00, $00 ; 0x06 - Arrow
#_0DB929: db $00, $FF, $40, $FF, $FC, $FB, $00, $00 ; 0x07 - Hookshot
#_0DB931: db $00, $04, $40, $FF, $FC, $FB, $20, $00 ; 0x08 - Bomb
#_0DB939: db $00, $64, $18, $64, $00, $00, $00, $00 ; 0x09 - Silver arrow
#_0DB941: db $00, $F9, $FA, $FF, $64, $00, $00, $00 ; 0x0A - Powder
#_0DB949: db $00, $08, $40, $FD, $04, $10, $00, $00 ; 0x0B - Fire rod
#_0DB951: db $00, $08, $40, $FE, $04, $00, $00, $00 ; 0x0C - Ice rod
#_0DB959: db $00, $10, $40, $FD, $00, $00, $00, $00 ; 0x0D - Bombos
#_0DB961: db $00, $FE, $40, $10, $00, $00, $00, $00 ; 0x0E - Ether
#_0DB969: db $00, $20, $40, $FF, $00, $00, $00, $FA ; 0x0F - Quake
# Special Values:
# $F9 Target becomes a faerie
# $FA Target becomes a blob
# $FB Target stunned for 32 frames
# $FC Target stunned for 128 frames
# $FD Target incinerated
# $FE Target becomes frozen
# $FF Target stunned for 255 frames
DamageSource:
Boomerang:
class: 0x00
subclass: [0x00, 0x01, 0x20, 0xFF, 0xFC, 0xFB, 0x00, 0x00]
Sword1:
class: 0x01
subclass: [0x00, 0x02, 0x40, 0x04, 0x00, 0x00, 0x00, 0x00]
Sword2:
class: 0x02
subclass: [0x00, 0x04, 0x40, 0x02, 0x03, 0x00, 0x00, 0x00]
Sword3:
class: 0x03
subclass: [0x00, 0x08, 0x40, 0x04, 0x00, 0x00, 0x00, 0x00]
Sword4:
class: 0x04
subclass: [0x00, 0x10, 0x40, 0x08, 0x00, 0x00, 0x00, 0x00]
Sword5:
class: 0x05
subclass: [0x00, 0x10, 0x40, 0x08, 0x00, 0x00, 0x00, 0x00]
Arrow:
class: 0x06
subclass: [0x00, 0x04, 0x40, 0x10, 0x00, 0x00, 0x00, 0x00]
Hookshot:
class: 0x07
subclass: [0x00, 0xFF, 0x40, 0xFF, 0xFC, 0xFB, 0x00, 0x00]
Bomb:
class: 0x08
subclass: [0x00, 0x04, 0x40, 0xFF, 0xFC, 0xFB, 0x20, 0x00]
SilverArrow:
class: 0x09
subclass: [0x00, 0x64, 0x18, 0x64, 0x00, 0x00, 0x00, 0x00]
Powder:
class: 0x0A
subclass: [0x00, 0xF9, 0xFA, 0xFF, 0x64, 0x00, 0x00, 0x00]
FireRod:
class: 0x0B
subclass: [0x00, 0x08, 0x40, 0xFD, 0x04, 0x10, 0x00, 0x00]
IceRod:
class: 0x0C
subclass: [0x00, 0x08, 0x40, 0xFE, 0x04, 0x00, 0x00, 0x00]
Bombos:
class: 0x0D
subclass: [0x00, 0x10, 0x40, 0xFD, 0x00, 0x00, 0x00, 0x00]
Ether:
class: 0x0E
subclass: [0x00, 0xFE, 0x40, 0x10, 0x00, 0x00, 0x00, 0x00]
Quake:
class: 0x0F
subclass: [0x00, 0x20, 0x40, 0xFF, 0x00, 0x00, 0x00, 0xFA]
# The subclass that each sprite should look for in each damage class is in a table in WRAM at $7F:6000
# Rando migrated it to $31:C800
SubClassTable:
0x0: [1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 0, 3, 1, 3, 1, 1]
0x1: [1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 0, 3, 1, 3, 1, 1]
0x2: [1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x3: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x4: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x5: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x6: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x7: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x8: [3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 3, 3, 1, 7]
0x9: [0, 1, 3, 3, 3, 3, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0]
0xA: [3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 3, 3, 1, 7]
0xB: [1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 0, 1, 1, 0, 0, 0]
0xC: [1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 0, 1, 1, 1, 3, 1]
0xD: [3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 1, 3]
0xE: [3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 3, 3, 2, 7]
0xF: [1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 0, 3, 1, 3, 3, 2]
0x10: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 3, 1]
0x11: [4, 1, 1, 1, 1, 2, 1, 0, 2, 1, 0, 1, 3, 3, 1, 7]
0x12: [3, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 3, 3, 3, 1, 7]
0x13: [0, 1, 1, 1, 1, 1, 1, 3, 2, 3, 2, 0, 0, 3, 2, 7]
0x14: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x15: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0]
0x16: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x17: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 7]
0x18: [0, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 3, 1, 3, 3, 7]
0x19: [1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 0, 1, 1, 3, 2, 3]
0x1A: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x1B: [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 3, 2]
0x1C: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x1D: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x1E: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x1F: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x20: [3, 1, 1, 1, 1, 1, 1, 1, 0, 1, 2, 3, 3, 3, 1, 7]
0x21: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x22: [3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 3, 3, 2, 7]
0x23: [0, 1, 1, 1, 1, 1, 1, 2, 1, 1, 0, 3, 2, 3, 2, 3]
0x24: [0, 1, 1, 1, 1, 1, 1, 2, 1, 1, 0, 3, 2, 3, 2, 3]
0x25: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x26: [0, 1, 1, 1, 1, 1, 0, 3, 3, 1, 0, 0, 0, 3, 1, 3]
0x27: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 7]
0x28: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x29: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x2A: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0]
0x2B: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x2C: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x2D: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x2E: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x2F: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x30: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x31: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x32: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x33: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x34: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x35: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x36: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x37: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x38: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x39: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x3A: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x3B: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x3C: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x3D: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x3E: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 2, 2, 7]
0x3F: [0, 0, 2, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1]
0x40: [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x41: [3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 3, 1, 3, 1, 7]
0x42: [3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 3, 3, 1, 7]
0x43: [3, 1, 4, 3, 1, 1, 1, 1, 1, 1, 0, 3, 0, 3, 1, 7]
0x44: [3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 3, 0, 3, 1, 7]
0x45: [3, 1, 4, 3, 1, 1, 1, 1, 1, 1, 0, 3, 0, 3, 1, 7]
0x46: [3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 3, 3, 3, 1, 7]
0x47: [3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 3, 1, 3, 2, 7]
0x48: [3, 1, 4, 3, 1, 1, 1, 1, 1, 1, 0, 3, 0, 3, 1, 7]
0x49: [3, 1, 4, 3, 1, 1, 1, 1, 1, 1, 0, 3, 0, 3, 2, 7]
0x4A: [3, 1, 4, 3, 1, 1, 1, 1, 1, 1, 0, 3, 3, 3, 1, 7]
0x4B: [3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 3, 3, 1, 7]
0x4C: [1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 0, 1, 1, 3, 3, 3]
0x4D: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 3, 2, 3, 2, 3]
0x4E: [3, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 3, 3, 3, 1, 7]
0x4F: [3, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 3, 3, 3, 1, 7]
0x50: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x51: [3, 1, 1, 1, 1, 1, 2, 1, 1, 1, 0, 1, 3, 3, 3, 3]
0x52: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x53: [1, 3, 3, 3, 3, 3, 3, 0, 1, 1, 0, 1, 1, 0, 0, 0]
0x54: [0, 1, 3, 3, 3, 3, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0]
0x55: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 3, 1, 3, 2, 1]
0x56: [3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 3, 1, 3, 2, 1]
0x57: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x58: [3, 1, 1, 1, 1, 1, 1, 3, 1, 1, 2, 1, 3, 3, 1, 7]
0x59: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x5A: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x5B: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 3]
0x5C: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 3]
0x5D: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x5E: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x5F: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x60: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x61: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x62: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x63: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 3, 3, 3] # the pit spawns the 0x64
0x64: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 3, 3, 3]
0x65: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x66: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x67: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x68: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x69: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x6A: [5, 1, 3, 1, 1, 1, 1, 1, 1, 1, 0, 3, 0, 3, 1, 7]
0x6B: [3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1]
0x6C: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x6D: [3, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 3, 3, 3, 1, 7]
0x6E: [3, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 3, 3, 3, 1, 7]
0x6F: [1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 0, 3, 3, 3, 1, 3]
0x70: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x71: [3, 1, 1, 1, 1, 1, 1, 3, 1, 1, 0, 3, 3, 3, 1, 3]
0x72: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x73: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x74: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x75: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x76: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x77: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x78: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x79: [1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 3, 1]
0x7A: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x7B: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x7C: [0, 1, 1, 1, 1, 1, 1, 0, 2, 1, 0, 3, 3, 3, 3, 3]
0x7D: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x7E: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x7F: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x80: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x81: [0, 1, 1, 1, 1, 1, 1, 2, 1, 1, 0, 3, 3, 2, 3, 2]
0x82: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x83: [0, 1, 1, 2, 2, 1, 2, 0, 1, 2, 0, 0, 0, 0, 0, 0]
0x84: [0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0]
0x85: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 2, 3, 2, 3]
0x86: [0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 3, 3, 1, 7]
0x87: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x88: [0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0] # mothula
0x89: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x8A: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x8B: [3, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 3, 3, 3, 2, 3]
0x8C: [0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0]
0x8D: [0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0]
0x8E: [1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 0, 1, 3, 2, 2, 3]
0x8F: [3, 1, 1, 1, 1, 1, 1, 2, 2, 1, 0, 3, 3, 3, 1, 2]
0x90: [1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 3, 3, 2]
0x91: [1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x92: [0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0]
0x93: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x94: [1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 0, 3, 1, 3, 2, 3]
0x95: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x96: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x97: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x98: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x99: [1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 0, 1, 0, 3, 1, 2]
0x9A: [1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 0, 2, 3, 2, 1, 1]
0x9B: [0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 2, 3, 2]
0x9C: [0, 1, 1, 1, 1, 1, 1, 2, 1, 1, 0, 3, 2, 3, 2, 2]
0x9D: [0, 1, 1, 1, 1, 1, 1, 2, 1, 1, 0, 3, 2, 3, 2, 2]
0x9E: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0x9F: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0xA0: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0xA1: [0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0]
0xA2: [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0]
0xA3: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0]
0xA4: [0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 3, 0, 1, 3, 1]
0xA5: [3, 1, 1, 1, 1, 1, 1, 1, 2, 1, 0, 3, 3, 3, 1, 3]
0xA6: [3, 1, 1, 1, 1, 1, 1, 1, 2, 1, 0, 3, 3, 3, 1, 3]
0xA7: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 3, 2, 7]
0xA8: [0, 1, 1, 1, 1, 1, 1, 2, 1, 1, 0, 3, 3, 3, 1, 1]
0xA9: [0, 1, 1, 1, 1, 1, 1, 2, 1, 1, 0, 3, 3, 3, 1, 1]
0xAA: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 3, 1, 3, 1, 3]
0xAB: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0]
0xAC: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0xAD: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0xAE: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0xAF: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0xB0: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0xB1: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0xB2: [1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 0, 1, 1, 1, 3, 1]
0xB3: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0xB4: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0xB5: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0xB6: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0xB7: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0xB8: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0xB9: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0xBA: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0xBB: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0xBC: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0xBD: [0, 0, 1, 1, 1, 1, 3, 0, 1, 1, 0, 0, 0, 0, 0, 0]
0xBE: [0, 0, 1, 1, 1, 1, 3, 0, 1, 1, 0, 0, 0, 0, 0, 0]
0xBF: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0xC0: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0xC1: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0xC2: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0xC3: [0, 1, 1, 1, 1, 1, 3, 0, 1, 1, 0, 0, 0, 0, 0, 0]
0xC4: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0xC5: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 1]
0xC6: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 1]
0xC7: [0, 1, 1, 1, 1, 1, 1, 0, 1, 2, 0, 3, 1, 3, 1, 3]
0xC8: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0xC9: [5, 1, 1, 1, 1, 1, 3, 0, 2, 1, 0, 3, 3, 1, 3, 1]
0xCA: [5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0xCB: [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0xCC: [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0]
0xCD: [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0]
0xCE: [0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0xCF: [1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 0, 1, 1, 1, 2, 1]
0xD0: [0, 0, 0, 1, 1, 1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0]
0xD1: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 2, 2]
0xD2: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 7]
0xD3: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 7]
0xD4: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0xD5: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0xD6: [0, 0, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
0xD7: [0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0]
0xEF: [0, 1, 1, 2, 2, 1, 2, 0, 1, 2, 0, 0, 0, 0, 0, 0]
0xF0: [0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0]

View File

@@ -0,0 +1,10 @@
0x00: [0x02, 0x01, 0x01]
0x01: [0x04, 0x04, 0x04]
0x02: [0x00, 0x00, 0x00]
0x03: [0x08, 0x04, 0x02]
0x04: [0x08, 0x08, 0x08]
0x05: [0x10, 0x08, 0x04]
0x06: [0x20, 0x10, 0x08]
0x07: [0x20, 0x18, 0x10]
0x08: [0x18, 0x10, 0x08] # Roller class damage
0x09: [0x40, 0x30, 0x18] # Ganon class damage - max 8 hearts

View File

@@ -17,9 +17,9 @@ UwGeneralDeny:
- [ 0x000e, 0, [ "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft" ] ] #"Ice Palace - Entrance - Freezor"
- [ 0x000e, 1, [ "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft" ] ] #"Ice Palace - Bari Key - Top Bari"
- [ 0x000e, 2, [ "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft" ] ] #"Ice Palace - Bari Key - Middle Bari"
- [ 0x0016, 0, [ "RollerVerticalDown", "RollerVerticalUp", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Swamp Palace - Pool - Zol 1"
- [ 0x0016, 1, [ "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Swamp Palace - Pool - Zol 2"
- [ 0x0016, 2, [ "SparkCW", "SparkCCW", "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Swamp Palace - Pool - Blue Bari"
- [ 0x0016, 0, [ "RollerVerticalDown", "RollerVerticalUp", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper", "GreenMimic", "RedMimic", "Pikit"] ] #"Swamp Palace - Pool - Zol 1"
- [ 0x0016, 1, [ "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper", "GreenMimic", "RedMimic", "Pikit" ] ] #"Swamp Palace - Pool - Zol 2"
- [ 0x0016, 2, [ "SparkCW", "SparkCCW", "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper", "GreenMimic", "RedMimic", "Pikit" ] ] #"Swamp Palace - Pool - Blue Bari"
- [ 0x0016, 3, [ "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Swamp Palace - Pool - Zol 3"
- [ 0x0017, 5, [ "Beamos", "AntiFairyCircle", "SpikeBlock", "Bumper" ] ] #"Tower Of Hera - Bumper Room - Fire Bar (Clockwise)"
- [ 0x0019, 0, [ "SparkCW", "SparkCCW", "RollerVerticalDown", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Palace of Darkness - Dark Maze - Kodongo 1"
@@ -52,7 +52,7 @@ UwGeneralDeny:
- [ 0x0028, 4, [ "RollerVerticalUp" ] ] #"Swamp Palace - Entrance Ledge - Spike Trap"
- [ 0x002a, 2, [ "SparkCW", "SparkCCW", "RollerHorizontalRight", "RollerHorizontalLeft", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper"]] #"Palace of Darkness - Arena Main - Hardhat Beetle 1"
- [ 0x002a, 3, [ "Statue", "SparkCW", "SparkCCW", "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "FirebarCW", "FirebarCCW", "SpikeBlock", "Bumper" ] ] #"Palace of Darkness - Arena Main - Hardhat Beetle 2"
- [ 0x002a, 4, [ "Statue", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ]]
- [ 0x002a, 4, [ "Statue", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper", "RollerHorizontalRight", "RollerHorizontalLeft"]]
- [ 0x002a, 6, [ "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Palace of Darkness - Arena Main - Hardhat Beetle 5"
- [ 0x002b, 5, [ "RollerHorizontalRight" ] ] #"Palace of Darkness - Fairies - Red Bari 2"
- [ 0x002e, 0, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "BigSpike", "FirebarCW", "FirebarCCW" ] ] #"Ice Palace - Penguin Chest - Pengator 1"
@@ -67,6 +67,7 @@ UwGeneralDeny:
- [ 0x0034, 4, [ "Statue", "SparkCW", "SparkCCW", "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Swamp Palace - West Wing - Zol"
- [ 0x0035, 6, [ "RollerHorizontalRight" ] ] #"Swamp Palace - West Lever - Stalfos 2"
- [ 0x0035, 9, [ "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "Bumper" ] ] #"Swamp Palace - West Lever - Blue Bari"
- [0x0036, 5, ["AntiFairyCircle", "Bumper"]]
- [ 0x0036, 7, [ "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "FirebarCW", "FirebarCCW", "SpikeBlock", "Bumper" ] ] #"Swamp Palace - Lobby - Hover 3"
- [ 0x0037, 7, [ "RollerHorizontalRight" ] ] #"Swamp Palace - Water 1 - Blue Bari"
- [ 0x0038, 4, [ "RollerHorizontalRight" ] ] #"Swamp Palace - Long Hall - Kyameron 2"
@@ -90,12 +91,12 @@ UwGeneralDeny:
- [ 0x0041, 0, [ "RollerHorizontalLeft" ] ] #"Sewers - Dark Cactus - Rat 1"
- [ 0x0041, 1, [ "RollerVerticalDown", "RollerHorizontalRight" ] ] #"Sewers - Dark Cactus - Rat 2"
- [ 0x0041, 2, [ "RollerVerticalUp" ] ] #"Sewers - Dark Cactus - Rat 3"
- [ 0x0042, 0, [ "SparkCW", "SparkCCW", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Sewers - Dark Rope Corridor - Rope 1"
- [ 0x0042, 1, [ "SparkCW", "SparkCCW", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Sewers - Dark Rope Corridor - Rope 2"
- [ 0x0042, 2, [ "SparkCW", "SparkCCW", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Sewers - Dark Rope Corridor - Rope 3"
- [ 0x0042, 3, [ "SparkCW", "SparkCCW", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Sewers - Dark Rope Corridor - Rope 4"
- [ 0x0042, 4, [ "SparkCW", "SparkCCW", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Sewers - Dark Rope Corridor - Rope 5"
- [ 0x0042, 5, [ "SparkCW", "SparkCCW", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Sewers - Dark Rope Corridor - Rope 6"
- [ 0x0042, 0, [ "SparkCW", "SparkCCW", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper", "Chainchomp" ] ] #"Sewers - Dark Rope Corridor - Rope 1"
- [ 0x0042, 1, [ "SparkCW", "SparkCCW", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper", "Chainchomp" ] ] #"Sewers - Dark Rope Corridor - Rope 2"
- [ 0x0042, 2, [ "SparkCW", "SparkCCW", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper", "Chainchomp" ] ] #"Sewers - Dark Rope Corridor - Rope 3"
- [ 0x0042, 3, [ "SparkCW", "SparkCCW", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper", "Chainchomp" ] ] #"Sewers - Dark Rope Corridor - Rope 4"
- [ 0x0042, 4, [ "SparkCW", "SparkCCW", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper", "Chainchomp" ] ] #"Sewers - Dark Rope Corridor - Rope 5"
- [ 0x0042, 5, [ "SparkCW", "SparkCCW", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper", "Chainchomp" ] ] #"Sewers - Dark Rope Corridor - Rope 6"
- [ 0x0044, 4, [ "RollerVerticalUp", "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Thieves' Town - Joke Room - Zol"
- [ 0x0044, 6, [ "RollerVerticalUp", "RollerVerticalDown", "Beamos", "BigSpike" ] ] #"Thieves' Town - Joke Room - Red Bari"
- [ 0x0044, 8, [ "Statue", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "SpikeBlock", "Bumper" ] ] #"Thieves' Town - Joke Room - Blue Bari 4"
@@ -125,7 +126,7 @@ UwGeneralDeny:
- [ 0x0052, 2, [ "RollerVerticalUp", "RollerVerticalDown", "AntiFairyCircle", "Bumper" ] ] #"Hyrule Castle - North East Passage - Green Knife Guard 2"
- [ 0x0053, 1, [ "AntiFairyCircle", "Bumper" ] ] #"Desert Palace - Bridge - Beamos 1"
- [ 0x0053, 5, [ "RollerVerticalDown" ] ] #"Desert Palace - Popo Genocide - Popo TL"
- [ 0x0053, 7, [ "Beamos", "AntiFairyCircle", "Bumper" ] ] #"Desert Palace - Bridge - Popo 5"
- [ 0x0053, 7, ["Beamos", "AntiFairyCircle", "Bumper", "RollerVerticalUp", "RollerVerticalDown"]] #"Desert Palace - Bridge - Popo 5"
- [ 0x0055, 1, [ "RollerVerticalUp", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Secret Passage Exit - Green Knife Guard 1"
- [ 0x0057, 0, [ "Wizzrobe", "Statue" ] ] # Wizzrobes can't spawn on pots
- [ 0x0057, 1, ["Statue"]] # Statue switch issues
@@ -139,8 +140,8 @@ UwGeneralDeny:
- [ 0x0057, 10, ["Statue"]] # Statue switch issues
- [ 0x0057, 11, ["Statue"]] # Statue switch issues
- [ 0x0057, 12, [ "RollerVerticalUp", "RollerVerticalDown", "Beamos", "AntiFairyCircle", "Bumper", "BigSpike", "SpikeBlock", "Statue"]] #"Skull Woods - Big Key Room - Gibdo 6"
- [ 0x0057, 13, [ "RollerVerticalDown", "Beamos", "AntiFairyCircle", "Bumper", "Statue" ] ] #"Skull Woods - Big Key Room - Blue Bari 1"
- [ 0x0057, 14, [ "RollerVerticalDown", "Beamos", "AntiFairyCircle", "Bumper", "Statue" ] ] #"Skull Woods - Big Key Room - Blue Bari 2"
- [ 0x0057, 13, [ "RollerVerticalDown", "Beamos", "AntiFairyCircle", "Bumper", "Statue", "BigSpike"]] #"Skull Woods - Big Key Room - Blue Bari 1"
- [ 0x0057, 14, [ "RollerVerticalDown", "Beamos", "AntiFairyCircle", "Bumper", "Statue", "BigSpike"]] #"Skull Woods - Big Key Room - Blue Bari 2"
- [ 0x0058, 0, ["Statue"]]
- [ 0x0058, 1, ["Statue"]]
- [ 0x0058, 2, ["Statue"]]
@@ -156,7 +157,7 @@ UwGeneralDeny:
- [ 0x005e, 4, [ "RollerVerticalUp", "RollerVerticalDown" ] ] #"Ice Palace - Pit Trap - Fire Bar (Clockwise)"
- [ 0x005f, 0, [ "RollerVerticalDown", "RollerHorizontalLeft" ] ] #"Ice Palace - Bari University - Blue Bari 1"
- [ 0x005f, 1, [ "RollerVerticalDown", "RollerHorizontalRight" ] ] #"Ice Palace - Bari University - Blue Bari 2"
- [ 0x0060, 0, [ "RollerVerticalUp", "RollerHorizontalLeft", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Hyrule Castle - West - Blue Guard"
- [ 0x0060, 0, [ "RollerVerticalUp", "RollerHorizontalLeft", "AntiFairyCircle", "BigSpike", "Bumper", "Beamos" ] ] #"Hyrule Castle - West - Blue Guard"
- [ 0x0062, 0, [ "RollerVerticalUp", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Hyrule Castle - East - Blue Guard"
- [ 0x0064, 2, [ "Bumper" , "Beamos" ] ] #"Thieves' Town - Attic Hall Left - Keese 2"
- [ 0x0064, 3, [ "Wizzrobe", "Statue" ] ] # Wizzrobes can't spawn on pots
@@ -170,7 +171,7 @@ UwGeneralDeny:
- [ 0x0067, 2, ["Bumper"]] #"Skull Woods - Firebar Pits - Blue Bari 2"
- [ 0x0067, 3, [ "RollerVerticalUp", "RollerVerticalDown" ] ] #"Skull Woods - Firebar Pits - Hardhat Beetle 1"
- [ 0x0067, 4, [ "AntiFairyCircle", "Bumper" ]]
- [ 0x0067, 5, [ "RollerVerticalDown" ] ] #"Skull Woods - Firebar Pits - Hardhat Beetle 3"
- [ 0x0067, 5, ["RollerVerticalDown", "Beamos"]] #"Skull Woods - Firebar Pits - Hardhat Beetle 3"
- [ 0x0067, 6, [ "RollerVerticalDown" ] ] #"Skull Woods - Firebar Pits - Hardhat Beetle 4"
- [ 0x0067, 7, [ "Beamos", "AntiFairyCircle", "Bumper", "BunnyBeam" ] ] #"Skull Woods - Firebar Pits - Fire Bar (Clockwise)"
- [ 0x006a, 0, [ "RollerVerticalUp", "RollerVerticalDown", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Palace of Darkness - Dark Alley - Terrorpin 1"
@@ -195,7 +196,7 @@ UwGeneralDeny:
- [ 0x007b, 7, [ "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Ganon's Tower - DMs Room - Hardhat Beetle"
- [ 0x007c, 1, [ "RollerVerticalUp", "RollerVerticalDown", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Ganon's Tower - Randomizer Room - Fire Bar (Counterclockwise)"
- [ 0x007c, 2, [ "RollerVerticalUp", "RollerVerticalDown", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ganon's Tower - Randomizer Room - Spike Trap"
- [ 0x007c, 3, [ "RollerVerticalUp", "RollerVerticalDown", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ganon's Tower - Randomizer Room - Fire Bar (Clockwise)"
- [ 0x007c, 3, [ "RollerVerticalUp", "RollerVerticalDown", "AntiFairyCircle", "BigSpike", "Bumper", "Statue"]] #"Ganon's Tower - Randomizer Room - Fire Bar (Clockwise)"
- [ 0x007c, 4, [ "RollerVerticalUp", "RollerVerticalDown", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Ganon's Tower - Randomizer Room - Hardhat Beetle"
- [ 0x007d, 0, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ganon's Tower - The Zoo - Fire Snake 1"
- [ 0x007d, 1, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ganon's Tower - The Zoo - Fire Snake 2"
@@ -244,6 +245,7 @@ UwGeneralDeny:
- [ 0x0098, 2, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Misery Mire - Entrance - Zol 3"
- [ 0x0098, 3, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Misery Mire - Entrance - Zol 4"
- [ 0x0098, 4, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Misery Mire - Entrance - Zol 5"
- [0x0099, 8, ["RollerHorizontalLeft", "RollerHorizontalRight"]]
- [ 0x009b, 3, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ganon's Tower - Spike Switch - Spike Trap 1"
- [ 0x009b, 4, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ganon's Tower - Spike Switch - Spike Trap 2"
- [ 0x009b, 5, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ]
@@ -288,7 +290,8 @@ UwGeneralDeny:
- [ 0x00b2, 9, [ "RollerVerticalUp" ] ] #"Misery Mire - Sluggula Cross - Sluggula BL"
- [ 0x00b3, 0, [ "RollerVerticalUp", "RollerHorizontalRight", "BigSpike", "SpikeBlock" ] ] #"Misery Mire - Spike Room - Stalfos 1"
- [ 0x00b3, 2, [ "Statue", "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "FirebarCW", "Bumper" ] ] #"Misery Mire - Spike Room - Beamos"
- [ 0x00b3, 3, [ "AntiFairyCircle", "Bumper" ] ] #"Misery Mire - Spike Room - Yomo Medusa"
- [ 0x00b3, 3, ["AntiFairyCircle", "Bumper" ]] #"Misery Mire - Spike Room - Yomo Medusa"
- [ 0x00b3, 4, ["AntiFairyCircle", "Bumper"]]
- [ 0x00b6, 7, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Turtle Rock - Tile Room - Zol 1"
- [ 0x00b6, 8, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Turtle Rock - Tile Room - Zol 2"
- [ 0x00ba, 1, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Eastern Palace - Dark Stalfos - Antifairy 1"
@@ -347,6 +350,7 @@ UwGeneralDeny:
- [ 0x00d8, 8, [ "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Eastern Palace - Kill Room 1 - Red Eyegore"
- [ 0x00d9, 1, [ "RollerHorizontalRight" ] ] #"Eastern Palace - Dodgeball - Green Eyegore 1"
- [ 0x00db, 0, [ "Wizzrobe", "Statue" ] ] # Wizzrobes can't spawn on pots
- [ 0x00db, 3, [ "Bumper" ] ] # Okay in vanilla
- [ 0x00dc, 2, [ "AntiFairyCircle", "BigSpike", "Bumper" ] ]
- [ 0x00dc, 9, [ "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Thieves' Town - Grand Room SE - Fire Snake 2"
- [ 0x00df, 0, [ "RollerVerticalDown", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Paradox Cave - Top - Mini Moldorm 1"
@@ -398,10 +402,10 @@ OwGeneralDeny:
- [0x40, 13, ["Beamos", "Bumper", "BigSpike", "AntiFairyCircle", "Thief"]]
- [0x40, 14, ["Beamos", "Bumper", "BigSpike", "AntiFairyCircle", "Thief"]]
- [0x5e, 0, ["Gibo"]] # kiki eating Gibo
- [0x5e, 1, ["Gibo"]] # kiki eating Gibo
- [0x5e, 1, ["Gibo", "RollerVerticalUp", "RollerVerticalDown"]] # kiki eating Gibo
- [0x5e, 2, ["Gibo"]] # kiki eating Gibo
- [0x5e, 3, ["Gibo"]] # kiki eating Gibo
- [0x5e, 4, ["RollerVerticalUp", "Gibo"]] # forbid that one roller for kiki pod, and the kiki eating Gibo
- [0x5e, 4, ["RollerVerticalUp", "RollerVerticalDown", "Gibo"]] # forbid that one roller for kiki pod, and the kiki eating Gibo
- [0x5e, 5, ["Gibo"]] # kiki eating Gibo
- [0x5e, 6, ["Gibo"]] # kiki eating Gibo
- [0x5e, 7, ["Gibo"]] # kiki eating Gibo
@@ -435,94 +439,97 @@ UwEnemyDrop:
- [0x00b0, 8, ["StalfosKnight", "Blob", "Stal", "Wizzrobe"]] # blocked, but Geldmen are probably okay
# the following are not allowed at certain pits (or on conveyors near pits)
# because they despawned or clipped away or immediately fell, etc
- [0x003d, 9, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
- [0x003d, 9, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard", "Hover",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
- [0x003d, 10, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
- [0x003d, 10, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard", "Hover",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
- [0x0044, 0, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic"]]
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "Hover"]]
- [0x0044, 1, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic"]]
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "Hover"]]
- [0x0044, 2, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic"]]
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "Hover"]]
- [0x0044, 3, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic"]]
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "Hover"]]
- [0x0044, 4, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic"]]
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "Hover"]]
- [0x0044, 5, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic"]]
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "Hover"]]
- [0x0044, 6, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic"]]
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "Hover"]]
- [0x0044, 8, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic"]]
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "Hover"]]
- [0x0049, 10, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic"]]
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "Hover"]]
- [0x007b, 0, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic"]]
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "Hover"]]
- [0x007b, 1, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic"]]
- [0x007f, 0, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "Hover"]]
- [0x007f, 0, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard", "Hover",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
- [0x007f, 1, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
- [0x007f, 1, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard", "Hover",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
- [0x007f, 2, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
- [0x007f, 2, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard", "Hover",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
- [0x007f, 3, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
- [0x007f, 3, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard", "Hover",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
- [0x0095, 0, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic"]]
- [0x0095, 1, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "Hover"]]
- [0x0095, 1, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard", "Hover",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
- [0x0095, 2, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
- [0x0095, 2, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard", "Hover",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
- [0x0095, 3, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic"]]
- [0x00b5, 0, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "Hover"]]
- [0x00af, 0, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "Hover"]]
- [0x00b5, 0, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard", "Hover",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
- [0x00b5, 1, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
- [0x00b5, 1, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard", "Hover",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
- [0x00b5, 2, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
- [0x00b5, 2, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard", "Hover",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
- [0x00c6, 2, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
- [0x00c6, 2, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard", "Hover",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
- [0x00c6, 3, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
- [0x00c6, 3, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard", "Hover",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
- [0x00c6, 4, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
- [0x00c6, 4, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard", "Hover",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
- [0x00c6, 5, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
- [0x00c6, 5, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard", "Hover",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Bumper", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
- [0x00c6, 6, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
- [0x00c6, 6, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard", "Hover",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
- [0x00e6, 0, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
- [0x00e6, 0, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard", "Hover",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
# wizzrobe despawn issues - on pots/blocks - too close to some object
@@ -577,7 +584,6 @@ UwEnemyDrop:
- [0x009f, 5, ["Wizzrobe", "Stal"]]
- [0x00a1, 1, ["Wizzrobe"]]
- [0x00aa, 5, ["Wizzrobe"]]
- [0x00af, 0, ["Wizzrobe", "Stal"]]
- [0x00b0, 1, ["Wizzrobe"]]
- [0x00b0, 2, ["Wizzrobe"]]
- [0x00b2, 4, ["Wizzrobe"]]

View File

@@ -0,0 +1,206 @@
UW: # Total 94431
AntiFairy: 40 # 1.82885% raw:1727 15.28319%
AntiFairyCircle: 40 # 1.82885% raw:1727 15.28319%
ArmosStatue: 186 # 0.53796% raw:508 4.49558%
Babasu: 80 # 1.15428% raw:1090 9.64602%
BallNChain: 163 # 0.61526% raw:581 5.14159%
Beamos: 155 # 0.64703% raw:611 5.40708%
BigSpike: 40 # 1.82885% raw:1727 15.28319%
Blob: 87 # 1.15428% raw:1090 9.64602%
BlueArcher: 325 # 0.30816% raw:291 2.57522%
BlueBari: 49 # 2.02688% raw:1914 16.93805%
BlueGuard: 44 # 2.28527% raw:2158 19.09735%
BlueZazak: 294 # 0.33993% raw:321 2.84071%
BlueZirro: 180 # 0.55702% raw:526 4.65487%
BluesainBolt: 150 # 0.66821% raw:631 5.58407%
BombGuard: 163 # 0.61526% raw:581 5.14159%
Bumper: 55 # 1.82885% raw:1727 15.28319%
BunnyBeam: 19 # 5.40077% raw:5100 45.13274%
Buzzblob: 123 # 0.81223% raw:767 6.78761%
CannonTrooper: 163 # 0.61526% raw:581 5.14159%
Chainchomp: 238 # 0.42041% raw:397 3.51327%
Crab: 204 # 0.48925% raw:462 4.08850%
CricketRat: 212 # 0.47230% raw:446 3.94690%
Cucco: 120 # 0.54325% raw:513 4.53982%
Deadrock: 186 # 0.53796% raw:508 4.49558%
Debirando: 154 # 0.65127% raw:615 5.44248%
DebirandoPit: 154 # 0.65127% raw:615 5.44248%
Faerie: 19
FakeMasterSword: 120 # 0.81223% raw:767 6.78761%
FireballZora: 165 # 0.60679% raw:573 5.07080%
FirebarCCW: 49 # 2.02688% raw:1914 16.93805%
FirebarCW: 49 # 2.02688% raw:1914 16.93805%
Firesnake: 49 # 2.02688% raw:1914 16.93805%
FloatingSkull: 49 # 2.02688% raw:1914 16.93805%
FloppingFish: 30 # 5.40077% raw:5100 45.13274%
Freezor: 454 # 0.22027% raw:208 1.84071%
Geldman: 445 # 0.22450% raw:212 1.87611%
Gibdo: 150 # 0.40453% raw:382 3.38053%
Gibo: 294 # 0.33993% raw:321 2.84071%
GreenBushGuard: 325 # 0.30816% raw:291 2.57522%
GreenEyegoreMimic: 175 # 0.57291% raw:541 4.78761%
GreenMimic: 175 # 0.57291% raw:541 4.78761%
GreenGuard: 55 # 1.80237% raw:1702 15.06195%
GreenKnifeGuard: 621 # 0.16096% raw:152 1.34513%
GreenZirro: 180 # 0.55702% raw:526 4.65487%
HardhatBeetle: 109 # 0.91495% raw:864 7.64602%
Hinox: 140 # 0.71269% raw:673 5.95575%
Hoarder: 123 # 0.81223% raw:767 6.78761%
Hoarder2: 123 # 0.81223% raw:767 6.78761%
Hover: 150 # 0.42147% raw:398 3.52212%
Keese: 212 # 0.47230% raw:446 3.94690%
Kodongo: 463 # 0.21603% raw:204 1.80531%
Kyameron: 237 # 0.42147% raw:398 3.52212%
Landmine: 19 # 5.40077% raw:5100 45.13274%
Leever: 154 # 0.65127% raw:615 5.44248%
Lynel: 400 # 0.17897% raw:169 1.49558%
MiniHelmasaur: 109 # 0.91495% raw:864 7.64602%
MiniMoldorm: 109 # 0.91495% raw:864 7.64602%
Moblin: 367 # 0.27216% raw:257 2.27434%
Octoballoon: 204 # 0.48925% raw:462 4.08850%
Octorok: 165 # 0.60679% raw:573 5.07080%
Octorok4Way: 204 # 0.48925% raw:462 4.08850%
Pengator: 300 # 0.22027% raw:208 1.84071%
Pikit: 180 # 0.55702% raw:526 4.65487%
Poe: 284 # 0.35264% raw:333 2.94690%
Pokey: 238 # 0.42041% raw:397 3.51327%
Popo: 155 # 0.64703% raw:611 5.40708%
Popo2: 155 # 0.64703% raw:611 5.40708%
Raven: 94 # 1.06109% raw:1002 8.86726%
RedBari: 49 # 2.02688% raw:1914 16.93805%
RedBushGuard: 163 # 0.61526% raw:581 5.14159%
RedEyegoreMimic: 175 # 0.57291% raw:541 4.78761%
RedMimic: 175 # 0.57291% raw:541 4.78761%
RedJavelinGuard: 163 # 0.61526% raw:581 5.14159%
RedSpearGuard: 44 # 2.28527% raw:2158 19.09735%
RedZazak: 294 # 0.33993% raw:321 2.84071%
RollerHorizontalLeft: 238 # 0.42041% raw:397 3.51327%
RollerHorizontalRight: 238 # 0.42041% raw:397 3.51327%
RollerVerticalDown: 238 # 0.42041% raw:397 3.51327%
RollerVerticalUp: 238 # 0.42041% raw:397 3.51327%
Ropa: 140 # 0.71269% raw:673 5.95575%
Sluggula: 360 # 0.27745% raw:262 2.31858%
Snake: 212 # 0.47230% raw:446 3.94690%
Snapdragon: 562 # 0.17791% raw:168 1.48673%
SparkCCW: 49 # 2.02688% raw:1914 16.93805%
SparkCW: 49 # 2.02688% raw:1914 16.93805%
SpikeBlock: 55 # 1.82885% raw:1727 15.28319%
Stal: 19 # 5.40077% raw:5100 45.13274%
Stalfos: 49 # 2.02688% raw:1914 16.93805%
StalfosKnight: 87 # 1.15428% raw:1090 9.64602%
Statue: 30 # 1.82885% raw:1727 15.28319%
Swamola: 402 # 0.24886% raw:235 2.07965%
Tektite: 186 # 0.53796% raw:508 4.49558%
Terrorpin: 463 # 0.21603% raw:204 1.80531%
Thief: 100 # 0.60997% raw:576 5.09735%
Toppo: 123 # 0.81223% raw:767 6.78761%
UsainBolt: 44 # 2.28527% raw:2158 19.09735%
Vulture: 445 # 0.22450% raw:212 1.87611%
Wallmaster: 247 # 0.40453% raw:382 3.38053%
Wizzrobe: 306 # 0.32722% raw:309 2.73451%
# YellowStalfos: 49
Zora: 609 # 0.16414% raw:155 1.37168%
Zoro: 80 # 1.15428% raw:1090 9.64602%
OW: # Total 117724
AntiFairy: 60 # 0.97346% raw:1146 10.14159%
AntiFairyCircle: 60 # 0.97346% raw:1146 10.14159%
ArmosStatue: 144 # 0.69570% raw:819 7.24779%
Babasu: 100 # 0.84605% raw:996 8.81416%
BallNChain: 121 # 0.82651% raw:973 8.61062%
Beamos: 184 # 0.54364% raw:640 5.66372%
BigSpike: 70 # 0.97346% raw:1146 10.14159%
Blob: 118 # 0.84605% raw:996 8.81416%
BlueArcher: 291 # 0.34403% raw:405 3.58407%
BlueBari: 47 # 2.11767% raw:2493 22.06195%
BlueGuard: 39 # 2.56617% raw:3021 26.73451%
BlueZazak: 247 # 0.40519% raw:477 4.22124%
BlueZirro: 158 # 0.63369% raw:746 6.60177%
BluesainBolt: 111 # 0.90381% raw:1064 9.41593%
BombGuard: 121 # 0.82651% raw:973 8.61062%
Bumper: 103 # 0.97346% raw:1146 10.14159%
BunnyBeam: 19 # 5.26656% raw:6200 54.86726%
Buzzblob: 86 # 1.15609% raw:1361 12.04425%
CannonTrooper: 121 # 0.82651% raw:973 8.61062%
Chainchomp: 226 # 0.44341% raw:522 4.61947%
Crab: 163 # 0.61500% raw:724 6.40708%
CricketRat: 236 # 0.42387% raw:499 4.41593%
Cucco: 140 # 0.60396% raw:711 6.29204%
Deadrock: 144 # 0.69570% raw:819 7.24779%
Debirando: 164 # 0.60905% raw:717 6.34513%
DebirandoPit: 164 # 0.60905% raw:717 6.34513%
Faerie: 19
FakeMasterSword: 120 # 1.15609% raw:1361 12.04425%
FireballZora: 119 # 0.84350% raw:993 8.78761%
FirebarCCW: 47 # 2.11767% raw:2493 22.06195%
FirebarCW: 47 # 2.11767% raw:2493 22.06195%
Firesnake: 47 # 2.11767% raw:2493 22.06195%
FloatingSkull: 47 # 2.11767% raw:2493 22.06195%
FloppingFish: 30 # 5.26656% raw:6200 54.86726%
Freezor: 692 # 0.14441% raw:170 1.50442%
Geldman: 229 # 0.43746% raw:515 4.55752%
Gibdo: 300 # 0.15545% raw:183 1.61947%
Gibo: 247 # 0.40519% raw:477 4.22124%
GreenBushGuard: 291 # 0.34403% raw:405 3.58407%
GreenEyegoreMimic: 171 # 0.58527% raw:689 6.09735%
GreenMimic: 171 # 0.58527% raw:689 6.09735%
GreenGuard: 48 # 2.06330% raw:2429 21.49558%
GreenKnifeGuard: 589 # 0.16989% raw:200 1.76991%
GreenZirro: 158 # 0.63369% raw:746 6.60177%
HardhatBeetle: 113 # 0.88682% raw:1044 9.23894%
Hinox: 123 # 0.81462% raw:959 8.48673%
Hoarder: 86 # 1.15609% raw:1361 12.04425%
Hoarder2: 86 # 1.15609% raw:1361 12.04425%
Hover: 200 # 0.32449% raw:382 3.38053%
Keese: 236 # 0.42387% raw:499 4.41593%
Kodongo: 346 # 0.28881% raw:340 3.00885%
Kyameron: 308 # 0.32449% raw:382 3.38053%
Landmine: 19 # 5.26656% raw:6200 54.86726%
Leever: 164 # 0.60905% raw:717 6.34513%
Lynel: 325 # 0.30750% raw:362 3.20354%
MiniHelmasaur: 113 # 0.88682% raw:1044 9.23894%
MiniMoldorm: 113 # 0.88682% raw:1044 9.23894%
Moblin: 303 # 0.33043% raw:389 3.44248%
Octoballoon: 163 # 0.61500% raw:724 6.40708%
Octorok: 119 # 0.84350% raw:993 8.78761%
Octorok4Way: 163 # 0.61500% raw:724 6.40708%
Pengator: 400 # 0.14441% raw:170 1.50442%
Pikit: 158 # 0.63369% raw:746 6.60177%
Poe: 202 # 0.49608% raw:584 5.16814%
Pokey: 226 # 0.44341% raw:522 4.61947%
Popo: 184 # 0.54364% raw:640 5.66372%
Popo2: 184 # 0.54364% raw:640 5.66372%
Raven: 65 # 1.53325% raw:1805 15.97345%
RedBari: 47 # 2.11767% raw:2493 22.06195%
RedBushGuard: 121 # 0.82651% raw:973 8.61062%
RedEyegoreMimic: 171 # 0.58527% raw:689 6.09735%
RedMimic: 171 # 0.58527% raw:689 6.09735%
RedJavelinGuard: 121 # 0.82651% raw:973 8.61062%
RedSpearGuard: 39 # 2.56617% raw:3021 26.73451%
RedZazak: 247 # 0.40519% raw:477 4.22124%
RollerHorizontalLeft: 226 # 0.44341% raw:522 4.61947%
RollerHorizontalRight: 226 # 0.44341% raw:522 4.61947%
RollerVerticalDown: 226 # 0.44341% raw:522 4.61947%
RollerVerticalUp: 226 # 0.44341% raw:522 4.61947%
Ropa: 123 # 0.81462% raw:959 8.48673%
Sluggula: 443 # 0.22595% raw:266 2.35398%
Snake: 236 # 0.42387% raw:499 4.41593%
Snapdragon: 526 # 0.19028% raw:224 1.98230%
SparkCCW: 47 # 2.11767% raw:2493 22.06195%
SparkCW: 47 # 2.11767% raw:2493 22.06195%
SpikeBlock: 103 # 0.97346% raw:1146 10.14159%
Stal: 19 # 5.26656% raw:6200 54.86726%
Stalfos: 47 # 2.11767% raw:2493 22.06195%
StalfosKnight: 118 # 0.84605% raw:996 8.81416%
Statue: 60 # 0.97346% raw:1146 10.14159%
Swamola: 265 # 0.37715% raw:444 3.92920%
Tektite: 144 # 0.69570% raw:819 7.24779%
Terrorpin: 346 # 0.28881% raw:340 3.00885%
Thief: 100 # 0.39244% raw:462 4.08850%
Toppo: 86 # 1.15609% raw:1361 12.04425%
UsainBolt: 39 # 2.56617% raw:3021 26.73451%
Vulture: 229 # 0.43746% raw:515 4.55752%
Wallmaster: 643 # 0.15545% raw:183 1.61947%
Wizzrobe: 345 # 0.28966% raw:341 3.01770%
# YellowStalfos: 47
Zora: 558 # 0.17923% raw:211 1.86726%
Zoro: 100 # 0.84605% raw:996 8.81416%

View File

@@ -0,0 +1,168 @@
SheetChoices:
# Complex
- slots: [0, 1]
assignments:
0: 0x46
1: 0xd
weight: .5 # BluesainBolt(1/2) - 2 types
- slots: [0, 1]
assignments:
0: 0x46
1: 0x49
weight: 5.5 # CannonTrooper, BallNChain, RedBushGuard, RedJavelinGuard, BombGuard, BluesainBolt(1/2)
- slots: [0, 1]
assignments:
0: 0x48
1: 0x49
weight: 2 # GreenBushGuard, BlueArcher
- slots: [1, 2]
assignments:
1: 0x49
2: 0x13
weight: 1 # GreenKnifeGuard
- slots: [0, 2]
assignments:
0: 0x16
2: 0x17
weight: 1 # Snapdragon
- slots: [2, 3]
assignments:
2: 0xc
3: 0x44
weight: 1 # Zora (walking)
# Slot 0 (21 enemy types require slot 0)
- slots: [0]
assignments:
0: [0xe, 0x15]
weight: 1 # Thief
- slots: [0]
assignments:
0: 0x16
weight: 2 # Ropa, Hinox
- slots: [0]
assignments:
0: 0x1f
weight: 7 # Sparks, Firebars, FloatingSkull, RedBari, BlueBari, Firesnake, Stalfos, ~~YellowStalfos~~
- slots: [0]
assignments:
0: 0x2f
weight: 2 # Debirandos, Leever
# Slot 1 (24 enemy types require slot 1)
- slots: [1]
assignments:
1: 0x1e
weight: 3 # MiniMoldorm, MiniHelmasaur, Hardhat
- slots: [1]
assignments:
1: 0x20
weight: 3 # StalfosKnight, Blob, Babasus
- slots: [1]
assignments:
1: 0x23
weight: 1 # Wallmaster
- slots: [1]
assignments:
1: 0x2c
weight: 4 # Beamos, Popos, Mimics (2)
- slots: [1]
assignments:
1: 0x49
weight: 2.5 # GreenGuard, RedSpearGuard, BlueGuard, UsainBolt (1/2)
- slots: [1]
assignments:
1: 0xd
weight: 1.5 # RedSpearGuard, BlueGuard, UsainBolt (1/2)
# Slot 2 (29 enemy types require slot 2)
- slots: [2]
assignments:
2: 0xc
weight: 3 # Crab, Octoballon, FireballZora(1/2), Octorocks(1/2) (4Way is 0xC only?)
- slots: [2]
assignments:
2: 0x12
weight: 2 # Vulture, Geldman
- slots: [2]
assignments:
2: 0x17
weight: 1 # Moblin
- slots: [2]
assignments:
2: 0x18
weight: 1 # FireballZora(1/2) (note: immersible only), Octoroks(1/2)
- slots: [2]
assignments:
2: [0x1c, 0x24]
weight: 3 # Keese, CricketRat, Snake
- slots: [2]
assignments:
2: 0x22
weight: 2 # Kyameron (note: immersible only), Hover
- slots: [2]
assignments:
2: 0x23
weight: 1 # Gibdo
- slots: [2]
assignments:
2: 0x25
weight: 1.5 # Sluggula, Wizzrobe (half)
- slots: [2]
assignments:
2: 0x26
weight: 1 # Pengator
- slots: [2]
assignments:
2: 0x27
weight: 3 # Rollers4, Chainchomp, Pokey
- slots: [2]
assignments:
2: 0x28
weight: 3 # Gibo, BlueZazak, RedZazak
- slots: [2]
assignments:
2: 0x29
weight: .5 # Wizzrobe (half)
- slots: [2]
assignments:
2: 0x2a
weight: 2 # Kodongo, Terrorpin
- slots: [2]
assignments:
2: 0x2e
weight: 2 # GreenEyeGoreMimic, RedEyeGoreMimic (Eyegores only)
# Slot 3 (21 enemy types require slot 3)
- slots: [3]
assignments:
3: 0x10
weight: 3 # Deadrock, Tektite, ArmosStatue
- slots: [3]
assignments:
3: 0x11
weight: 4.5 # FakeMasterSword, Hoarder, Buzzblob, Toppo, Raven(1/2)
- slots: [3]
assignments:
3: 0x14
weight: 1 # Lynel
- slots: [3]
assignments:
3: 0x15
weight: 1.5 # Poe, Cucco(1/2)
- slots: [3]
assignments:
3: 0x19
weight: 1.5 # Swamola, Raven(1/2)
- slots: [3]
assignments:
3: 0x1b
weight: 3 # GreenZirro, BlueZirro, Pikit
- slots: [3]
assignments:
3: [0x50]
weight: .5 # Cucco(1/2)
- slots: [3]
assignments:
3: [0x52, 0x53]
weight: 5 # SpikeBlock, Bumper, BigSpike, AntiFairy, Statue (AntiFairyCircle?)

View File

@@ -1,4 +1,4 @@
from tkinter import ttk, messagebox, StringVar, Button, Entry, Frame, Label, E, W, LEFT, RIGHT, X
from tkinter import ttk, messagebox, StringVar, Button, Entry, Frame, Label, LEFT, RIGHT, X
from argparse import Namespace
import logging
import os
@@ -79,65 +79,67 @@ def bottom_frame(self, parent, args=None):
guiargs = create_guiargs(parent)
# get default values for missing parameters
for k,v in vars(parse_cli(['--multi', str(guiargs.multi)])).items():
cliargs = ['--multi', str(guiargs.multi)]
if hasattr(guiargs, 'customizer'):
cliargs.extend(['--customizer', str(guiargs.customizer)])
for k,v in vars(parse_cli(cliargs)).items():
if k not in vars(guiargs):
setattr(guiargs, k, v)
elif type(v) is dict: # use same settings for every player
setattr(guiargs, k, {player: getattr(guiargs, k) for player in range(1, guiargs.multi + 1)})
setattr(guiargs, k, {player: getattr(guiargs, k) for player in range(1, len(v) + 1)})
argsDump = vars(guiargs)
hasEnemizer = "enemizercli" in argsDump and os.path.isfile(argsDump["enemizercli"])
needEnemizer = False
if hasEnemizer:
falsey = ["none", "default", False, 0]
for enemizerOption in ["shuffleenemies", "enemy_damage", "shufflebosses", "enemy_health"]:
if enemizerOption in argsDump:
if isinstance(argsDump[enemizerOption], dict):
for playerID,playerSetting in argsDump[enemizerOption].items():
if not playerSetting in falsey:
needEnemizer = True
elif not argsDump[enemizerOption] in falsey:
needEnemizer = True
seeds = []
if not needEnemizer or (needEnemizer and hasEnemizer):
try:
if guiargs.count is not None and guiargs.seed:
seed = guiargs.seed
for _ in range(guiargs.count):
seeds.append(seed)
main(seed=seed, args=guiargs, fish=parent.fish)
seed = random.randint(0, 999999999)
else:
if guiargs.seed:
seeds.append(guiargs.seed)
else:
random.seed(None)
guiargs.seed = random.randint(0, 999999999)
seeds.append(guiargs.seed)
main(seed=guiargs.seed, args=guiargs, fish=parent.fish)
except (FillError, EnemizerError, Exception, RuntimeError) as e:
logging.exception(e)
messagebox.showerror(title="Error while creating seed", message=str(e))
else:
YES = parent.fish.translate("cli","cli","yes")
NO = parent.fish.translate("cli","cli","no")
successMsg = ""
made = {}
for k in [ "rom", "playthrough", "spoiler" ]:
made[k] = parent.fish.translate("cli","cli","made." + k)
made["enemizer"] = parent.fish.translate("cli","cli","used.enemizer")
for k in made:
v = made[k]
pattern = "([\w]+)(:)([\s]+)(.*)"
m = re.search(pattern,made[k])
made[k] = m.group(1) + m.group(2) + ' ' + m.group(4)
successMsg += (made["rom"] % (YES if (guiargs.create_rom) else NO)) + "\n"
successMsg += (made["playthrough"] % (YES if (guiargs.calc_playthrough) else NO)) + "\n"
successMsg += (made["spoiler"] % (YES if (not guiargs.jsonout and guiargs.create_spoiler) else NO)) + "\n"
successMsg += (made["enemizer"] % (YES if needEnemizer else NO)) + "\n"
# FIXME: English
successMsg += ("Seed%s: %s" % ('s' if len(seeds) > 1 else "", ','.join(str(x) for x in seeds)))
messagebox.showinfo(title="Success", message=successMsg)
needEnemizer = False
falsey = ["none", "default", False, 0]
for enemizerOption in ["shuffleenemies", "enemy_damage", "shufflebosses", "enemy_health"]:
if enemizerOption in argsDump:
if isinstance(argsDump[enemizerOption], dict):
for playerID,playerSetting in argsDump[enemizerOption].items():
if not playerSetting in falsey:
needEnemizer = True
elif not argsDump[enemizerOption] in falsey:
needEnemizer = True
seeds = []
try:
if guiargs.count is not None and guiargs.seed:
seed = guiargs.seed
for _ in range(guiargs.count):
seeds.append(seed)
main(seed=seed, args=guiargs, fish=parent.fish)
seed = random.randint(0, 999999999)
else:
if guiargs.seed:
seeds.append(guiargs.seed)
else:
random.seed(None)
guiargs.seed = random.randint(0, 999999999)
seeds.append(guiargs.seed)
main(seed=guiargs.seed, args=guiargs, fish=parent.fish)
except (FillError, EnemizerError, Exception, RuntimeError) as e:
logging.exception(e)
messagebox.showerror(title="Error while creating seed", message=str(e))
else:
YES = parent.fish.translate("cli","cli","yes")
NO = parent.fish.translate("cli","cli","no")
successMsg = ""
made = {}
for k in [ "rom", "playthrough", "spoiler" ]:
made[k] = parent.fish.translate("cli","cli","made." + k)
made["enemizer"] = parent.fish.translate("cli","cli","used.enemizer")
for k in made:
v = made[k]
pattern = "([\w]+)(:)([\s]+)(.*)"
m = re.search(pattern,made[k])
made[k] = m.group(1) + m.group(2) + ' ' + m.group(4)
successMsg += (made["rom"] % (YES if (guiargs.create_rom) else NO)) + "\n"
successMsg += (made["playthrough"] % (YES if (guiargs.calc_playthrough) else NO)) + "\n"
successMsg += (made["spoiler"] % (YES if (not guiargs.jsonout and guiargs.create_spoiler) else NO)) + "\n"
successMsg += (made["enemizer"] % (YES if needEnemizer else NO)) + "\n"
# FIXME: English
successMsg += ("Seed%s: %s" % ('s' if len(seeds) > 1 else "", ','.join(str(x) for x in seeds)))
messagebox.showinfo(title="Success", message=successMsg)
## Generate Button
# widget ID
@@ -273,9 +275,6 @@ def create_guiargs(parent):
if hasattr(pagewidgets[widget], 'storageVar'):
setattr(guiargs, arg, pagewidgets[widget].storageVar.get())
# Get EnemizerCLI setting
guiargs.enemizercli = parent.pages["randomizer"].pages["enemizer"].widgets["enemizercli"].storageVar.get()
# Get Multiworld Worlds count
guiargs.multi = int(parent.pages["bottom"].pages["content"].widgets["worlds"].storageVar.get())

View File

@@ -80,20 +80,6 @@ def loadcliargs(gui, args, settings=None):
# If we've got a Game Options val and we don't have an Adjust val, use the Game Options val
gui.pages["adjust"].content.widgets[widget].storageVar.set(args[arg])
# Get EnemizerCLI setting
mainpage = "randomizer"
subpage = "enemizer"
widget = "enemizercli"
setting = "enemizercli"
# set storagevar
gui.pages[mainpage].pages[subpage].widgets[widget].storageVar.set(args[setting])
# set textbox/frame label
label = fish.translate("gui","gui",mainpage + '.' + subpage + '.' + widget)
gui.pages[mainpage].pages[subpage].widgets[widget].pieces["frame"].label.configure(text=label)
# set get from web label
label = fish.translate("gui","gui",mainpage + '.' + subpage + '.' + widget + ".online")
gui.pages[mainpage].pages[subpage].widgets[widget].pieces["online"].label.configure(text=label)
# Get baserom path
mainpage = "randomizer"
subpage = "generation"

View File

@@ -6,10 +6,7 @@ import webbrowser
from source.classes.Empty import Empty
def enemizer_page(parent,settings):
def open_enemizer_download(_evt):
webbrowser.open("https://github.com/Bonta0/Enemizer/releases")
# Enemizer
# Enemizer
self = ttk.Frame(parent)
# Enemizer options
@@ -29,7 +26,7 @@ def enemizer_page(parent,settings):
self.frames["selectOptionsFrame"].pack(fill=X)
self.frames["leftEnemizerFrame"].pack(side=LEFT)
self.frames["rightEnemizerFrame"].pack(side=RIGHT)
self.frames["bottomEnemizerFrame"].pack(fill=X)
self.frames["bottomEnemizerFrame"].pack(fill=X, padx=(12, 0))
# Load Enemizer option widgets as defined by JSON file
# Defns include frame name, widget type, widget options, widget placement attributes
@@ -43,47 +40,8 @@ def enemizer_page(parent,settings):
packAttrs = {"anchor":E}
if self.widgets[key].type == "checkbox":
packAttrs["anchor"] = W
if framename == 'bottomEnemizerFrame':
packAttrs["anchor"] = W
self.widgets[key].pack(packAttrs)
## Enemizer CLI Path
# This one's more-complicated, build it and stuff it
# widget ID
widget = "enemizercli"
# Empty object
self.widgets[widget] = Empty()
# pieces
self.widgets[widget].pieces = {}
# frame
self.widgets[widget].pieces["frame"] = Frame(self.frames["bottomEnemizerFrame"])
# frame: label
self.widgets[widget].pieces["frame"].label = Label(self.widgets[widget].pieces["frame"], text="EnemizerCLI path: ")
self.widgets[widget].pieces["frame"].label.pack(side=LEFT)
# get app online
self.widgets[widget].pieces["online"] = Empty()
# get app online: label
self.widgets[widget].pieces["online"].label = Label(self.widgets[widget].pieces["frame"], text="(get online)", fg="blue", cursor="hand2")
self.widgets[widget].pieces["online"].label.pack(side=LEFT)
# get app online: open browser
self.widgets[widget].pieces["online"].label.bind("<Button-1>", open_enemizer_download)
# storage var
self.widgets[widget].storageVar = StringVar(value=settings["enemizercli"])
# textbox
self.widgets[widget].pieces["textbox"] = Entry(self.widgets[widget].pieces["frame"], textvariable=self.widgets[widget].storageVar)
self.widgets[widget].pieces["textbox"].pack(side=LEFT, fill=X, expand=True)
def EnemizerSelectPath():
path = filedialog.askopenfilename(filetypes=[("EnemizerCLI executable", "*EnemizerCLI*")], initialdir=os.path.join("."))
if path:
self.widgets[widget].storageVar.set(path)
settings["enemizercli"] = path
# dialog button
self.widgets[widget].pieces["opendialog"] = Button(self.widgets[widget].pieces["frame"], text='...', command=EnemizerSelectPath)
self.widgets[widget].pieces["opendialog"].pack(side=LEFT)
# frame: pack
self.widgets[widget].pieces["frame"].pack(fill=X)
return self,settings
return self, settings

View File

@@ -287,9 +287,9 @@ def widget_command(widget, command=""):
temp_widget.storageVar.set('keys')
temp_widget = root.pages["randomizer"].pages["item"].widgets["dropshuffle"]
text_output += f'\n {temp_widget.checkbox.cget("text")}'
if temp_widget.storageVar.get() == 0:
temp_widget.storageVar.set(1)
text_output += f'\n {temp_widget.label.cget("text")}'
if temp_widget.storageVar.get() == 'none':
temp_widget.storageVar.set('keys')
if text_output:
messagebox.showinfo('', f'The following settings were changed:{text_output}')

View File

@@ -70,7 +70,7 @@ def create_item_pool_config(world):
for player in range(1, world.players + 1):
config.static_placement[player] = defaultdict(list)
config.static_placement[player].update(vanilla_mapping)
if world.dropshuffle[player]:
if world.dropshuffle[player] != 'none':
for item, locs in keydrop_vanilla_mapping.items():
config.static_placement[player][item].extend(locs)
if world.pottery[player] not in ['none', 'cave']:
@@ -96,7 +96,7 @@ def create_item_pool_config(world):
for item, locs in vanilla_mapping.items():
if 'Small Key' in item:
universal_key_locations.extend(locs)
if world.dropshuffle[player]:
if world.dropshuffle[player] != 'none':
for item, locs in keydrop_vanilla_mapping.items():
if 'Small Key' in item:
universal_key_locations.extend(locs)
@@ -129,11 +129,11 @@ def create_item_pool_config(world):
groups = LocationGroup('Major').locs(init_set)
if world.bigkeyshuffle[player]:
groups.locations.extend(mode_grouping['Big Keys'])
if world.dropshuffle[player]:
if world.dropshuffle[player] != 'none':
groups.locations.extend(mode_grouping['Big Key Drops'])
if world.keyshuffle[player] != 'none':
groups.locations.extend(mode_grouping['Small Keys'])
if world.dropshuffle[player]:
if world.dropshuffle[player] != 'none':
groups.locations.extend(mode_grouping['Key Drops'])
if world.pottery[player] not in ['none', 'cave']:
groups.locations.extend(mode_grouping['Pot Keys'])
@@ -357,7 +357,7 @@ def determine_major_items(world, player):
major_item_set.add('Single Arrow')
if world.keyshuffle[player] == 'universal':
major_item_set.add('Small Key (Universal)')
if world.goal[player] in ['triforcehunt', 'trinity', 'ganonhunt']:
if world.goal[player] in {'triforcehunt', 'ganonhunt', 'trinity'}:
major_item_set.add('Triforce Piece')
if world.bombbag[player]:
major_item_set.add('Bomb Upgrade (+10)')
@@ -416,11 +416,11 @@ def filter_locations(item_to_place, locations, world, vanilla_skip=False, potion
return filtered
if world.algorithm == 'district':
config = world.item_pool_config
if ((isinstance(item_to_place,str) and item_to_place == 'Placeholder')
if ((isinstance(item_to_place, str) and item_to_place == 'Placeholder')
or item_to_place.name in config.item_pool[item_to_place.player]):
restricted = config.location_groups[0].locations
filtered = [l for l in locations if l.name in restricted and l.player in restricted[l.name]]
return filtered if len(filtered) > 0 else locations
return filtered
elif potion:
restricted = config.location_groups[0].locations
filtered = [l for l in locations if l.name not in restricted or l.player not in restricted[l.name]]
@@ -439,14 +439,14 @@ def filter_locations(item_to_place, locations, world, vanilla_skip=False, potion
return locations
def filter_pot_locations(locations, world):
def filter_special_locations(locations, world, vanilla_matcher):
if world.algorithm == 'district':
config = world.item_pool_config
restricted = config.location_groups[0].locations
filtered = [l for l in locations if l.name not in restricted or l.player not in restricted[l.name]]
return filtered if len(filtered) > 0 else locations
if world.algorithm == 'vanilla_fill':
filtered = [l for l in locations if l.pot and l.pot.item in [PotItem.Chicken, PotItem.BigMagic]]
filtered = [l for l in locations if vanilla_matcher(l)]
return filtered if len(filtered) > 0 else locations
return locations

576
source/logic/Rule.py Normal file
View File

@@ -0,0 +1,576 @@
import itertools
from collections import OrderedDict
try:
from fast_enum import FastEnum
except ImportError:
from enum import IntFlag as FastEnum
from BaseClasses import CrystalBarrier, KeyRuleType
from Dungeons import dungeon_keys
class RuleType(FastEnum):
Conjunction = 0
Disjunction = 1
Item = 2
Glitch = 3
Reachability = 4
Static = 5
Bottle = 6
Crystal = 7
Barrier = 8
Hearts = 9
Unlimited = 10
ExtendMagic = 11
Boss = 12
Negate = 13
LocationCheck = 14
SmallKeyDoor = 15
class Rule(object):
def __init__(self, rule_type):
self.rule_type = rule_type
self.sub_rules = []
self.principal = None
self.player = 0
self.resolution_hint = None
self.barrier = None
self.flag = None
self.locations = []
self.count = 1
self.std_req = None
self.rule_lambda = lambda state: True
def eval(self, state):
return self.rule_lambda(state)
def get_requirements(self, progressive_flag=True):
if not self.std_req:
reqs = rule_requirements[self.rule_type](self, progressive_flag)
self.std_req = standardize_requirements(reqs, progressive_flag)
return self.std_req
def __str__(self):
return str(self.__unicode__())
def __unicode__(self):
return rule_prints[self.rule_type](self)
rule_prints = {
RuleType.Conjunction: lambda self: f'({" and ".join([str(x) for x in self.sub_rules])})',
RuleType.Disjunction: lambda self: f'({" or ".join([str(x) for x in self.sub_rules])})',
RuleType.Item: lambda self: f'has {self.principal}' if self.count == 1 else f'has {self.count} {self.principal}(s)',
RuleType.Reachability: lambda self: f'canReach {self.principal}',
RuleType.Static: lambda self: f'{self.principal}',
RuleType.Crystal: lambda self: f'has {self.principal} crystals',
RuleType.Barrier: lambda self: f'{self.barrier} @ {self.principal}',
RuleType.Hearts: lambda self: f'has {self.principal} hearts',
RuleType.Unlimited: lambda self: f'canBuyUnlimited {self.principal}',
RuleType.ExtendMagic: lambda self: f'magicNeeded {self.principal}',
RuleType.Boss: lambda self: f'canDefeat({self.principal.defeat_rule})',
RuleType.Negate: lambda self: f'not ({self.sub_rules[0]})',
RuleType.LocationCheck: lambda self: f'{self.principal} in [{", ".join(self.locations)}]',
RuleType.SmallKeyDoor: lambda self: f'doorOpen {self.principal[0]}:{self.principal[1]}'
}
def or_rule(rule1, rule2):
return lambda state: rule1(state) or rule2(state)
def and_rule(rule1, rule2):
return lambda state: rule1(state) and rule2(state)
class RuleFactory(object):
@staticmethod
def static_rule(boolean):
rule = Rule(RuleType.Static)
rule.principal = boolean
rule.rule_lambda = lambda state: boolean
return rule
@staticmethod
def conj(rules):
if len(rules) == 1:
return rules[0]
rule = Rule(RuleType.Conjunction)
rule_lambda = None
for r in rules:
if r is None:
continue
if r.rule_type == RuleType.Conjunction:
rule.sub_rules.extend(r.sub_rules) # todo: this extension for the lambda calc
elif r.rule_type == RuleType.Static and r.principal: # remove static flag if unnecessary
continue
elif r.rule_type == RuleType.Static and not r.principal: # always evaluates to false
return r
else:
rule.sub_rules.append(r)
if not rule_lambda:
rule_lambda = r.rule_lambda
else:
rule_lambda = and_rule(rule_lambda, r.rule_lambda)
rule.rule_lambda = rule_lambda if rule_lambda else lambda state: True
return rule
@staticmethod
def disj(rules):
if len(rules) == 1:
return rules[0]
rule = Rule(RuleType.Disjunction)
rule_lambda = None
for r in rules:
if r is None:
continue
if r.rule_type == RuleType.Disjunction:
rule.sub_rules.extend(r.sub_rules) # todo: this extension for the lambda calc
elif r.rule_type == RuleType.Static and not r.principal: # remove static flag if unnecessary
continue
elif r.rule_type == RuleType.Static and r.principal: # always evaluates to true
return r
else:
rule.sub_rules.append(r)
if not rule_lambda:
rule_lambda = r.rule_lambda
else:
rule_lambda = or_rule(rule_lambda, r.rule_lambda)
rule.rule_lambda = rule_lambda if rule_lambda else lambda state: True
return rule
@staticmethod
def item(item, player, count=1):
rule = Rule(RuleType.Item)
rule.principal = item
rule.player = player
rule.count = count
rule.rule_lambda = lambda state: state.has(item, player, count)
return rule
@staticmethod
def bottle(player):
rule = Rule(RuleType.Bottle)
rule.player = player
rule.rule_lambda = lambda state: state.has_bottle(player)
return rule
@staticmethod
def crystals(number, player):
rule = Rule(RuleType.Crystal)
rule.principal = number
rule.player = player
rule.rule_lambda = lambda state: state.has_crystals(number, player)
return rule
@staticmethod
def barrier(region, player, barrier):
rule = Rule(RuleType.Barrier)
rule.principal = region
rule.player = player
rule.barrier = barrier
rule.rule_lambda = lambda state: state.can_cross_barrier(region, player, barrier)
return rule
@staticmethod
def hearts(number, player):
rule = Rule(RuleType.Hearts)
rule.principal = number
rule.player = player
rule.rule_lambda = lambda state: state.has_hearts(number, player)
return rule
@staticmethod
def unlimited(item, player, shop_regions):
rule = Rule(RuleType.Unlimited)
rule.principal = item
rule.player = player
rule.locations = shop_regions # list of regions where said item can be bought
rule.rule_lambda = lambda state: state.can_buy_unlimited(item, player)
return rule
@staticmethod
def extend_magic(player, magic, difficulty, magic_potion_regions, flag):
rule = Rule(RuleType.ExtendMagic)
rule.principal = magic
rule.player = player
rule.resolution_hint = difficulty # world difficulty setting
rule.locations = magic_potion_regions # list of regions where blue/green can be bought
rule.flag = flag
rule.rule_lambda = lambda state: state.can_extend_magic(player, magic, flag)
return rule
@staticmethod
def boss(boss):
rule = Rule(RuleType.Boss)
rule.principal = boss
rule.rule_lambda = lambda state: boss.defeat_rule.eval(state)
return rule
@staticmethod
def neg(orig):
rule = Rule(RuleType.Negate)
rule.sub_rules.append(orig)
rule.rule_lambda = lambda state: not orig.rule_lambda(state)
return rule
@staticmethod
def check_location(item, location, player):
rule = Rule(RuleType.LocationCheck)
rule.principal = item
rule.location = location
rule.player = player
rule.rule_lambda = eval_location(item, location, player)
return rule
@staticmethod
def small_key_door(door_name, dungeon, player, door_rules):
rule = Rule(RuleType.SmallKeyDoor)
rule.principal = (door_name, dungeon)
rule.player = player
rule.resolution_hint = door_rules # door_rule object from KeyDoorShuffle
rule.rule_lambda = eval_small_key_door(door_name, dungeon, player)
return rule
def eval_location(item, location, player):
return lambda state: eval_location_main(item, location, player, state)
def eval_location_main(item, location, player, state):
location = state.world.get_location(location, player)
return location.item and location.item.name == item and location.player == player
def eval_small_key_door_main(state, door_name, dungeon, player):
if state.is_door_open(door_name, player):
return True
key_logic = state.world.key_logic[player][dungeon]
door_rule = key_logic.door_rules[door_name]
door_openable = False
for ruleType, number in door_rule.new_rules.items():
if door_openable:
return True
if ruleType == KeyRuleType.WorstCase:
door_openable |= state.has_sm_key(key_logic.small_key_name, player, number)
elif ruleType == KeyRuleType.AllowSmall:
if (door_rule.small_location.item and door_rule.small_location.item.name == key_logic.small_key_name
and door_rule.small_location.item.player == player):
return True # always okay if allow small is on
elif isinstance(ruleType, tuple):
lock, lock_item = ruleType
# this doesn't track logical locks yet, i.e. hammer locks the item and hammer is there, but the item isn't
for loc in door_rule.alternate_big_key_loc:
spot = state.world.get_location(loc, player)
if spot.item and spot.item.name == lock_item:
door_openable |= state.has_sm_key(key_logic.small_key_name, player, number)
break
return door_openable
def eval_small_key_door(door_name, dungeon, player):
return lambda state: eval_small_key_door_main(state, door_name, dungeon, player)
def conjunction_requirements(rule, f):
combined = [ReqSet()]
for r in rule.sub_rules:
result = r.get_requirements(f)
combined = merge_requirements(combined, result)
return combined
def disjunction_requirements(rule, f):
results = []
for r in rule.sub_rules:
result = r.get_requirements(f)
results.extend(result)
return results
rule_requirements = {
RuleType.Conjunction: conjunction_requirements,
RuleType.Disjunction: disjunction_requirements,
RuleType.Item: lambda rule, f: [ReqSet([Requirement(ReqType.Item, rule.principal, rule.player, rule, rule.count)])],
RuleType.Reachability: lambda rule, f: [ReqSet([Requirement(ReqType.Reachable, rule.principal, rule.player, rule)])],
RuleType.Static: lambda rule, f: static_req(rule),
RuleType.Crystal: lambda rule, f: crystal_requirements(rule),
RuleType.Bottle: lambda rule, f: [ReqSet([Requirement(ReqType.Item, 'Bottle', rule.player, rule, 1)])],
RuleType.Barrier: lambda rule, f: barrier_req(rule),
RuleType.Hearts: lambda rule, f: empty_req(), # todo: the one heart container
RuleType.Unlimited: lambda rule, f: unlimited_buys(rule),
RuleType.ExtendMagic: lambda rule, f: magic_requirements(rule),
RuleType.Boss: lambda rule, f: rule.principal.defeat_rule.get_requirements(f),
RuleType.Negate: lambda rule, f: empty_req(), # ignore these and just don't flood the key too early
RuleType.LocationCheck: lambda rule, f: location_check(rule),
RuleType.SmallKeyDoor: lambda rule, f: small_key_reqs(rule)
}
avail_crystals = ['Crystal 1', 'Crystal 2', 'Crystal 3', 'Crystal 4', 'Crystal 5', 'Crystal 6', 'Crystal 7']
def crystal_requirements(rule):
crystal_rules = map(lambda c: Requirement(ReqType.Item, c, rule.player, rule), avail_crystals)
combinations = itertools.combinations(crystal_rules, rule.principal)
counter_list = []
for combo in combinations:
counter_list.append(ReqSet(combo))
return counter_list
# todo: 1/4 magic
def magic_requirements(rule):
if rule.principal <= 8:
return [set()]
bottle_val = 1.0
if rule.resolution_hint == 'expert' and not rule.flag:
bottle_val = 0.25
elif rule.resolution_hint == 'hard' and not rule.flag:
bottle_val = 0.5
base, min_bot, reqs = 8, None, []
for i in range(1, 5):
if base + bottle_val*base*i >= rule.principal:
min_bot = i
break
if min_bot:
for region in rule.locations:
reqs.append(ReqSet([Requirement(ReqType.Item, 'Bottle', rule.player, rule, min_bot),
Requirement(ReqType.Reachable, region, rule.player, rule)]))
if rule.principal <= 16:
reqs.append(ReqSet([Requirement(ReqType.Item, 'Magic Upgrade (1/2)', rule.player, rule, 1)]))
return reqs
else:
base, min_bot = 16, 4
for i in range(1, 5):
if base + bottle_val*base*i >= rule.principal:
min_bot = i
break
if min_bot:
for region in rule.locations:
reqs.append(ReqSet([Requirement(ReqType.Item, 'Magic Upgrade (1/2)', rule.player, rule, 1),
Requirement(ReqType.Item, 'Bottle', rule.player, rule, min_bot),
Requirement(ReqType.Reachable, region, rule.player, rule)]))
return reqs
def static_req(rule):
return [ReqSet()] if rule.principal else [ReqSet([Requirement(ReqType.Item, 'Impossible', rule.player, rule)])]
def barrier_req(rule):
return [ReqSet([Requirement(ReqType.Reachable, rule.principal, rule.player, rule, crystal=rule.barrier)])]
def empty_req():
return [ReqSet()]
def location_check(rule):
return [ReqSet([Requirement(ReqType.Placement, rule.principal, rule.player, rule, locations=rule.locations)])]
def unlimited_buys(rule):
requirements = []
for region in rule.locations:
requirements.append(ReqSet([Requirement(ReqType.Reachable, region, rule.player, rule)]))
return requirements
def small_key_reqs(rule):
requirements = []
door_name, dungeon = rule.principal
key_name = dungeon_keys[dungeon]
for rule_type, number in rule.resolution_hint.new_rules.items():
if rule_type == KeyRuleType.WorstCase:
requirements.append(ReqSet([Requirement(ReqType.Item, key_name, rule.player, rule, number)]))
elif rule_type == KeyRuleType.AllowSmall:
small_loc = rule.resolution_hint.small_location.name
requirements.append(ReqSet([
Requirement(ReqType.Placement, key_name, rule.player, rule, locations=[small_loc]),
Requirement(ReqType.Item, key_name, rule.player, rule, number)]))
elif isinstance(rule_type, tuple):
lock, lock_item = rule_type
locs = [x.name for x in rule.resolution_hint.alternate_big_key_loc]
requirements.append(ReqSet([
Requirement(ReqType.Placement, lock_item, rule.player, rule, locations=locs),
Requirement(ReqType.Item, key_name, rule.player, rule, number)]))
return requirements
class ReqType(FastEnum):
Item = 0
Placement = 2
class ReqSet(object):
def __init__(self, requirements=None):
if requirements is None:
requirements = []
self.keyed = OrderedDict()
for r in requirements:
self.keyed[r.simple_key()] = r
def append(self, req):
self.keyed[req.simple_key()] = req
def get_values(self):
return self.keyed.values()
def merge(self, other):
new_set = ReqSet(self.get_values())
for r in other.get_values():
key = r.simple_key()
if key in new_set.keyed:
new_set.keyed[key] = max(r, new_set.keyed[key], key=lambda r: r.amount)
else:
new_set.keyed[key] = r
return new_set
def redundant(self, other):
for k, req in other.keyed.items():
if k not in self.keyed:
return False
elif self.keyed[k].amount < req.amount:
return False
return True
def different(self, other):
for key in self.keyed.keys():
if key not in other.keyed:
return True
if key in other.keyed and self.keyed[key].amount > other.keyed[key].amount:
return True
return False
def find_item(self, item_name):
for key, req in self.keyed.items():
if req.req_type == ReqType.Item and req.item == item_name:
return req
return None
def __eq__(self, other):
for key, req in self.keyed.items():
if key not in other.keyed:
return False
if req.amount != other.keyed[key].amount:
return False
for key in other.keyed:
if key not in self.keyed:
return False
return True
def __str__(self):
return str(self.__unicode__())
def __unicode__(self):
return " and ".join([str(x) for x in self.keyed.values()])
class Requirement(object):
def __init__(self, req_type, item, player, rule, amount=1, crystal=CrystalBarrier.Null, locations=()):
self.req_type = req_type
self.item = item
self.player = player
self.rule = rule
self.amount = amount
self.crystal = crystal
self.locations = tuple(locations)
def simple_key(self):
return self.req_type, self.item, self.player, self.crystal, self.locations
def key(self):
return self.req_type, self.item, self.player, self.amount, self.crystal, self.locations
def __eq__(self, other):
if isinstance(other, Requirement):
return self.key() == other.key()
return NotImplemented
def __hash__(self):
return hash(self.key())
def __str__(self):
return str(self.__unicode__())
def __unicode__(self):
if self.req_type == ReqType.Item:
return f'has {self.item}' if self.amount == 1 else f'has {self.amount} {self.item}(s)'
elif self.req_type == ReqType.Placement:
return f'{self.item} located @ {",".join(self.locations)}'
# requirement utility methods
def merge_requirements(starting_requirements, new_requirements):
merge = []
for req in starting_requirements:
for new_r in new_requirements:
merge.append(req.merge(new_r))
return reduce_requirements(merge)
only_one = {'Moon Pearl', 'Hammer', 'Blue Boomerang', 'Red Boomerang', 'Hookshot', 'Mushroom', 'Powder',
'Fire Rod', 'Ice Rod', 'Bombos', 'Ether', 'Quake', 'Lamp', 'Shovel', 'Ocarina', 'Bug Catching Net',
'Book of Mudora', 'Magic Mirror', 'Cape', 'Cane of Somaria', 'Cane of Byrna', 'Flippers', 'Pegasus Boots'}
def standardize_requirements(requirements, progressive_flag):
assert isinstance(requirements, list)
for req in requirements:
for thing in req.get_values():
if thing.item in only_one and thing.amount > 1:
thing.amount = 1
if progressive_flag:
substitute_progressive(req)
return reduce_requirements(requirements)
def reduce_requirements(requirements):
removals = []
reduced = list(requirements)
# subset manip
ttl = len(reduced)
for i in range(0, ttl - 1):
for j in range(i + 1, ttl):
req, other_req = reduced[i], reduced[j]
if req.redundant(other_req):
removals.append(req)
elif other_req.redundant(req):
removals.append(other_req)
for removal in removals:
if removal in reduced:
reduced.remove(removal)
assert len(reduced) != 0
return reduced
progress_sub = {
'Fighter Sword': ('Progressive Sword', 1),
'Master Sword': ('Progressive Sword', 2),
'Tempered Sword': ('Progressive Sword', 3),
'Golden Sword': ('Progressive Sword', 4),
'Power Glove': ('Progressive Glove', 1),
'Titans Mitts': ('Progressive Glove', 2),
'Bow': ('Progressive Bow', 1),
'Silver Arrows': ('Progressive Bow', 2),
'Blue Mail': ('Progressive Armor', 1),
'Red Mail': ('Progressive Armor', 2),
'Blue Shield': ('Progressive Shield', 1),
'Red Shield': ('Progressive Shield', 2),
'Mirror Shield': ('Progressive Shield', 3),
}
def substitute_progressive(req):
for item in req.get_values():
if item.item in progress_sub.keys():
item.item, item.amount = progress_sub[item.item]

View File

@@ -2561,9 +2561,13 @@ mandatory_connections = [('Lost Woods Hideout (top to bottom)', 'Lost Woods Hide
('Lumberjack Tree (top to bottom)', 'Lumberjack Tree (bottom)'),
('Death Mountain Return Cave E', 'Death Mountain Return Cave (right)'),
('Death Mountain Return Cave W', 'Death Mountain Return Cave (left)'),
('Old Man Cave Dropdown', 'Old Man Cave'),
('Spectacle Rock Cave Drop', 'Spectacle Rock Cave (Bottom)'),
('Spectacle Rock Cave Peak Drop', 'Spectacle Rock Cave (Bottom)'),
('Old Man Cave Dropdown', 'Old Man Cave (East)'),
('Old Man Cave W', 'Old Man Cave (West)'),
('Old Man Cave E', 'Old Man Cave (East)'),
('Spectacle Rock Cave Drop', 'Spectacle Rock Cave Pool'),
('Spectacle Rock Cave Peak Drop', 'Spectacle Rock Cave Pool'),
('Spectacle Rock Cave West Edge', 'Spectacle Rock Cave (Bottom)'),
('Spectacle Rock Cave East Edge', 'Spectacle Rock Cave Pool'),
('Old Man House Front to Back', 'Old Man House Back'),
('Old Man House Back to Front', 'Old Man House'),
('Spiral Cave (top to bottom)', 'Spiral Cave (Bottom)'),
@@ -2582,11 +2586,19 @@ mandatory_connections = [('Lost Woods Hideout (top to bottom)', 'Lost Woods Hide
('Sewer Drop', 'Sewers Rat Path'),
('Missing Smith', 'Missing Smith'),
('Bat Cave Door', 'Bat Cave (left)'),
('Good Bee Cave Front to Back', 'Good Bee Cave (back)'),
('Good Bee Cave Back to Front', 'Good Bee Cave'),
('Capacity Upgrade East', 'Capacity Fairy Pool'),
('Capacity Fairy Pool West', 'Capacity Upgrade'),
('Bonk Fairy (Dark) Pool', 'Bonk Fairy Pool'),
('Bonk Fairy (Light) Pool', 'Bonk Fairy Pool'),
('Hookshot Cave Front to Middle', 'Hookshot Cave (Middle)'),
('Hookshot Cave Middle to Front', 'Hookshot Cave (Front)'),
('Hookshot Cave Middle to Back', 'Hookshot Cave (Back)'),
('Hookshot Cave Back to Middle', 'Hookshot Cave (Middle)'),
('Hookshot Cave Back to Fairy', 'Hookshot Cave (Fairy Pool)'),
('Hookshot Cave Fairy to Back', 'Hookshot Cave (Back)'),
('Hookshot Cave Bonk Path', 'Hookshot Cave (Bonk Islands)'),
('Hookshot Cave Hook Path', 'Hookshot Cave (Hook Islands)'),
('Superbunny Cave Climb', 'Superbunny Cave (Top)'),
@@ -2606,7 +2618,7 @@ default_connections = {'Lost Woods Gamble': 'Lost Woods Gamble',
'Lumberjack Tree Exit': 'Lumberjack Area',
'Death Mountain Return Cave (East)': 'Death Mountain Return Cave (right)',
'Death Mountain Return Cave Exit (East)': 'West Death Mountain (Bottom)',
'Old Man Cave (East)': 'Old Man Cave',
'Old Man Cave (East)': 'Old Man Cave (East)',
'Old Man Cave Exit (East)': 'West Death Mountain (Bottom)',
'Spectacle Rock Cave': 'Spectacle Rock Cave (Top)',
'Spectacle Rock Cave Exit (Top)': 'West Death Mountain (Bottom)',

228
source/rom/DataTables.py Normal file
View File

@@ -0,0 +1,228 @@
from collections import defaultdict
from Utils import snes_to_pc, int24_as_bytes, int16_as_bytes, load_cached_yaml, pc_to_snes
from source.dungeon.EnemyList import EnemyTable, init_vanilla_sprites, vanilla_sprites, init_enemy_stats, EnemySprite
from source.dungeon.EnemyList import sprite_translation
from source.dungeon.RoomHeader import init_room_headers
from source.dungeon.RoomList import Room0127
from source.enemizer.OwEnemyList import init_vanilla_sprites_ow, vanilla_sprites_ow
from source.enemizer.SpriteSheets import init_sprite_sheets, init_sprite_requirements, SheetChoice
def convert_area_id_to_offset(area_id):
if area_id < 0x40:
return area_id
if 0x40 <= area_id < 0x80:
return area_id + 0x40
if 0x90 <= area_id <= 0xCF:
return area_id - 0x50
raise Exception(f'{hex(area_id)} is not a valid area id for offset math')
class DataTables:
def __init__(self):
self.room_headers = None
self.room_list = None
self.sprite_sheets = None
self.uw_enemy_table = None
self.ow_enemy_table = None
self.pot_secret_table = None
self.overworld_sprite_sheets = None
# associated data
self.sprite_requirements = None
self.room_requirements = None
self.enemy_stats = None
self.enemy_damage = None
self.bush_sprite_table = {}
# enemizer conditions
self.uw_enemy_denials = {}
self.ow_enemy_denials = {}
self.uw_enemy_drop_denials = {}
self.sheet_choices = []
denial_data = load_cached_yaml(['source', 'enemizer', 'enemy_deny.yaml'])
for denial in denial_data['UwGeneralDeny']:
self.uw_enemy_denials[denial[0], denial[1]] = {sprite_translation[x] for x in denial[2]}
for denial in denial_data['OwGeneralDeny']:
self.ow_enemy_denials[denial[0], denial[1]] = {sprite_translation[x] for x in denial[2]}
for denial in denial_data['UwEnemyDrop']:
self.uw_enemy_drop_denials[denial[0], denial[1]] = {sprite_translation[x] for x in denial[2]}
weights = load_cached_yaml(['source', 'enemizer', 'enemy_weight.yaml'])
self.uw_weights = {sprite_translation[k]: v for k, v in weights['UW'].items()}
self.ow_weights = {sprite_translation[k]: v for k, v in weights['OW'].items()}
sheet_weights = load_cached_yaml(['source', 'enemizer', 'sheet_weight.yaml'])
for item in sheet_weights['SheetChoices']:
choice = SheetChoice(tuple(item['slots']), item['assignments'], item['weight'])
self.sheet_choices.append(choice)
def write_to_rom(self, rom, colorize_pots=False, increase_bush_sprite_chance=False):
if self.pot_secret_table.size() > 0x11c0:
raise Exception('Pot table is too big for current area')
self.pot_secret_table.write_pot_data_to_rom(rom, colorize_pots, self)
for room_id, header in self.room_headers.items():
data_location = (0x30DA00 + room_id * 14) & 0xFFFF
rom.write_bytes(snes_to_pc(0x04F1E2) + room_id * 2, int16_as_bytes(data_location))
header.write_to_rom(rom, snes_to_pc(0x30DA00)) # new header table, bank30, tables.asm
room_start_address = 0x378000
for room_id, room in self.room_list.items():
rom.write_bytes(snes_to_pc(0x1F8000 + room_id * 3), int24_as_bytes(room_start_address))
door_start, bytes_written = room.write_to_rom(snes_to_pc(room_start_address), rom)
rom.write_bytes(snes_to_pc(0x1F83C0 + room_id * 3), int24_as_bytes(room_start_address + door_start))
room_start_address += bytes_written
if room_start_address > 0x380000:
raise Exception('Room list exceeded bank size')
# size notes: bank 03 uses 140E bytes
# bank 0A uses 372A bytes
# bank 1F uses 77CE bytes: total is about a bank and a half
# probably should reuse bank 1F if writing all the rooms out
for sheet in self.sprite_sheets.values():
sheet.write_to_rom(rom, snes_to_pc(0x00DB97)) # bank 00, SheetsTable_AA3
if self.uw_enemy_table.size() > 0x2800:
raise Exception('Sprite table is too big for current area')
self.uw_enemy_table.write_sprite_data_to_rom(rom)
self.uw_enemy_table.check_special_bitmasks_size()
self.uw_enemy_table.write_special_bitmask_table(rom)
for area_id, sheet in self.overworld_sprite_sheets.items():
if area_id in [0x80, 0x81]:
offset = area_id - 0x80 # 02E575 for special areas?
rom.write_byte(snes_to_pc(0x02E576+offset), sheet.id)
else:
offset = convert_area_id_to_offset(area_id)
rom.write_byte(snes_to_pc(0x00FA81+offset), sheet.id)
# _00FA81 is LW normal
# _00FAC1 is LW post-aga
# _00FB01 is DW
self.write_ow_sprite_data_to_rom(rom)
for sprite, stats in self.enemy_stats.items():
# write health to rom
if stats.health is not None:
if isinstance(stats.health, tuple):
if sprite == EnemySprite.Octorok4Way: # skip this one
continue
if sprite in special_health_table:
a1, a2 = special_health_table[sprite]
rom.write_byte(snes_to_pc(a1), stats.health[0])
rom.write_byte(snes_to_pc(a2), stats.health[1])
else:
rom.write_byte(snes_to_pc(0x0DB173+int(sprite)), stats.health)
# write damage class to rom
if stats.damage is not None:
if isinstance(stats.damage, tuple):
if sprite == EnemySprite.Octorok4Way: # skip this one
continue
if sprite in special_damage_table:
a1, a2 = special_damage_table[sprite]
rom.write_byte(snes_to_pc(a1), stats.dmask | stats.damage[0])
rom.write_byte(snes_to_pc(a2), stats.dmask | stats.damage[1])
else:
rom.write_byte(snes_to_pc(0x0DB266+int(sprite)), stats.dmask | stats.damage)
# write damage table to rom
for idx, damage_list in self.enemy_damage.items():
rom.write_bytes(snes_to_pc(0x06F42D + idx * 3), damage_list)
# write bush spawns to rom:
for area_id, bush_sprite in self.bush_sprite_table.items():
rom.write_byte(snes_to_pc(0x368120 + area_id), bush_sprite.sprite)
if increase_bush_sprite_chance:
rom.write_bytes(snes_to_pc(0x1AFBBB), [
0x01, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x12,
0x0F, 0x01, 0x0F, 0x0F, 0x11, 0x0F, 0x0F, 0x03
])
def write_ow_sprite_data_to_rom(self, rom):
# calculate how big this table is going to be?
# bytes = sum(1+len(x)*3 for x in self.ow_enemy_table.values() if len(x) > 0)+1
# ending_byte = 0x09CB3B + bytes
max_per_state = {0: 0x40, 1: 0x90, 2: 0x8D} # dropped max on state 2 to steal space for a couple extra sprites (Murahdahla)
pointer_address = snes_to_pc(0x09C881)
data_pointer = snes_to_pc(0x09CB3B) # was originally 0x09CB41 - stealing space for a couple extra sprites (Murahdahla)
empty_pointer = pc_to_snes(data_pointer) & 0xFFFF
rom.write_byte(data_pointer, 0xff)
cached_dark_world = {}
data_pointer += 1
for state in range(0, 3):
if state > 0: # move pointer to next section
pointer_address += max_per_state[state-1] * 2
for screen in range(0, max_per_state[state]):
internal_screen_id = screen
if state == 0:
internal_screen_id += 0x200
if state == 2 and screen < 0x40:
internal_screen_id += 0x90
# has no sprites
if internal_screen_id not in self.ow_enemy_table or len(self.ow_enemy_table[internal_screen_id]) == 0:
rom.write_bytes(pointer_address + screen * 2, int16_as_bytes(empty_pointer))
else:
if state == 2 and screen >= 0x40: # state 2 uses state 1 pointer for screens >= 0x40
rom.write_bytes(pointer_address + screen * 2, cached_dark_world[screen])
# the sprites are already written out
elif len(self.ow_enemy_table[internal_screen_id]) > 0:
data_address = pc_to_snes(data_pointer) & 0xFFFF
ref = int16_as_bytes(data_address)
if screen >= 40:
cached_dark_world[screen] = ref
rom.write_bytes(pointer_address + screen * 2, ref)
for sprite in self.ow_enemy_table[internal_screen_id]:
data = sprite.sprite_data()
rom.write_bytes(data_pointer, data)
data_pointer += len(data)
rom.write_byte(data_pointer, 0xff)
data_pointer += 1
special_health_table = {
EnemySprite.Octorok: (0x068F76, 0x068F77),
EnemySprite.HardhatBeetle: (0x06911F, 0x069120),
EnemySprite.Tektite: (0x068D97, 0x068D98),
EnemySprite.CricketRat: (0x068876, 0x068877),
EnemySprite.Keese: (0x06888A, 0x06888B),
EnemySprite.Snake: (0x0688A6, 0x0688A7),
EnemySprite.Raven: (0x068965, 0x068966)
}
special_damage_table = {
EnemySprite.Octorok: (0x068F74, 0x068F75),
EnemySprite.Tektite: (0x068D99, 0x068D9A),
EnemySprite.CricketRat: (0x068874, 0x068875),
EnemySprite.Keese: (0x068888, 0x068889),
EnemySprite.Snake: (0x0688A4, 0x0688A5),
EnemySprite.Raven: (0x068963, 0x068964)
}
def init_data_tables(world, player):
data_tables = DataTables()
data_tables.room_headers = init_room_headers()
data_tables.room_list = {}
if world.pottery[player] not in ['none']:
data_tables.room_list[0x0127] = Room0127
data_tables.sprite_requirements = init_sprite_requirements()
data_tables.sprite_sheets = init_sprite_sheets(data_tables.sprite_requirements)
init_vanilla_sprites()
data_tables.enemy_stats = init_enemy_stats()
uw_table = data_tables.uw_enemy_table = EnemyTable()
for room, sprite_list in vanilla_sprites.items():
for sprite in sprite_list:
uw_table.room_map[room].append(sprite.copy())
data_tables.overworld_sprite_sheets = {}
data_tables.ow_enemy_table = defaultdict(list)
init_vanilla_sprites_ow()
for area, sprite_list in vanilla_sprites_ow.items():
for sprite in sprite_list:
if sprite.bonk and world.shuffle_bonk_drops[player]:
sprite.kind = EnemySprite.GreenRupee
data_tables.ow_enemy_table[area].append(sprite.copy())
data_tables.enemy_damage = {k: list(v) for k, v in world.damage_table[player].enemy_damage.items()}
# todo: more denials based on enemy drops
return data_tables
def get_uw_enemy_table():
init_vanilla_sprites()
uw_table = EnemyTable()
for room, sprite_list in vanilla_sprites.items():
for sprite in sprite_list:
uw_table.room_map[room].append(sprite.copy())
return uw_table

1
source/rom/__init__.py Normal file
View File

@@ -0,0 +1 @@
# do nothing, just exist to make "source" package

View File

@@ -32,6 +32,39 @@ def roll_settings(weights):
return default
return choice
def get_choice_bool(option, root=weights):
choice = get_choice(option, root)
if choice is True or choice == 'on':
return True
if choice is False or choice == 'off':
return False
if choice is None:
return choice
raise Exception("This fields needs to be true/false or off/on")
def get_choice_non_bool(option, root=weights):
choice = get_choice(option, root)
if choice is True or choice == 'on':
return 'on'
if choice is False or choice == 'off':
return 'off'
return choice
def get_choice_yn(option, root=weights):
choice = get_choice(option, root)
if choice is True or choice == 'yes':
return 'yes'
if choice is False or choice == 'no':
return 'no'
return choice
def get_choice_bool_default(option, root=weights, default=None):
choice = get_choice_bool(option, root)
if choice is None and default is not None:
return default
return choice
while True:
subweights = weights.get('subweights', {})
if len(subweights) == 0:
@@ -46,9 +79,10 @@ def roll_settings(weights):
ret.algorithm = get_choice('algorithm')
glitch_map = {'none': 'noglitches', 'minorglitches': 'minorglitches', 'no_logic': 'nologic',
glitch_map = {'none': 'noglitches', 'minorglitches': 'minorglitches',
'hmg': 'hybridglitches', 'hybridglitches': 'hybridglitches',
'owg': 'owglitches', 'owglitches': 'owglitches'}
'owg': 'owglitches', 'owglitches': 'owglitches',
'no_logic': 'nologic'}
glitches_required = get_choice('glitches_required')
if glitches_required is not None:
if glitches_required not in glitch_map.keys():
@@ -62,8 +96,8 @@ def roll_settings(weights):
dungeon_items = get_choice('dungeon_items')
dungeon_items = '' if dungeon_items == 'standard' or dungeon_items is None else dungeon_items
dungeon_items = 'mcsb' if dungeon_items == 'full' else dungeon_items
ret.mapshuffle = get_choice('map_shuffle') == 'on' if 'map_shuffle' in weights else 'm' in dungeon_items
ret.compassshuffle = get_choice('compass_shuffle') == 'on' if 'compass_shuffle' in weights else 'c' in dungeon_items
ret.mapshuffle = get_choice_bool('map_shuffle') if 'map_shuffle' in weights else 'm' in dungeon_items
ret.compassshuffle = get_choice_bool('compass_shuffle') if 'compass_shuffle' in weights else 'c' in dungeon_items
if 'smallkey_shuffle' in weights:
ret.keyshuffle = get_choice('smallkey_shuffle')
else:
@@ -71,23 +105,23 @@ def roll_settings(weights):
ret.keyshuffle = 'wild'
if 'u' in dungeon_items:
ret.keyshuffle = 'universal'
ret.bigkeyshuffle = get_choice('bigkey_shuffle') == 'on' if 'bigkey_shuffle' in weights else 'b' in dungeon_items
ret.bigkeyshuffle = get_choice_bool('bigkey_shuffle') if 'bigkey_shuffle' in weights else 'b' in dungeon_items
ret.accessibility = get_choice('accessibility')
ret.restrict_boss_items = get_choice('restrict_boss_items')
overworld_shuffle = get_choice('overworld_shuffle')
ret.ow_shuffle = overworld_shuffle if overworld_shuffle != 'none' else 'vanilla'
ret.ow_terrain = get_choice('overworld_terrain') == 'on'
ret.ow_terrain = get_choice_bool('overworld_terrain')
valid_options = {'none': 'none', 'polar': 'polar', 'grouped': 'polar', 'chaos': 'unrestricted', 'unrestricted': 'unrestricted'}
ret.ow_crossed = get_choice('overworld_crossed')
ret.ow_crossed = valid_options[ret.ow_crossed] if ret.ow_crossed in valid_options else 'none'
ret.ow_keepsimilar = get_choice('overworld_keepsimilar') == 'on'
ret.ow_mixed = get_choice('overworld_swap') == 'on'
ret.ow_whirlpool = get_choice('whirlpool_shuffle') == 'on'
ret.ow_keepsimilar = get_choice_bool('overworld_keepsimilar')
ret.ow_mixed = get_choice_bool('overworld_swap')
ret.ow_whirlpool = get_choice_bool('whirlpool_shuffle')
overworld_flute = get_choice('flute_shuffle')
ret.ow_fluteshuffle = overworld_flute if overworld_flute != 'none' else 'vanilla'
ret.bonk_drops = get_choice('bonk_drops') == 'on'
ret.bonk_drops = get_choice_bool('bonk_drops')
entrance_shuffle = get_choice('entrance_shuffle')
ret.shuffle = entrance_shuffle if entrance_shuffle != 'none' else 'vanilla'
overworld_map = get_choice('overworld_map')
@@ -98,29 +132,30 @@ def roll_settings(weights):
ret.door_type_mode = get_choice('door_type_mode')
ret.trap_door_mode = get_choice('trap_door_mode')
ret.key_logic_algorithm = get_choice('key_logic_algorithm')
ret.decoupledoors = get_choice('decoupledoors') == 'on'
ret.door_self_loops = get_choice('door_self_loops') == 'on'
ret.experimental = get_choice('experimental') == 'on'
ret.collection_rate = get_choice('collection_rate') == 'on'
ret.decoupledoors = get_choice_bool('decoupledoors')
ret.door_self_loops = get_choice_bool('door_self_loops')
ret.experimental = get_choice_bool('experimental')
ret.collection_rate = get_choice_bool('collection_rate')
ret.dungeon_counters = get_choice('dungeon_counters') if 'dungeon_counters' in weights else 'default'
ret.dungeon_counters = get_choice_non_bool('dungeon_counters') if 'dungeon_counters' in weights else 'default'
if ret.dungeon_counters == 'default':
ret.dungeon_counters = 'pickup' if ret.door_shuffle != 'vanilla' or ret.compassshuffle == 'on' else 'off'
ret.pseudoboots = get_choice('pseudoboots') == 'on'
ret.shopsanity = get_choice('shopsanity') == 'on'
keydropshuffle = get_choice('keydropshuffle') == 'on'
ret.dropshuffle = get_choice('dropshuffle') == 'on' or keydropshuffle
ret.pseudoboots = get_choice_bool('pseudoboots')
ret.shopsanity = get_choice_bool('shopsanity')
keydropshuffle = get_choice_bool('keydropshuffle')
ret.dropshuffle = get_choice('dropshuffle') if 'dropshuffle' in weights else 'none'
ret.dropshuffle = 'keys' if ret.dropshuffle == 'none' and keydropshuffle else ret.dropshuffle
ret.pottery = get_choice('pottery') if 'pottery' in weights else 'none'
ret.pottery = 'keys' if ret.pottery == 'none' and keydropshuffle else ret.pottery
ret.colorizepots = get_choice_default('colorizepots', default='on') == 'on'
ret.shufflepots = get_choice('pot_shuffle') == 'on'
ret.aga_randomness = get_choice('aga_randomness') == 'on'
ret.colorizepots = get_choice_bool_default('colorizepots', default=True)
ret.shufflepots = get_choice_bool('pot_shuffle')
ret.aga_randomness = get_choice_bool('aga_randomness')
ret.mixed_travel = get_choice('mixed_travel') if 'mixed_travel' in weights else 'prevent'
ret.standardize_palettes = (get_choice('standardize_palettes') if 'standardize_palettes' in weights
else 'standardize')
goal = get_choice('goals')
goal = get_choice_default('goals', default='ganon')
if goal is not None:
ret.goal = {'ganon': 'ganon',
'fast_ganon': 'crystals',
@@ -134,9 +169,9 @@ def roll_settings(weights):
ret.openpyramid = get_choice('open_pyramid') if 'open_pyramid' in weights else 'auto'
ret.shuffleganon = get_choice('shuffleganon') == 'on'
ret.shufflelinks = get_choice('shufflelinks') == 'on'
ret.shuffletavern = get_choice('shuffletavern') == 'on'
ret.shuffleganon = get_choice_bool('shuffleganon')
ret.shufflelinks = get_choice_bool('shufflelinks')
ret.shuffletavern = get_choice_bool('shuffletavern')
ret.crystals_gt = get_choice('tower_open')
ret.crystals_ganon = get_choice('ganon_open')
@@ -154,12 +189,12 @@ def roll_settings(weights):
if ret.mode == 'retro':
ret.mode = 'open'
ret.retro = True
ret.retro = get_choice('retro') == 'on' # this overrides world_state if used
ret.retro = get_choice_bool('retro') # this overrides world_state if used
ret.take_any = get_choice_default('take_any', default='none')
ret.bombbag = get_choice('bombbag') == 'on'
ret.bombbag = get_choice_bool('bombbag')
ret.hints = get_choice('hints') == 'on'
ret.hints = get_choice_bool('hints')
swords = get_choice('weapons')
if swords is not None:
@@ -196,6 +231,7 @@ def roll_settings(weights):
ret.enemy_damage = damage_choice
ret.enemy_health = get_choice('enemy_health')
ret.any_enemy_logic = get_choice('any_enemy_logic')
ret.beemizer = get_choice('beemizer') if 'beemizer' in weights else '0'
@@ -211,18 +247,17 @@ def roll_settings(weights):
if 'rom' in weights:
romweights = weights['rom']
ret.sprite = get_choice('sprite', romweights)
ret.disablemusic = get_choice('disablemusic', romweights) == 'on'
ret.quickswap = get_choice('quickswap', romweights) == 'on'
ret.reduce_flashing = get_choice('reduce_flashing', romweights) == 'on'
ret.msu_resume = get_choice('msu_resume', romweights) == 'on'
ret.disablemusic = get_choice_bool('disablemusic', romweights)
ret.quickswap = get_choice_bool('quickswap', romweights)
ret.reduce_flashing = get_choice_bool('reduce_flashing', romweights)
ret.fastmenu = get_choice('menuspeed', romweights)
ret.heartcolor = get_choice('heartcolor', romweights)
ret.heartbeep = get_choice('heartbeep', romweights)
ret.heartbeep = get_choice_non_bool('heartbeep', romweights)
ret.ow_palettes = get_choice('ow_palettes', romweights)
ret.uw_palettes = get_choice('uw_palettes', romweights)
ret.shuffle_sfx = get_choice('shuffle_sfx', romweights) == 'on'
ret.shuffle_sfxinstruments = get_choice('shuffle_sfxinstruments', romweights) == 'on'
ret.shuffle_songinstruments = get_choice('shuffle_songinstruments', romweights) == 'on'
ret.msu_resume = get_choice('msu_resume', romweights) == 'on'
ret.shuffle_sfx = get_choice_bool('shuffle_sfx', romweights)
ret.shuffle_sfxinstruments = get_choice_bool('shuffle_sfxinstruments', romweights)
ret.shuffle_songinstruments = get_choice_bool('shuffle_songinstruments', romweights)
ret.msu_resume = get_choice_bool('msu_resume', romweights)
return ret