UW Enemizer Work

This commit is contained in:
aerinon
2022-09-26 14:07:41 -06:00
parent 5b4bcc02d4
commit 037a9479d8
20 changed files with 2287 additions and 271 deletions

View File

@@ -1,3 +1,4 @@
from collections import defaultdict
import math
import typing
@@ -6,11 +7,17 @@ try:
except ImportError:
from enum import IntFlag as FastEnum
import RaceRandom as random
from BaseClasses import Location, LocationType
from Items import ItemFactory
from Utils import snes_to_pc, pc_to_snes, int16_as_bytes
from source.logic.Rule import RuleFactory
# todo: bosses shifted coordinates
class EnemyStats:
def __init__(self, sprite, static, drop_flag=False, prize_pack=0, sub_type=0):
def __init__(self, sprite, static, drop_flag=False, prize_pack: typing.Union[tuple, int] = 0, sub_type=0):
self.sprite = sprite
self.sub_type = sub_type
self.static = static
@@ -21,11 +28,16 @@ class EnemyStats:
class EnemySprite(FastEnum):
CorrectPullSwitch = 0x04,
Raven = 0x00
Vulture = 0x01
CorrectPullSwitch = 0x04
WrongPullSwitch = 0x06
Octorok = 0x08
Moldorm = 0x09
Octorok4Way = 0x0a
Cucco = 0x0b
Buzzblob = 0x0d
Snapdragon = 0x0e
Octoballoon = 0x0f
OctoballoonBaby = 0x10
@@ -90,16 +102,20 @@ class EnemySprite(FastEnum):
BombGuard = 0x4a
GreenKnifeGuard = 0x4b
Geldman = 0x4c
Toppo = 0x4d
Popo = 0x4e
Popo2 = 0x4f
ArmosStatue = 0x51
KingZora = 0x52
ArmosKnight = 0x53
Lanmolas = 0x54
FireballZora = 0x55
Zora = 0x56
DesertStatue = 0x57
Crab = 0x58
LostWoodsBird = 0x59
LostWoodsSquirrel =0x5a
LostWoodsSquirrel = 0x5a
SparkCW = 0x5b
SparkCCW = 0x5c
RollerVerticalUp = 0x5d
@@ -159,8 +175,8 @@ class EnemySprite(FastEnum):
Pengator = 0x99
Kyameron = 0x9a
Wizzrobe = 0x9b
Zoro = 0x9c
Babasu = 0x9d
Zoro = 0x9c # babasu horizontal?
Babasu = 0x9d # babasu vertical?
GroveOstritch = 0x9e
GroveRabbit = 0x9f
GroveBird = 0xa0
@@ -171,6 +187,10 @@ class EnemySprite(FastEnum):
BlueZazak = 0xa5
RedZazak = 0xa6
Stalfos = 0xa7
GreenZirro = 0xa8
BlueZirro = 0xa9
Pikit = 0xaa
CrystalMaiden = 0xab
# ... OW
OldMan = 0xad
PipeDown = 0xae
@@ -179,9 +199,12 @@ class EnemySprite(FastEnum):
PipeLeft = 0xb1
GoodBee = 0xb2
PedestalPlaque = 0xb3
PurpleChest = 0xb4
BombShopGuy = 0xb5
Kiki = 0xb6
BlindMaiden = 0xb7
BullyPinkBall = 0xb9
Whirlpool = 0xba
Shopkeeper = 0xbb
Drunkard = 0xbc
@@ -206,14 +229,18 @@ class EnemySprite(FastEnum):
Lynel = 0xd0
BunnyBeam = 0xd1
FloppingFish = 0xd2
Stal = 0xd3
Stal = 0xd3 # alive skull rock?
DiggingGameNPC = 0xd5
Ganon = 0xd6
Faerie = 0xe3
SmallKey = 0xe4
FakeMasterSword = 0xe8
MagicShopAssistant = 0xe9
HeartPiece = 0xeb
SomariaPlatform = 0xed
CastleMantle = 0xee
MedallionTablet = 0xf2
class SpriteType(FastEnum):
@@ -222,7 +249,7 @@ class SpriteType(FastEnum):
def init_enemy_stats():
enemy_stats = {
stats = {
EnemySprite.CorrectPullSwitch: EnemyStats(EnemySprite.CorrectPullSwitch, True),
EnemySprite.WrongPullSwitch: EnemyStats(EnemySprite.WrongPullSwitch, True),
EnemySprite.Octorok: EnemyStats(EnemySprite.Octorok, False, True, 2),
@@ -417,6 +444,22 @@ def init_enemy_stats():
EnemySprite.CastleMantle: EnemyStats(EnemySprite.CastleMantle, True),
}
return stats
def handle_native_dungeon(location, itemid):
# Keys in their native dungeon should use the original item code for keys
if location.parent_region.dungeon:
if location.parent_region.dungeon.name == location.item.dungeon:
if location.item.bigkey:
return 0x32
if location.item.smallkey:
return 0x24
if location.item.map:
return 0x33
if location.item.compass:
return 0x25
return itemid
class Sprite(object):
@@ -432,15 +475,36 @@ class Sprite(object):
self.drops_item = drops_item
self.drop_item_kind = drop_item_kind
self.location = None
def copy(self):
return Sprite(self.super_tile, self.kind, self.sub_type, self.layer, self.tile_x, self.tile_y, self.region,
self.drops_item, self.drop_item_kind)
def sprite_data(self):
data = [(self.layer << 7) | ((self.sub_type & 0x18) << 2) | self.tile_y,
((self.sub_type & 7) << 5) | self.tile_x, self.kind]
if self.location is not None:
item_id = self.location.item.code if self.location.item is not None else 0x5A
code = 0xF9 if self.location.item.player != self.location.player else 0xF8
if code == 0xF8:
item_id = handle_native_dungeon(self.location, item_id)
data.append(item_id)
data.append(0 if code == 0xF8 else self.location.item.player)
data.append(code)
return data
# map of super_tile to list of Sprite objects:
vanilla_sprites = {}
enemy_stats = {}
def create_sprite(super_tile, kind, sub_type, layer, tile_x, tile_y, region=None, drops_item=False, drop_item_kind=None):
def create_sprite(super_tile, kind, sub_type, layer, tile_x, tile_y, region=None,
drops_item=False, drop_item_kind=None):
if super_tile not in vanilla_sprites:
vanilla_sprites[super_tile] = []
vanilla_sprites[super_tile].append(Sprite(kind, sub_type, layer, tile_x, tile_y,
vanilla_sprites[super_tile].append(Sprite(super_tile, kind, sub_type, layer, tile_x, tile_y,
region, drops_item, drop_item_kind))
@@ -672,22 +736,22 @@ def init_vanilla_sprites():
create_sprite(0x0027, EnemySprite.SparkCW, 0x00, 0, 0x0f, 0x06, 'Hera Big Chest Landing')
create_sprite(0x0027, EnemySprite.Kondongo, 0x00, 0, 0x05, 0x0e, 'Hera 4F')
create_sprite(0x0027, EnemySprite.Kondongo, 0x00, 0, 0x04, 0x16, 'Hera 4F')
create_sprite(0x0028, EnemySprite.Kyameron, 0x00, 0, 0x0a, 0x06, 'Hera 4F')
create_sprite(0x0028, EnemySprite.Kyameron, 0x00, 0, 0x0a, 0x06, 'Swamp Entrance')
create_sprite(0x0028, EnemySprite.Hover, 0x00, 0, 0x08, 0x08, 'Swamp Entrance')
create_sprite(0x0028, EnemySprite.Hover, 0x00, 0, 0x0b, 0x0a, 'Swamp Entrance')
create_sprite(0x0028, EnemySprite.Hover, 0x00, 0, 0x07, 0x0d, 'Swamp Entrance')
create_sprite(0x0028, EnemySprite.SpikeBlock, 0x00, 0, 0x08, 0x10, 'Swamp Entrance')
create_sprite(0x0029, EnemySprite.Mothula, 0x00, 0, 0x18, 0x16)
create_sprite(0x0029, 0x07, SpriteType.Overlord, 0, 0x07, 0x16)
create_sprite(0x002a, EnemySprite.CrystalSwitch, 0x00, 0, 0x10, 0x17)
create_sprite(0x002a, EnemySprite.Bumper, 0x00, 0, 0x0f, 0x0f)
create_sprite(0x002a, EnemySprite.CrystalSwitch, 0x00, 0, 0x10, 0x17, 'PoD Arena Main')
create_sprite(0x002a, EnemySprite.Bumper, 0x00, 0, 0x0f, 0x0f, 'PoD Arena Main')
create_sprite(0x002a, EnemySprite.HardhatBeetle, 0x00, 0, 0x0d, 0x08, 'PoD Arena North')
create_sprite(0x002a, EnemySprite.HardhatBeetle, 0x00, 0, 0x07, 0x0c, 'PoD Arena Main')
create_sprite(0x002a, EnemySprite.HardhatBeetle, 0x00, 0, 0x10, 0x0c, 'PoD Arena Main')
create_sprite(0x002a, EnemySprite.HardhatBeetle, 0x00, 0, 0x0d, 0x0f, 'PoD Arena Main')
create_sprite(0x002a, EnemySprite.HardhatBeetle, 0x00, 0, 0x13, 0x11, 'PoD Arena Main')
create_sprite(0x002a, EnemySprite.HardhatBeetle, 0x00, 0, 0x0f, 0x13, 'PoD Arena Main')
create_sprite(0x002b, EnemySprite.CrystalSwitch, 0x00, 0, 0x0a, 0x11, 'PoD Arena Main')
create_sprite(0x002b, EnemySprite.CrystalSwitch, 0x00, 0, 0x0a, 0x11)
create_sprite(0x002b, EnemySprite.Statue, 0x00, 0, 0x0a, 0x0a)
create_sprite(0x002b, EnemySprite.RedBari, 0x00, 0, 0x07, 0x17, 'PoD Map Balcony')
create_sprite(0x002b, EnemySprite.Faerie, 0x00, 0, 0x16, 0x17)
@@ -776,9 +840,9 @@ def init_vanilla_sprites():
create_sprite(0x0039, 0x09, SpriteType.Overlord, 0, 0x0f, 0x0f)
create_sprite(0x0039, EnemySprite.Gibdo, 0x00, 0, 0x05, 0x15, 'Skull Spike Corner', True, 0xe4)
create_sprite(0x0039, EnemySprite.MiniHelmasaur, 0x00, 0, 0x09, 0x15, 'Skull Spike Corner')
create_sprite(0x0039, EnemySprite.SpikeBlock, 0x00, 0, 0x17, 0x16, 'Skull Spike Corner')
create_sprite(0x0039, EnemySprite.SpikeBlock, 0x00, 0, 0x17, 0x16, 'Skull Final Drop')
create_sprite(0x0039, EnemySprite.HardhatBeetle, 0x00, 0, 0x0b, 0x18, 'Skull Spike Corner')
create_sprite(0x0039, EnemySprite.SpikeBlock, 0x00, 0, 0x17, 0x1a, 'Skull Spike Corner')
create_sprite(0x0039, EnemySprite.SpikeBlock, 0x00, 0, 0x17, 0x1a, 'Skull Final Drop')
create_sprite(0x003a, EnemySprite.Terrorpin, 0x00, 0, 0x0e, 0x11, 'PoD Pit Room',)
create_sprite(0x003a, EnemySprite.Terrorpin, 0x00, 0, 0x11, 0x11, 'PoD Pit Room',)
create_sprite(0x003a, EnemySprite.Medusa, 0x00, 0, 0x04, 0x14, 'PoD Pit Room',)
@@ -1920,6 +1984,8 @@ def init_vanilla_sprites():
create_sprite(0x0126, EnemySprite.Faerie, 0x00, 0, 0x08, 0x16)
create_sprite(0x0126, EnemySprite.HeartPiece, 0x00, 0, 0x1c, 0x14)
create_sprite(0x0127, EnemySprite.HeartPiece, 0x00, 0, 0x07, 0x16)
global enemy_stats
enemy_stats = init_enemy_stats()
def kill_rules(world, player, stats):
@@ -1984,6 +2050,132 @@ def kill_rules(world, player, stats):
return defeat_rules
layered_oam_rooms = {
0x14, 0x15, 0x51, 0x59, 0x5b, 0x60, 0x62, 0x81, 0x86, 0xa8, 0xaa, 0xb2, 0xb9, 0xc2, 0xcb, 0xcc, 0xdb, 0xdc
}
class EnemyTable:
def __init__(self):
self.room_map = defaultdict(list)
self.multiworld_count = 0
def write_sprite_data_to_rom(self, rom):
pointer_address = snes_to_pc(0x09D62E)
data_pointer = snes_to_pc(0x288000)
empty_pointer = pc_to_snes(data_pointer) & 0xFFFF
rom.write_bytes(data_pointer, [0x00, 0xff])
data_pointer += 2
for room in range(0, 0x128):
if room in self.room_map:
data_address = pc_to_snes(data_pointer) & 0xFFFF
rom.write_bytes(pointer_address + room * 2, int16_as_bytes(data_address))
rom.write_byte(data_pointer, 0x01 if room in layered_oam_rooms else 0x00)
list_offset = 1
for sprite in self.room_map[room]:
data = sprite.sprite_data()
rom.write_bytes(data_pointer + list_offset, data)
list_offset + len(data)
rom.write_byte(data_pointer, 0xff)
data_pointer += list_offset + 1
else:
rom.write_bytes(pointer_address + room * 2, int16_as_bytes(empty_pointer))
def size(self):
size = 2
for room in range(0, 0x128):
if room in self.room_map:
size += sum(len(sprite.sprite_data()) for sprite in self.room_map[room]) + 2
return size
def setup_enemy_locations(world, player):
world.enemy_list[player] = EnemyTable()
for super_tile, enemy_list in vanilla_sprites.items():
for index, sprite in enumerate(enemy_list):
# if sprite.drops_item and sprite.drop_item_kind == 0xe4:
# # normal key drops
# pass
my_sprite = sprite.copy()
world.enemy_list[player].room_map[super_tile].append()
if valid_drop_location(my_sprite, world, player):
create_drop_location(my_sprite, index, super_tile, world, player)
def valid_drop_location(sprite, world, player):
if world.dropshuffle[player] == 'underworld':
if sprite.drops_item and sprite.drop_item_kind == 0xe4:
# already has a location -- hook it up?
return False
else:
stat = enemy_stats[sprite.kind]
return not stat.static and stat.drop_flag
def create_drop_location(sprite, index, super_tile, world, player):
address = drop_address(index, super_tile)
region_name = sprite.region
parent = world.get_region(region_name, player)
descriptor = f'Enemy #{index+1}'
modifier = parent.hint_text not in {'a storyteller', 'fairies deep in a cave', 'a spiky hint',
'a bounty of five items', 'the sick kid', 'Sahasrahla'}
hint_text = f'{"held by an enemy"} {"in" if modifier else "near"} {parent.hint_text}'
drop_location = Location(player, f'{region_name} {descriptor}', address, hint_text=hint_text, parent=parent)
world.dynamic_locations.append(drop_location)
drop_location.drop = sprite
sprite.location = drop_location
drop_location.type = LocationType.Drop
# todo: placeholder address
def drop_address(index, super_tile):
return 0x7f9000 + super_tile * 2 + (index << 24)
prize_pack_selector = {
0: ['Nothing'],
1: ['Small Heart', 'Small Heart', 'Small Heart', 'Small Heart',
'Rupee (1)', 'Small Heart', 'Small Heart', 'Rupee (1)'],
2: ['Rupees (5)', 'Rupee (1)', 'Rupees (5)', 'Rupees (20)',
'Rupees (5)', 'Rupee (1)', 'Rupees (5)', 'Rupees (5)'],
3: ['Big Magic', 'Small Magic', 'Small Magic', 'Rupees (5)',
'Big Magic', 'Small Magic', 'Small Heart', 'Small Magic'],
4: ['Single Bomb', 'Single Bomb', 'Single Bomb', 'Single Bomb',
'Single Bomb', 'Single Bomb', 'Bombs (10)', 'Single Bomb'],
5: ['Arrows (5)', 'Small Heart', 'Arrows (5)', 'Arrows (10)',
'Arrows (5)', 'Small Heart', 'Arrows (5)', 'Arrows (10)'],
6: ['Small Magic', 'Rupee (1)', 'Small Heart', 'Arrows (5)',
'Small Magic', 'Single Bomb', 'Rupee (1)', 'Small Heart'],
7: ['Small Heart', 'Fairy', 'Big Magic', 'Rupees (20)',
'Bombs (10)', 'Small Heart', 'Rupees (20)', 'Arrows (10)'],
}
def add_drop_contents(world, player):
retro_bow = world.bow_mode[player].startswith('retro')
index_selector = [0]*8
for super_tile, enemy_list in world.enemy_list[player].room_map.items():
for sprite in enemy_list:
if sprite.drops_item and sprite.drop_item_kind == 0xe4:
continue
else:
stat = enemy_stats[sprite.kind]
if not stat.static and stat.drop_flag:
pack = 0
if isinstance(stat.prize_pack, int):
pack = stat.prize_pack
elif isinstance(stat.prize_pack, tuple):
pack = random.choice(stat.prize_pack)
pack_contents = prize_pack_selector[pack]
idx = index_selector[pack]
index_selector[pack] = (idx + 1) % len(pack_contents)
item_name = pack_contents[idx]
item_name = 'Rupees (5)' if retro_bow and 'Arrows' in item_name else item_name
world.itempool.append(ItemFactory(item_name, player))
def or_rule(*rules):
return RuleFactory.disj(rules)
@@ -2126,3 +2318,218 @@ def can_shoot_arrows(world, player):
def can_use_bombs(world, player):
return or_rule(RuleFactory.static_rule(not world.bombag[player]), has('Bomb Upgrade (+10)', player))
enemy_names = {
0x00: 'Raven',
0x01: 'Vulture',
0x04: 'CorrectPullSwitch',
0x06: 'WrongPullSwitch',
0x08: 'Octorok',
0x09: 'Moldorm',
0x0a: 'Octorok4Way',
0x0b: 'Cucco',
0x0d: 'Buzzblob',
0x0e: 'Snapdragon',
0x0f: 'Octoballoon',
0x10: 'OctoballoonBaby',
0x11: 'Hinox',
0x12: 'Moblin',
0x13: 'MiniHelmasaur',
0x14: 'ThievesTownGrate',
0x15: 'AntiFairy',
0x16: 'Wiseman',
0x17: 'Hoarder',
0x18: 'MiniMoldorm',
0x19: 'Poe',
0x1a: 'Smithy',
0x1b: 'Arrow',
0x1c: 'Statue',
0x1d: 'FluteQuest',
0x1e: 'CrystalSwitch',
0x1f: 'SickKid',
0x20: 'Sluggula',
0x21: 'WaterSwitch',
0x22: 'Ropa',
0x23: 'RedBari',
0x24: 'BlueBari',
0x25: 'TalkingTree',
0x26: 'HardhatBeetle',
0x27: 'Deadrock',
0x28: 'DarkWorldHintNpc',
0x29: 'AdultNpc',
0x2a: 'SweepingLady',
0x2b: 'Hobo',
0x2c: 'Lumberjacks',
0x2d: 'TelepathicTile',
0x2e: 'FluteKid',
0x2f: 'RaceGameLady',
0x31: 'FortuneTeller',
0x32: 'ArgueBros',
0x33: 'RupeePull',
0x34: 'YoungSnitch',
0x35: 'Innkeeper',
0x36: 'Witch',
0x37: 'Waterfall',
0x38: 'EyeStatue',
0x39: 'Locksmith',
0x3a: 'MagicBat',
0x3b: 'BonkItem',
0x3c: 'KidInKak',
0x3d: 'OldSnitch',
0x3e: 'Hoarder2',
0x3f: 'TutorialGuard',
0x40: 'LightningGate',
0x41: 'BlueGuard',
0x42: 'GreenGuard',
0x43: 'RedSpearGuard',
0x44: 'BluesainBolt',
0x45: 'UsainBolt',
0x46: 'BlueArcher',
0x47: 'GreenBushGuard',
0x48: 'RedJavelinGuard',
0x49: 'RedBushGuard',
0x4a: 'BombGuard',
0x4b: 'GreenKnifeGuard',
0x4c: 'Geldman',
0x4d: 'Toppo',
0x4e: 'Popo',
0x4f: 'Popo2',
0x51: 'ArmosStatue',
0x52: 'KingZora',
0x53: 'ArmosKnight',
0x54: 'Lanmolas',
0x55: 'FireballZora',
0x56: 'Zora',
0x57: 'DesertStatue',
0x58: 'Crab',
0x59: 'LostWoodsBird',
0x5a: 'LostWoodsSquirrel',
0x5b: 'SparkCW',
0x5c: 'SparkCCW',
0x5d: 'RollerVerticalUp',
0x5e: 'RollerVerticalDown',
0x5f: 'RollerHorizontalLeft',
0x60: 'RollerHorizontalRight',
0x61: 'Beamos',
0x62: 'MasterSword',
0x63: 'DebirandoPit',
0x64: 'Debirando',
0x65: 'ArcheryNpc',
0x66: 'WallCannonVertLeft',
0x67: 'WallCannonVertRight',
0x68: 'WallCannonHorzTop',
0x69: 'WallCannonHorzBottom',
0x6a: 'BallNChain',
0x6b: 'CannonTrooper',
0x6d: 'CricketRat',
0x6e: 'Snake',
0x6f: 'Keese',
0x71: 'Leever',
0x72: 'FairyPondTrigger',
0x73: 'UnclePriest',
0x74: 'RunningNpc',
0x75: 'BottleMerchant',
0x76: 'Zelda',
0x78: 'Grandma',
0x7a: 'Agahnim',
0x7c: 'FloatingSkull',
0x7d: 'BigSpike',
0x7e: 'FirebarCW',
0x7f: 'FirebarCCW',
0x80: 'Firesnake',
0x81: 'Hover',
0x82: 'AntiFairyCircle',
0x83: 'GreenEyegoreMimic',
0x84: 'RedEyegoreMimic',
0x85: 'YellowStalfos', # falling stalfos that shoots head
0x86: 'Kondongo',
0x88: 'Mothula',
0x8a: 'SpikeBlock',
0x8b: 'Gibdo',
0x8c: 'Arrghus',
0x8d: 'Arrghi',
0x8e: 'Terrorpin',
0x8f: 'Blob',
0x90: 'Wallmaster',
0x91: 'StalfosKnight',
0x92: 'HelmasaurKing',
0x93: 'Bumper',
0x94: 'Pirogusu',
0x95: 'LaserEyeLeft',
0x96: 'LaserEyeRight',
0x97: 'LaserEyeTop',
0x98: 'LaserEyeBottom',
0x99: 'Pengator',
0x9a: 'Kyameron',
0x9b: 'Wizzrobe',
0x9c: 'Zoro', # babasu horizontal?
0x9d: 'Babasu', # babasu vertical?
0x9e: 'GroveOstritch',
0x9f: 'GroveRabbit',
0xa0: 'GroveBird',
0xa1: 'Freezor',
0xa2: 'Kholdstare',
0xa3: 'KholdstareShell',
0xa4: 'FallingIce',
0xa5: 'BlueZazak',
0xa6: 'RedZazak',
0xa7: 'Stalfos',
0xa8: 'GreenZirro',
0xa9: 'BlueZirro',
0xaa: 'Pikit',
0xab: 'CrystalMaiden',
# ... OW
0xad: 'OldMan',
0xae: 'PipeDown',
0xaf: 'PipeUp',
0xb0: 'PipeRight',
0xb1: 'PipeLeft',
0xb2: 'GoodBee',
0xb3: 'PedestalPlaque',
0xb4: 'PurpleChest',
0xb5: 'BombShopGuy',
0xb6: 'Kiki',
0xb7: 'BlindMaiden',
0xb9: 'BullyPinkBall',
0xba: 'Whirlpool',
0xbb: 'Shopkeeper',
0xbc: 'Drunkard',
0xbd: 'Vitreous',
# ... (spawnables)
0xc0: 'Catfish',
0xc1: 'CutsceneAgahnim',
0xc2: 'Boulder',
0xc3: 'Gibo', # patrick!
0xc4: 'Thief',
0xc5: 'Medusa',
0xc6: 'FourWayShooter',
0xc7: 'Pokey',
0xc8: 'BigFairy',
0xc9: 'Tektite', # firebat?
0xca: 'Chainchomp',
0xcb: 'TrinexxRockHead',
0xcc: 'TrinexxFireHead',
0xcd: 'TrinexxIceHead',
0xce: 'Blind',
0xcf: 'Swamola',
0xd0: 'Lynel',
0xd1: 'BunnyBeam',
0xd2: 'FloppingFish',
0xd3: 'Stal', # alive skull rock?
0xd5: 'DiggingGameNPC',
0xd6: 'Ganon',
0xe3: 'Faerie',
0xe4: 'SmallKey',
0xe8: 'FakeMasterSword',
0xe9: 'MagicShopAssistant',
0xeb: 'HeartPiece',
0xed: 'SomariaPlatform',
0xee: 'CastleMantle',
0xf2: 'MedallionTablet',
}

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,326 @@
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.sprite_sheet = byte_array[3]
def write_to_rom(self, rom, base_address):
rom.write_byte(base_address + self.room_id*14 + 3, self.sprite_sheet)
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,3 +1,9 @@
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

View File

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

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

@@ -0,0 +1,253 @@
import RaceRandom as random
from source.dungeon.EnemyList import SpriteType
from source.enemizer.SpriteSheets import uw_sub_group_choices, setup_required_dungeon_groups
water_rooms = {
0x16, 0x28, 0x34, 0x36, 0x38, 0x46, 0x66
} # these room need to be locked on the gfx ID : 17
# todo: task list
# anti-fairy shutter logic
# check cucco, implement flag for certain immune enemies that are okay in shutter rooms
# Room 0x16 (sprites 4,5,6 need to be water but 0-3 don't)
#
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, 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: {3, 4, 8}, 0x7d: {4, 5, 6, 7, 8}, 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}
}
water_sprites = {
0x16: {4, 5, 6}, 0x28: {0, 1, 2, 3}, 0x34: {0, 1, 2}, 0x36: {1, 2, 5, 7, 8}, 0x38: {0, 1, 2, 4, 5, 6},
}
# not really shutters: only tiles:
# 0xb6 TR Tile, TR Pokey 1, Chain chomp?
# 0x87 hera tile room?
# 0x3d gt minihelma?
# 0x8d gt tile room?
# 0x96 gt torch cross?
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 uw_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, 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
water_needed = room_id in water_rooms
for sheet in data_tables.sprite_sheets.values():
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:
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 water_needed:
if water_groups:
match_any_room_groups.update(water_groups)
for i in range(0, 4):
if water_sub_groups[i]:
match_any_sub_groups[i].update(water_sub_groups[i])
else: # exclude water stuff
exclude_all_groups.update(water_groups)
for i in range(0, 4):
exclude_all_sub_groups[i].update(water_sub_groups[i])
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:
str(sheet)
if match_all_room_groups and sheet 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 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 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 uw_candidate_sprites(data_tables):
requirements = data_tables.sprite_requirements
uw_sprite_candidates = []
uw_sheet_candidates = []
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
if not r.static and r.uw_valid 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])
uw_sprite_candidates.append(k)
for num in range(65, 124):
sheet = data_tables.sprite_sheets[num]
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
uw_sheet_candidates.append(sheet)
return uw_sprite_candidates, uw_sheet_candidates
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_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:
sprite_table[idx] = sprite
return sprite_table
# RandomizeRooms(optionFlags);
def randomize_underworld_rooms(data_tables):
# RoomCollection.RandomizeRoomSpriteGroups
# randomize room sprite sheets
specific = setup_specific_requirements(data_tables)
uw_candidates, uw_sheets = uw_candidate_sprites(data_tables)
for room_id in range(0, 0x128):
if room_id in {0, 1, 3, 6, 7, 0xd, 0x14, 0x1c, 0x20, 0x29, 0x30, 0x33,
0x4d, 0x5a, 0x7F, 0x90, 0xa4, 0xac, 0xc8, 0xde}:
continue
if room_id not in data_tables.uw_enemy_table.room_map:
continue
# sprite_reqs = data_tables.sprite_requirements
randomizeable_sprites = get_randomize_able_sprites(room_id, data_tables)
if randomizeable_sprites:
candidate_sheets = get_possible_sheets(room_id, data_tables, specific, uw_sheets)
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)
if room_id in water_rooms:
water_sprites = [x for x in candidate_sprites if x.water_only]
for i, sprite in randomizeable_sprites.items():
chosen = random.choice(water_sprites)
sprite.kind = chosen.sprite
else:
# todo: stal sprites
for i, sprite in randomizeable_sprites.items():
if sprite.drops_item:
key_sprites = [x for x in candidate_sprites if x.good_for_key_drop() and not x.water_only]
chosen = random.choice(key_sprites)
elif room_id in shutter_sprites and i in shutter_sprites[room_id]:
killable_sprite = [x for x in candidate_sprites if x.good_for_shutter() and not x.water_only]
chosen = random.choice(killable_sprite)
else:
non_water = [x for x in candidate_sprites if not x.water_only]
chosen = random.choice(non_water)
sprite.kind = chosen.sprite
# done with sprites
# done with rooms

