diff --git a/BaseClasses.py b/BaseClasses.py index a296dce2..6eb27720 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -242,6 +242,9 @@ class World(object): return dungeon raise RuntimeError('No such dungeon %s for player %d' % (dungeonname, player)) + def get_dungeons(self, player): + return [d for d in self.dungeons if d.player == player] + def get_door(self, doorname, player): if isinstance(doorname, Door): return doorname diff --git a/Main.py b/Main.py index b5466a4f..c6e0d618 100644 --- a/Main.py +++ b/Main.py @@ -315,34 +315,13 @@ def main(args, seed=None, fish=None): rom_names = [] jsonout = {} - enemized = False if not args.suppress_rom or args.bps: logger.info(world.fish.translate("cli","cli","patching.rom")) for team in range(world.teams): for player in range(1, world.players + 1): - sprite_random_on_hit = type(args.sprite[player]) is str and args.sprite[player].lower() == 'randomonhit' - use_enemizer = (world.boss_shuffle[player] != 'none' or world.enemy_shuffle[player] != 'none' - or world.enemy_health[player] != 'default' or world.enemy_damage[player] != 'default' - or sprite_random_on_hit) + rom = JsonRom() if args.jsonout else LocalRom(args.rom) - rom = JsonRom() if args.jsonout or use_enemizer else LocalRom(args.rom) - - if use_enemizer and (args.enemizercli or not args.jsonout): - local_rom = LocalRom(args.rom) # update base2current.json (side effect) - if args.rom and not(os.path.isfile(args.rom)): - raise RuntimeError("Could not find valid base rom for enemizing at expected path %s." % args.rom) - if os.path.exists(args.enemizercli): - patch_enemizer(world, player, rom, local_rom, args.enemizercli, sprite_random_on_hit) - enemized = True - if not args.jsonout: - rom = LocalRom.fromJsonRom(rom, args.rom, 0x400000) - else: - enemizerMsg = world.fish.translate("cli","cli","enemizer.not.found") + ': ' + args.enemizercli + "\n" - enemizerMsg += world.fish.translate("cli","cli","enemizer.nothing.applied") - logging.warning(enemizerMsg) - raise EnemizerError(enemizerMsg) - - patch_rom(world, rom, player, team, enemized, bool(args.mystery)) + patch_rom(world, rom, player, team, bool(args.mystery)) if args.race: patch_race_rom(rom) @@ -417,7 +396,6 @@ def main(args, seed=None, fish=None): logger.info(world.fish.translate("cli","cli","made.rom") % (YES if (args.create_rom) else NO)) logger.info(world.fish.translate("cli","cli","made.playthrough") % (YES if (args.calc_playthrough) else NO)) logger.info(world.fish.translate("cli","cli","made.spoiler") % (YES if (not args.jsonout and args.create_spoiler) else NO)) - logger.info(world.fish.translate("cli","cli","used.enemizer") % (YES if enemized else NO)) logger.info(world.fish.translate("cli","cli","seed") + ": %s", world.seed) logger.info(world.fish.translate("cli","cli","total.time"), time.perf_counter() - start) diff --git a/Rom.py b/Rom.py index dc08f9d3..ca9de066 100644 --- a/Rom.py +++ b/Rom.py @@ -34,10 +34,11 @@ from InitialSram import InitialSram from source.classes.SFX import randomize_sfx from source.item.FillUtil import valid_pot_items from source.dungeon.EnemyList import EnemySprite +from source.enemizer.Bossmizer import boss_writes JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '81d7cf07a34d06ec875074296c39cd97' +RANDOMIZERBASEHASH = 'c9bf2a8b285fc8cdb98c30844bc3c821' class JsonRom(object): @@ -344,19 +345,6 @@ def patch_enemizer(world, player, rom, local_rom, enemizercli, random_sprite_on_ for patch in json.load(f): rom.write_bytes(patch["address"], patch["patchData"]) - if world.get_dungeon("Thieves Town", player).boss.enemizer_name == "Blind": - rom.write_byte(0x04DE81, 0x6) # maiden spawn - # restore blind spawn code - necessary because the old enemizer clobbers this stuff - # this line could be commented out if ijwu's enemizer is used exclusively - # if keeping this line, note the jump to the dr_baserom's enemizer section - rom.write_bytes(0xEA081, [0x5c, 0x00, 0x80, 0xb7, 0xc9, 0x6, 0xf0, 0x24, - 0xad, 0x3, 0x4, 0x29, 0x20, 0xf0, 0x1d]) - rom.write_byte(0x200101, 0) # Do not close boss room door on entry. - rom.write_byte(0x1B0101, 0) # Do not close boss room door on entry. (for Ijwu's enemizer) - else: - rom.write_byte(0x04DE83, 0xB3) # maiden is now something else - - if random_sprite_on_hit: _populate_sprite_table() sprites = list(_sprite_table.values()) @@ -585,7 +573,7 @@ def handle_native_dungeon(location, itemid): return itemid -def patch_rom(world, rom, player, team, enemized, is_mystery=False): +def patch_rom(world, rom, player, team, is_mystery=False): random.seed(world.rom_seeds[player]) # progressive bow silver arrow hint hack @@ -1241,8 +1229,6 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): if (world.shuffle[player] != 'vanilla' or world.doorShuffle[player] != 'vanilla' or world.dropshuffle[player] != 'none' or world.pottery[player] != 'none'): gametype |= 0x02 # entrance/door - if enemized: - gametype |= 0x01 # enemizer rom.write_byte(0x180211, gametype) # Game type # assorted fixes @@ -1427,9 +1413,9 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): rom.write_byte(0x180175, 0x01 if world.bow_mode[player].startswith('retro') else 0x00) # rupee bow rom.write_byte(0x180176, 0x0A if world.bow_mode[player].startswith('retro') else 0x00) # wood arrow cost rom.write_byte(0x180178, 0x32 if world.bow_mode[player].startswith('retro') else 0x00) # silver arrow cost - rom.write_byte(0x301FC, 0xDA if world.bow_mode[player].startswith('retro') else 0xE1) # rupees replace arrows under pots - if enemized: - rom.write_byte(0x1B152e, 0xDA if world.bow_mode[player].startswith('retro') else 0xE1) + # rupees replace arrows under pots for original and enemizer code + rom.write_byte(0x301FC, 0xDA if world.bow_mode[player].startswith('retro') else 0xE1) + rom.write_byte(snes_to_pc(0x36837D), 0xDA if world.bow_mode[player].startswith('retro') else 0xE1) rom.write_byte(0x30052, 0xDB if world.bow_mode[player].startswith('retro') else 0xE2) # replace arrows in fish prize from bottle merchant rom.write_bytes(0xECB4E, [0xA9, 0x00, 0xEA, 0xEA] if world.bow_mode[player].startswith('retro') else [0xAF, 0x77, 0xF3, 0x7E]) # Thief steals rupees instead of arrows rom.write_bytes(0xF0D96, [0xA9, 0x00, 0xEA, 0xEA] if world.bow_mode[player].startswith('retro') else [0xAF, 0x77, 0xF3, 0x7E]) # Pikit steals rupees instead of arrows @@ -1523,6 +1509,9 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): rom.write_byte(0xFED31, 0x0E) # preopen bombable exit rom.write_byte(0xFEE41, 0x0E) # preopen bombable exit + if world.boss_shuffle[player] != 'none': + boss_writes(world, player, rom) + # todo: combine this with data_tables for in place edits if (world.doorShuffle[player] != 'vanilla' or world.dropshuffle[player] != 'none' or world.pottery[player] != 'none'): diff --git a/data/base2current.bps b/data/base2current.bps index ff5041eb..21edfa06 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 295e6762..f7df3c92 100644 --- a/source/dungeon/EnemyList.py +++ b/source/dungeon/EnemyList.py @@ -405,7 +405,7 @@ def init_enemy_stats(): EnemySprite.GroveOstritch: EnemyStats(EnemySprite.GroveOstritch, True), EnemySprite.GroveRabbit: EnemyStats(EnemySprite.GroveRabbit, True), EnemySprite.GroveBird: EnemyStats(EnemySprite.GroveBird, True), - EnemySprite.Freezor: EnemyStats(EnemySprite.Freezor, True, True, 0, health=16), + EnemySprite.Freezor: EnemyStats(EnemySprite.Freezor, True, False, 0, health=16), EnemySprite.Kholdstare: EnemyStats(EnemySprite.Kholdstare, True), EnemySprite.KholdstareShell: EnemyStats(EnemySprite.KholdstareShell, True), EnemySprite.FallingIce: EnemyStats(EnemySprite.FallingIce, True), @@ -2169,7 +2169,7 @@ def add_drop_contents(world, player): continue elif sprite.sub_type != SpriteType.Overlord: stat = world.data_tables[player].enemy_stats[sprite.kind] - if not stat.static and stat.drop_flag: + if stat.drop_flag: pack = 0 if isinstance(stat.prize_pack, int): pack = stat.prize_pack @@ -2291,6 +2291,15 @@ def can_ether_kill(world, player, damage, health): else: return and_rule(has('Ether', player), has_sword(player)) + +def can_bombos_kill(world, player, damage, health): + magic_needed = math.ceil(health / damage) * 2 + if magic_needed > 8: + return and_rule(has('Bombos', player), has_sword(player), can_extend_magic(world, player, magic_needed)) + else: + return and_rule(has('Bombos', player), has_sword(player)) + + # main enemy types def defeat_rule(world, player, health, class1=1, arrow: typing.Optional[int] = 1, silver=1, @@ -2359,7 +2368,8 @@ special_rules_check = { def special_rules_for_region(world, player, region_name, location, original_rule, enemy): if region_name == 'Swamp Waterway': stats = world.data_tables[player].enemy_stats[enemy.kind] - return or_rule(can_quake_kill(world, player, 64, stats.health), can_ether_kill(world, player, 64, stats.health)) + return or_rule(can_quake_kill(world, player, 64, stats.health), can_ether_kill(world, player, 16, stats.health), + can_bombos_kill(world, player, 64, stats.health)) elif region_name in ['Hera Back', 'GT Petting Zoo', 'Mimic Cave']: enemy_number = int(location.name.split('#')[1]) if enemy_number in special_rules_check[region_name]: diff --git a/source/dungeon/RoomList.py b/source/dungeon/RoomList.py index 11dd8a61..e7636ff1 100644 --- a/source/dungeon/RoomList.py +++ b/source/dungeon/RoomList.py @@ -10,10 +10,11 @@ from source.dungeon.RoomObject import RoomObject, DoorObject class Room: - def __init__(self, layout, layer1, layer2, doors): + def __init__(self, layout, layer1, layer2, doors, layer3=None): self.layout = layout self.layer1 = layer1 self.layer2 = layer2 + self.layer3 = layer3 self.doors = doors def write_to_rom(self, address, rom): @@ -28,8 +29,14 @@ class Room: for obj in self.layer2: rom.write_bytes(address + offset, obj.data) offset += 3 - rom.write_bytes(address + offset, [0xFF, 0xFF, 0xF0, 0xFF]) - offset += 4 + rom.write_bytes(address + offset, [0xFF, 0xFF]) + offset += 2 + if self.layer3: + for obj in self.layer3: + rom.write_bytes(address + offset, obj.data) + offset += 3 + rom.write_bytes(address + offset, [0xF0, 0xFF]) + offset += 2 door_start = offset for door in self.doors: rom.write_bytes(address + offset, door.get_bytes()) @@ -38,6 +45,366 @@ class Room: return door_start, offset + 2 # how many bytes were written +Room0006 = Room([0xE1, 0x00], + [RoomObject(0x1FA15C, [0x1B, 0xA3, 0xC8]), + RoomObject(0x1FA15F, [0x58, 0xA3, 0xC8]), + RoomObject(0x1FA162, [0x1B, 0xD8, 0xC8]), + RoomObject(0x1FA165, [0x58, 0xD8, 0xC8]), + RoomObject(0x1FA168, [0x17, 0x9F, 0x3F]), + RoomObject(0x1FA16B, [0x54, 0x9F, 0x3F]), + RoomObject(0x1FA16E, [0x17, 0xA3, 0x79]), + RoomObject(0x1FA171, [0x14, 0xE1, 0x79]), + RoomObject(0x1FA174, [0x17, 0xEB, 0x40]), + RoomObject(0x1FA177, [0x54, 0xEB, 0x40]), + RoomObject(0x1FA17A, [0x6B, 0xA3, 0x7A]), + RoomObject(0x1FA17D, [0x68, 0xE1, 0x7A]), + RoomObject(0x1FA180, [0x21, 0x90, 0xF8]), + RoomObject(0x1FA183, [0x51, 0x90, 0xF8]), + RoomObject(0x1FA186, [0x0C, 0xA5, 0x7F]), + RoomObject(0x1FA189, [0x6C, 0xA5, 0x80])], + [], [DoorObject(Position.SouthW, DoorKind.Trap)]) + + +Room0007 = Room([0x81, 0x1C], + [RoomObject(0x1FCAF0, [0x0A, 0x4E, 0x0D]), + RoomObject(0x1FCAF3, [0x0A, 0xAA, 0x0E]), + RoomObject(0x1FCAF6, [0x0B, 0x51, 0x61]), + RoomObject(0x1FCAF9, [0xC0, 0x2C, 0xA2]), + RoomObject(0x1FCAFC, [0xB0, 0x20, 0x0F]), + RoomObject(0x1FCAFF, [0xB0, 0x22, 0x62]), + RoomObject(0x1FCB02, [0xFE, 0xC1, 0x02]), + RoomObject(0x1FCB05, [0xC9, 0x38, 0x01]), + RoomObject(0x1FCB08, [0xFF, 0xA3, 0x82]), + RoomObject(0x1FCB0B, [0xBA, 0xE6, 0x10]), + RoomObject(0x1FCB0E, [0xE8, 0xAA, 0x62]), + RoomObject(0x1FCB11, [0xFF, 0x43, 0xB9]), + RoomObject(0x1FCB14, [0x53, 0x53, 0xE0]), + RoomObject(0x1FCB17, [0x91, 0x53, 0xE0]), + RoomObject(0x1FCB1A, [0x53, 0x91, 0xE0]), + RoomObject(0x1FCB1D, [0x91, 0x91, 0xE0]), + RoomObject(0x1FCB20, [0x3C, 0x6B, 0xC2]), + RoomObject(0x1FCB23, [0x3D, 0x9B, 0xC3]), + RoomObject(0x1FCB26, [0x54, 0xA6, 0xC3]), + RoomObject(0x1FCB29, [0x5C, 0xAA, 0xC3]), + RoomObject(0x1FCB2C, [0x68, 0xB1, 0xC3]), + RoomObject(0x1FCB2F, [0x75, 0xB0, 0xC3]), + RoomObject(0x1FCB32, [0x8F, 0xB1, 0xC3]), + RoomObject(0x1FCB35, [0x9B, 0xAA, 0xC3]), + RoomObject(0x1FCB38, [0xA6, 0xA0, 0xC3]), + RoomObject(0x1FCB3B, [0xAD, 0x98, 0xC3]), + RoomObject(0x1FCB3E, [0xB4, 0x6A, 0xC2]), + RoomObject(0x1FCB41, [0x51, 0x3D, 0xC3]), + RoomObject(0x1FCB44, [0x45, 0x49, 0xC3]), + RoomObject(0x1FCB47, [0x3D, 0x51, 0xC3]), + RoomObject(0x1FCB4A, [0x9C, 0x39, 0xC2]), + RoomObject(0x1FCB4D, [0xA1, 0x49, 0xC3]), + RoomObject(0x1FCB50, [0xAD, 0x51, 0xC3]), + RoomObject(0x1FCB53, [0x3A, 0x50, 0x8A]), + RoomObject(0x1FCB56, [0x38, 0x50, 0x22]), + RoomObject(0x1FCB59, [0x44, 0x44, 0x69]), + RoomObject(0x1FCB5C, [0x44, 0x44, 0x22]), + RoomObject(0x1FCB5F, [0x58, 0x13, 0x05]), + RoomObject(0x1FCB62, [0x60, 0x15, 0x55]), + RoomObject(0x1FCB65, [0x78, 0x10, 0x3A]), + RoomObject(0x1FCB68, [0x08, 0x5B, 0x65]), + RoomObject(0x1FCB6B, [0x0C, 0x61, 0x7F]), + RoomObject(0x1FCB6E, [0xC8, 0x39, 0x05]), + RoomObject(0x1FCB71, [0xE8, 0x5B, 0x66]), + RoomObject(0x1FCB74, [0xEC, 0x4A, 0x80]), + RoomObject(0x1FCB77, [0x58, 0xEB, 0x06]), + RoomObject(0x1FCB7A, [0x60, 0xED, 0x56]), + RoomObject(0x1FCB7D, [0x78, 0xEC, 0x3B]), + RoomObject(0x1FCB80, [0x50, 0x38, 0x69]), + RoomObject(0x1FCB83, [0x50, 0x38, 0x5F]), + RoomObject(0x1FCB86, [0xA8, 0x38, 0x69]), + RoomObject(0x1FCB89, [0xA8, 0x44, 0x22]), + RoomObject(0x1FCB8C, [0xB4, 0x44, 0x69]), + RoomObject(0x1FCB8F, [0xB4, 0x51, 0x22]), + RoomObject(0x1FCB92, [0xC6, 0x50, 0x8A]), + RoomObject(0x1FCB95, [0x3B, 0xC8, 0x22]), + RoomObject(0x1FCB98, [0x8B, 0xC8, 0x22]), + RoomObject(0x1FCB9B, [0x74, 0xBC, 0x69]), + RoomObject(0x1FCB9E, [0x88, 0xBC, 0x69]), + RoomObject(0x1FCBA1, [0x63, 0x3C, 0xC2]), + RoomObject(0x1FCBA4, [0x66, 0x4F, 0x29]), + RoomObject(0x1FCBA7, [0x64, 0x50, 0x6B]), + RoomObject(0x1FCBAA, [0x5C, 0x54, 0x2B]), + RoomObject(0x1FCBAD, [0x5C, 0x58, 0x6B]), + RoomObject(0x1FCBB0, [0x54, 0x5C, 0x2B]), + RoomObject(0x1FCBB3, [0x54, 0x60, 0x6B]), + RoomObject(0x1FCBB6, [0x4C, 0x64, 0x2B]), + RoomObject(0x1FCBB9, [0x4E, 0x6B, 0x6B]), + RoomObject(0x1FCBBC, [0x4C, 0x98, 0x2D]), + RoomObject(0x1FCBBF, [0x54, 0x9C, 0x6B]), + RoomObject(0x1FCBC2, [0x54, 0xA0, 0x2D]), + RoomObject(0x1FCBC5, [0x5C, 0xA4, 0x6B]), + RoomObject(0x1FCBC8, [0x5C, 0xA8, 0x2D]), + RoomObject(0x1FCBCB, [0x64, 0xAC, 0x6B]), + RoomObject(0x1FCBCE, [0x66, 0xB3, 0x2A]), + RoomObject(0x1FCBD1, [0x98, 0xAC, 0x6A]), + RoomObject(0x1FCBD4, [0x98, 0xA8, 0x2E]), + RoomObject(0x1FCBD7, [0xA0, 0xA4, 0x6A]), + RoomObject(0x1FCBDA, [0xA0, 0xA0, 0x2E]), + RoomObject(0x1FCBDD, [0xA8, 0x9C, 0x6A]), + RoomObject(0x1FCBE0, [0xA8, 0x98, 0x2E]), + RoomObject(0x1FCBE3, [0xB2, 0x6B, 0x6A]), + RoomObject(0x1FCBE6, [0xA8, 0x64, 0x2C]), + RoomObject(0x1FCBE9, [0xA8, 0x60, 0x6A]), + RoomObject(0x1FCBEC, [0xA0, 0x5C, 0x2C]), + RoomObject(0x1FCBEF, [0xA0, 0x58, 0x6A]), + RoomObject(0x1FCBF2, [0x98, 0x54, 0x2C]), + RoomObject(0x1FCBF5, [0x98, 0x50, 0x6A]), + RoomObject(0x1FCBF8, [0x68, 0x74, 0xC2]), + RoomObject(0x1FCBFB, [0x68, 0x71, 0x27]), + RoomObject(0x1FCBFE, [0x68, 0x77, 0x6A]), + RoomObject(0x1FCC01, [0x74, 0x77, 0x6B]), + RoomObject(0x1FCC04, [0x68, 0x85, 0x28]), + RoomObject(0x1FCC07, [0xFC, 0x31, 0x72]), + RoomObject(0x1FCC0A, [0x74, 0xAE, 0x04]), + RoomObject(0x1FCC0D, [0x71, 0xA0, 0xE0]), + RoomObject(0x1FCC10, [0x0A, 0x13, 0xA0]), + RoomObject(0x1FCC13, [0x0A, 0xBF, 0xA1]), + RoomObject(0x1FCC16, [0xBE, 0xF7, 0xA3]), + RoomObject(0x1FCC19, [0xC3, 0x11, 0xC0]), + RoomObject(0x1FCC1C, [0xD1, 0x31, 0x00])], + [], []) + +Room001C = Room([0xE1, 0x00], + [RoomObject(0x1FF74B, [0x2D, 0x32, 0xA4]), + RoomObject(0x1FF74E, [0xA9, 0x1E, 0xDC]), + RoomObject(0x1FF751, [0xA8, 0x91, 0x3A]), + RoomObject(0x1FF754, [0x88, 0xAD, 0x76]), + RoomObject(0x1FF757, [0xEC, 0xAD, 0x77]), + RoomObject(0x1FF75A, [0xA8, 0x50, 0x3D]), + RoomObject(0x1FF75D, [0xD0, 0x50, 0x3D]), + RoomObject(0x1FF760, [0x30, 0xA9, 0x3D]), + RoomObject(0x1FF763, [0x30, 0xC1, 0x3D]), + RoomObject(0x1FF766, [0xFC, 0x69, 0x38]), + RoomObject(0x1FF769, [0x97, 0x9F, 0xD1]), + RoomObject(0x1FF76C, [0xCD, 0x9F, 0xD1]), + RoomObject(0x1FF76F, [0x97, 0xDC, 0xD1]), + RoomObject(0x1FF772, [0xCD, 0xDC, 0xD1]), + RoomObject(0x1FF775, [0xBD, 0x32, 0xF9]), + RoomObject(0x1FF778, [0xB1, 0x22, 0xF9]), + RoomObject(0x1FF77B, [0xC9, 0x22, 0xF9]),], [], + [DoorObject(Position.InteriorE, DoorKind.TrapTriggerable), + DoorObject(Position.InteriorS, DoorKind.Trap), DoorObject(Position.InteriorW, DoorKind.Dashable)]) + + +Room0029 = Room([0xE5, 0x00], + [RoomObject(0x1FC188, [0x97, 0x9C, 0xDE]), + RoomObject(0x1FC18B, [0xB7, 0x9C, 0xDE]), + RoomObject(0x1FC18E, [0xD6, 0x9C, 0xDE]), + RoomObject(0x1FC191, [0x97, 0xE4, 0xDE]), + RoomObject(0x1FC194, [0xB7, 0xE4, 0xDE]), + RoomObject(0x1FC197, [0xD6, 0xE4, 0xDE]), + RoomObject(0x1FC19A, [0x94, 0xA7, 0xDE]), + RoomObject(0x1FC19D, [0x94, 0xC7, 0xDE]), + RoomObject(0x1FC1A0, [0xE4, 0xA7, 0xDE]), + RoomObject(0x1FC1A3, [0xE4, 0xC7, 0xDE])], + [RoomObject(0x1FC1A8, [0x03, 0x03, 0xCA]), + RoomObject(0x1FC1AB, [0x43, 0x03, 0xCA]), + RoomObject(0x1FC1AE, [0x83, 0x03, 0xCA]), + RoomObject(0x1FC1B1, [0xC3, 0x03, 0xCA]), + RoomObject(0x1FC1B4, [0x03, 0x43, 0xCA]), + RoomObject(0x1FC1B7, [0x43, 0x43, 0xCA]), + RoomObject(0x1FC1BA, [0x83, 0x43, 0xCA]), + RoomObject(0x1FC1BD, [0xC3, 0x43, 0xCA]), + RoomObject(0x1FC1C0, [0x03, 0x83, 0xCA]), + RoomObject(0x1FC1C3, [0x43, 0x83, 0xCA]), + RoomObject(0x1FC1C6, [0x83, 0x83, 0xCA]), + RoomObject(0x1FC1C9, [0xC3, 0x83, 0xCA]), + RoomObject(0x1FC1CC, [0x03, 0xC3, 0xCA]), + RoomObject(0x1FC1CF, [0x43, 0xC3, 0xCA]), + RoomObject(0x1FC1D2, [0x83, 0xC3, 0xCA]), + RoomObject(0x1FC1D5, [0xC3, 0xC3, 0xCA])], + [], layer3=[RoomObject(0x1FC1DA, [0x9F, 0xA7, 0xC6]), + RoomObject(0x1FC1DD, [0xD4, 0xA7, 0xC6]), + RoomObject(0x1FC1E0, [0xFE, 0xF9, 0xF4]), + RoomObject(0x1FC1E3, [0xFF, 0x1E, 0x74]), + RoomObject(0x1FC1E6, [0xFE, 0x5C, 0x74]), + RoomObject(0x1FC1E9, [0xFF, 0x9C, 0x74])]) + + +Room0033 = Room([0xE9, 0x00], [], [], [DoorObject(Position.SouthW, DoorKind.Trap)]) + + +Room004D = Room([0x82, 0x1C], + [RoomObject(0x1FFD43, [0x09, 0x34, 0x0D]), + RoomObject(0x1FFD46, [0x08, 0x3A, 0x61]), + RoomObject(0x1FFD49, [0x09, 0xC0, 0x0E]), + RoomObject(0x1FFD4C, [0x08, 0xC2, 0x61]), + RoomObject(0x1FFD4F, [0xD1, 0x10, 0x0F]), + RoomObject(0x1FFD52, [0xE8, 0x3A, 0x62]), + RoomObject(0x1FFD55, [0x5E, 0x1C, 0x03]), + RoomObject(0x1FFD58, [0x17, 0x49, 0x63]), + RoomObject(0x1FFD5B, [0xDF, 0x4B, 0x64]), + RoomObject(0x1FFD5E, [0xDC, 0xCA, 0x64]), + RoomObject(0x1FFD61, [0xFF, 0x7D, 0xCB]), + RoomObject(0x1FFD64, [0x9D, 0xDF, 0x04]), + RoomObject(0x1FFD67, [0x3B, 0x5B, 0xE0]), + RoomObject(0x1FFD6A, [0x7B, 0x5B, 0xE0]), + RoomObject(0x1FFD6D, [0xB8, 0x5B, 0xE0]), + RoomObject(0x1FFD70, [0x6A, 0xB1, 0xE0]), + RoomObject(0x1FFD73, [0x78, 0x54, 0xC2]), + RoomObject(0x1FFD76, [0x5B, 0x2A, 0xC2]), + RoomObject(0x1FFD79, [0x98, 0x2A, 0xC2]), + RoomObject(0x1FFD7C, [0x21, 0x4B, 0xC3]), + RoomObject(0x1FFD7F, [0x21, 0x7B, 0xC3]), + RoomObject(0x1FFD82, [0x21, 0xA1, 0xC3]), + RoomObject(0x1FFD85, [0x38, 0x7B, 0xC2]), + RoomObject(0x1FFD88, [0x48, 0x8A, 0xC2]), + RoomObject(0x1FFD8B, [0x3A, 0xAA, 0xC2]), + RoomObject(0x1FFD8E, [0x5B, 0x9C, 0xC2]), + RoomObject(0x1FFD91, [0xC9, 0x4B, 0xC3]), + RoomObject(0x1FFD94, [0xC9, 0x7B, 0xC3]), + RoomObject(0x1FFD97, [0xB8, 0x79, 0xC2]), + RoomObject(0x1FFD9A, [0xA8, 0x88, 0xC2]), + RoomObject(0x1FFD9D, [0x9B, 0x9B, 0xC2]), + RoomObject(0x1FFDA0, [0x9B, 0xD0, 0xC2]), + RoomObject(0x1FFDA3, [0xD0, 0xA3, 0xC2]), + RoomObject(0x1FFDA6, [0x78, 0x8C, 0xC2]), + RoomObject(0x1FFDA9, [0x15, 0x45, 0x22]), + RoomObject(0x1FFDAC, [0x59, 0x1F, 0x69]), + RoomObject(0x1FFDAF, [0xA5, 0x1F, 0x69]), + RoomObject(0x1FFDB2, [0xC9, 0x45, 0x22]), + RoomObject(0x1FFDB5, [0x68, 0xE4, 0x5E]), + RoomObject(0x1FFDB8, [0x15, 0xB9, 0x22]), + RoomObject(0x1FFDBB, [0x35, 0xB9, 0x69]), + RoomObject(0x1FFDBE, [0x37, 0xD9, 0x22]), + RoomObject(0x1FFDC1, [0x88, 0xD9, 0x22]), + RoomObject(0x1FFDC4, [0x98, 0xD9, 0x69]), + RoomObject(0x1FFDC7, [0x66, 0xCB, 0x2A]), + RoomObject(0x1FFDCA, [0x69, 0xC9, 0x04]), + RoomObject(0x1FFDCD, [0x79, 0xCB, 0xF9]), + RoomObject(0x1FFDD0, [0x8D, 0xBA, 0xF9]), + RoomObject(0x1FFDD3, [0x37, 0x57, 0x29]), + RoomObject(0x1FFDD6, [0x87, 0x57, 0x29]), + RoomObject(0x1FFDD9, [0x78, 0x5A, 0x6A]), + RoomObject(0x1FFDDC, [0x84, 0x5A, 0x6B]), + RoomObject(0x1FFDDF, [0x78, 0x65, 0x28]), + RoomObject(0x1FFDE2, [0x35, 0x5B, 0x6B]), + RoomObject(0x1FFDE5, [0x34, 0x7A, 0x2D]), + RoomObject(0x1FFDE8, [0x44, 0x7E, 0x6B]), + RoomObject(0x1FFDEB, [0x44, 0x8A, 0x2D]), + RoomObject(0x1FFDEE, [0x54, 0x8E, 0x6B]), + RoomObject(0x1FFDF1, [0x55, 0x9B, 0x2A]), + RoomObject(0x1FFDF4, [0x78, 0x8E, 0x6A]), + RoomObject(0x1FFDF7, [0x78, 0x89, 0x27]), + RoomObject(0x1FFDFA, [0x84, 0x8E, 0x6B]), + RoomObject(0x1FFDFD, [0x85, 0x9B, 0x2A]), + RoomObject(0x1FFE00, [0xA8, 0x8E, 0x6A]), + RoomObject(0x1FFE03, [0xA8, 0x8A, 0x2E]), + RoomObject(0x1FFE06, [0xB8, 0x7E, 0x6A]), + RoomObject(0x1FFE09, [0xB8, 0x7A, 0x2E]), + RoomObject(0x1FFE0C, [0xC9, 0x5B, 0x6A]), + RoomObject(0x1FFE0F, [0x66, 0xAF, 0x29]), + RoomObject(0x1FFE12, [0x65, 0xB1, 0x6B]), + RoomObject(0x1FFE15, [0x99, 0xB1, 0x6A]), + RoomObject(0x1FFE18, [0x38, 0x4B, 0x03]), + RoomObject(0x1FFE1B, [0xA8, 0x4B, 0x03]), + RoomObject(0x1FFE1E, [0x48, 0x13, 0x3A]), + RoomObject(0x1FFE21, [0x0C, 0x4A, 0x7F]), + RoomObject(0x1FFE24, [0xEC, 0x4A, 0x80]), + RoomObject(0x1FFE27, [0xFE, 0xE1, 0x39]), + RoomObject(0x1FFE2A, [0x09, 0x11, 0xA0]), + RoomObject(0x1FFE2D, [0xD5, 0x11, 0xA2]), + RoomObject(0x1FFE30, [0x09, 0xD5, 0xA1])], + [RoomObject(0x1FFE35, [0x5B, 0x19, 0xDB]), + RoomObject(0x1FFE38, [0x98, 0x19, 0xDB]), + RoomObject(0x1FFE3B, [0x11, 0x4B, 0xDB]), + RoomObject(0x1FFE3E, [0x11, 0x8A, 0xDB]), + RoomObject(0x1FFE41, [0x39, 0x48, 0xDB]), + RoomObject(0x1FFE44, [0xA9, 0x48, 0xDB]), + RoomObject(0x1FFE47, [0xD9, 0x4B, 0xDB]), + RoomObject(0x1FFE4A, [0xD9, 0x8B, 0xDB]), + RoomObject(0x1FFE4D, [0x6A, 0xC8, 0xDB]), + RoomObject(0x1FFE50, [0x9B, 0xCA, 0xDB]), + RoomObject(0x1FFE53, [0xD9, 0xCA, 0xDB])], + [DoorObject(Position.NorthW, DoorKind.SmallKey), DoorObject(Position.WestS, DoorKind.Normal)]) + +Room005A = Room([0xE9, 0x00], + [RoomObject(0x1FA7CD, [0xA8, 0xA8, 0xDE]), + RoomObject(0x1FA7D0, [0xB0, 0xA0, 0xDE]), + RoomObject(0x1FA7D3, [0xB8, 0xA8, 0xDE]), + RoomObject(0x1FA7D6, [0xC0, 0xA0, 0xDE]), + RoomObject(0x1FA7D9, [0xC8, 0xA8, 0xDE]), + RoomObject(0x1FA7DC, [0xD0, 0xA0, 0xDE])], + [], [DoorObject(Position.SouthE, DoorKind.Trap)]) + +Room006C = Room([0xE2, 0x00], + [RoomObject(0x1FFA58, [0x17, 0x9F, 0xE8]), + RoomObject(0x1FFA5B, [0x4D, 0x9F, 0xE8]), + RoomObject(0x1FFA5E, [0x17, 0xDC, 0xE8]), + RoomObject(0x1FFA61, [0x4D, 0xDC, 0xE8]), + RoomObject(0x1FFA64, [0x18, 0xE1, 0xFE]), + RoomObject(0x1FFA67, [0x88, 0xAD, 0x76]), + RoomObject(0x1FFA6A, [0x99, 0xBC, 0x33]), + RoomObject(0x1FFA6D, [0x9B, 0xBB, 0x34]), + RoomObject(0x1FFA70, [0x9B, 0xCF, 0x34]), + RoomObject(0x1FFA73, [0xD8, 0xB8, 0x34]), + RoomObject(0x1FFA76, [0xD8, 0xCC, 0x34]), + RoomObject(0x1FFA79, [0xAF, 0xAA, 0xFE]), + RoomObject(0x1FFA7C, [0xC7, 0xAA, 0xFE]), + RoomObject(0x1FFA7F, [0xAF, 0xD2, 0xFE]), + RoomObject(0x1FFA82, [0xC7, 0xD2, 0xFE]), + RoomObject(0x1FFA85, [0x28, 0x11, 0x3A]), + RoomObject(0x1FFA88, [0x28, 0x91, 0x3A]), + RoomObject(0x1FFA8B, [0xFC, 0xE1, 0x38]), + RoomObject(0x1FFA8E, [0x2B, 0x33, 0xFA]), + RoomObject(0x1FFA91, [0x53, 0x33, 0xFA]), + RoomObject(0x1FFA94, [0x2B, 0x53, 0xFA]), + RoomObject(0x1FFA97, [0x53, 0x53, 0xFA])], [], + [DoorObject(Position.InteriorS, DoorKind.Trap2), DoorObject(Position.InteriorW, DoorKind.Trap), + DoorObject(Position.EastS, DoorKind.Normal)]) + +Room0090 = Room([0xE1, 0x00], + [RoomObject(0x1FBAA0, [0x28, 0xEC, 0x56]), + RoomObject(0x1FBAA3, [0x48, 0xEC, 0x56]), + RoomObject(0x1FBAA6, [0x1B, 0xA2, 0xFF])], + [RoomObject(0x1FBAAB, [0x16, 0x9C, 0xFE])], [DoorObject(Position.SouthW, DoorKind.Trap)]) + +Room00A4 = Room([0xE1, 0x00], + [RoomObject(0x1FE702, [0xFC, 0x08, 0x00]), + RoomObject(0x1FE705, [0x13, 0x80, 0x01]), + RoomObject(0x1FE708, [0xFD, 0xC8, 0x02]), + RoomObject(0x1FE70B, [0x02, 0x93, 0x61]), + RoomObject(0x1FE70E, [0xFC, 0x0E, 0x81]), + RoomObject(0x1FE711, [0x13, 0xE8, 0x02]), + RoomObject(0x1FE714, [0xFD, 0xCE, 0x83]), + RoomObject(0x1FE717, [0x72, 0x93, 0x62]), + RoomObject(0x1FE71A, [0x13, 0x93, 0xC4]), + RoomObject(0x1FE71D, [0x51, 0x93, 0xC4]), + RoomObject(0x1FE720, [0x51, 0xC9, 0xC4]), + RoomObject(0x1FE723, [0x10, 0xC9, 0xC4]), + RoomObject(0x1FE726, [0x0E, 0x8D, 0xDE]), + RoomObject(0x1FE729, [0x0D, 0x9C, 0xDE]), + RoomObject(0x1FE72C, [0x0C, 0xA5, 0xDE]), + RoomObject(0x1FE72F, [0x5E, 0x8C, 0xDE]), + RoomObject(0x1FE732, [0x65, 0x94, 0xDE]), + RoomObject(0x1FE735, [0x6C, 0x9C, 0xDE])], + [RoomObject(0x1FE73A, [0x2E, 0x98, 0xFF])], [DoorObject(Position.SouthW, DoorKind.Trap)]) + +Room00AC = Room([0xE9, 0x00], + [RoomObject(0x1FD9B1, [0x88, 0xA4, 0x0D]), + RoomObject(0x1FD9B4, [0x88, 0xD0, 0x0E]), + RoomObject(0x1FD9B7, [0xE0, 0x90, 0x0F]), + RoomObject(0x1FD9BA, [0xE0, 0xE4, 0x10]), + RoomObject(0x1FD9BD, [0x89, 0xAB, 0x61]), + RoomObject(0x1FD9C0, [0xE9, 0xAB, 0x62]), + RoomObject(0x1FD9C3, [0x88, 0x91, 0xA0]), + RoomObject(0x1FD9C6, [0x88, 0xE5, 0xA1]), + RoomObject(0x1FD9C9, [0xE4, 0x91, 0xA2]), + RoomObject(0x1FD9CC, [0xE4, 0xF5, 0xA3])], + [RoomObject(0x1FD9D1, [0xB1, 0xA8, 0xFF])], [DoorObject(Position.SouthE, DoorKind.Trap)]) + +Room00C8 = Room([0xE1, 0x00], + [RoomObject(0x0A9587, [0x98, 0x92, 0x3A]), + RoomObject(0x0A958A, [0x88, 0xAA, 0x65]), + RoomObject(0x0A958D, [0xE8, 0xAA, 0x66])], [], [DoorObject(Position.SouthE, DoorKind.Trap)]) + +Room00DE = Room([0xE4, 0x00], [], [RoomObject(0x1FCAE5, [0xAD, 0x21, 0xF9])], []) + Room0127 = Room([0xE1, 0x00], [RoomObject(0x0AB600, [0xFE, 0x89, 0x00]), RoomObject(0x0AB603, [0xA2, 0xA1, 0x61]), @@ -64,3 +431,23 @@ Room0127 = Room([0xE1, 0x00], RoomObject(0x0AB642, [0xE1, 0xD2, 0xC0])], [], [DoorObject(Position.SouthW, DoorKind.CaveEntrance), DoorObject(Position.SouthE, DoorKind.CaveEntrance)]) + +# boss room id, room data, shell x, shell y, clear layer 2 +boss_rooms = { + 'Eastern Palace': (0xc8, Room00C8, 0x2B, 0x28, False), + 'Desert Palace': (0x33, Room0033, 0x0B, 0x28, False), + 'Tower of Hera': (7, Room0007, 0x18, 0x16, False), + 'Palace of Darkness': (0x5A, Room005A, 0x2B, 0x28, False), + 'Swamp Palace': (6, Room0006, 0x0B, 0x28, False), + 'Skull Woods': (0x29, Room0029, 0x2B, 0x28, False), + 'Thieves Town': (0xac, Room00AC, 0x2B, 0x28, True), + 'Ice Palace': (0xde, Room00DE, 0x2B, 0x08, True), + 'Misery Mire': (0x90, Room0090, 0x0B, 0x28, True), + 'Turtle Rock': (0xa4, Room00A4, 0x0B, 0x28, True), +} + +gt_boss_room = { + 'bottom': (0x1C, Room001C, 0x2B, 0x28, False), + 'middle': (0x6C, Room006C, 0x0B, 0x28, False), + 'top': (0x4D, Room004D, 0x18, 0x16, False), +} diff --git a/source/dungeon/RoomObject.py b/source/dungeon/RoomObject.py index 359231e0..4a890021 100644 --- a/source/dungeon/RoomObject.py +++ b/source/dungeon/RoomObject.py @@ -22,6 +22,17 @@ class RoomObject: def write_to_rom(self, rom): rom.write_bytes(snes_to_pc(self.address), self.data) + # subtype 3 only? + def matches_oid(self, oid): + my_oid = (self.data[2] << 4) | ((self.data[1] & 3) << 2) | (self.data[0] & 3) + return my_oid == oid + + @staticmethod + def subtype3_factory(x, y, type_id): + return RoomObject(None, [((x << 2) & 0xFC) | (type_id & 0x3), + ((y << 2) & 0xFC) | ((type_id >> 2) & 0x3), + 0xF0 | ((type_id >> 4) & 0xF)]) + class DoorObject: diff --git a/source/enemizer/Bossmizer.py b/source/enemizer/Bossmizer.py new file mode 100644 index 00000000..935b11e3 --- /dev/null +++ b/source/enemizer/Bossmizer.py @@ -0,0 +1,211 @@ +import RaceRandom as random +from Utils import snes_to_pc + +from source.dungeon.EnemyList import EnemySprite, SpriteType, Sprite +from source.dungeon.RoomList import boss_rooms, gt_boss_room, Room0006 +from source.dungeon.RoomObject import RoomObject +from source.enemizer.SpriteSheets import required_boss_sheets + + +def get_dungeon_boss_room(dungeon_name, level): + if level is None: + return boss_rooms[dungeon_name] + return gt_boss_room[level] + + +def get_dungeon_boss_default(dungeon_name, level): + if level is None: + return boss_defaults[dungeon_name] + return gt_boss_defaults[level] + + +def add_shell_to_boss_room(data_tables, dungeon_name, level, shell_id): + room_id, room, shell_x, shell_y, clear_layer_2 = get_dungeon_boss_room(dungeon_name, level) + if room_id in data_tables.room_list: + room = data_tables.room_list[room_id] + else: + data_tables.room_list[room_id] = room + room.layout[0] = 0xF0 + if clear_layer_2: + room.layer2.clear() + y_offset = 0 if shell_id == 0xF95 else -2 + room.layer2.append(RoomObject.subtype3_factory(shell_x, shell_y + y_offset, shell_id)) + + +def remove_shell_from_boss_room(data_tables, dungeon_name, level, shell_id): + room_id, room, shell_x, shell_y, clear_layer_2 = get_dungeon_boss_room(dungeon_name, level) + if room_id in data_tables.room_list: + room = data_tables.room_list[room_id] + else: + data_tables.room_list[room_id] = room + room.layer2[:] = [obj for obj in room.layer2 if not obj.matches_oid(shell_id)] + + +def remove_water_tiles(data_tables): + room = Room0006 + if 0x6 in data_tables.room_list: + room = data_tables.room_list[0x6] + else: + data_tables.room_list[0x6] = room + room.layer1.clear() + + +def create_sprite(super_tile, kind, sub_type, layer, tile_x, tile_y): + return Sprite(super_tile, kind, sub_type, layer, tile_x, tile_y, None, False, None) + + +def add_armos_to_list(sprite_list, room_id): + sprite_list.insert(0, create_sprite(room_id, EnemySprite.ArmosKnight, 0x00, 0, 0x04, 0x05)) + sprite_list.insert(1, create_sprite(room_id, EnemySprite.ArmosKnight, 0x00, 0, 0x07, 0x05)) + sprite_list.insert(2, create_sprite(room_id, EnemySprite.ArmosKnight, 0x00, 0, 0x0a, 0x05)) + sprite_list.insert(3, create_sprite(room_id, EnemySprite.ArmosKnight, 0x00, 0, 0x0a, 0x08)) + sprite_list.insert(4, create_sprite(room_id, EnemySprite.ArmosKnight, 0x00, 0, 0x07, 0x08)) + sprite_list.insert(5, create_sprite(room_id, EnemySprite.ArmosKnight, 0x00, 0, 0x04, 0x08)) + sprite_list.insert(6, create_sprite(room_id, 0x19, SpriteType.Overlord, 0, 0x07, 0x08)) + + +def add_lanmolas_to_list(sprite_list, room_id): + sprite_list.insert(0, create_sprite(room_id, EnemySprite.Lanmolas, 0x00, 0, 0x06, 0x07)) + sprite_list.insert(1, create_sprite(room_id, EnemySprite.Lanmolas, 0x00, 0, 0x09, 0x07)) + sprite_list.insert(2, create_sprite(room_id, EnemySprite.Lanmolas, 0x00, 0, 0x07, 0x09)) + + +def add_moldorm_to_list(sprite_list, room_id): + sprite_list.insert(0, create_sprite(room_id, EnemySprite.Moldorm, 0x00, 0, 0x09, 0x09)) + + +def add_helmasaur_king_to_list(sprite_list, room_id): + sprite_list.insert(0, create_sprite(room_id, EnemySprite.HelmasaurKing, 0x00, 0, 0x07, 0x06)) + + +def add_arrghus_to_list(sprite_list, room_id): + sprite_list.insert(0, create_sprite(room_id, EnemySprite.Arrghus, 0x00, 0, 0x07, 0x07)) + sprite_list.insert(1, create_sprite(room_id, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07)) + sprite_list.insert(2, create_sprite(room_id, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07)) + sprite_list.insert(3, create_sprite(room_id, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07)) + sprite_list.insert(4, create_sprite(room_id, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07)) + sprite_list.insert(5, create_sprite(room_id, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07)) + sprite_list.insert(6, create_sprite(room_id, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07)) + sprite_list.insert(7, create_sprite(room_id, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07)) + sprite_list.insert(8, create_sprite(room_id, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07)) + sprite_list.insert(9, create_sprite(room_id, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07)) + sprite_list.insert(10, create_sprite(room_id, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07)) + sprite_list.insert(11, create_sprite(room_id, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07)) + sprite_list.insert(12, create_sprite(room_id, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07)) + sprite_list.insert(13, create_sprite(room_id, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07)) + + +def add_mothula_to_list(sprite_list, room_id): + sprite_list.insert(0, create_sprite(room_id, EnemySprite.Mothula, 0x00, 0, 0x08, 0x06)) + + +def add_blind_to_list(sprite_list, room_id): + sprite_list.insert(0, create_sprite(room_id, EnemySprite.Blind, 0x00, 0, 0x09, 0x05)) + + +def add_kholdstare_to_list(sprite_list, room_id): + sprite_list.insert(0, create_sprite(room_id, EnemySprite.KholdstareShell, 0x00, 0, 0x07, 0x05)) + sprite_list.insert(1, create_sprite(room_id, EnemySprite.FallingIce, 0x00, 0, 0x07, 0x05)) + sprite_list.insert(2, create_sprite(room_id, EnemySprite.Kholdstare, 0x00, 0, 0x07, 0x05)) + + +def add_vitreous_to_list(sprite_list, room_id): + sprite_list.insert(0, create_sprite(room_id, EnemySprite.Vitreous, 0x00, 0, 0x07, 0x05)) + + +def add_trinexx_to_list(sprite_list, room_id): + sprite_list.insert(0, create_sprite(room_id, EnemySprite.TrinexxRockHead, 0x00, 0, 0x07, 0x05)) + sprite_list.insert(1, create_sprite(room_id, EnemySprite.TrinexxFireHead, 0x00, 0, 0x07, 0x05)) + sprite_list.insert(2, create_sprite(room_id, EnemySprite.TrinexxIceHead, 0x00, 0, 0x07, 0x05)) + + +def boss_writes(world, player, rom): + rom.write_byte(snes_to_pc(0x368107), 1) # centralize drops + eye_number = random.randint(0, 8) # randomize moldorm eyes (var + 1) + rom.write_byte(snes_to_pc(0x368102), eye_number) # enemizer flag + rom.write_byte(snes_to_pc(0x1DDBB3), eye_number) # loop variable + data_tables = world.data_tables[player] + arrghus_can_swim = True + water_tiles_on = True + for dungeon in world.get_dungeons(player): + for level, boss in dungeon.bosses.items(): + if not boss or boss.name in ['Agahnim', 'Agahnim2']: + continue + default_boss = get_dungeon_boss_default(dungeon.name, level) + room_data = get_dungeon_boss_room(dungeon.name, level) + room_id = room_data[0] + if default_boss != boss.name: + sprite_list = data_tables.uw_enemy_table.room_map[room_id] + data = boss_room_remove_data[room_id] + del sprite_list[:data] + add_func, sprite_type = boss_addition_table[boss.name] + add_func(sprite_list, room_id) + if len(sprite_list) > 16: + del sprite_list[16:] + data_tables.room_headers[room_id].sprite_sheet = required_boss_sheets[sprite_type] + # room changes + if boss.name == 'Arrghus' and (dungeon.name != 'Swamp Palace' or level is not None): + rom.write_byte(snes_to_pc(0x0DB6BE), 0) # arrghus can stand on ground + arrghus_can_swim = False + if boss.name != 'Arrghus' and dungeon.name == 'Swamp Palace' and level is None: + remove_water_tiles(data_tables) + water_tiles_on = False + if boss.name == 'Trinexx' and (dungeon.name != 'Turtle Rock' or level is not None): + add_shell_to_boss_room(data_tables, dungeon.name, level, 0xFF2) + data_tables.room_headers[room_id].byte_0 = 0x60 + data_tables.room_headers[room_id].effect = 4 + # $2E, $98, $FF (original shell) + if boss.name == 'Kholdstare' and (dungeon.name != 'Ice Palace' or level is not None): + add_shell_to_boss_room(data_tables, dungeon.name, level, 0xF95) + data_tables.room_headers[room_id].byte_0 = 0xE0 + data_tables.room_headers[room_id].effect = 1 + if boss.name != 'Trinexx' and dungeon.name == 'Turtle Rock' and level is None: + remove_shell_from_boss_room(data_tables, dungeon.name, level, 0xFF2) + # disable trinexx ice breath with No-ops + rom.write_bytes(snes_to_pc(0x09B37E), [0xEA, 0xEA, 0xEA, 0xEA]) + if boss.name != 'Kholdstare' and dungeon.name == 'Ice Palace' and level is None: + remove_shell_from_boss_room(data_tables, dungeon.name, level, 0xF95) + if boss.name != 'Blind' and dungeon.name == 'Thieves Town' and level is None: + rom.write_byte(snes_to_pc(0x368101), 1) # set blind boss door flag + # maiden becomes a random invisible enemy + data_tables.uw_enemy_table.room_map[0x45][0].kind = EnemySprite.PedestalPlaque + if not arrghus_can_swim and water_tiles_on: + remove_water_tiles(data_tables) + + +boss_defaults = { + 'Eastern Palace': 'Armos Knights', + 'Desert Palace': 'Lanmolas', + 'Tower of Hera': 'Moldorm', + 'Palace of Darkness': 'Helmasaur King', + 'Swamp Palace': 'Arrghus', + 'Skull Woods': 'Mothula', + 'Thieves Town': 'Blind', + 'Ice Palace': 'Kholdstare', + 'Misery Mire': 'Vitreous', + 'Turtle Rock': 'Trinexx', +} + +gt_boss_defaults = { + 'bottom': 'Armos Knights', + 'middle': 'Lanmolas', + 'top': 'Moldorm', +} + +boss_room_remove_data = { + 6: 14, 7: 1, 0x1c: 7, 0x29: 1, 0x33: 3, 0x4d: 1, 0x5a: 1, + 0x6c: 3, 0x90: 1, 0xa4: 2, 0xac: 1, 0xc8: 7, 0xde: 3 +} + +boss_addition_table = { + 'Armos Knights': (add_armos_to_list, EnemySprite.ArmosKnight), + 'Lanmolas': (add_lanmolas_to_list, EnemySprite.Lanmolas), + 'Moldorm': (add_moldorm_to_list, EnemySprite.Moldorm), + 'Helmasaur King': (add_helmasaur_king_to_list, EnemySprite.HelmasaurKing), + 'Arrghus': (add_arrghus_to_list, EnemySprite.Arrghus), + 'Mothula': (add_mothula_to_list, EnemySprite.Mothula), + 'Blind': (add_blind_to_list, EnemySprite.Blind), + 'Kholdstare': (add_kholdstare_to_list, EnemySprite.Kholdstare), + 'Vitreous': (add_vitreous_to_list, EnemySprite.Vitreous), + 'Trinexx': (add_trinexx_to_list, EnemySprite.TrinexxRockHead) +} diff --git a/source/rom/DataTables.py b/source/rom/DataTables.py index 136c9b29..792ae2e7 100644 --- a/source/rom/DataTables.py +++ b/source/rom/DataTables.py @@ -29,9 +29,9 @@ class DataTables: header.write_to_rom(rom, snes_to_pc(0x30DA00)) # new header table, bank30, tables.asm room_start_address = 0x378000 for room_id, room in self.room_list.items(): - rom.write_bytes(0x1F8000 + room_id * 3, int24_as_bytes(room_start_address)) + rom.write_bytes(snes_to_pc(0x1F8000 + room_id * 3), int24_as_bytes(room_start_address)) door_start, bytes_written = room.write_to_rom(snes_to_pc(room_start_address), rom) - rom.write_bytes(0x1F83C0 + room_id * 3, int24_as_bytes(room_start_address + door_start)) + rom.write_bytes(snes_to_pc(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: