1001 lines
		
	
	
		
			43 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
		
		
			
		
	
	
			1001 lines
		
	
	
		
			43 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
|   | from itertools import chain | ||
|  | 
 | ||
|  | class Address(): | ||
|  |     prev_address = None | ||
|  | 
 | ||
|  |     def __init__(self, address=None, size=4, mask=0xFFFFFFFF, max=None, choices=None, value=None): | ||
|  |         if address is None: | ||
|  |             self.address = Address.prev_address | ||
|  |         else: | ||
|  |             self.address = address            | ||
|  |         self.value = value | ||
|  |         self.size = size | ||
|  |         self.choices = choices | ||
|  |         self.mask = mask | ||
|  | 
 | ||
|  |         Address.prev_address = self.address + self.size | ||
|  | 
 | ||
|  |         self.bit_offset = 0 | ||
|  |         while mask & 1 == 0: | ||
|  |             mask = mask >> 1 | ||
|  |             self.bit_offset += 1 | ||
|  | 
 | ||
|  |         if max is None: | ||
|  |             self.max = mask | ||
|  |         else: | ||
|  |             self.max = max | ||
|  | 
 | ||
|  | 
 | ||
|  |     def get_value(self, default=0): | ||
|  |         if self.value is None: | ||
|  |             return default | ||
|  |         return self.value | ||
|  | 
 | ||
|  | 
 | ||
|  |     def get_value_raw(self): | ||
|  |         if self.value is None: | ||
|  |             return None | ||
|  | 
 | ||
|  |         value = self.value | ||
|  |         if self.choices is not None: | ||
|  |             value = self.choices[value] | ||
|  |         if not isinstance(value, int): | ||
|  |             raise ValueError("Invalid value type '%s'" % str(value)) | ||
|  | 
 | ||
|  |         if isinstance(value, bool): | ||
|  |             value = 1 if value else 0 | ||
|  |         if value > self.max: | ||
|  |             value = self.max | ||
|  | 
 | ||
|  |         value = (value << self.bit_offset) & self.mask | ||
|  |         return value | ||
|  | 
 | ||
|  | 
 | ||
|  |     def set_value_raw(self, value): | ||
|  |         if value is None: | ||
|  |             self.value = None | ||
|  |             return | ||
|  | 
 | ||
|  |         if not isinstance(value, int): | ||
|  |             raise ValueError("Invalid value type '%s'" % str(value)) | ||
|  | 
 | ||
|  |         value = (value & self.mask) >> self.bit_offset | ||
|  |         if value > self.max: | ||
|  |             value = self.max | ||
|  |          | ||
|  |         if self.choices is not None: | ||
|  |             for choice_name, choice_value in self.choices.items(): | ||
|  |                 if choice_value == value: | ||
|  |                     value = choice_name | ||
|  |                     break | ||
|  | 
 | ||
|  |         self.value = value | ||
|  | 
 | ||
|  | 
 | ||
|  |     def get_writes(self, save_context): | ||
|  |         if self.value is None: | ||
|  |             return | ||
|  | 
 | ||
|  |         value = self.get_value_raw() | ||
|  |         if value is None: | ||
|  |             return | ||
|  | 
 | ||
|  |         values = zip(Address.to_bytes(value, self.size),  | ||
|  |                      Address.to_bytes(self.mask, self.size)) | ||
|  | 
 | ||
|  |         for i, (byte, mask) in enumerate(values): | ||
|  |             if mask == 0: | ||
|  |                 continue | ||
|  |             if mask == 0xFF: | ||
|  |                 save_context.write_byte(self.address + i, byte) | ||
|  |             else: | ||
|  |                 save_context.write_bits(self.address + i, byte, mask=mask) | ||
|  | 
 | ||
|  | 
 | ||
|  |     def to_bytes(value, size): | ||
|  |         ret = [] | ||
|  |         for _ in range(size): | ||
|  |             ret.insert(0, value & 0xFF) | ||
|  |             value = value >> 8 | ||
|  |         return ret | ||
|  | 
 | ||
|  | 
 | ||
|  | class SaveContext(): | ||
|  |     def __init__(self): | ||
|  |         self.save_bits = {} | ||
|  |         self.save_bytes = {} | ||
|  |         self.addresses = self.get_save_context_addresses() | ||
|  | 
 | ||
|  | 
 | ||
|  |     # will set the bits of value to the offset in the save (or'ing them with what is already there) | ||
|  |     def write_bits(self, address, value, mask=None, predicate=None): | ||
|  |         if predicate and not predicate(value): | ||
|  |             return | ||
|  | 
 | ||
|  |         if mask is not None: | ||
|  |             value = value & mask | ||
|  | 
 | ||
|  |         if address in self.save_bytes: | ||
|  |             old_val = self.save_bytes[address] | ||
|  |             if mask is not None: | ||
|  |                 old_val &= ~mask | ||
|  |             value = old_val | value | ||
|  |             self.write_byte(address, value, predicate) | ||
|  |         elif address in self.save_bits: | ||
|  |             if mask is not None: | ||
|  |                 self.save_bits[address] &= ~mask | ||
|  |             self.save_bits[address] |= value | ||
|  |         else: | ||
|  |             self.save_bits[address] = value | ||
|  | 
 | ||
|  | 
 | ||
|  |     # will overwrite the byte at offset with the given value | ||
|  |     def write_byte(self, address, value, predicate=None): | ||
|  |         if predicate and not predicate(value): | ||
|  |             return | ||
|  | 
 | ||
|  |         if address in self.save_bits: | ||
|  |             del self.save_bits[address] | ||
|  | 
 | ||
|  |         self.save_bytes[address] = value | ||
|  | 
 | ||
|  | 
 | ||
|  |     # will overwrite the byte at offset with the given value | ||
|  |     def write_bytes(self, address, bytes, predicate=None): | ||
|  |         for i, value in enumerate(bytes): | ||
|  |             self.write_byte(address + i, value, predicate) | ||
|  | 
 | ||
|  | 
 | ||
|  |     def write_save_entry(self, address): | ||
|  |         if isinstance(address, dict): | ||
|  |             for name, sub_address in address.items(): | ||
|  |                 self.write_save_entry(sub_address) | ||
|  |         elif isinstance(address, list): | ||
|  |             for sub_address in address: | ||
|  |                 self.write_save_entry(sub_address) | ||
|  |         else: | ||
|  |             address.get_writes(self) | ||
|  | 
 | ||
|  | 
 | ||
|  |     def set_ammo_max(self): | ||
|  |         ammo_maxes = { | ||
|  |             'stick'     : ('stick_upgrade', [10,  10,  20,  30]), | ||
|  |             'nut'       : ('nut_upgrade',   [20,  20,  30,  40]), | ||
|  |             'bomb'      : ('bomb_bag',      [00,  20,  30,  40]), | ||
|  |             'bow'       : ('quiver',        [00,  30,  40,  50]), | ||
|  |             'slingshot' : ('bullet_bag',    [00,  30,  40,  50]), | ||
|  |             'rupees'    : ('wallet',        [99, 200, 500, 999]), | ||
|  |         } | ||
|  | 
 | ||