View File

@@ -0,0 +1,19 @@
from source.dungeon.EnemyList import enemy_names, SpriteType
from source.enemizer.Enemizer import randomize_underworld_rooms
from source.enemizer.SpriteSheets import randomize_underworld_sprite_sheets
from source.rom.DataTables import init_data_tables
import RaceRandom as random
if __name__ == '__main__':
random.seed(42)
data_tables = init_data_tables(None, None)
randomize_underworld_sprite_sheets(data_tables.sprite_sheets)
randomize_underworld_rooms(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 sprite.sub_type == SpriteType.Overlord:
print(f' Overlord #{i+1} {hex(sprite.kind)}:')
else:
print(f' Enemy #{i+1} {enemy_names[sprite.kind]}:')

View File

@@ -0,0 +1,630 @@
from collections import defaultdict
import RaceRandom as random
from source.dungeon.EnemyList import EnemySprite, enemy_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.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 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):
return self.killable and not self.static and not self.dont_use and self.uw_valid
def good_for_key_drop(self):
return self.good_for_shutter() and self.can_drop
def __str__(self):
return f'Req for {enemy_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),
# todo: Buzzblob kill rule for mimics
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),
# todo: antifairy kill rule
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).no_drop().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).affix().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).no_drop().sub_group(0, 0x1f),
SpriteRequirement(EnemySprite.BlueBari).sub_group(0, 0x1f),
# todo: don't randomize red/blue bari in room 0x7F
SpriteRequirement(EnemySprite.TalkingTree).affix().sub_group(0, 0x15),
SpriteRequirement(EnemySprite.HardhatBeetle).sub_group(1, 0x1e),
# todo: deadrock kill rule for mimics (not sure why ice spike room...)
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).no_drop().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).no_drop().sub_group(2, 0x12).exclude({0x10c}),
SpriteRequirement(EnemySprite.Toppo).no_drop().sub_group(3, 0x11),
SpriteRequirement(EnemySprite.Popo).sub_group(1, 0x2c),
SpriteRequirement(EnemySprite.Popo2).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().uw_skip().sub_group(2, [0xc, 0x18]),
SpriteRequirement(EnemySprite.Zora).immerse().no_drop().uw_skip().sub_group(2, 0xc).sub_group(3, 0x44),
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).immune().sub_group(1, 0x2c).exclude(NoBeamosOrTrapRooms),
SpriteRequirement(EnemySprite.MasterSword).affix().sub_group(2, 0x37).sub_group(3, 0x36),
# these are excluded for now
SpriteRequirement(EnemySprite.DebirandoPit).skip().sub_group(0, 0x2f),
SpriteRequirement(EnemySprite.Debirando).skip().sub_group(0, 0x2f),
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).no_drop().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).no_drop().sub_group(0, 0x1f).exclude(NoFlyingRooms),
SpriteRequirement(EnemySprite.FirebarCW).immune().sub_group(0, 0x1f),
SpriteRequirement(EnemySprite.FirebarCCW).immune().sub_group(0, 0x1f),
# todo: don't randomize these in GT Torch Cross and TR Dark Ride? was that ever implemented?
SpriteRequirement(EnemySprite.Firesnake).immune().sub_group(0, 0x1f),
SpriteRequirement(EnemySprite.Hover).immerse().sub_group(2, 0x22).exclude(NoFlyingRooms),
# todo: leave them in swamp palace entrance...
SpriteRequirement(EnemySprite.AntiFairyCircle).skip().no_drop().sub_group(3, [0x52, 0x53]),
SpriteRequirement(EnemySprite.GreenEyegoreMimic).sub_group(2, 0x2e),
SpriteRequirement(EnemySprite.RedEyegoreMimic).sub_group(2, 0x2e),
# kodongos apparently broken?
SpriteRequirement(EnemySprite.Kondongo).skip().sub_group(2, 0x2a),
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),
# todo: wallmaster overlords
SpriteRequirement(EnemySprite.Wallmaster).immune().ow_skip().sub_group(2, 0x23)
.allow(WallmasterValidRooms),
SpriteRequirement(EnemySprite.StalfosKnight).sub_group(1, 0x10).exclude({0x10c}),
SpriteRequirement(EnemySprite.HelmasaurKing).exalt().sub_group(2, 0x3a).sub_group(3, 0x3e),
SpriteRequirement(EnemySprite.Bumper).affix().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),
# todo: leave them in swamp palace entrance...
SpriteRequirement(EnemySprite.Wizzrobe).sub_group(2, [0x25, 0x29]),
SpriteRequirement(EnemySprite.Zoro).no_drop().sub_group(1, 0x20),
SpriteRequirement(EnemySprite.Babasu).no_drop().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).no_drop().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).no_drop().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).immerse().no_drop().sub_group(3, 0x19),
SpriteRequirement(EnemySprite.Lynel).sub_group(3, 0x14),
SpriteRequirement(EnemySprite.BunnyBeam).affix(),
SpriteRequirement(EnemySprite.FloppingFish).uw_skip().immune(),
SpriteRequirement(EnemySprite.Stal).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).affix(),
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.MedallionTablet).affix().sub_group(2, 0x12),
# todo: overlord requirements
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}),
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
vanilla_sheets = [
(0x00, 0x49, 0x00, 0x00), (0x46, 0x49, 0x0C, 0x1D), (0x48, 0x49, 0x13, 0x1D), (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, 0x1D), (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):
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, 0x11a, 0x11c, 0x122})
sheets[did(7)].add_sprite_to_sheet([75, 77, 57, 54], {0x8, 0x2c, 0x114, 0x115}) # 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, 0x112, 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], [0x3e, 0x9f]), # babasu spawners
([31, None, None, None], [0x7f]), # force baris
([None, None, 35, None], [0x39, 0x49, 0x56, 0x57, 0x68, 0x8d]), # wallmasters
# bumpers - why the split - because of other requirements -
([None, None, None, (82, 83)], [0x17, 0x2a, 0x4c, 0x59, 0x67, 0x68, 0x7e, 0x8b, 0xeb, 0xfb]),
# crystal switches - split for some reason
([None, None, None, (82, 83)], [0xb, 0x13, 0x1b, 0x1e, 0x2a, 0x2b, 0x31, 0x3e, 0x5b, 0x6b, 0x77, 0xb7, 0x8b, 0x91, 0x92, 0x9b, 0x9d, 0xa1, 0xab, 0xb6, 0xbf, 0xc1, 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, 0x57, 0x6b, 0x7b]),
# non-optional
([None, None, None, 82], [0x2, 0x58, 0x64, 0x8c, 0x10b]), # pull switches
([None, None, None, 82], [0x1a, 0x3d, 0x44, 0x56, 0x5e, 0x7c, 0x95, 0xc3]), # collasping bridges
([None, None, None, 83], [0x4, 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...
]
# find home for the free_sheet_reqs
for pair in free_sheet_reqs:
groups, room_list = pair
possible_sheets = []
found_match = False
for num in range(65, 124):
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
break
if valid:
possible_sheets.append(sheet)
if not found_match:
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)
# RandomizeRooms(optionFlags);
# roomCollection.LoadRooms()
# roomCollection.RandomizeRoomSpriteGroups(spriteGroupCollection, optionFlags);
# more stuff
uw_sub_group_choices = {
0: [22, 31, 47, 14], # 70, 72 for guards
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]
}
def randomize_underworld_sprite_sheets(sheets):
setup_required_dungeon_groups(sheets)
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]:
sheet.locked[1] = True
sheet.sub_groups[1] = random.choice([13, 73])
for idx in range(0, 4):
if not sheet.locked[idx]:
sheet.sub_groups[idx] = random.choice(uw_sub_group_choices[idx])
# lock the group?

View File

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

View File

@@ -2,6 +2,7 @@ import RaceRandom as random
import logging
from collections import defaultdict
from source.dungeon.EnemyList import enemy_stats
from source.item.District import resolve_districts
from BaseClasses import PotItem, PotFlags
from DoorShuffle import validate_vanilla_reservation
@@ -421,19 +422,20 @@ 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
vanilla_mapping = {
'Green Pendant': ['Eastern Palace - Prize'],
'Red Pendant': ['Desert Palace - Prize', 'Tower of Hera - Prize'],

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

@@ -0,0 +1,45 @@
from Utils import snes_to_pc
from source.dungeon.EnemyList import EnemyTable, init_vanilla_sprites, vanilla_sprites
from source.dungeon.RoomHeader import init_room_headers
from source.dungeon.RoomList import Room0127
from source.enemizer.SpriteSheets import init_sprite_sheets, init_sprite_requirements
class DataTables:
def __init__(self):
self.room_headers = None
self.room_list = None # todo: for boss rando
self.sprite_sheets = None
self.uw_enemy_table = None
self.ow_enemy_tables = None # todo : data migration
self.pot_secret_table = None # todo : migrate storage
# associated data
self.sprite_requirements = None
def write_to_rom(self, rom):
for header in self.room_headers.values():
header.write_to_rom(rom, snes_to_pc(0x30DA00)) # new header table, bank30, tables.asm
# room list
for sheet in self.sprite_sheets.values():
sheet.write_to_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)
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()
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())
return data_tables

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

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