diff --git a/BaseClasses.py b/BaseClasses.py index 60d04d82..c361ef82 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -87,7 +87,7 @@ class World(object): self._portal_cache = {} self.sanc_portal = {} self.fish = BabelFish() - self.pot_contents = {} + self.data_tables = {} for player in range(1, players + 1): def set_player_attr(attr, val): @@ -151,6 +151,7 @@ class World(object): set_player_attr('exp_cache', defaultdict(dict)) set_player_attr('enabled_entrances', {}) + set_player_attr('data_tables', None) def finish_init(self): for player in range(1, self.players + 1): @@ -393,7 +394,7 @@ class World(object): item.location = location item.world = self if location.player != item.player and location.type == LocationType.Pot: - self.pot_contents[location.player].multiworld_count += 1 + self.data_tables[location.player].pot_secret_table.multiworld_count += 1 if collect: self.state.collect(item, location.event, location) @@ -2136,6 +2137,7 @@ class Location(object): self.skip = False self.type = LocationType.Normal if not crystal else LocationType.Prize self.pot = None + self.drop = None def can_fill(self, state, item, check_access=True): if not self.valid_multiworld(state, item): @@ -2144,7 +2146,7 @@ class Location(object): def valid_multiworld(self, state, item): if self.type == LocationType.Pot and self.player != item.player: - return state.world.pot_contents[self.player].multiworld_count < 256 + return state.world.data_tables[self.player].pot_secret_table.multiworld_count < 256 return True def can_reach(self, state): diff --git a/Fill.py b/Fill.py index 4ebd4c04..6ae73dcf 100644 --- a/Fill.py +++ b/Fill.py @@ -581,7 +581,7 @@ def fast_fill_pot_for_multiworld(world, item_pool, fill_locations): if loc.type == LocationType.Pot: pot_fill_locations[loc.player].append(loc) for player in range(1, world.players+1): - flex = 256 - world.pot_contents[player].multiworld_count + flex = 256 - world.data_tables[player].pot_secret_table.multiworld_count fill_count = len(pot_fill_locations[player]) - flex if fill_count > 0: fill_spots = random.sample(pot_fill_locations[player], fill_count) diff --git a/Main.py b/Main.py index 2db44f17..7ed757cc 100644 --- a/Main.py +++ b/Main.py @@ -32,6 +32,8 @@ from source.item.FillUtil import create_item_pool_config, massage_item_pool, dis from source.overworld.EntranceShuffle2 import link_entrances_new from source.tools.BPS import create_bps_from_data from source.classes.CustomSettings import CustomSettings +from source.rom.DataTables import init_data_tables + __version__ = '1.0.1.3-x' @@ -186,6 +188,7 @@ def main(args, seed=None, fish=None): create_doors(world, player) create_rooms(world, player) create_dungeons(world, player) + world.data_tables[player] = init_data_tables(world, player) adjust_locations(world, player) place_bosses(world, player) diff --git a/PotShuffle.py b/PotShuffle.py index ec6536ef..d2d2547a 100644 --- a/PotShuffle.py +++ b/PotShuffle.py @@ -919,14 +919,14 @@ def shuffle_pots(world, player): new_pot_contents.room_map[super_tile] = new_pots - world.pot_contents[player] = new_pot_contents + world.data_tables[player].pot_secret_table = new_pot_contents def shuffle_pot_switches(world, player): import RaceRandom as random for super_tile in vanilla_pots: - new_pots = world.pot_contents[player].room_map[super_tile] + new_pots = world.data_tables[player].pot_secret_table.room_map[super_tile] # sort in the order Hole, Switch, Key, Other, Nothing sort_order = {PotItem.Hole: 4, PotItem.Switch: 3, PotItem.Key: 2, PotItem.Nothing: 0} old_pots = sorted(new_pots, key=lambda pot: sort_order.get(pot.item, 1), reverse=True) diff --git a/Regions.py b/Regions.py index 203a564a..93a88093 100644 --- a/Regions.py +++ b/Regions.py @@ -3,6 +3,8 @@ from Items import ItemFactory from BaseClasses import Region, Location, Entrance, RegionType, Shop, ShopType, LocationType, PotItem, PotFlags from PotShuffle import key_drop_data, vanilla_pots, choose_pots, PotSecretTable +from source.dungeon.EnemyList import setup_enemy_locations + def create_regions(world, player): world.regions += [ @@ -1005,7 +1007,7 @@ def create_shops(world, player): def adjust_locations(world, player): # handle pots - world.pot_contents[player] = PotSecretTable() + world.data_tables[player].pot_secret_table = PotSecretTable() for location, datum in key_drop_data.items(): loc = world.get_location(location, player) drop_location = 'Drop' == datum[0] @@ -1013,6 +1015,7 @@ def adjust_locations(world, player): loc.type = LocationType.Drop snes_address, room, sprite_idx = datum[1] loc.address = snes_address + world.data_tables[player].uw_enemy_table.room_map[room][sprite_idx].location = loc else: loc.type = LocationType.Pot pot, pot_index = next((p, i) for i, p in enumerate(vanilla_pots[datum[1]]) if p.item == PotItem.Key) @@ -1044,7 +1047,7 @@ def adjust_locations(world, player): pot = world.get_location(loc, player).pot else: pot = pot_orig.copy() - world.pot_contents[player].room_map[super_tile].append(pot) + world.data_tables[player].pot_secret_table.room_map[super_tile].append(pot) if valid_pot_location(pot, world.pot_pool[player], world, player): create_pot_location(pot, pot_index, super_tile, world, player) @@ -1057,6 +1060,7 @@ def adjust_locations(world, player): loc.type = LocationType.Shop # player address? it is in the shop table index += 1 + setup_enemy_locations(world, player) # unreal events: for l in ['Ganon', 'Agahnim 1', 'Agahnim 2', 'Dark Blacksmith Ruins', 'Frog', 'Missing Smith', 'Floodgate', 'Trench 1 Switch', 'Trench 2 Switch', 'Swamp Drain', 'Attic Cracked Floor', 'Suspicious Maiden', @@ -1180,7 +1184,7 @@ flooded_keys_reverse = { 'Swamp Palace - Trench 2 Pot Key': 'Trench 2 Switch' } -lookup_id_to_name = {data[0]: name for name, data in location_table.items() if type(data[0]) == int} + location_table = {'Mushroom': (0x180013, 0x186df8, False, 'in the woods'), 'Bottle Merchant': (0x2eb18, 0x186df9, False, 'with a merchant'), 'Flute Spot': (0x18014a, 0x186dfd, False, 'underground'), @@ -1457,6 +1461,7 @@ location_table = {'Mushroom': (0x180013, 0x186df8, False, 'in the woods'), 'Potion Shop - Middle': (None, None, False, 'for sale near potions'), 'Potion Shop - Right': (None, None, False, 'for sale near potions'), } +lookup_id_to_name = {data[0]: name for name, data in location_table.items() if type(data[0]) == int} lookup_id_to_name.update(shop_table_by_location_id) lookup_name_to_id = {name: data[0] for name, data in location_table.items() if type(data[0]) == int} lookup_name_to_id.update(shop_table_by_location) diff --git a/Rom.py b/Rom.py index 26b54dbf..22b534bd 100644 --- a/Rom.py +++ b/Rom.py @@ -37,7 +37,7 @@ from source.dungeon.RoomList import Room0127 JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '61c296effe6180274721d570d2471e1c' +RANDOMIZERBASEHASH = '0587709ac8c5f2abf95b14d1e1264945' class JsonRom(object): @@ -1539,20 +1539,11 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): if room.player == player and room.modified: rom.write_bytes(room.address(), room.rom_data()) - if world.pottery[player] not in ['none']: - rom.write_bytes(snes_to_pc(0x1F8375), int32_as_bytes(0x2B8000)) - # make hammer pegs use different tiles - Room0127.write_to_rom(snes_to_pc(0x2B8000), rom) - - if world.pot_contents[player]: + if world.data_tables[player]: colorize_pots = is_mystery or (world.pottery[player] not in ['vanilla', 'lottery'] and (world.colorizepots[player] or world.pottery[player] in ['reduced', 'clustered'])) - if world.pot_contents[player].size() > 0x11c0: - raise Exception('Pot table is too big for current area') - world.pot_contents[player].write_pot_data_to_rom(rom, colorize_pots) - - # todo: write sprites + world.data_tables[player].write_to_rom(rom) write_strings(rom, world, player, team) diff --git a/Utils.py b/Utils.py index a4e3cee2..74e79d61 100644 --- a/Utils.py +++ b/Utils.py @@ -14,6 +14,11 @@ def int16_as_bytes(value): return [value & 0xFF, (value >> 8) & 0xFF] +def int24_as_bytes(value): + value = value & 0xFFFFFF + return [value & 0xFF, (value >> 8) & 0xFF, (value >> 16) & 0xFF] + + def int32_as_bytes(value): value = value & 0xFFFFFFFF return [value & 0xFF, (value >> 8) & 0xFF, (value >> 16) & 0xFF, (value >> 24) & 0xFF] diff --git a/data/base2current.bps b/data/base2current.bps index 03d6471e..52a73ada 100644 Binary files a/data/base2current.bps and b/data/base2current.bps differ diff --git a/source/dungeon/EnemyList.py b/source/dungeon/EnemyList.py index 37e5e627..732990cd 100644 --- a/source/dungeon/EnemyList.py +++ b/source/dungeon/EnemyList.py @@ -542,21 +542,21 @@ def init_vanilla_sprites(): create_sprite(0x0004, EnemySprite.Blob, 0x00, 0, 0x1a, 0x1a, 'TR Tongue Pull') create_sprite(0x0004, EnemySprite.Blob, 0x00, 0, 0x15, 0x1b, 'TR Tongue Pull') create_sprite(0x0004, EnemySprite.Pokey, 0x00, 0, 0x07, 0x18, 'TR Dash Room') - create_sprite(0x0006, EnemySprite.Arrghus, 0x00, 0, 0x07, 0x17) - create_sprite(0x0006, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x17) - create_sprite(0x0006, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x17) - create_sprite(0x0006, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x17) - create_sprite(0x0006, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x17) - create_sprite(0x0006, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x17) - create_sprite(0x0006, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x17) - create_sprite(0x0006, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x17) - create_sprite(0x0006, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x17) - create_sprite(0x0006, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x17) - create_sprite(0x0006, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x17) - create_sprite(0x0006, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x17) - create_sprite(0x0006, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x17) - create_sprite(0x0006, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x17) - create_sprite(0x0007, EnemySprite.Moldorm, 0x00, 0, 0x12, 0x0e) + create_sprite(0x0006, EnemySprite.Arrghus, 0x00, 0, 0x07, 0x07) + create_sprite(0x0006, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07) + create_sprite(0x0006, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07) + create_sprite(0x0006, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07) + create_sprite(0x0006, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07) + create_sprite(0x0006, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07) + create_sprite(0x0006, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07) + create_sprite(0x0006, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07) + create_sprite(0x0006, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07) + create_sprite(0x0006, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07) + create_sprite(0x0006, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07) + create_sprite(0x0006, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07) + create_sprite(0x0006, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07) + create_sprite(0x0006, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07) + create_sprite(0x0007, EnemySprite.Moldorm, 0x00, 0, 0x9, 0x09) create_sprite(0x0008, EnemySprite.BigFairy, 0x00, 0, 0x07, 0x16) create_sprite(0x0009, EnemySprite.Medusa, 0x00, 0, 0x07, 0x08) create_sprite(0x0009, EnemySprite.Medusa, 0x00, 0, 0x08, 0x08) @@ -660,13 +660,13 @@ def init_vanilla_sprites(): create_sprite(0x001b, EnemySprite.RedEyegoreMimic, 0x00, 0, 0x07, 0x14, 'PoD Mimics 2') create_sprite(0x001b, EnemySprite.GreenEyegoreMimic, 0x00, 0, 0x03, 0x1c, 'PoD Mimics 2') create_sprite(0x001b, EnemySprite.GreenEyegoreMimic, 0x00, 0, 0x0c, 0x1c, 'PoD Mimics 2') - create_sprite(0x001c, EnemySprite.ArmosKnight, 0x00, 0, 0x14, 0x15) - create_sprite(0x001c, EnemySprite.ArmosKnight, 0x00, 0, 0x17, 0x15) - create_sprite(0x001c, EnemySprite.ArmosKnight, 0x00, 0, 0x1a, 0x15) - create_sprite(0x001c, EnemySprite.ArmosKnight, 0x00, 0, 0x1a, 0x18) - create_sprite(0x001c, EnemySprite.ArmosKnight, 0x00, 0, 0x17, 0x18) - create_sprite(0x001c, EnemySprite.ArmosKnight, 0x00, 0, 0x14, 0x18) - create_sprite(0x001c, 0x19, SpriteType.Overlord, 0, 0x17, 0x18) + create_sprite(0x001c, EnemySprite.ArmosKnight, 0x00, 0, 0x04, 0x05) + create_sprite(0x001c, EnemySprite.ArmosKnight, 0x00, 0, 0x07, 0x05) + create_sprite(0x001c, EnemySprite.ArmosKnight, 0x00, 0, 0x0a, 0x05) + create_sprite(0x001c, EnemySprite.ArmosKnight, 0x00, 0, 0x0a, 0x08) + create_sprite(0x001c, EnemySprite.ArmosKnight, 0x00, 0, 0x07, 0x08) + create_sprite(0x001c, EnemySprite.ArmosKnight, 0x00, 0, 0x04, 0x08) + create_sprite(0x001c, 0x19, SpriteType.Overlord, 0, 0x07, 0x08) create_sprite(0x001c, EnemySprite.Faerie, 0x00, 0, 0x07, 0x07) create_sprite(0x001c, EnemySprite.Faerie, 0x00, 0, 0x08, 0x07) create_sprite(0x001c, EnemySprite.Faerie, 0x00, 0, 0x07, 0x08) @@ -741,7 +741,7 @@ def init_vanilla_sprites(): 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, EnemySprite.Mothula, 0x00, 0, 0x08, 0x06) create_sprite(0x0029, 0x07, SpriteType.Overlord, 0, 0x07, 0x16) create_sprite(0x002a, EnemySprite.CrystalSwitch, 0x00, 0, 0x10, 0x17, 'PoD Arena Main') create_sprite(0x002a, EnemySprite.Bumper, 0x00, 0, 0x0f, 0x0f, 'PoD Arena Main') @@ -787,9 +787,9 @@ def init_vanilla_sprites(): create_sprite(0x0032, EnemySprite.Keese, 0x00, 0, 0x13, 0x0d, 'Sewers Dark Cross') create_sprite(0x0032, EnemySprite.Snake, 0x00, 0, 0x10, 0x0e, 'Sewers Dark Cross') create_sprite(0x0032, EnemySprite.Snake, 0x00, 0, 0x12, 0x0f, 'Sewers Dark Cross') - create_sprite(0x0033, EnemySprite.Lanmolas, 0x00, 0, 0x06, 0x17) - create_sprite(0x0033, EnemySprite.Lanmolas, 0x00, 0, 0x09, 0x17) - create_sprite(0x0033, EnemySprite.Lanmolas, 0x00, 0, 0x07, 0x19) + create_sprite(0x0033, EnemySprite.Lanmolas, 0x00, 0, 0x06, 0x07) + create_sprite(0x0033, EnemySprite.Lanmolas, 0x00, 0, 0x09, 0x07) + create_sprite(0x0033, EnemySprite.Lanmolas, 0x00, 0, 0x07, 0x09) create_sprite(0x0034, EnemySprite.Hover, 0x00, 0, 0x0f, 0x0b, 'Swamp West Shallows') create_sprite(0x0034, EnemySprite.Hover, 0x00, 0, 0x10, 0x12, 'Swamp West Shallows') create_sprite(0x0034, EnemySprite.Kyameron, 0x00, 0, 0x0f, 0x15, 'Swamp West Shallows') @@ -965,7 +965,7 @@ def init_vanilla_sprites(): create_sprite(0x004c, EnemySprite.MiniHelmasaur, 0x00, 0, 0x18, 0x0a, 'GT Frozen Over') create_sprite(0x004c, EnemySprite.MiniHelmasaur, 0x00, 0, 0x14, 0x15, 'GT Frozen Over') create_sprite(0x004c, EnemySprite.SpikeBlock, 0x00, 0, 0x13, 0x18, 'GT Frozen Over') - create_sprite(0x004d, EnemySprite.Moldorm, 0x00, 0, 0x0e, 0x0e) + create_sprite(0x004d, EnemySprite.Moldorm, 0x00, 0, 0x09, 0x09) create_sprite(0x004e, EnemySprite.Blob, 0x00, 0, 0x14, 0x08, 'Ice Narrow Corridor') create_sprite(0x004e, EnemySprite.Blob, 0x00, 0, 0x16, 0x08, 'Ice Narrow Corridor') create_sprite(0x004e, EnemySprite.Blob, 0x00, 0, 0x18, 0x08, 'Ice Narrow Corridor') @@ -1056,7 +1056,7 @@ def init_vanilla_sprites(): create_sprite(0x0059, EnemySprite.Gibdo, 0x00, 0, 0x17, 0x14, 'Skull East Bridge') create_sprite(0x0059, EnemySprite.Gibdo, 0x00, 1, 0x15, 0x15, 'Skull East Bridge') create_sprite(0x0059, EnemySprite.Gibdo, 0x00, 1, 0x1a, 0x15, 'Skull East Bridge') - create_sprite(0x005a, EnemySprite.HelmasaurKing, 0x00, 0, 0x17, 0x16) + create_sprite(0x005a, EnemySprite.HelmasaurKing, 0x00, 0, 0x07, 0x06) create_sprite(0x005b, EnemySprite.CrystalSwitch, 0x00, 1, 0x17, 0x0c) create_sprite(0x005b, EnemySprite.CrystalSwitch, 0x00, 1, 0x18, 0x13) create_sprite(0x005b, EnemySprite.SpikeBlock, 0x00, 1, 0x17, 0x15, 'GT Hidden Spikes') @@ -1169,9 +1169,9 @@ def init_vanilla_sprites(): create_sprite(0x006b, EnemySprite.Beamos, 0x00, 0, 0x1b, 0x15, 'GT Mimics 2') create_sprite(0x006b, EnemySprite.Beamos, 0x00, 0, 0x14, 0x1b, 'GT Mimics 2') create_sprite(0x006b, EnemySprite.RedEyegoreMimic, 0x00, 0, 0x18, 0x1b, 'GT Mimics 2') - create_sprite(0x006c, EnemySprite.Lanmolas, 0x00, 0, 0x06, 0x17, 'GT Lanmolas 2') - create_sprite(0x006c, EnemySprite.Lanmolas, 0x00, 0, 0x09, 0x17, 'GT Lanmolas 2') - create_sprite(0x006c, EnemySprite.Lanmolas, 0x00, 0, 0x07, 0x19, 'GT Lanmolas 2') + create_sprite(0x006c, EnemySprite.Lanmolas, 0x00, 0, 0x06, 0x07, 'GT Lanmolas 2') + create_sprite(0x006c, EnemySprite.Lanmolas, 0x00, 0, 0x09, 0x07, 'GT Lanmolas 2') + create_sprite(0x006c, EnemySprite.Lanmolas, 0x00, 0, 0x07, 0x09, 'GT Lanmolas 2') create_sprite(0x006c, EnemySprite.BunnyBeam, 0x00, 0, 0x17, 0x18, 'GT Beam Dash') create_sprite(0x006c, EnemySprite.Medusa, 0x00, 0, 0x03, 0x1c, 'GT Lanmolas 2') create_sprite(0x006d, EnemySprite.RedZazak, 0x00, 0, 0x05, 0x06, 'GT Gauntlet 4') @@ -1369,7 +1369,7 @@ def init_vanilla_sprites(): create_sprite(0x008e, EnemySprite.Blob, 0x00, 0, 0x16, 0x0a, 'Ice Lonely Freezor') create_sprite(0x008e, EnemySprite.Blob, 0x00, 0, 0x14, 0x0b, 'Ice Lonely Freezor') create_sprite(0x008e, EnemySprite.Blob, 0x00, 0, 0x18, 0x0b, 'Ice Lonely Freezor') - create_sprite(0x0090, EnemySprite.Vitreous, 0x00, 0, 0x07, 0x15) + create_sprite(0x0090, EnemySprite.Vitreous, 0x00, 0, 0x07, 0x05) create_sprite(0x0091, EnemySprite.CrystalSwitch, 0x00, 0, 0x18, 0x04, 'Mire Falling Foes') create_sprite(0x0091, EnemySprite.SpikeBlock, 0x00, 0, 0x1b, 0x0e, 'Mire Falling Foes') create_sprite(0x0091, 0x08, SpriteType.Overlord, 0, 0x17, 0x0f) @@ -1475,9 +1475,9 @@ def init_vanilla_sprites(): create_sprite(0x00a1, EnemySprite.Stalfos, 0x00, 0, 0x15, 0x19, 'Mire South Fish') create_sprite(0x00a1, EnemySprite.BunnyBeam, 0x00, 0, 0x17, 0x19, 'Mire South Fish') create_sprite(0x00a1, EnemySprite.Stalfos, 0x00, 0, 0x1b, 0x19, 'Mire South Fish') - create_sprite(0x00a4, EnemySprite.TrinexxRockHead, 0x00, 0, 0x07, 0x15) - create_sprite(0x00a4, EnemySprite.TrinexxFireHead, 0x00, 0, 0x07, 0x15) - create_sprite(0x00a4, EnemySprite.TrinexxIceHead, 0x00, 0, 0x07, 0x15) + create_sprite(0x00a4, EnemySprite.TrinexxRockHead, 0x00, 0, 0x07, 0x05) + create_sprite(0x00a4, EnemySprite.TrinexxFireHead, 0x00, 0, 0x07, 0x05) + create_sprite(0x00a4, EnemySprite.TrinexxIceHead, 0x00, 0, 0x07, 0x05) create_sprite(0x00a5, EnemySprite.Wizzrobe, 0x00, 0, 0x16, 0x05, 'GT Wizzrobes 2') create_sprite(0x00a5, EnemySprite.Wizzrobe, 0x00, 0, 0x19, 0x05, 'GT Wizzrobes 2') create_sprite(0x00a5, EnemySprite.Wizzrobe, 0x00, 0, 0x04, 0x07, 'GT Wizzrobes 1') @@ -1521,7 +1521,7 @@ def init_vanilla_sprites(): create_sprite(0x00ab, EnemySprite.SpikeBlock, 0x00, 0, 0x03, 0x19, 'Thieves Spike Switch') create_sprite(0x00ab, EnemySprite.SpikeBlock, 0x00, 0, 0x0c, 0x1a, 'Thieves Spike Switch') create_sprite(0x00ab, EnemySprite.SpikeBlock, 0x00, 0, 0x03, 0x1b, 'Thieves Spike Switch') - create_sprite(0x00ac, EnemySprite.Blind, 0x00, 0, 0x19, 0x15) + create_sprite(0x00ac, EnemySprite.Blind, 0x00, 0, 0x09, 0x05) create_sprite(0x00ae, EnemySprite.BlueBari, 0x00, 0, 0x13, 0x07, 'Iced T') create_sprite(0x00ae, EnemySprite.BlueBari, 0x00, 0, 0x15, 0x07, 'Iced T') create_sprite(0x00af, EnemySprite.FirebarCW, 0x00, 0, 0x0a, 0x08, 'Ice Catwalk') @@ -1688,13 +1688,13 @@ def init_vanilla_sprites(): create_sprite(0x00c6, EnemySprite.FloatingSkull, 0x00, 0, 0x10, 0x0e, 'TR Hub Ledges') create_sprite(0x00c6, EnemySprite.BlueBari, 0x00, 0, 0x18, 0x14, 'TR Hub Ledges') create_sprite(0x00c6, EnemySprite.BlueBari, 0x00, 0, 0x08, 0x17, 'TR Hub Ledges') - create_sprite(0x00c8, EnemySprite.ArmosKnight, 0x00, 0, 0x14, 0x15) - create_sprite(0x00c8, EnemySprite.ArmosKnight, 0x00, 0, 0x17, 0x15) - create_sprite(0x00c8, EnemySprite.ArmosKnight, 0x00, 0, 0x1a, 0x15) - create_sprite(0x00c8, EnemySprite.ArmosKnight, 0x00, 0, 0x1a, 0x18) - create_sprite(0x00c8, EnemySprite.ArmosKnight, 0x00, 0, 0x17, 0x18) - create_sprite(0x00c8, EnemySprite.ArmosKnight, 0x00, 0, 0x14, 0x18) - create_sprite(0x00c8, 0x19, SpriteType.Overlord, 0, 0x17, 0x18) + create_sprite(0x00c8, EnemySprite.ArmosKnight, 0x00, 0, 0x04, 0x05) + create_sprite(0x00c8, EnemySprite.ArmosKnight, 0x00, 0, 0x07, 0x05) + create_sprite(0x00c8, EnemySprite.ArmosKnight, 0x00, 0, 0x0a, 0x05) + create_sprite(0x00c8, EnemySprite.ArmosKnight, 0x00, 0, 0x0a, 0x08) + create_sprite(0x00c8, EnemySprite.ArmosKnight, 0x00, 0, 0x07, 0x08) + create_sprite(0x00c8, EnemySprite.ArmosKnight, 0x00, 0, 0x04, 0x08) + create_sprite(0x00c8, 0x19, SpriteType.Overlord, 0, 0x07, 0x08) create_sprite(0x00c9, EnemySprite.Popo2, 0x00, 0, 0x10, 0x05, 'Eastern Lobby Bridge') create_sprite(0x00c9, EnemySprite.Popo2, 0x00, 0, 0x0f, 0x06, 'Eastern Lobby Bridge') create_sprite(0x00c9, EnemySprite.Popo2, 0x00, 0, 0x10, 0x07, 'Eastern Lobby Bridge') @@ -1804,9 +1804,9 @@ def init_vanilla_sprites(): create_sprite(0x00dc, EnemySprite.Firesnake, 0x00, 1, 0x16, 0x17, 'Thieves Compass Room') create_sprite(0x00dc, EnemySprite.Firesnake, 0x00, 0, 0x05, 0x1c, 'Thieves Compass Room') create_sprite(0x00dc, EnemySprite.Blob, 0x00, 0, 0x0f, 0x1c, 'Thieves Compass Room') - create_sprite(0x00de, EnemySprite.KholdstareShell, 0x00, 0, 0x17, 0x05) - create_sprite(0x00de, EnemySprite.FallingIce, 0x00, 0, 0x17, 0x05) - create_sprite(0x00de, EnemySprite.Kholdstare, 0x00, 0, 0x17, 0x05) + create_sprite(0x00de, EnemySprite.KholdstareShell, 0x00, 0, 0x07, 0x05) + create_sprite(0x00de, EnemySprite.FallingIce, 0x00, 0, 0x07, 0x05) + create_sprite(0x00de, EnemySprite.Kholdstare, 0x00, 0, 0x07, 0x05) create_sprite(0x00df, EnemySprite.MiniMoldorm, 0x00, 1, 0x0c, 0x15, 'Paradox Cave') create_sprite(0x00df, EnemySprite.MiniMoldorm, 0x00, 1, 0x0c, 0x16, 'Paradox Cave') create_sprite(0x00e0, EnemySprite.BallNChain, 0x00, 0, 0x04, 0x06, 'Tower Gold Knights') @@ -2075,8 +2075,8 @@ class EnemyTable: 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) + list_offset += len(data) + rom.write_byte(data_pointer + list_offset, 0xff) data_pointer += list_offset + 1 else: rom.write_bytes(pointer_address + room * 2, int16_as_bytes(empty_pointer)) @@ -2090,23 +2090,16 @@ class EnemyTable: def setup_enemy_locations(world, player): - world.enemy_list[player] = EnemyTable() - for super_tile, enemy_list in vanilla_sprites.items(): + for super_tile, enemy_list in world.data_tables[player].uw_enemy_table.room_map.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) + if valid_drop_location(sprite, world, player): + create_drop_location(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? + # already has a location return False else: stat = enemy_stats[sprite.kind] diff --git a/source/dungeon/RoomHeader.py b/source/dungeon/RoomHeader.py index 13a4f7b7..37272724 100644 --- a/source/dungeon/RoomHeader.py +++ b/source/dungeon/RoomHeader.py @@ -315,7 +315,8 @@ class RoomHeader: 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) + room_offest = self.room_id*14 + rom.write_byte(base_address + room_offest + 3, self.sprite_sheet) def init_room_headers(): diff --git a/source/dungeon/RoomList.py b/source/dungeon/RoomList.py index ceff9405..11dd8a61 100644 --- a/source/dungeon/RoomList.py +++ b/source/dungeon/RoomList.py @@ -17,23 +17,25 @@ class Room: self.doors = doors def write_to_rom(self, address, rom): + offset = 0 rom.write_bytes(address, self.layout) - address += 2 + offset += 2 for obj in self.layer1: - rom.write_bytes(address, obj.data) - address += 3 - rom.write_bytes(address, [0xFF, 0xFF]) - address += 2 + rom.write_bytes(address + offset, obj.data) + offset += 3 + rom.write_bytes(address + offset, [0xFF, 0xFF]) + offset += 2 for obj in self.layer2: - rom.write_bytes(address, obj.data) - address += 3 - rom.write_bytes(address, [0xFF, 0xFF, 0xF0, 0xFF]) - address += 4 + rom.write_bytes(address + offset, obj.data) + offset += 3 + rom.write_bytes(address + offset, [0xFF, 0xFF, 0xF0, 0xFF]) + offset += 4 + door_start = offset for door in self.doors: - rom.write_bytes(address, door.get_bytes()) - address += 2 - rom.write_bytes(address, [0xFF, 0xFF]) - return address + 2 # where the data ended + rom.write_bytes(address + offset, door.get_bytes()) + offset += 2 + rom.write_bytes(address + offset, [0xFF, 0xFF]) + return door_start, offset + 2 # how many bytes were written Room0127 = Room([0xE1, 0x00], diff --git a/source/enemizer/EnemizerTestHarness.py b/source/enemizer/EnemizerTestHarness.py index 09395da1..a05c0d0c 100644 --- a/source/enemizer/EnemizerTestHarness.py +++ b/source/enemizer/EnemizerTestHarness.py @@ -1,3 +1,5 @@ +from types import SimpleNamespace + 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 @@ -6,7 +8,8 @@ import RaceRandom as random if __name__ == '__main__': random.seed(42) - data_tables = init_data_tables(None, None) + world = SimpleNamespace(pottery={1: 'none'}) + data_tables = init_data_tables(world, 1) randomize_underworld_sprite_sheets(data_tables.sprite_sheets) randomize_underworld_rooms(data_tables) diff --git a/source/rom/DataTables.py b/source/rom/DataTables.py index b05b319c..ab946c00 100644 --- a/source/rom/DataTables.py +++ b/source/rom/DataTables.py @@ -1,4 +1,4 @@ -from Utils import snes_to_pc +from Utils import snes_to_pc, int24_as_bytes, int16_as_bytes from source.dungeon.EnemyList import EnemyTable, init_vanilla_sprites, vanilla_sprites from source.dungeon.RoomHeader import init_room_headers @@ -9,32 +9,50 @@ from source.enemizer.SpriteSheets import init_sprite_sheets, init_sprite_require class DataTables: def __init__(self): self.room_headers = None - self.room_list = None # todo: for boss rando + self.room_list = None 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 + self.ow_enemy_table = None # todo : data migration + self.pot_secret_table = None # associated data self.sprite_requirements = None - def write_to_rom(self, rom): - for header in self.room_headers.values(): + def write_to_rom(self, rom, colorize_pots=False): + if self.pot_secret_table.size() > 0x11c0: + raise Exception('Pot table is too big for current area') + self.pot_secret_table.write_pot_data_to_rom(rom, colorize_pots) + for room_id, header in self.room_headers.items(): + data_location = (0x30DA00 + room_id * 14) & 0xFFFF + rom.write_bytes(snes_to_pc(0x04F1E2) + room_id * 2, int16_as_bytes(data_location)) header.write_to_rom(rom, snes_to_pc(0x30DA00)) # new header table, bank30, tables.asm - # room list + room_start_address = 0x378000 + for room_id, room in self.room_list.items(): + rom.write_bytes(0x1F8000 + room_id * 3, int24_as_bytes(room_start_address)) + door_start, bytes_written = room.write_to_rom(snes_to_pc(room_start_address), rom) + rom.write_bytes(0x1F83C0 + room_id * 3, int24_as_bytes(room_start_address + door_start)) + room_start_address += bytes_written + # todo: room data doors pointers at 1F83C0 + if room_start_address > 0x380000: + raise Exception('Room list exceeded bank size') + # size notes: bank 03 uses 140E bytes + # bank 0A uses 372A bytes + # bank 1F uses 77CE bytes: total is about a bank and a half + # probably should reuse bank 1F if writing all the rooms out for sheet in self.sprite_sheets.values(): - sheet.write_to_rom(snes_to_pc(0x00DB97)) # bank 00, SheetsTable_AA3 + sheet.write_to_rom(rom, snes_to_pc(0x00DB97)) # bank 00, SheetsTable_AA3 if self.uw_enemy_table.size() > 0x2800: raise Exception('Sprite table is too big for current area') self.uw_enemy_table.write_sprite_data_to_rom(rom) + # todo: write ow enemy table 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 + 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()