|  |         for ammo, (upgrade, maxes) in ammo_maxes.items(): | ||
|  |             upgrade_count = self.addresses['upgrades'][upgrade].get_value() | ||
|  |             try: | ||
|  |                 ammo_max = maxes[upgrade_count] | ||
|  |             except IndexError: | ||
|  |                 ammo_max = maxes[-1] | ||
|  |             if ammo == 'rupees': | ||
|  |                 self.addresses[ammo].max = ammo_max | ||
|  |             else: | ||
|  |                 self.addresses['ammo'][ammo].max = ammo_max | ||
|  | 
 | ||
|  | 
 | ||
|  |     # will overwrite the byte at offset with the given value | ||
|  |     def write_save_table(self, rom): | ||
|  |         self.set_ammo_max() | ||
|  |         for name, address in self.addresses.items(): | ||
|  |             self.write_save_entry(address) | ||
|  | 
 | ||
|  |         save_table = [] | ||
|  |         for address, value in self.save_bits.items(): | ||
|  |             if value != 0: | ||
|  |                 save_table += [(address & 0xFF00) >> 8, address & 0xFF, 0x00, value] | ||
|  |         for address, value in self.save_bytes.items(): | ||
|  |             save_table += [(address & 0xFF00) >> 8, address & 0xFF, 0x01, value] | ||
|  |         save_table += [0x00,0x00,0x00,0x00] | ||
|  | 
 | ||
|  |         table_len = len(save_table) | ||
|  |         if table_len > 0x400: | ||
|  |             raise Exception("The Initial Save Table has exceeded its maximum capacity: 0x%03X/0x400" % table_len) | ||
|  |         rom.write_bytes(rom.sym('INITIAL_SAVE_DATA'), save_table) | ||
|  | 
 | ||
|  | 
 | ||
|  |     def give_bottle(self, item, count): | ||
|  |         for bottle_id in range(4): | ||
|  |             item_slot = 'bottle_%d' % (bottle_id + 1) | ||
|  |             if self.addresses['item_slot'][item_slot].get_value(0xFF) != 0xFF: | ||
|  |                 continue | ||
|  | 
 | ||
|  |             self.addresses['item_slot'][item_slot].value = SaveContext.bottle_types[item] | ||
|  |             count -= 1 | ||
|  | 
 | ||
|  |             if count == 0: | ||
|  |                 return | ||
|  | 
 | ||
|  | 
 | ||
|  |     def give_health(self, health): | ||
|  |         health += self.addresses['health_capacity'].get_value(0x30) / 0x10 | ||
|  |         health += self.addresses['quest']['heart_pieces'].get_value() / 4 | ||
|  | 
 | ||
|  |         self.addresses['health_capacity'].value       = int(health) * 0x10 | ||
|  |         self.addresses['health'].value                = int(health) * 0x10 | ||
|  |         self.addresses['quest']['heart_pieces'].value = int((health % 1) * 4) | ||
|  | 
 | ||
|  | 
 | ||
|  |     def give_raw_item(self, item): | ||
|  |         if item.endswith(')'): | ||
|  |             item_base, count = item[:-1].split(' (', 1) | ||
|  |             if count.isdigit(): | ||
|  |                 return self.give_item(item_base, count=int(count)) | ||
|  |         return self.give_item(item) | ||
|  | 
 | ||
|  | 
 | ||
|  |     def give_item(self, item, count=1): | ||
|  |         if item in SaveContext.bottle_types: | ||
|  |             self.give_bottle(item, count) | ||
|  |         elif item in ["Piece of Heart", "Piece of Heart (Treasure Chest Game)"]: | ||
|  |             self.give_health(count / 4) | ||
|  |         elif item == "Heart Container": | ||
|  |             self.give_health(count) | ||
|  |         elif item == "Bombchu Item": | ||
|  |             self.give_bombchu_item() | ||
|  |         elif item in SaveContext.save_writes_table: | ||
|  |             for address, value in SaveContext.save_writes_table[item].items(): | ||
|  |                 if value is None: | ||
|  |                     value = count | ||
|  |                 elif isinstance(value, list): | ||
|  |                     value = value[min(len(value), count) - 1] | ||
|  |                 elif isinstance(value, bool): | ||
|  |                     value = 1 if value else 0 | ||
|  | 
 | ||
|  |                 address_value = self.addresses | ||
|  |                 prev_sub_address = 'Save Context' | ||
|  |                 for sub_address in address.split('.'): | ||
|  |                     if sub_address not in address_value: | ||
|  |                         raise ValueError('Unknown key %s in %s of SaveContext' % (sub_address, prev_sub_address)) | ||
|  | 
 | ||
|  |                     if isinstance(address_value, list): | ||
|  |                         sub_address =  int(sub_address) | ||
|  | 
 | ||
|  |                     address_value = address_value[sub_address] | ||
|  |                     prev_sub_address = sub_address | ||
|  |                 if not isinstance(address_value, Address): | ||
|  |                     raise ValueError('%s does not resolve to an Address in SaveContext' % (sub_address)) | ||
|  | 
 | ||
|  |                 if isinstance(value, int) and value < address_value.get_value(): | ||
|  |                     continue | ||
|  | 
 | ||
|  |                 address_value.value = value | ||
|  |         else: | ||
|  |             raise ValueError("Cannot give unknown starting item %s" % item) | ||
|  | 
 | ||
|  | 
 | ||
|  |     def give_bombchu_item(self): | ||
|  |         self.give_item("Bombchus", 0) | ||
|  | 
 | ||
|  | 
 | ||
|  |     def equip_default_items(self, age): | ||
|  |         self.equip_items(age, 'equips_' + age) | ||
|  | 
 | ||
|  | 
 | ||
|  |     def equip_current_items(self, age): | ||
|  |         self.equip_items(age, 'equips') | ||
|  | 
 | ||
|  | 
 | ||
|  |     def equip_items(self, age, equip_type): | ||
|  |         if age not in ['child', 'adult']: | ||
|  |             raise ValueError("Age must be 'adult' or 'child', not %s" % age) | ||
|  | 
 | ||
|  |         if equip_type not in ['equips', 'equips_child', 'equips_adult']: | ||
|  |             raise ValueError("Equip type must be 'equips', 'equips_child' or 'equips_adult', not %s" % equip_type) | ||
|  | 
 | ||
|  |         age = 'equips_' + age | ||
|  |         c_buttons = list(self.addresses[age]['button_slots'].keys()) | ||
|  |         for item_slot in SaveContext.equipable_items[age]['items']: | ||
|  |             item = self.addresses['item_slot'][item_slot].get_value('none') | ||
|  |             if item != 'none': | ||
|  |                 c_button = c_buttons.pop() | ||
|  |                 self.addresses[equip_type]['button_slots'][c_button].value = item_slot | ||
|  |                 self.addresses[equip_type]['button_items'][c_button].value = item | ||
|  |                 if not c_buttons: | ||
|  |                     break | ||
|  | 
 | ||
|  |         for equip_item, equip_addresses in self.addresses[age]['equips'].items(): | ||
|  |             for item in SaveContext.equipable_items[age][equip_item]: | ||
|  |                 if self.addresses['equip_items'][item].get_value(): | ||
|  |                     item_value = self.addresses['equip_items'][item].get_value_raw() | ||
|  |                     self.addresses[equip_type]['equips'][equip_item].set_value_raw(item_value) | ||
|  |                     if equip_item == 'tunic': | ||
|  |                         self.addresses[equip_type]['equips'][equip_item].value = 1 | ||
|  |                     if equip_item == 'sword': | ||
|  |                         self.addresses[equip_type]['button_items']['b'].value = item | ||
|  |                     break | ||
|  | 
 | ||
|  | 
 | ||
|  |     def get_save_context_addresses(self): | ||
|  |         return { | ||
|  |             'entrance_index'             : Address(0x0000, size=4), | ||
|  |             'link_age'                   : Address(size=4, max=1), | ||
|  |             'unk_00'                     : Address(size=2), | ||
|  |             'cutscene_index'             : Address(size=2), | ||
|  |             'time_of_day'                : Address(size=2), | ||
|  |             'unk_01'                     : Address(size=2), | ||
|  |             'night_flag'                 : Address(size=4, max=1), | ||
|  |             'unk_02'                     : Address(size=8), | ||
|  |             'id'                         : Address(size=6), | ||
|  |             'deaths'                     : Address(size=2), | ||
|  |             'file_name'                  : Address(size=8), | ||
|  |             'n64dd_flag'                 : Address(size=2), | ||
|  |             'health_capacity'            : Address(size=2, max=0x140), | ||
|  |             'health'                     : Address(size=2, max=0x140), | ||
|  |             'magic_level'                : Address(size=1, max=2), | ||
|  |             'magic'                      : Address(size=1, max=0x60), | ||
|  |             'rupees'                     : Address(size=2), | ||
|  |             'bgs_hits_left'              : Address(size=2), | ||
|  |             'navi_timer'                 : Address(size=2), | ||
|  |             'magic_acquired'             : Address(size=1, max=1), | ||
|  |             'unk_03'                     : Address(size=1), | ||
|  |             'double_magic'               : Address(size=1, max=1), | ||
|  |             'double_defense'             : Address(size=1, max=1), | ||
|  |             'bgs_flag'                   : Address(size=1, max=1), | ||
|  |             'unk_05'                     : Address(size=1), | ||
|  | 
 | ||
|  |             # Equiped Items | ||
|  |             'equips_child' : { | ||
|  |                 'button_items' : { | ||
|  |                     'b'                  : Address(size=1, choices=SaveContext.item_id_map), | ||
|  |                     'left'               : Address(size=1, choices=SaveContext.item_id_map), | ||
|  |                     'down'               : Address(size=1, choices=SaveContext.item_id_map), | ||
|  |                     'right'              : Address(size=1, choices=SaveContext.item_id_map), | ||
|  |                 }, | ||
|  |                 'button_slots' : { | ||
|  |                     'left'               : Address(size=1, choices=SaveContext.slot_id_map), | ||
|  |                     'down'               : Address(size=1, choices=SaveContext.slot_id_map), | ||
|  |                     'right'              : Address(size=1, choices=SaveContext.slot_id_map), | ||
|  |                 }, | ||
|  |                 'equips' : { | ||
|  |                     'sword'              : Address(0x0048, size=2, mask=0x000F), | ||
|  |                     'shield'             : Address(0x0048, size=2, mask=0x00F0), | ||
|  |                     'tunic'              : Address(0x0048, size=2, mask=0x0F00), | ||
|  |                     'boots'              : Address(0x0048, size=2, mask=0xF000),                 | ||
|  |                 }, | ||
|  |             }, | ||
|  |             'equips_adult' : { | ||
|  |                 'button_items' : { | ||
|  |                     'b'                  : Address(size=1, choices=SaveContext.item_id_map), | ||
|  |                     'left'               : Address(size=1, choices=SaveContext.item_id_map), | ||
|  |                     'down'               : Address(size=1, choices=SaveContext.item_id_map), | ||
|  |                     'right'              : Address(size=1, choices=SaveContext.item_id_map), | ||
|  |                 }, | ||
|  |                 'button_slots' : { | ||
|  |                     'left'               : Address(size=1, choices=SaveContext.slot_id_map), | ||
|  |                     'down'               : Address(size=1, choices=SaveContext.slot_id_map), | ||
|  |                     'right'              : Address(size=1, choices=SaveContext.slot_id_map), | ||
|  |                 }, | ||
|  |                 'equips' : { | ||
|  |                     'sword'              : Address(0x0052, size=2, mask=0x000F), | ||
|  |                     'shield'             : Address(0x0052, size=2, mask=0x00F0), | ||
|  |                     'tunic'              : Address(0x0052, size=2, mask=0x0F00), | ||
|  |                     'boots'              : Address(0x0052, size=2, mask=0xF000),                 | ||
|  |                 }, | ||
|  |             }, | ||
|  |             'unk_06'                     : Address(size=0x12), | ||
|  |             'scene_index'                : Address(size=2), | ||
|  | 
 | ||
|  |             'equips' : { | ||
|  |                 'button_items' : { | ||
|  |                     'b'                  : Address(size=1, choices=SaveContext.item_id_map), | ||
|  |                     'left'               : Address(size=1, choices=SaveContext.item_id_map), | ||
|  |                     'down'               : Address(size=1, choices=SaveContext.item_id_map), | ||
|  |                     'right'              : Address(size=1, choices=SaveContext.item_id_map), | ||
|  |                 }, | ||
|  |                 'button_slots' : { | ||
|  |                     'left'               : Address(size=1, choices=SaveContext.slot_id_map), | ||
|  |                     'down'               : Address(size=1, choices=SaveContext.slot_id_map), | ||
|  |                     'right'              : Address(size=1, choices=SaveContext.slot_id_map), | ||
|  |                 }, | ||
|  |                 'equips' : { | ||
|  |                     'sword'              : Address(0x0070, size=2, mask=0x000F, max=3), | ||
|  |                     'shield'             : Address(0x0070, size=2, mask=0x00F0, max=3), | ||
|  |                     'tunic'              : Address(0x0070, size=2, mask=0x0F00, max=3), | ||
|  |                     'boots'              : Address(0x0070, size=2, mask=0xF000, max=3),                 | ||
|  |                 }, | ||
|  |             }, | ||
|  |             'unk_07'                     : Address(size=2), | ||
|  | 
 | ||
|  |             # Item Slots | ||
|  |             'item_slot'                  : { | ||
|  |                 'stick'                  : Address(size=1, choices=SaveContext.item_id_map), | ||
|  |                 'nut'                    : Address(size=1, choices=SaveContext.item_id_map), | ||
|  |                 'bomb'                   : Address(size=1, choices=SaveContext.item_id_map), | ||
|  |                 'bow'                    : Address(size=1, choices=SaveContext.item_id_map), | ||
|  |                 'fire_arrow'             : Address(size=1, choices=SaveContext.item_id_map), | ||
|  |                 'dins_fire'              : Address(size=1, choices=SaveContext.item_id_map), | ||
|  |                 'slingshot'              : Address(size=1, choices=SaveContext.item_id_map), | ||
|  |                 'ocarina'                : Address(size=1, choices=SaveContext.item_id_map), | ||
|  |                 'bombchu'                : Address(size=1, choices=SaveContext.item_id_map), | ||
|  |                 'hookshot'               : Address(size=1, choices=SaveContext.item_id_map), | ||
|  |                 'ice_arrow'              : Address(size=1, choices=SaveContext.item_id_map), | ||
|  |                 'farores_wind'           : Address(size=1, choices=SaveContext.item_id_map), | ||
|  |                 'boomerang'              : Address(size=1, choices=SaveContext.item_id_map), | ||
|  |                 'lens'                   : Address(size=1, choices=SaveContext.item_id_map), | ||
|  |                 'beans'                  : Address(size=1, choices=SaveContext.item_id_map), | ||
|  |                 'hammer'                 : Address(size=1, choices=SaveContext.item_id_map), | ||
|  |                 'light_arrow'            : Address(size=1, choices=SaveContext.item_id_map), | ||
|  |                 'nayrus_love'            : Address(size=1, choices=SaveContext.item_id_map), | ||
|  |                 'bottle_1'               : Address(size=1, choices=SaveContext.item_id_map), | ||
|  |                 'bottle_2'               : Address(size=1, choices=SaveContext.item_id_map), | ||
|  |                 'bottle_3'               : Address(size=1, choices=SaveContext.item_id_map), | ||
|  |                 'bottle_4'               : Address(size=1, choices=SaveContext.item_id_map), | ||
|  |                 'adult_trade'            : Address(size=1, choices=SaveContext.item_id_map), | ||
|  |                 'child_trade'            : Address(size=1, choices=SaveContext.item_id_map), | ||
|  |             }, | ||
|  | 
 | ||
|  |             # Item Ammo | ||
|  |             'ammo' : { | ||
|  |                 'stick'                  : Address(size=1), | ||
|  |                 'nut'                    : Address(size=1), | ||
|  |                 'bomb'                   : Address(size=1), | ||
|  |                 'bow'                    : Address(size=1), | ||
|  |                 'fire_arrow'             : Address(size=1, max=0), | ||
|  |                 'dins_fire'              : Address(size=1, max=0), | ||
|  |                 'slingshot'              : Address(size=1), | ||
|  |                 'ocarina'                : Address(size=1, max=0), | ||
|  |                 'bombchu'                : Address(size=1, max=50), | ||
|  |                 'hookshot'               : Address(size=1, max=0), | ||
|  |                 'ice_arrow'              : Address(size=1, max=0), | ||
|  |                 'farores_wind'           : Address(size=1, max=0), | ||
|  |                 'boomerang'              : Address(size=1, max=0), | ||
|  |                 'lens'                   : Address(size=1, max=0), | ||
|  |                 'beans'                  : Address(size=1, max=10), | ||
|  |             }, | ||
|  |             'magic_beans_sold'           : Address(size=1, max=10), | ||
|  | 
 | ||
|  |             # Equipment | ||
|  |             'equip_items' : { | ||
|  |                 'kokiri_sword'           : Address(0x009C, size=2, mask=0x0001), | ||
|  |                 'master_sword'           : Address(0x009C, size=2, mask=0x0002), | ||
|  |                 'biggoron_sword'         : Address(0x009C, size=2, mask=0x0004), | ||
|  |                 'broken_knife'           : Address(0x009C, size=2, mask=0x0008), | ||
|  |                 'deku_shield'            : Address(0x009C, size=2, mask=0x0010), | ||
|  |                 'hylian_shield'          : Address(0x009C, size=2, mask=0x0020), | ||
|  |                 'mirror_shield'          : Address(0x009C, size=2, mask=0x0040), | ||
|  |                 'kokiri_tunic'           : Address(0x009C, size=2, mask=0x0100), | ||
|  |                 'goron_tunic'            : Address(0x009C, size=2, mask=0x0200), | ||
|  |                 'zora_tunic'             : Address(0x009C, size=2, mask=0x0400), | ||
|  |                 'kokiri_boots'           : Address(0x009C, size=2, mask=0x1000), | ||
|  |                 'iron_boots'             : Address(0x009C, size=2, mask=0x2000), | ||
|  |                 'hover_boots'            : Address(0x009C, size=2, mask=0x4000), | ||
|  |             }, | ||
|  | 
 | ||
|  |             'unk_08'                     : Address(size=2), | ||
|  | 
 | ||
|  |             # Upgrades | ||
|  |             'upgrades' : { | ||
|  |                 'quiver'                 : Address(0x00A0, mask=0x00000007, max=3), | ||
|  |                 'bomb_bag'               : Address(0x00A0, mask=0x00000038, max=3), | ||
|  |                 'strength_upgrade'       : Address(0x00A0, mask=0x000001C0, max=3), | ||
|  |                 'diving_upgrade'         : Address(0x00A0, mask=0x00000E00, max=2), | ||
|  |                 'wallet'                 : Address(0x00A0, mask=0x00003000, max=3), | ||
|  |                 'bullet_bag'             : Address(0x00A0, mask=0x0001C000, max=3), | ||
|  |                 'stick_upgrade'          : Address(0x00A0, mask=0x000E0000, max=3), | ||
|  |                 'nut_upgrade'            : Address(0x00A0, mask=0x00700000, max=3), | ||
|  |             }, | ||
|  | 
 | ||
|  |             # Medallions | ||
|  |             'quest' : { | ||
|  |                 'medallions' : { | ||
|  |                     'forest'             : Address(0x00A4, mask=0x00000001), | ||
|  |                     'fire'               : Address(0x00A4, mask=0x00000002), | ||
|  |                     'water'              : Address(0x00A4, mask=0x00000004), | ||
|  |                     'spirit'             : Address(0x00A4, mask=0x00000008), | ||
|  |                     'shadow'             : Address(0x00A4, mask=0x00000010), | ||
|  |                     'light'              : Address(0x00A4, mask=0x00000020), | ||
|  | 
 | ||
|  |                 }, | ||
|  |                 'songs' : { | ||
|  |                     'minuet_of_forest'   : Address(0x00A4, mask=0x00000040), | ||
|  |                     'bolero_of_fire'     : Address(0x00A4, mask=0x00000080), | ||
|  |                     'serenade_of_water'  : Address(0x00A4, mask=0x00000100), | ||
|  |                     'requiem_of_spirit'  : Address(0x00A4, mask=0x00000200), | ||
|  |                     'nocturne_of_shadow' : Address(0x00A4, mask=0x00000400), | ||
|  |                     'prelude_of_light'   : Address(0x00A4, mask=0x00000800), | ||
|  |                     'zeldas_lullaby'     : Address(0x00A4, mask=0x00001000), | ||
|  |                     'eponas_song'        : Address(0x00A4, mask=0x00002000), | ||
|  |                     'sarias_song'        : Address(0x00A4, mask=0x00004000), | ||
|  |                     'suns_song'          : Address(0x00A4, mask=0x00008000), | ||
|  |                     'song_of_time'       : Address(0x00A4, mask=0x00010000), | ||
|  |                     'song_of_storms'     : Address(0x00A4, mask=0x00020000), | ||
|  |                 }, | ||
|  |                 'stones' : { | ||
|  |                     'kokiris_emerald'    : Address(0x00A4, mask=0x00040000), | ||
|  |                     'gorons_ruby'        : Address(0x00A4, mask=0x00080000), | ||
|  |                     'zoras_sapphire'     : Address(0x00A4, mask=0x00100000), | ||
|  |                 }, | ||
|  |                 'stone_of_agony'         : Address(0x00A4, mask=0x00200000), | ||
|  |                 'gerudos_card'           : Address(0x00A4, mask=0x00400000), | ||
|  |                 'gold_skulltula'         : Address(0x00A4, mask=0x00800000), | ||
|  |                 'heart_pieces'           : Address(0x00A4, mask=0xFF000000), | ||
|  |             }, | ||
|  | 
 | ||
|  |             # Dungeon Items | ||
|  |             'dungeon_items' : { | ||
|  |                 'deku' : { | ||
|  |                      'boss_key'          : Address(0x00A8, size=1, mask=0x01), | ||
|  |                      'compass'           : Address(0x00A8, size=1, mask=0x02), | ||
|  |                      'map'               : Address(0x00A8, size=1, mask=0x04), | ||
|  |                 }, | ||
|  |                 'dodongo' : { | ||
|  |                      'boss_key'          : Address(0x00A9, size=1, mask=0x01), | ||
|  |                      'compass'           : Address(0x00A9, size=1, mask=0x02), | ||
|  |                      'map'               : Address(0x00A9, size=1, mask=0x04), | ||
|  |                 }, | ||
|  |                 'jabu' : { | ||
|  |                      'boss_key'          : Address(0x00AA, size=1, mask=0x01), | ||
|  |                      'compass'           : Address(0x00AA, size=1, mask=0x02), | ||
|  |                      'map'               : Address(0x00AA, size=1, mask=0x04), | ||
|  |                 }, | ||
|  |                 'forest' : { | ||
|  |                      'boss_key'          : Address(0x00AB, size=1, mask=0x01), | ||
|  |                      'compass'           : Address(0x00AB, size=1, mask=0x02), | ||
|  |                      'map'               : Address(0x00AB, size=1, mask=0x04), | ||
|  |                 }, | ||
|  |                 'fire' : { | ||
|  |                      'boss_key'          : Address(0x00AC, size=1, mask=0x01), | ||
|  |                      'compass'           : Address(0x00AC, size=1, mask=0x02), | ||
|  |                      'map'               : Address(0x00AC, size=1, mask=0x04), | ||
|  |                 }, | ||
|  |                 'water' : { | ||
|  |                      'boss_key'          : Address(0x00AD, size=1, mask=0x01), | ||
|  |                      'compass'           : Address(0x00AD, size=1, mask=0x02), | ||
|  |                      'map'               : Address(0x00AD, size=1, mask=0x04), | ||
|  |                 }, | ||
|  |                 'spirit' : { | ||
|  |                      'boss_key'          : Address(0x00AE, size=1, mask=0x01), | ||
|  |                      'compass'           : Address(0x00AE, size=1, mask=0x02), | ||
|  |                      'map'               : Address(0x00AE, size=1, mask=0x04), | ||
|  |                 }, | ||
|  |                 'shadow' : { | ||
|  |                      'boss_key'          : Address(0x00AF, size=1, mask=0x01), | ||
|  |                      'compass'           : Address(0x00AF, size=1, mask=0x02), | ||
|  |                      'map'               : Address(0x00AF, size=1, mask=0x04), | ||
|  |                 }, | ||
|  |                 'botw' : { | ||
|  |                      'boss_key'          : Address(0x00B0, size=1, mask=0x01), | ||
|  |                      'compass'           : Address(0x00B0, size=1, mask=0x02), | ||
|  |                      'map'               : Address(0x00B0, size=1, mask=0x04), | ||
|  |                 }, | ||
|  |                 'ice' : { | ||
|  |                      'boss_key'          : Address(0x00B1, size=1, mask=0x01), | ||
|  |                      'compass'           : Address(0x00B1, size=1, mask=0x02), | ||
|  |                      'map'               : Address(0x00B1, size=1, mask=0x04), | ||
|  |                 }, | ||
|  |                 'gt' : { | ||
|  |                      'boss_key'          : Address(0x00B2, size=1, mask=0x01), | ||
|  |                      'compass'           : Address(0x00B2, size=1, mask=0x02), | ||
|  |                      'map'               : Address(0x00B2, size=1, mask=0x04), | ||
|  |                 }, | ||
|  |                 'gtg' : { | ||
|  |                      'boss_key'          : Address(0x00B3, size=1, mask=0x01), | ||
|  |                      'compass'           : Address(0x00B3, size=1, mask=0x02), | ||
|  |                      'map'               : Address(0x00B3, size=1, mask=0x04), | ||
|  |                 }, | ||
|  |                 'fortress' : { | ||
|  |                      'boss_key'          : Address(0x00B4, size=1, mask=0x01), | ||
|  |                      'compass'           : Address(0x00B4, size=1, mask=0x02), | ||
|  |                      'map'               : Address(0x00B4, size=1, mask=0x04), | ||
|  |                 }, | ||
|  |                 'gc' : { | ||
|  |                      'boss_key'          : Address(0x00B5, size=1, mask=0x01), | ||
|  |                      'compass'           : Address(0x00B5, size=1, mask=0x02), | ||
|  |                      'map'               : Address(0x00B5, size=1, mask=0x04), | ||
|  |                 }, | ||
|  |                 'unused'                 : Address(size=6), | ||
|  |             }, | ||
|  |             'keys' : { | ||
|  |                 'deku'                   : Address(size=1), | ||
|  |                 'dodongo'                : Address(size=1), | ||
|  |                 'jabu'                   : Address(size=1), | ||
|  |                 'forest'                 : Address(size=1), | ||
|  |                 'fire'                   : Address(size=1), | ||
|  |                 'water'                  : Address(size=1), | ||
|  |                 'spirit'                 : Address(size=1), | ||
|  |                 'shadow'                 : Address(size=1), | ||
|  |                 'botw'                   : Address(size=1), | ||
|  |                 'ice'                    : Address(size=1), | ||
|  |                 'gt'                     : Address(size=1), | ||
|  |                 'gtg'                    : Address(size=1), | ||
|  |                 'fortress'               : Address(size=1), | ||
|  |                 'gc'                     : Address(size=1), | ||
|  |                 'unused'                 : Address(size=5), | ||
|  |             }, | ||
|  |             'defense_hearts'             : Address(size=1, max=20), | ||
|  |             'gs_tokens'                  : Address(size=2, max=100), | ||
|  |             'triforce_pieces'            : Address(0xD4 + 0x1C * 0x48 + 0x10, size=4), # Unused word in scene x48 | ||
|  |         } | ||
|  | 
 | ||
|  | 
 | ||
|  |     item_id_map = { | ||
|  |         'none'                : 0xFF, | ||
|  |         'stick'               : 0x00, | ||
|  |         'nut'                 : 0x01, | ||
|  |         'bomb'                : 0x02, | ||
|  |         'bow'                 : 0x03, | ||
|  |         'fire_arrow'          : 0x04, | ||
|  |         'dins_fire'           : 0x05, | ||
|  |         'slingshot'           : 0x06, | ||
|  |         'fairy_ocarina'       : 0x07, | ||
|  |         'ocarina_of_time'     : 0x08, | ||
|  |         'bombchu'             : 0x09, | ||
|  |         'hookshot'            : 0x0A, | ||
|  |         'longshot'            : 0x0B, | ||
|  |         'ice_arrow'           : 0x0C, | ||
|  |         'farores_wind'        : 0x0D, | ||
|  |         'boomerang'           : 0x0E, | ||
|  |         'lens'                : 0x0F, | ||
|  |         'beans'               : 0x10, | ||
|  |         'hammer'              : 0x11, | ||
|  |         'light_arrow'         : 0x12, | ||
|  |         'nayrus_love'         : 0x13, | ||
|  |         'bottle'              : 0x14, | ||
|  |         'red_potion'          : 0x15, | ||
|  |         'green_potion'        : 0x16, | ||
|  |         'blue_potion'         : 0x17, | ||
|  |         'fairy'               : 0x18, | ||
|  |         'fish'                : 0x19, | ||
|  |         'milk'                : 0x1A, | ||
|  |         'letter'              : 0x1B, | ||
|  |         'blue_fire'           : 0x1C, | ||
|  |         'bug'                 : 0x1D, | ||
|  |         'big_poe'             : 0x1E, | ||
|  |         'half_milk'           : 0x1F, | ||
|  |         'poe'                 : 0x20, | ||
|  |         'weird_egg'           : 0x21, | ||
|  |         'chicken'             : 0x22, | ||
|  |         'zeldas_letter'       : 0x23, | ||
|  |         'keaton_mask'         : 0x24, | ||
|  |         'skull_mask'          : 0x25, | ||
|  |         'spooky_mask'         : 0x26, | ||
|  |         'bunny_hood'          : 0x27, | ||
|  |         'goron_mask'          : 0x28, | ||
|  |         'zora_mask'           : 0x29, | ||
|  |         'gerudo_mask'         : 0x2A, | ||
|  |         'mask_of_truth'       : 0x2B, | ||
|  |         'sold_out'            : 0x2C, | ||
|  |         'pocket_egg'          : 0x2D, | ||
|  |         'pocket_cucco'        : 0x2E, | ||
|  |         'cojiro'              : 0x2F, | ||
|  |         'odd_mushroom'        : 0x30, | ||
|  |         'odd_potion'          : 0x31, | ||
|  |         'poachers_saw'        : 0x32, | ||
|  |         'broken_gorons_sword' : 0x33, | ||
|  |         'prescription'        : 0x34, | ||
|  |         'eyeball_frog'        : 0x35, | ||
|  |         'eye_drops'           : 0x36, | ||
|  |         'claim_check'         : 0x37, | ||
|  |         'bow_fire_arrow'      : 0x38, | ||
|  |         'bow_ice_arrow'       : 0x39, | ||
|  |         'bow_light_arrow'     : 0x3A, | ||
|  |         'kokiri_sword'        : 0x3B, | ||
|  |         'master_sword'        : 0x3C, | ||
|  |         'biggoron_sword'      : 0x3D, | ||
|  |         'deku_shield'         : 0x3E, | ||
|  |         'hylian_shield'       : 0x3F, | ||
|  |         'mirror_shield'       : 0x40, | ||
|  |         'kokiri_tunic'        : 0x41, | ||
|  |         'goron_tunic'         : 0x42, | ||
|  |         'zora_tunic'          : 0x43, | ||
|  |         'kokiri_boots'        : 0x44, | ||
|  |         'iron_boots'          : 0x45, | ||
|  |         'hover_boots'         : 0x46, | ||
|  |         'bullet_bag_30'       : 0x47, | ||
|  |         'bullet_bag_40'       : 0x48, | ||
|  |         'bullet_bag_50'       : 0x49, | ||
|  |         'quiver_30'           : 0x4A, | ||
|  |         'quiver_40'           : 0x4B, | ||
|  |         'quiver_50'           : 0x4C, | ||
|  |         'bomb_bag_20'         : 0x4D, | ||
|  |         'bomb_bag_30'         : 0x4E, | ||
|  |         'bomb_bag_40'         : 0x4F, | ||
|  |         'gorons_bracelet'     : 0x40, | ||
|  |         'silver_gauntlets'    : 0x41, | ||
|  |         'golden_gauntlets'    : 0x42, | ||
|  |         'silver_scale'        : 0x43, | ||
|  |         'golden_scale'        : 0x44, | ||
|  |         'broken_giants_knife' : 0x45, | ||
|  |         'adults_wallet'       : 0x46, | ||
|  |         'giants_wallet'       : 0x47, | ||
|  |         'deku_seeds'          : 0x48, | ||
|  |         'fishing_pole'        : 0x49, | ||
|  |         'minuet'              : 0x4A, | ||
|  |         'bolero'              : 0x4B, | ||
|  |         'serenade'            : 0x4C, | ||
|  |         'requiem'             : 0x4D, | ||
|  |         'nocturne'            : 0x4E, | ||
|  |         'prelude'             : 0x4F, | ||
|  |         'zeldas_lullaby'      : 0x50, | ||
|  |         'eponas_song'         : 0x51, | ||
|  |         'sarias_song'         : 0x52, | ||
|  |         'suns_song'           : 0x53, | ||
|  |         'song_of_time'        : 0x54, | ||
|  |         'song_of_storms'      : 0x55, | ||
|  |         'forest_medallion'    : 0x56, | ||
|  |         'fire_medallion'      : 0x57, | ||
|  |         'water_medallion'     : 0x58, | ||
|  |         'spirit_medallion'    : 0x59, | ||
|  |         'shadow_medallion'    : 0x5A, | ||
|  |         'light_medallion'     : 0x5B, | ||
|  |         'kokiris_emerald'     : 0x5C, | ||
|  |         'gorons_ruby'         : 0x5D, | ||
|  |         'zoras_sapphire'      : 0x5E, | ||
|  |         'stone_of_agony'      : 0x5F, | ||
|  |         'gerudos_card'        : 0x60, | ||
|  |         'gold_skulltula'      : 0x61, | ||
|  |         'heart_container'     : 0x62, | ||
|  |         'piece_of_heart'      : 0x63, | ||
|  |         'boss_key'            : 0x64, | ||
|  |         'compass'             : 0x65, | ||
|  |         'dungeon_map'         : 0x66, | ||
|  |         'small_key'           : 0x67, | ||
|  |     } | ||
|  | 
 | ||
|  | 
 | ||
|  |     slot_id_map = { | ||
|  |         'stick'               : 0x00, | ||
|  |         'nut'                 : 0x01, | ||
|  |         'bomb'                : 0x02, | ||
|  |         'bow'                 : 0x03, | ||
|  |         'fire_arrow'          : 0x04, | ||
|  |         'dins_fire'           : 0x05, | ||
|  |         'slingshot'           : 0x06, | ||
|  |         'ocarina'             : 0x07, | ||
|  |         'bombchu'             : 0x08, | ||
|  |         'hookshot'            : 0x09, | ||
|  |         'ice_arrow'           : 0x0A, | ||
|  |         'farores_wind'        : 0x0B, | ||
|  |         'boomerang'           : 0x0C, | ||
|  |         'lens'                : 0x0D, | ||
|  |         'beans'               : 0x0E, | ||
|  |         'hammer'              : 0x0F, | ||
|  |         'light_arrow'         : 0x10, | ||
|  |         'nayrus_love'         : 0x11, | ||
|  |         'bottle_1'            : 0x12, | ||
|  |         'bottle_2'            : 0x13, | ||
|  |         'bottle_3'            : 0x14, | ||
|  |         'bottle_4'            : 0x15, | ||
|  |         'adult_trade'         : 0x16, | ||
|  |         'child_trade'         : 0x17, | ||
|  |     } | ||
|  | 
 | ||
|  | 
 | ||
|  |     bottle_types = { | ||
|  |         "Bottle"                   : 'bottle', | ||
|  |         "Bottle with Red Potion"   : 'red_potion', | ||
|  |         "Bottle with Green Potion" : 'green_potion', | ||
|  |         "Bottle with Blue Potion"  : 'blue_potion', | ||
|  |         "Bottle with Fairy"        : 'fairy', | ||
|  |         "Bottle with Fish"         : 'fish', | ||
|  |         "Bottle with Milk"         : 'milk', | ||
|  |         "Rutos Letter"             : 'letter', | ||
|  |         "Bottle with Blue Fire"    : 'blue_fire', | ||
|  |         "Bottle with Bugs"         : 'bug', | ||
|  |         "Bottle with Big Poe"      : 'big_poe', | ||
|  |         "Bottle with Milk (Half)"  : 'half_milk', | ||
|  |         "Bottle with Poe"          : 'poe',     | ||
|  |     } | ||
|  | 
 | ||
|  | 
 | ||
|  |     save_writes_table = { | ||
|  |         "Deku Stick Capacity": { | ||
|  |             'item_slot.stick'            : 'stick', | ||
|  |             'upgrades.stick_upgrade'     : [2,3], | ||
|  |         }, | ||
|  |         "Deku Sticks": { | ||
|  |             'item_slot.stick'            : 'stick', | ||
|  |             'upgrades.stick_upgrade'     : 1, | ||
|  |             'ammo.stick'                 : None, | ||
|  |         }, | ||
|  |         "Deku Nut Capacity": { | ||
|  |             'item_slot.nut'              : 'nut', | ||
|  |             'upgrades.nut_upgrade'       : [2,3], | ||
|  |         }, | ||
|  |         "Deku Nuts": { | ||
|  |             'item_slot.nut'              : 'nut', | ||
|  |             'upgrades.nut_upgrade'       : 1, | ||
|  |             'ammo.nut'                   : None, | ||
|  |         }, | ||
|  |         "Bomb Bag": { | ||
|  |             'item_slot.bomb'             : 'bomb', | ||
|  |             'upgrades.bomb_bag'          : None, | ||
|  |         }, | ||
|  |         "Bombs" : { | ||
|  |             'ammo.bomb'                  : None, | ||
|  |         }, | ||
|  |         "Bombchus" : { | ||
|  |             'item_slot.bombchu'          : 'bombchu', | ||
|  |             'ammo.bombchu'               : None, | ||
|  |         }, | ||
|  |         "Bow" : { | ||
|  |             'item_slot.bow'              : 'bow', | ||
|  |             'upgrades.quiver'            : None, | ||
|  |         }, | ||
|  |         "Arrows" : { | ||
|  |             'ammo.bow'                   : None, | ||
|  |         }, | ||
|  |         "Slingshot"    : { | ||
|  |             'item_slot.slingshot'        : 'slingshot', | ||
|  |             'upgrades.bullet_bag'        : None, | ||
|  |         }, | ||
|  |         "Deku Seeds" : { | ||
|  |             'ammo.slingshot'             : None, | ||
|  |         }, | ||
|  |         "Magic Bean" : { | ||
|  |             'item_slot.beans'            : 'beans', | ||
|  |             'ammo.beans'                 : None, | ||
|  |             'magic_beans_sold'           : None, | ||
|  |         }, | ||
|  |         "Fire Arrows"    : {'item_slot.fire_arrow'      : 'fire_arrow'}, | ||
|  |         "Ice Arrows"     : {'item_slot.ice_arrow'       : 'ice_arrow'}, | ||
|  |         "Light Arrows"   : {'item_slot.light_arrow'     : 'light_arrow'}, | ||
|  |         "Dins Fire"      : {'item_slot.dins_fire'       : 'dins_fire'}, | ||
|  |         "Farores Wind"   : {'item_slot.farores_wind'    : 'farores_wind'}, | ||
|  |         "Nayrus Love"    : {'item_slot.nayrus_love'     : 'nayrus_love'}, | ||
|  |         "Ocarina"        : {'item_slot.ocarina'         : ['fairy_ocarina', 'ocarina_of_time']}, | ||
|  |         "Progressive Hookshot" : {'item_slot.hookshot'  : ['hookshot', 'longshot']}, | ||
|  |         "Boomerang"      : {'item_slot.boomerang'       : 'boomerang'}, | ||
|  |         "Lens of Truth"  : {'item_slot.lens'            : 'lens'}, | ||
|  |         "Megaton Hammer"         : {'item_slot.hammer'          : 'hammer'}, | ||
|  |         "Pocket Egg"     : {'item_slot.adult_trade'     : 'pocket_egg'}, | ||
|  |         "Pocket Cucco"   : {'item_slot.adult_trade'     : 'pocket_cucco'}, | ||
|  |         "Cojiro"         : {'item_slot.adult_trade'     : 'cojiro'}, | ||
|  |         "Odd Mushroom"   : {'item_slot.adult_trade'     : 'odd_mushroom'}, | ||
|  |         "Poachers Saw"   : {'item_slot.adult_trade'     : 'poachers_saw'}, | ||
|  |         "Broken Sword"   : {'item_slot.adult_trade'     : 'broken_knife'}, | ||
|  |         "Prescription"   : {'item_slot.adult_trade'     : 'prescription'}, | ||
|  |         "Eyeball Frog"   : {'item_slot.adult_trade'     : 'eyeball_frog'}, | ||
|  |         "Eyedrops"       : {'item_slot.adult_trade'     : 'eye_drops'}, | ||
|  |         "Claim Check"    : {'item_slot.adult_trade'     : 'claim_check'}, | ||
|  |         "Weird Egg"      : {'item_slot.child_trade'     : 'weird_egg'}, | ||
|  |         "Chicken"        : {'item_slot.child_trade'     : 'chicken'}, | ||
|  |         "Zeldas Letter"  : {'item_slot.child_trade'     : 'zeldas_letter'}, | ||
|  |         "Goron Tunic"    : {'equip_items.goron_tunic'   : True}, | ||
|  |         "Zora Tunic"     : {'equip_items.zora_tunic'    : True}, | ||
|  |         "Iron Boots"     : {'equip_items.iron_boots'    : True}, | ||
|  |         "Hover Boots"    : {'equip_items.hover_boots'   : True}, | ||
|  |         "Deku Shield"    : {'equip_items.deku_shield'   : True}, | ||
|  |         "Hylian Shield"  : {'equip_items.hylian_shield' : True}, | ||
|  |         "Mirror Shield"  : {'equip_items.mirror_shield' : True}, | ||
|  |         "Kokiri Sword"   : {'equip_items.kokiri_sword'  : True}, | ||
|  |         "Master Sword"   : {'equip_items.master_sword'  : True}, | ||
|  |         "Giants Knife" : { | ||
|  |             'equip_items.biggoron_sword' : True, | ||
|  |             'bgs_hits_left'              : 8, | ||
|  |         }, | ||
|  |         "Biggoron Sword" : { | ||
|  |             'equip_items.biggoron_sword' : True, | ||
|  |             'bgs_flag'                   : True, | ||
|  |             'bgs_hits_left'              : 1, | ||
|  |         }, | ||
|  |         "Gerudo Membership Card" : {'quest.gerudos_card'             : True}, | ||
|  |         "Stone of Agony"         : {'quest.stone_of_agony'           : True}, | ||
|  |         "Zeldas Lullaby"         : {'quest.songs.zeldas_lullaby'     : True}, | ||
|  |         "Eponas Song"            : {'quest.songs.eponas_song'        : True}, | ||
|  |         "Sarias Song"            : {'quest.songs.sarias_song'        : True}, | ||
|  |         "Suns Song"              : {'quest.songs.suns_song'          : True}, | ||
|  |         "Song of Time"           : {'quest.songs.song_of_time'       : True}, | ||
|  |         "Song of Storms"         : {'quest.songs.song_of_storms'     : True}, | ||
|  |         "Minuet of Forest"       : {'quest.songs.minuet_of_forest'   : True}, | ||
|  |         "Bolero of Fire"         : {'quest.songs.bolero_of_fire'     : True}, | ||
|  |         "Serenade of Water"      : {'quest.songs.serenade_of_water'  : True}, | ||
|  |         "Requiem of Spirit"      : {'quest.songs.requiem_of_spirit'  : True}, | ||
|  |         "Nocturne of Shadow"     : {'quest.songs.nocturne_of_shadow' : True}, | ||
|  |         "Prelude of Light"       : {'quest.songs.prelude_of_light'   : True}, | ||
|  |         "Kokiri Emerald"         : {'quest.stones.kokiris_emerald'   : True}, | ||
|  |         "Goron Ruby"             : {'quest.stones.gorons_ruby'       : True}, | ||
|  |         "Zora Sapphire"          : {'quest.stones.zoras_sapphire'    : True}, | ||
|  |         "Light Medallion"        : {'quest.medallions.light'         : True}, | ||
|  |         "Forest Medallion"       : {'quest.medallions.forest'        : True}, | ||
|  |         "Fire Medallion"         : {'quest.medallions.fire'          : True}, | ||
|  |         "Water Medallion"        : {'quest.medallions.water'         : True}, | ||
|  |         "Spirit Medallion"       : {'quest.medallions.spirit'        : True}, | ||
|  |         "Shadow Medallion"       : {'quest.medallions.shadow'        : True}, | ||
|  |         "Progressive Strength Upgrade" : {'upgrades.strength_upgrade' : None}, | ||
|  |         "Progressive Scale"            : {'upgrades.diving_upgrade'   : None}, | ||
|  |         "Progressive Wallet"           : {'upgrades.wallet'           : None}, | ||
|  |         "Gold Skulltula Token" : { | ||
|  |             'quest.gold_skulltula'  : True, | ||
|  |             'gs_tokens'             : None, | ||
|  |         }, | ||
|  |         "Double Defense" : { | ||
|  |             'double_defense'        : True, | ||
|  |             'defense_hearts'        : 20, | ||
|  |         }, | ||
|  |         "Magic Meter" : { | ||
|  |             'magic_acquired'        : True, | ||
|  |             'magic'                 : [0x30, 0x60], | ||
|  |             'magic_level'           : None, | ||
|  |             'double_magic'          : [False, True], | ||
|  |         }, | ||
|  |         "Rupee"                     : {'rupees' : None}, | ||
|  |         "Rupees"                    : {'rupees' : None}, | ||
|  |         "Magic Bean Pack" : { | ||
|  |             'item_slot.beans'       : 'beans', | ||
|  |             'ammo.beans'            : 10 | ||
|  |         }, | ||
|  |         "Triforce Piece"            : {'triforce_pieces': None}, | ||
|  |     } | ||
|  | 
 | ||
