From 163988ca1b2defefc2ed622cd6da6a62b83169e8 Mon Sep 17 00:00:00 2001 From: cassidoxa Date: Wed, 20 Apr 2022 22:00:05 -0400 Subject: [PATCH] New SRAM changes --- InitialSram.py | 252 ++++++++++++++++++++++++++++++++++++++++++ Items.py | 1 + Rom.py | 213 +++++++---------------------------- Utils.py | 5 + data/base2current.bps | Bin 85671 -> 85800 bytes 5 files changed, 300 insertions(+), 171 deletions(-) create mode 100644 InitialSram.py diff --git a/InitialSram.py b/InitialSram.py new file mode 100644 index 00000000..7a1ccba4 --- /dev/null +++ b/InitialSram.py @@ -0,0 +1,252 @@ +from dataclasses import dataclass, field + +from BaseClasses import CollectionState +from Utils import count_set_bits + +SRAM_SIZE = 0x500 +ROOM_DATA = 0x000 +OVERWORLD_DATA = 0x280 + +def _new_default_sram(): + sram_buf = [0x00] * 0x500 + sram_buf[ROOM_DATA+0x20D] = 0xF0 + sram_buf[ROOM_DATA+0x20F] = 0xF0 + sram_buf[0x379] = 0x68 + sram_buf[0x401] = 0xFF + sram_buf[0x402] = 0xFF + return sram_buf + +@dataclass +class InitialSram: + _initial_sram_bytes: list[int] = field(default_factory=_new_default_sram) + + def _set_value(self, idx: int, val:int): + if idx > SRAM_SIZE: + raise IndexError('SRAM index out of bounds: {idx}') + if not (-1 < val < 256): + raise ValueError('SRAM value must be between 0 and 255: {val}') + self._initial_sram_bytes[idx] = val + + def _or_value(self, idx: int, val:int): + if idx > SRAM_SIZE: + raise IndexError('SRAM index out of bounds: {idx}') + if not (-1 < val < 256): + raise ValueError('SRAM value must be between 0 and 255: {val}') + self._initial_sram_bytes[idx] |= val + + def pre_open_aga_curtains(self): + self._or_value(ROOM_DATA+0x61, 0x80) + + def pre_open_skullwoods_curtains(self): + self._or_value(ROOM_DATA+0x93, 0x80) + + def pre_open_lumberjack(self): + self._or_value(OVERWORLD_DATA+0x02, 0x20) + + def pre_open_castle_gate(self): + self._or_value(OVERWORLD_DATA+0x1B, 0x20) + + def pre_open_ganons_tower(self): + self._or_value(OVERWORLD_DATA+0x43, 0x20) + + def pre_open_pyramid_hole(self): + self._or_value(OVERWORLD_DATA+0x5B, 0x20) + + def set_starting_equipment(self, world: object, player: int): + equip = [0] * (0x340 + 0x4F) + equip[0x36C] = 0x18 + equip[0x36D] = 0x18 + equip[0x379] = 0x68 + if world.bombbag[player]: + starting_max_bombs = 0 + else: + starting_max_bombs = 10 + starting_max_arrows = 30 + starting_bomb_cap_upgrades = 0 + starting_arrow_cap_upgrades = 0 + starting_bombs = 0 + starting_arrows = 0 + + startingstate = CollectionState(world) + + if startingstate.has('Bow', player): + equip[0x340] = 3 if startingstate.has('Silver Arrows', player) else 1 + equip[0x38E] |= 0x20 # progressive flag to get the correct hint in all cases + if not world.retro[player]: + equip[0x38E] |= 0x80 + if startingstate.has('Silver Arrows', player): + equip[0x38E] |= 0x40 + + if startingstate.has('Titans Mitts', player): + equip[0x354] = 2 + elif startingstate.has('Power Glove', player): + equip[0x354] = 1 + + if startingstate.has('Golden Sword', player): + equip[0x359] = 4 + elif startingstate.has('Tempered Sword', player): + equip[0x359] = 3 + elif startingstate.has('Master Sword', player): + equip[0x359] = 2 + elif startingstate.has('Fighter Sword', player): + equip[0x359] = 1 + + if startingstate.has('Mirror Shield', player): + equip[0x35A] = 3 + elif startingstate.has('Red Shield', player): + equip[0x35A] = 2 + elif startingstate.has('Blue Shield', player): + equip[0x35A] = 1 + + if startingstate.has('Red Mail', player): + equip[0x35B] = 2 + elif startingstate.has('Blue Mail', player): + equip[0x35B] = 1 + + if startingstate.has('Magic Upgrade (1/4)', player): + equip[0x37B] = 2 + equip[0x36E] = 0x80 + elif startingstate.has('Magic Upgrade (1/2)', player): + equip[0x37B] = 1 + equip[0x36E] = 0x80 + + for item in world.precollected_items: + if item.player != player: + continue + + if item.name in ['Bow', 'Silver Arrows', 'Progressive Bow', 'Progressive Bow (Alt)', + 'Titans Mitts', 'Power Glove', 'Progressive Glove', + 'Golden Sword', 'Tempered Sword', 'Master Sword', 'Fighter Sword', 'Progressive Sword', + 'Mirror Shield', 'Red Shield', 'Blue Shield', 'Progressive Shield', + 'Red Mail', 'Blue Mail', 'Progressive Armor', + 'Magic Upgrade (1/4)', 'Magic Upgrade (1/2)']: + continue + + set_table = {'Book of Mudora': (0x34E, 1), 'Hammer': (0x34B, 1), 'Bug Catching Net': (0x34D, 1), 'Hookshot': (0x342, 1), 'Magic Mirror': (0x353, 2), + 'Cape': (0x352, 1), 'Lamp': (0x34A, 1), 'Moon Pearl': (0x357, 1), 'Cane of Somaria': (0x350, 1), 'Cane of Byrna': (0x351, 1), + 'Fire Rod': (0x345, 1), 'Ice Rod': (0x346, 1), 'Bombos': (0x347, 1), 'Ether': (0x348, 1), 'Quake': (0x349, 1)} + or_table = {'Green Pendant': (0x374, 0x04), 'Red Pendant': (0x374, 0x01), 'Blue Pendant': (0x374, 0x02), + 'Crystal 1': (0x37A, 0x02), 'Crystal 2': (0x37A, 0x10), 'Crystal 3': (0x37A, 0x40), 'Crystal 4': (0x37A, 0x20), + 'Crystal 5': (0x37A, 0x04), 'Crystal 6': (0x37A, 0x01), 'Crystal 7': (0x37A, 0x08), + 'Big Key (Eastern Palace)': (0x367, 0x20), 'Compass (Eastern Palace)': (0x365, 0x20), 'Map (Eastern Palace)': (0x369, 0x20), + 'Big Key (Desert Palace)': (0x367, 0x10), 'Compass (Desert Palace)': (0x365, 0x10), 'Map (Desert Palace)': (0x369, 0x10), + 'Big Key (Tower of Hera)': (0x366, 0x20), 'Compass (Tower of Hera)': (0x364, 0x20), 'Map (Tower of Hera)': (0x368, 0x20), + 'Big Key (Escape)': (0x367, 0xC0), 'Compass (Escape)': (0x365, 0xC0), 'Map (Escape)': (0x369, 0xC0), + 'Big Key (Agahnims Tower)': (0x367, 0x08), 'Compass (Agahnims Tower)': (0x365, 0x08), 'Map (Agahnims Tower)': (0x369, 0x08), + 'Big Key (Palace of Darkness)': (0x367, 0x02), 'Compass (Palace of Darkness)': (0x365, 0x02), 'Map (Palace of Darkness)': (0x369, 0x02), + 'Big Key (Thieves Town)': (0x366, 0x10), 'Compass (Thieves Town)': (0x364, 0x10), 'Map (Thieves Town)': (0x368, 0x10), + 'Big Key (Skull Woods)': (0x366, 0x80), 'Compass (Skull Woods)': (0x364, 0x80), 'Map (Skull Woods)': (0x368, 0x80), + 'Big Key (Swamp Palace)': (0x367, 0x04), 'Compass (Swamp Palace)': (0x365, 0x04), 'Map (Swamp Palace)': (0x369, 0x04), + 'Big Key (Ice Palace)': (0x366, 0x40), 'Compass (Ice Palace)': (0x364, 0x40), 'Map (Ice Palace)': (0x368, 0x40), + 'Big Key (Misery Mire)': (0x367, 0x01), 'Compass (Misery Mire)': (0x365, 0x01), 'Map (Misery Mire)': (0x369, 0x01), + 'Big Key (Turtle Rock)': (0x366, 0x08), 'Compass (Turtle Rock)': (0x364, 0x08), 'Map (Turtle Rock)': (0x368, 0x08), + 'Big Key (Ganons Tower)': (0x366, 0x04), 'Compass (Ganons Tower)': (0x364, 0x04), 'Map (Ganons Tower)': (0x368, 0x04)} + set_or_table = {'Flippers': (0x356, 1, 0x379, 0x02),'Pegasus Boots': (0x355, 1, 0x379, 0x04), + 'Shovel': (0x34C, 1, 0x38C, 0x04), 'Ocarina': (0x34C, 3, 0x38C, 0x01), + 'Mushroom': (0x344, 1, 0x38C, 0x20 | 0x08), 'Magic Powder': (0x344, 2, 0x38C, 0x10), + 'Blue Boomerang': (0x341, 1, 0x38C, 0x80), 'Red Boomerang': (0x341, 2, 0x38C, 0x40)} + keys = {'Small Key (Eastern Palace)': [0x37E], 'Small Key (Desert Palace)': [0x37F], + 'Small Key (Tower of Hera)': [0x386], + 'Small Key (Agahnims Tower)': [0x380], 'Small Key (Palace of Darkness)': [0x382], + 'Small Key (Thieves Town)': [0x387], + 'Small Key (Skull Woods)': [0x384], 'Small Key (Swamp Palace)': [0x381], + 'Small Key (Ice Palace)': [0x385], + 'Small Key (Misery Mire)': [0x383], 'Small Key (Turtle Rock)': [0x388], + 'Small Key (Ganons Tower)': [0x389], + 'Small Key (Universal)': [0x38B], 'Small Key (Escape)': [0x37C, 0x37D]} + bottles = {'Bottle': 2, 'Bottle (Red Potion)': 3, 'Bottle (Green Potion)': 4, 'Bottle (Blue Potion)': 5, + 'Bottle (Fairy)': 6, 'Bottle (Bee)': 7, 'Bottle (Good Bee)': 8} + rupees = {'Rupee (1)': 1, 'Rupees (5)': 5, 'Rupees (20)': 20, 'Rupees (50)': 50, 'Rupees (100)': 100, 'Rupees (300)': 300} + bomb_caps = {'Bomb Upgrade (+5)': 5, 'Bomb Upgrade (+10)': 10} + arrow_caps = {'Arrow Upgrade (+5)': 5, 'Arrow Upgrade (+10)': 10} + bombs = {'Single Bomb': 1, 'Bombs (3)': 3, 'Bombs (10)': 10} + arrows = {'Single Arrow': 1, 'Arrows (10)': 10} + + if item.name in set_table: + equip[set_table[item.name][0]] = set_table[item.name][1] + elif item.name in or_table: + equip[or_table[item.name][0]] |= or_table[item.name][1] + elif item.name in set_or_table: + equip[set_or_table[item.name][0]] = set_or_table[item.name][1] + equip[set_or_table[item.name][2]] |= set_or_table[item.name][3] + elif item.name in keys: + for address in keys[item.name]: + equip[address] = min(equip[address] + 1, 99) + elif item.name in bottles: + if equip[0x34F] < world.difficulty_requirements[player].progressive_bottle_limit: + equip[0x35C + equip[0x34F]] = bottles[item.name] + equip[0x34F] += 1 + elif item.name in rupees: + equip[0x360:0x362] = list(min(equip[0x360] + (equip[0x361] << 8) + rupees[item.name], 9999).to_bytes(2, byteorder='little', signed=False)) + equip[0x362:0x364] = list(min(equip[0x362] + (equip[0x363] << 8) + rupees[item.name], 9999).to_bytes(2, byteorder='little', signed=False)) + elif item.name in bomb_caps: + starting_bomb_cap_upgrades += bomb_caps[item.name] + elif item.name in arrow_caps: + starting_arrow_cap_upgrades += arrow_caps[item.name] + elif item.name in bombs: + starting_bombs += bombs[item.name] + elif item.name in arrows: + if world.retro[player]: + equip[0x38E] |= 0x80 + starting_arrows = 1 + else: + starting_arrows += arrows[item.name] + elif item.name in ['Piece of Heart', 'Boss Heart Container', 'Sanctuary Heart Container']: + if item.name == 'Piece of Heart': + equip[0x36B] = (equip[0x36B] + 1) % 4 + if item.name != 'Piece of Heart' or equip[0x36B] == 0: + equip[0x36C] = min(equip[0x36C] + 0x08, 0xA0) + equip[0x36D] = min(equip[0x36D] + 0x08, 0xA0) + else: + raise RuntimeError(f'Unsupported item in starting equipment: {item.name}') + + equip[0x370] = min(starting_bomb_cap_upgrades, 50) + equip[0x371] = min(starting_arrow_cap_upgrades, 70) + equip[0x343] = min(starting_bombs, (equip[0x370] + starting_max_bombs)) + equip[0x377] = min(starting_arrows, (equip[0x371] + starting_max_arrows)) + + # Assertion and copy equip to initial_sram_bytes + assert equip[:0x340] == [0] * 0x340 + self._initial_sram_bytes[0x340:0x38F] = equip[0x340:0x38F] + + # Set counters and highest equipment values + self._initial_sram_bytes[0x471] = count_set_bits(self._initial_sram_bytes[0x37A]) + self._initial_sram_bytes[0x429] = count_set_bits(self._initial_sram_bytes[0x374]) + self._initial_sram_bytes[0x417] = self._initial_sram_bytes[0x359] + self._initial_sram_bytes[0x422] = self._initial_sram_bytes[0x35A] + self._initial_sram_bytes[0x46E] = self._initial_sram_bytes[0x35B] + + if world.swords[player] == "swordless": + self.__initial_sram_bytes[0x359] = 0xFF + self.__initial_sram_bytes[0x417] = 0x00 + + def set_starting_rupees(self, rupees: int): + if not (-1 < rupees < 10000): + raise ValueError("Starting rupees must be between 0 and 9999") + self._initial_sram_bytes[0x362] = self._initial_sram_bytes[0x360] = rupees & 0xFF + self._initial_sram_bytes[0x363] = self._initial_sram_bytes[0x361] = rupees >> 8 + + def set_progress_indicator(self, indicator: int): + self._set_value(0x3C5, indicator) + + def set_progress_flags(self, flags: int): + self._set_value(0x3C6, flags) + + def set_starting_entrance(self, entrance: int): + self._set_value(0x3C8, entrance) + + def set_starting_timer(self, seconds: int): + timer = (seconds * 60).to_bytes(4, "little") + self._initial_sram_bytes[0x454] = timer[0] + self._initial_sram_bytes[0x455] = timer[1] + self._initial_sram_bytes[0x456] = timer[2] + self._initial_sram_bytes[0x457] = timer[3] + + def set_swordless_curtains(self): + self._or_value(ROOM_DATA+0x61, 0x80) + self._or_value(ROOM_DATA+0x93, 0x80) + + def get_initial_sram(self): + assert len(self._initial_sram_bytes) == SRAM_SIZE + + return self._initial_sram_bytes[:] diff --git a/Items.py b/Items.py index c88bccf7..f8bc7a85 100644 --- a/Items.py +++ b/Items.py @@ -57,6 +57,7 @@ item_table = {'Bow': (True, False, None, 0x0B, 200, 'You have\nchosen the\narche 'Master Sword': (True, False, 'Sword', 0x50, 100, 'I beat barries and pigs alike', 'and the master sword', 'sword-wielding kid', 'glow sword for sale', 'fungus for blue slasher', 'sword boy fights again', 'the Master Sword'), 'Tempered Sword': (True, False, 'Sword', 0x02, 150, 'I stole the\nblacksmith\'s\njob!', 'the tempered sword', 'sword-wielding kid', 'flame sword for sale', 'fungus for red slasher', 'sword boy fights again', 'the Tempered Sword'), 'Fighter Sword': (True, False, 'Sword', 0x49, 50, 'A pathetic\nsword rests\nhere!', 'the tiny sword', 'sword-wielding kid', 'tiny sword for sale', 'fungus for tiny slasher', 'sword boy fights again', 'the small sword'), + 'Sword and Shield': (True, False, 'Sword', 0x00, 'An uncle\nsword rests\nhere!', 'the sword and shield', 'sword and shield-wielding kid', 'training set for sale', 'fungus for training set', 'sword and shield boy fights again', 'the small sword and shield'), 'Golden Sword': (True, False, 'Sword', 0x03, 200, 'The butter\nsword rests\nhere!', 'and the butter sword', 'sword-wielding kid', 'butter for sale', 'cap churned to butter', 'sword boy fights again', 'the Golden Sword'), 'Progressive Sword': (True, False, 'Sword', 0x5E, 150, 'a better copy\nof your sword\nfor your time', 'the unknown sword', 'sword-wielding kid', 'sword for sale', 'fungus for some slasher', 'sword boy fights again', 'a sword'), 'Progressive Glove': (True, False, None, 0x61, 150, 'a way to lift\nheavier things', 'and the lift upgrade', 'body-building kid', 'some glove for sale', 'fungus for gloves', 'body-building boy lifts again', 'a glove'), diff --git a/Rom.py b/Rom.py index 0a392c1f..e0134579 100644 --- a/Rom.py +++ b/Rom.py @@ -29,13 +29,14 @@ from Text import Lumberjacks_texts, SickKid_texts, FluteBoy_texts, Zora_texts, M from Utils import output_path, local_path, int16_as_bytes, int32_as_bytes, snes_to_pc from Items import ItemFactory from EntranceShuffle import door_addresses, exit_ids, ow_prize_table +from InitialSram import InitialSram from source.classes.SFX import randomize_sfx from source.item.FillUtil import valid_pot_items JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '8d196e8024faebbbbe1304032158ccea' +RANDOMIZERBASEHASH = '65c56d252ed3d6d94546912526bffb70' class JsonRom(object): @@ -46,6 +47,7 @@ class JsonRom(object): self.orig_buffer = None self.patches = {} self.addresses = [] + self.initial_sram = InitialSram() def write_byte(self, address, value): self.write_bytes(address, [value]) @@ -75,6 +77,9 @@ class JsonRom(object): del self.patches[str(intervalstart)] del self.addresses[pos] + def write_initial_sram(self): + self.write_bytes(0x183000, self.initial_sram.get_initial_sram()) + def write_to_file(self, file): with open(file, 'w') as stream: json.dump([self.patches], stream) @@ -92,6 +97,7 @@ class LocalRom(object): self.hash = hash self.orig_buffer = None self.file = file + self.initial_sram = InitialSram() self.has_smc_header = False if not os.path.isfile(file): raise RuntimeError("Could not find valid local base rom for patching at expected path %s." % file) @@ -107,6 +113,9 @@ class LocalRom(object): def write_bytes(self, startaddress, values): self.buffer[startaddress:startaddress + len(values)] = values + def write_initial_sram(self): + self.write_bytes(0x183000, self.initial_sram.get_initial_sram()) + def write_to_file(self, file): with open(file, 'wb') as outfile: outfile.write(self.buffer) @@ -956,11 +965,11 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): # set open mode: if world.mode[player] in ['open', 'inverted']: - rom.write_byte(0x180032, 0x01) # open mode + init_open_mode_sram(rom) if world.mode[player] == 'inverted': - set_inverted_mode(world, player, rom) + set_inverted_mode(world, rom) elif world.mode[player] == 'standard': - rom.write_byte(0x180032, 0x00) # standard mode + init_standard_mode_sram(rom) uncle_location = world.get_location('Link\'s Uncle', player) if uncle_location.item is None or uncle_location.item.name not in ['Master Sword', 'Tempered Sword', 'Fighter Sword', 'Golden Sword', 'Progressive Sword']: @@ -1184,10 +1193,9 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): # set swordless mode settings rom.write_byte(0x18003F, 0x01 if world.swords[player] == 'swordless' else 0x00) # hammer can harm ganon - rom.write_byte(0x180040, 0x01 if world.swords[player] == 'swordless' else 0x00) # open curtains rom.write_byte(0x180041, 0x01 if world.swords[player] == 'swordless' else 0x00) # swordless medallions - rom.write_byte(0x180043, 0xFF if world.swords[player] == 'swordless' else 0x00) # starting sword for link rom.write_byte(0x180044, 0x01 if world.swords[player] == 'swordless' else 0x00) # hammer activates tablets + rom.initial_sram.set_swordless_curtains() # open curtains # set up clocks for timed modes if world.shuffle[player] == 'vanilla': @@ -1203,34 +1211,34 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): write_int32(rom, 0x180200, 0) # red clock adjustment time (in frames, sint32) write_int32(rom, 0x180204, 0) # blue clock adjustment time (in frames, sint32) write_int32(rom, 0x180208, 0) # green clock adjustment time (in frames, sint32) - write_int32(rom, 0x18020C, 0) # starting time (in frames, sint32) + rom.initial_sram.set_starting_timer(0) # starting time (in frames, sint32) elif world.clock_mode == 'ohko': rom.write_bytes(0x180190, [0x01, 0x02, 0x01]) # ohko timer with resetable timer functionality write_int32(rom, 0x180200, 0) # red clock adjustment time (in frames, sint32) write_int32(rom, 0x180204, 0) # blue clock adjustment time (in frames, sint32) write_int32(rom, 0x180208, 0) # green clock adjustment time (in frames, sint32) - write_int32(rom, 0x18020C, 0) # starting time (in frames, sint32) + rom.initial_sram.set_starting_timer(0) # starting time (in frames, sint32) elif world.clock_mode == 'countdown-ohko': rom.write_bytes(0x180190, [0x01, 0x02, 0x01]) # ohko timer with resetable timer functionality write_int32(rom, 0x180200, -100 * 60 * 60 * 60) # red clock adjustment time (in frames, sint32) write_int32(rom, 0x180204, 2 * 60 * 60) # blue clock adjustment time (in frames, sint32) write_int32(rom, 0x180208, 4 * 60 * 60) # green clock adjustment time (in frames, sint32) - if world.difficulty_adjustments[player] == 'normal': - write_int32(rom, 0x18020C, (10 + ERtimeincrease) * 60 * 60) # starting time (in frames, sint32) + if world.difficulty_adjustments == 'normal': + rom.initial_sram.set_starting_timer((10 + ERtimeincrease) * 60) # starting time (in seconds) else: - write_int32(rom, 0x18020C, int((5 + ERtimeincrease / 2) * 60 * 60)) # starting time (in frames, sint32) + rom.initial_sram.set_starting_timer(int((5 + ERtimeincrease / 2) * 60)) # starting time (in seconds) if world.clock_mode == 'stopwatch': rom.write_bytes(0x180190, [0x02, 0x01, 0x00]) # set stopwatch mode write_int32(rom, 0x180200, -2 * 60 * 60) # red clock adjustment time (in frames, sint32) write_int32(rom, 0x180204, 2 * 60 * 60) # blue clock adjustment time (in frames, sint32) write_int32(rom, 0x180208, 4 * 60 * 60) # green clock adjustment time (in frames, sint32) - write_int32(rom, 0x18020C, 0) # starting time (in frames, sint32) + rom.initial_sram.set_starting_timer(0) # starting time (in frames, sint32) if world.clock_mode == 'countdown': rom.write_bytes(0x180190, [0x01, 0x01, 0x00]) # set countdown, with no reset available write_int32(rom, 0x180200, -2 * 60 * 60) # red clock adjustment time (in frames, sint32) write_int32(rom, 0x180204, 2 * 60 * 60) # blue clock adjustment time (in frames, sint32) write_int32(rom, 0x180208, 4 * 60 * 60) # green clock adjustment time (in frames, sint32) - write_int32(rom, 0x18020C, (40 + ERtimeincrease) * 60 * 60) # starting time (in frames, sint32) + rom.initial_sram.set_starting_timer((40 + ERtimeincrease) * 60) # starting time (in seconds) # set up goals for treasure hunt rom.write_bytes(0x180165, [0x0E, 0x28] if world.treasure_hunt_icon[player] == 'Triforce Piece' else [0x0D, 0x28]) @@ -1255,14 +1263,16 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): rom.write_byte(0x180169, 0x02) # lock aga/ganon tower door with crystals in inverted rom.write_byte(0x180171, 0x01 if world.ganon_at_pyramid[player] else 0x00) # Enable respawning on pyramid after ganon death rom.write_byte(0x180173, 0x01) # Bob is enabled - rom.write_byte(0x180168, 0x08) # Spike Cave Damage + rom.write_byte(0x180195, 0x08) # Spike Cave Damage rom.write_bytes(0x18016B, [0x04, 0x02, 0x01]) # Set spike cave and MM spike room Byrna usage rom.write_bytes(0x18016E, [0x04, 0x08, 0x10]) # Set spike cave and MM spike room Cape usage rom.write_bytes(0x50563, [0x3F, 0x14]) # disable below ganon chest rom.write_byte(0x50599, 0x00) # disable below ganon chest rom.write_bytes(0xE9A5, [0x7E, 0x00, 0x24]) # disable below ganon chest - rom.write_byte(0x18008B, 0x01 if world.open_pyramid[player] else 0x00) # pre-open Pyramid Hole - rom.write_byte(0x18008C, 0x01 if world.crystals_needed_for_gt[player] == 0 else 0x00) # GT pre-opened if crystal requirement is 0 + if world.open_pyramid[player]: + rom.initial_sram.pre_open_pyramid_hole() + if world.crystals_needed_for_gt == 0: + rom.initial_sram.pre_open_ganons_tower() rom.write_byte(0xF5D73, 0xF0) # bees are catchable rom.write_byte(0xF5F10, 0xF0) # bees are catchable rom.write_byte(0x180086, 0x00 if world.aga_randomness else 0x01) # set blue ball and ganon warp randomness @@ -1274,161 +1284,9 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): # Starting equipment if world.pseudoboots[player]: rom.write_byte(0x18008E, 0x01) - - equip = [0] * (0x340 + 0x4F) - equip[0x36C] = 0x18 - equip[0x36D] = 0x18 - equip[0x379] = 0x68 - if world.bombbag[player]: - starting_max_bombs = 0 - else: - starting_max_bombs = 10 - starting_max_arrows = 30 - - startingstate = CollectionState(world) - - if startingstate.has('Bow', player): - equip[0x340] = 3 if startingstate.has('Silver Arrows', player) else 1 - equip[0x38E] |= 0x20 # progressive flag to get the correct hint in all cases - if not world.retro[player]: - equip[0x38E] |= 0x80 - if startingstate.has('Silver Arrows', player): - equip[0x38E] |= 0x40 - - if startingstate.has('Titans Mitts', player): - equip[0x354] = 2 - elif startingstate.has('Power Glove', player): - equip[0x354] = 1 - - if startingstate.has('Golden Sword', player): - equip[0x359] = 4 - elif startingstate.has('Tempered Sword', player): - equip[0x359] = 3 - elif startingstate.has('Master Sword', player): - equip[0x359] = 2 - elif startingstate.has('Fighter Sword', player): - equip[0x359] = 1 - - if startingstate.has('Mirror Shield', player): - equip[0x35A] = 3 - elif startingstate.has('Red Shield', player): - equip[0x35A] = 2 - elif startingstate.has('Blue Shield', player): - equip[0x35A] = 1 - - if startingstate.has('Red Mail', player): - equip[0x35B] = 2 - elif startingstate.has('Blue Mail', player): - equip[0x35B] = 1 - - if startingstate.has('Magic Upgrade (1/4)', player): - equip[0x37B] = 2 - equip[0x36E] = 0x80 - elif startingstate.has('Magic Upgrade (1/2)', player): - equip[0x37B] = 1 - equip[0x36E] = 0x80 - - for item in world.precollected_items: - if item.player != player: - continue - - if item.name in ['Bow', 'Silver Arrows', 'Progressive Bow', 'Progressive Bow (Alt)', - 'Titans Mitts', 'Power Glove', 'Progressive Glove', - 'Golden Sword', 'Tempered Sword', 'Master Sword', 'Fighter Sword', 'Progressive Sword', - 'Mirror Shield', 'Red Shield', 'Blue Shield', 'Progressive Shield', - 'Red Mail', 'Blue Mail', 'Progressive Armor', - 'Magic Upgrade (1/4)', 'Magic Upgrade (1/2)']: - continue - - set_table = {'Book of Mudora': (0x34E, 1), 'Hammer': (0x34B, 1), 'Bug Catching Net': (0x34D, 1), 'Hookshot': (0x342, 1), 'Magic Mirror': (0x353, 2), - 'Cape': (0x352, 1), 'Lamp': (0x34A, 1), 'Moon Pearl': (0x357, 1), 'Cane of Somaria': (0x350, 1), 'Cane of Byrna': (0x351, 1), - 'Fire Rod': (0x345, 1), 'Ice Rod': (0x346, 1), 'Bombos': (0x347, 1), 'Ether': (0x348, 1), 'Quake': (0x349, 1)} - or_table = {'Green Pendant': (0x374, 0x04), 'Red Pendant': (0x374, 0x01), 'Blue Pendant': (0x374, 0x02), - 'Crystal 1': (0x37A, 0x02), 'Crystal 2': (0x37A, 0x10), 'Crystal 3': (0x37A, 0x40), 'Crystal 4': (0x37A, 0x20), - 'Crystal 5': (0x37A, 0x04), 'Crystal 6': (0x37A, 0x01), 'Crystal 7': (0x37A, 0x08), - 'Big Key (Eastern Palace)': (0x367, 0x20), 'Compass (Eastern Palace)': (0x365, 0x20), 'Map (Eastern Palace)': (0x369, 0x20), - 'Big Key (Desert Palace)': (0x367, 0x10), 'Compass (Desert Palace)': (0x365, 0x10), 'Map (Desert Palace)': (0x369, 0x10), - 'Big Key (Tower of Hera)': (0x366, 0x20), 'Compass (Tower of Hera)': (0x364, 0x20), 'Map (Tower of Hera)': (0x368, 0x20), - 'Big Key (Escape)': (0x367, 0xC0), 'Compass (Escape)': (0x365, 0xC0), 'Map (Escape)': (0x369, 0xC0), - 'Big Key (Agahnims Tower)': (0x367, 0x08), 'Compass (Agahnims Tower)': (0x365, 0x08), 'Map (Agahnims Tower)': (0x369, 0x08), - 'Big Key (Palace of Darkness)': (0x367, 0x02), 'Compass (Palace of Darkness)': (0x365, 0x02), 'Map (Palace of Darkness)': (0x369, 0x02), - 'Big Key (Thieves Town)': (0x366, 0x10), 'Compass (Thieves Town)': (0x364, 0x10), 'Map (Thieves Town)': (0x368, 0x10), - 'Big Key (Skull Woods)': (0x366, 0x80), 'Compass (Skull Woods)': (0x364, 0x80), 'Map (Skull Woods)': (0x368, 0x80), - 'Big Key (Swamp Palace)': (0x367, 0x04), 'Compass (Swamp Palace)': (0x365, 0x04), 'Map (Swamp Palace)': (0x369, 0x04), - 'Big Key (Ice Palace)': (0x366, 0x40), 'Compass (Ice Palace)': (0x364, 0x40), 'Map (Ice Palace)': (0x368, 0x40), - 'Big Key (Misery Mire)': (0x367, 0x01), 'Compass (Misery Mire)': (0x365, 0x01), 'Map (Misery Mire)': (0x369, 0x01), - 'Big Key (Turtle Rock)': (0x366, 0x08), 'Compass (Turtle Rock)': (0x364, 0x08), 'Map (Turtle Rock)': (0x368, 0x08), - 'Big Key (Ganons Tower)': (0x366, 0x04), 'Compass (Ganons Tower)': (0x364, 0x04), 'Map (Ganons Tower)': (0x368, 0x04)} - set_or_table = {'Flippers': (0x356, 1, 0x379, 0x02),'Pegasus Boots': (0x355, 1, 0x379, 0x04), - 'Shovel': (0x34C, 1, 0x38C, 0x04), 'Ocarina': (0x34C, 3, 0x38C, 0x01), - 'Mushroom': (0x344, 1, 0x38C, 0x20 | 0x08), 'Magic Powder': (0x344, 2, 0x38C, 0x10), - 'Blue Boomerang': (0x341, 1, 0x38C, 0x80), 'Red Boomerang': (0x341, 2, 0x38C, 0x40)} - keys = {'Small Key (Eastern Palace)': [0x37E], 'Small Key (Desert Palace)': [0x37F], - 'Small Key (Tower of Hera)': [0x386], - 'Small Key (Agahnims Tower)': [0x380], 'Small Key (Palace of Darkness)': [0x382], - 'Small Key (Thieves Town)': [0x387], - 'Small Key (Skull Woods)': [0x384], 'Small Key (Swamp Palace)': [0x381], - 'Small Key (Ice Palace)': [0x385], - 'Small Key (Misery Mire)': [0x383], 'Small Key (Turtle Rock)': [0x388], - 'Small Key (Ganons Tower)': [0x389], - 'Small Key (Universal)': [0x38B], 'Small Key (Escape)': [0x37C, 0x37D]} - bottles = {'Bottle': 2, 'Bottle (Red Potion)': 3, 'Bottle (Green Potion)': 4, 'Bottle (Blue Potion)': 5, - 'Bottle (Fairy)': 6, 'Bottle (Bee)': 7, 'Bottle (Good Bee)': 8} - rupees = {'Rupee (1)': 1, 'Rupees (5)': 5, 'Rupees (20)': 20, 'Rupees (50)': 50, 'Rupees (100)': 100, 'Rupees (300)': 300} - bomb_caps = {'Bomb Upgrade (+5)': 5, 'Bomb Upgrade (+10)': 10} - arrow_caps = {'Arrow Upgrade (+5)': 5, 'Arrow Upgrade (+10)': 10} - bombs = {'Single Bomb': 1, 'Bombs (3)': 3, 'Bombs (10)': 10} - arrows = {'Single Arrow': 1, 'Arrows (10)': 10} - - if item.name in set_table: - equip[set_table[item.name][0]] = set_table[item.name][1] - elif item.name in or_table: - equip[or_table[item.name][0]] |= or_table[item.name][1] - elif item.name in set_or_table: - equip[set_or_table[item.name][0]] = set_or_table[item.name][1] - equip[set_or_table[item.name][2]] |= set_or_table[item.name][3] - elif item.name in keys: - for address in keys[item.name]: - equip[address] = min(equip[address] + 1, 99) - elif item.name in bottles: - if equip[0x34F] < world.difficulty_requirements[player].progressive_bottle_limit: - equip[0x35C + equip[0x34F]] = bottles[item.name] - equip[0x34F] += 1 - elif item.name in rupees: - equip[0x360:0x362] = list(min(equip[0x360] + (equip[0x361] << 8) + rupees[item.name], 9999).to_bytes(2, byteorder='little', signed=False)) - equip[0x362:0x364] = list(min(equip[0x362] + (equip[0x363] << 8) + rupees[item.name], 9999).to_bytes(2, byteorder='little', signed=False)) - elif item.name in bomb_caps: - starting_max_bombs = min(starting_max_bombs + bomb_caps[item.name], 50) - elif item.name in arrow_caps: - starting_max_arrows = min(starting_max_arrows + arrow_caps[item.name], 70) - elif item.name in bombs: - equip[0x343] += bombs[item.name] - elif item.name in arrows: - if world.retro[player]: - equip[0x38E] |= 0x80 - equip[0x377] = 1 - else: - equip[0x377] += arrows[item.name] - elif item.name in ['Piece of Heart', 'Boss Heart Container', 'Sanctuary Heart Container']: - if item.name == 'Piece of Heart': - equip[0x36B] = (equip[0x36B] + 1) % 4 - if item.name != 'Piece of Heart' or equip[0x36B] == 0: - equip[0x36C] = min(equip[0x36C] + 0x08, 0xA0) - equip[0x36D] = min(equip[0x36D] + 0x08, 0xA0) - else: - raise RuntimeError(f'Unsupported item in starting equipment: {item.name}') - - equip[0x343] = min(equip[0x343], starting_max_bombs) - rom.write_byte(0x180034, starting_max_bombs) - equip[0x377] = min(equip[0x377], starting_max_arrows) - rom.write_byte(0x180035, starting_max_arrows) - rom.write_bytes(0x180046, equip[0x360:0x362]) - if equip[0x359]: - rom.write_byte(0x180043, equip[0x359]) - - assert equip[:0x340] == [0] * 0x340 - rom.write_bytes(0x183000, equip[0x340:]) - rom.write_bytes(0x271A6, equip[0x340:0x340+60]) + rom.initial_sram.set_starting_equipment(world, player) + rom.write_byte(0x180034, 10 if not world.bombbag[player] else 0) # starting max bombs + rom.write_byte(0x180035, 30) # starting max arrows rom.write_byte(0x18004A, 0x00 if world.mode[player] != 'inverted' else 0x01) # Inverted mode rom.write_byte(0x18005D, 0x00) # Hammer always breaks barrier @@ -1678,6 +1536,9 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False): write_strings(rom, world, player, team) + # write initial sram + rom.write_initial_sram() + rom.write_byte(0x18636C, 1 if world.remote_items[player] else 0) # set rom name @@ -2501,6 +2362,16 @@ def text_for_item(item, world, player, team): else: return f'{item.hint_text} for {world.player_names[item.player][team]}' +def init_open_mode_sram(rom): + rom.initial_sram.pre_open_castle_gate() + rom.initial_sram.set_progress_indicator(0x02) + rom.initial_sram.set_progress_flags(0x14) + rom.initial_sram.set_starting_entrance(0x01) + +def init_standard_mode_sram(rom): + rom.initial_sram.set_progress_indicator(0x00) + rom.initial_sram.set_progress_flags(0x0) + rom.initial_sram.set_starting_entrance(0x00) def set_inverted_mode(world, player, rom): rom.write_byte(snes_to_pc(0x0283E0), 0xF0) # residual portals diff --git a/Utils.py b/Utils.py index a307a6cd..74386593 100644 --- a/Utils.py +++ b/Utils.py @@ -678,6 +678,11 @@ def extract_data_from_jp_rom(rom): # print_data_block(secretdata) # print() +def count_set_bits(val): + if val == 0: + return 0 + else: + return (val & 1) + count_set_bits(val >> 1) if __name__ == '__main__': # make_new_base2current() diff --git a/data/base2current.bps b/data/base2current.bps index e4759a9cb06c9a0621447ee21979121ff6fe9960..c2e58058f06d3c93f3ccee851d7d25316d1d4f54 100644 GIT binary patch delta 21690 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 delta 21497 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