|  |     giveable_items = set(chain(save_writes_table.keys(), bottle_types.keys(), | ||
|  |         ["Piece of Heart", "Piece of Heart (Treasure Chest Game)", "Heart Container", "Rupee (1)"])) | ||
|  | 
 | ||
|  | 
 | ||
|  |     equipable_items = { | ||
|  |         'equips_adult' : { | ||
|  |             'items': [ | ||
|  |                 'hookshot', | ||
|  |                 'hammer', | ||
|  |                 'bomb', | ||
|  |                 'bow', | ||
|  |                 'nut', | ||
|  |                 'lens', | ||
|  |                 'farores_wind', | ||
|  |                 'dins_fire', | ||
|  |                 'bombchu', | ||
|  |                 'nayrus_love', | ||
|  |                 'adult_trade', | ||
|  |                 'bottle_1', | ||
|  |                 'bottle_2', | ||
|  |                 'bottle_3', | ||
|  |                 'bottle_4', | ||
|  |             ], | ||
|  |             'sword' : [ | ||
|  |                 'biggoron_sword', | ||
|  |                 'master_sword', | ||
|  |             ], | ||
|  |             'shield' : [ | ||
|  |                 'mirror_shield', | ||
|  |                 'hylian_shield', | ||
|  |             ], | ||
|  |             'tunic' : [ | ||
|  |                 'goron_tunic', | ||
|  |                 'zora_tunic', | ||
|  |                 'kokiri_tunic', | ||
|  |             ], | ||
|  |             'boots' : [ | ||
|  |                 'kokiri_boots' | ||
|  |             ], | ||
|  |         }, | ||
|  |         'equips_child' : { | ||
|  |             'items': [ | ||
|  |                 'bomb', | ||
|  |                 'boomerang', | ||
|  |                 'slingshot', | ||
|  |                 'stick', | ||
|  |                 'nut', | ||
|  |                 'lens', | ||
|  |                 'farores_wind', | ||
|  |                 'dins_fire', | ||
|  |                 'bombchu', | ||
|  |                 'nayrus_love', | ||
|  |                 'beans', | ||
|  |                 'child_trade', | ||
|  |                 'bottle_1', | ||
|  |                 'bottle_2', | ||
|  |                 'bottle_3', | ||
|  |                 'bottle_4', | ||
|  |             ], | ||
|  |             'sword' : [ | ||
|  |                 'kokiri_sword', | ||
|  |             ], | ||
|  |             'shield' : [ | ||
|  |                 'deku_shield', | ||
|  |                 'hylian_shield', | ||
|  |             ], | ||
|  |             'tunic' : [ | ||
|  |                 'kokiri_tunic', | ||
|  |             ], | ||
|  |             'boots' : [ | ||
|  |                 'kokiri_boots', | ||
|  |             ], | ||
|  |         } | ||
|  |     } |