Skip to content

Commit

Permalink
Merge 'Fix effective starting trade items' (#2217)
Browse files Browse the repository at this point in the history
  • Loading branch information
fenhl committed Dec 13, 2024
2 parents 16c48c4 + b0ce93f commit 909bc6d
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 62 deletions.
14 changes: 1 addition & 13 deletions Patches.py
Original file line number Diff line number Diff line change
Expand Up @@ -1017,18 +1017,6 @@ def set_entrance_updates(entrances: Iterable[Entrance]) -> None:
elif world.settings.open_kakariko != 'closed':
rom.write_byte(rom.sym('OPEN_KAKARIKO'), 1)

# Mark starting trade items as owned
# The effective starting item seen in the player inventory will be the
# latest shuffled item in the trade sequence, calculated in
# Plandomizer.WorldDistribution.configure_effective_starting_items.
owned_flags = 0
for item_name in world.distribution.starting_items.keys():
if item_name in child_trade_items:
owned_flags += 0x1 << (child_trade_items.index(item_name))
if item_name in trade_items:
owned_flags += 0x1 << (trade_items.index(item_name) + 11)
save_context.write_permanent_flags(Scenes.DEATH_MOUNTAIN_TRAIL, FlagType.UNK00, owned_flags)

# Mark unreachable trade-ins as traded. Only applicable with trade quest shuffle off,
# and only practically affects the Blue Potion purchase from Granny's Potion Shop.
if not world.settings.adult_trade_shuffle and len(world.settings.adult_trade_start) > 0:
Expand Down Expand Up @@ -1068,7 +1056,7 @@ def calculate_traded_flags(world):
save_context.write_bits(0x0EDD, 0x01) # "Obtained Zelda's Letter"
save_context.write_bits(0x0EDE, 0x02) # "Learned Zelda's Lullaby"
save_context.write_bits(0x00D4 + 0x5F * 0x1C + 0x04 + 0x3, 0x10) # "Moved crates to access the courtyard"
if world.skip_child_zelda or "Zeldas Letter" in world.distribution.starting_items.keys():
if 'Zeldas Letter' in world.distribution.starting_items:
if world.settings.open_kakariko != 'closed':
save_context.write_bits(0x0F07, 0x40) # "Spoke to Gate Guard About Mask Shop"
if world.settings.complete_mask_quest:
Expand Down
18 changes: 2 additions & 16 deletions Plandomizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -1108,32 +1108,18 @@ def configure_effective_starting_items(self, worlds: list[World], world: World)
add_starting_item_with_ammo(items, location.item.name)

effective_adult_trade_item_index = -1
effective_child_trade_item_index = -1
effective_adult_trade_item = None
effective_child_trade_item = None
trade_starting_items = list(items.keys())
for item_name in trade_starting_items:
for item_name in items:
if item_name in trade_items:
if item_name in world.settings.adult_trade_start:
if trade_items.index(item_name) > effective_adult_trade_item_index:
effective_adult_trade_item_index = trade_items.index(item_name)
effective_adult_trade_item = items[item_name]
else:
raise RuntimeError(f'An unshuffled trade item was included as a starting item. Please either remove {item_name} from starting items or add it to Adult Trade Sequence Items.')
del items[item_name]
if item_name in child_trade_items:
if item_name in world.settings.shuffle_child_trade or item_name == 'Zeldas Letter':
if child_trade_items.index(item_name) > effective_child_trade_item_index:
effective_child_trade_item_index = child_trade_items.index(item_name)
effective_child_trade_item = items[item_name]
else:
if item_name not in world.settings.shuffle_child_trade and item_name != 'Zeldas Letter':
raise RuntimeError(f'An unshuffled trade item was included as a starting item. Please either remove {item_name} from starting items or add it to Shuffled Child Trade Sequence Items.')
del items[item_name]

if effective_child_trade_item_index >= 0:
items[child_trade_items[effective_child_trade_item_index]] = effective_child_trade_item
if effective_adult_trade_item_index >= 0:
items[trade_items[effective_adult_trade_item_index]] = effective_adult_trade_item
world.adult_trade_starting_inventory = trade_items[effective_adult_trade_item_index]

self.effective_starting_items = items
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ issue. You should always Hard Reset to avoid this issue entirely.
* Fix a Mac-specific issue when loading track .meta files.
* Fix an error in the easy bite fishing hack.
* The randomizer no longer ignores errors when decompressing the base rom or compressing the randomized rom.
* Trade quest items from skipped locations are no longer lost when another trade item is found.

#### New Speedups
* The first text box from each carpenter in the Thieves' Hideout is skipped.
Expand Down
156 changes: 124 additions & 32 deletions SaveContext.py
Original file line number Diff line number Diff line change
Expand Up @@ -858,11 +858,37 @@ def get_save_context_addresses() -> AddressesDict:
},
'triforce_pieces' : Address(0xD4 + 0x1C * 0x48 + 0x10, size=4), # Unused word in scene x48
'pending_freezes' : Address(0xD4 + 0x1C * 0x49 + 0x10, size=4), # Unused word in scene x49
'Ocarina_A_Button' : Address(0xD4 + 0x1C * 0x50 + 0x10, mask=0x01), # Unused word in scene x50
'Ocarina_C_up_Button' : Address(0xD4 + 0x1C * 0x50 + 0x10, mask=0x02), # Unused word in scene x50
'Ocarina_C_down_Button' : Address(0xD4 + 0x1C * 0x50 + 0x10, mask=0x04), # Unused word in scene x50
'Ocarina_C_left_Button' : Address(0xD4 + 0x1C * 0x50 + 0x10, mask=0x08), # Unused word in scene x50
'Ocarina_C_right_Button' : Address(0xD4 + 0x1C * 0x50 + 0x10, mask=0x10), # Unused word in scene x50
'ocarina_buttons' : { # Unused word in scene x50
'a' : Address(0xD4 + 0x1C * 0x50 + 0x10, size=4, mask=0x00000001),
'c_up' : Address(0xD4 + 0x1C * 0x50 + 0x10, size=4, mask=0x00000002),
'c_down' : Address(0xD4 + 0x1C * 0x50 + 0x10, size=4, mask=0x00000004),
'c_left' : Address(0xD4 + 0x1C * 0x50 + 0x10, size=4, mask=0x00000008),
'c_right' : Address(0xD4 + 0x1C * 0x50 + 0x10, size=4, mask=0x00000010),
},
'owned_trade_items' : { # Unused word in scene x60
'weird_egg' : Address(0xD4 + 0x1C * 0x60 + 0x10, size=4, mask=0x00000001),
'chicken' : Address(0xD4 + 0x1C * 0x60 + 0x10, size=4, mask=0x00000002),
'zeldas_letter' : Address(0xD4 + 0x1C * 0x60 + 0x10, size=4, mask=0x00000004),
'keaton_mask' : Address(0xD4 + 0x1C * 0x60 + 0x10, size=4, mask=0x00000008),
'skull_mask' : Address(0xD4 + 0x1C * 0x60 + 0x10, size=4, mask=0x00000010),
'spooky_mask' : Address(0xD4 + 0x1C * 0x60 + 0x10, size=4, mask=0x00000020),
'bunny_hood' : Address(0xD4 + 0x1C * 0x60 + 0x10, size=4, mask=0x00000040),
'goron_mask' : Address(0xD4 + 0x1C * 0x60 + 0x10, size=4, mask=0x00000080),
'zora_mask' : Address(0xD4 + 0x1C * 0x60 + 0x10, size=4, mask=0x00000100),
'gerudo_mask' : Address(0xD4 + 0x1C * 0x60 + 0x10, size=4, mask=0x00000200),
'mask_of_truth' : Address(0xD4 + 0x1C * 0x60 + 0x10, size=4, mask=0x00000400),
'pocket_egg' : Address(0xD4 + 0x1C * 0x60 + 0x10, size=4, mask=0x00000800),
'pocket_cucco' : Address(0xD4 + 0x1C * 0x60 + 0x10, size=4, mask=0x00001000),
'cojiro' : Address(0xD4 + 0x1C * 0x60 + 0x10, size=4, mask=0x00002000),
'odd_mushroom' : Address(0xD4 + 0x1C * 0x60 + 0x10, size=4, mask=0x00004000),
'odd_potion' : Address(0xD4 + 0x1C * 0x60 + 0x10, size=4, mask=0x00008000),
'poachers_saw' : Address(0xD4 + 0x1C * 0x60 + 0x10, size=4, mask=0x00010000),
'broken_sword' : Address(0xD4 + 0x1C * 0x60 + 0x10, size=4, mask=0x00020000),
'prescription' : Address(0xD4 + 0x1C * 0x60 + 0x10, size=4, mask=0x00040000),
'eyeball_frog' : Address(0xD4 + 0x1C * 0x60 + 0x10, size=4, mask=0x00080000),
'eyedrops' : Address(0xD4 + 0x1C * 0x60 + 0x10, size=4, mask=0x00100000),
'claim_check' : Address(0xD4 + 0x1C * 0x60 + 0x10, size=4, mask=0x00200000),
},

# begin extended save data items
'silver_rupee_counts' : {
Expand Down Expand Up @@ -1129,28 +1155,94 @@ def get_save_context_addresses() -> AddressesDict:
"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'},
"Odd Potion" : {'item_slot.adult_trade' : 'odd_potion'},
"Poachers Saw" : {'item_slot.adult_trade' : 'poachers_saw'},
"Broken Sword" : {'item_slot.adult_trade' : 'broken_sword'},
"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'},
"Keaton Mask" : {'item_slot.child_trade' : 'keaton_mask'},
"Skull Mask" : {'item_slot.child_trade' : 'skull_mask'},
"Spooky Mask" : {'item_slot.child_trade' : 'spooky_mask'},
"Bunny Hood" : {'item_slot.child_trade' : 'bunny_hood'},
"Goron Mask" : {'item_slot.child_trade' : 'goron_mask'},
"Zora Mask" : {'item_slot.child_trade' : 'zora_mask'},
"Gerudo Mask" : {'item_slot.child_trade' : 'gerudo_mask'},
"Mask of Truth" : {'item_slot.child_trade' : 'mask_of_truth'},
"Pocket Egg" : {
'item_slot.adult_trade' : 'pocket_egg',
'owned_trade_items.pocket_egg' : True,
},
"Pocket Cucco" : {
'item_slot.adult_trade' : 'pocket_cucco',
'owned_trade_items.pocket_cucco' : True,
},
"Cojiro" : {
'item_slot.adult_trade' : 'cojiro',
'owned_trade_items.cojiro' : True,
},
"Odd Mushroom" : {
'item_slot.adult_trade' : 'odd_mushroom',
'owned_trade_items.odd_mushroom' : True,
},
"Odd Potion" : {
'item_slot.adult_trade' : 'odd_potion',
'owned_trade_items.odd_potion' : True,
},
"Poachers Saw" : {
'item_slot.adult_trade' : 'poachers_saw',
'owned_trade_items.poachers_saw' : True,
},
"Broken Sword" : {
'item_slot.adult_trade' : 'broken_sword',
'owned_trade_items.broken_sword' : True,
},
"Prescription" : {
'item_slot.adult_trade' : 'prescription',
'owned_trade_items.prescription' : True,
},
"Eyeball Frog" : {
'item_slot.adult_trade' : 'eyeball_frog',
'owned_trade_items.eyeball_frog' : True,
},
"Eyedrops" : {
'item_slot.adult_trade' : 'eye_drops',
'owned_trade_items.eye_drops' : True,
},
"Claim Check" : {
'item_slot.adult_trade' : 'claim_check',
'owned_trade_items.claim_check' : True,
},
"Weird Egg" : {
'item_slot.child_trade' : 'weird_egg',
'owned_trade_items.weird_egg' : True,
},
"Chicken" : {
'item_slot.child_trade' : 'chicken',
'owned_trade_items.chicken' : True,
},
"Zeldas Letter" : {
'item_slot.child_trade' : 'zeldas_letter',
'owned_trade_items.zeldas_letter' : True,
},
"Keaton Mask" : {
'item_slot.child_trade' : 'keaton_mask',
'owned_trade_items.keaton_mask' : True,
},
"Skull Mask" : {
'item_slot.child_trade' : 'skull_mask',
'owned_trade_items.skull_mask' : True,
},
"Spooky Mask" : {
'item_slot.child_trade' : 'spooky_mask',
'owned_trade_items.spooky_mask' : True,
},
"Bunny Hood" : {
'item_slot.child_trade' : 'bunny_hood',
'owned_trade_items.bunny_hood' : True,
},
"Goron Mask" : {
'item_slot.child_trade' : 'goron_mask',
'owned_trade_items.goron_mask' : True,
},
"Zora Mask" : {
'item_slot.child_trade' : 'zora_mask',
'owned_trade_items.zora_mask' : True,
},
"Gerudo Mask" : {
'item_slot.child_trade' : 'gerudo_mask',
'owned_trade_items.gerudo_mask' : True,
},
"Mask of Truth" : {
'item_slot.child_trade' : 'mask_of_truth',
'owned_trade_items.mask_of_truth' : True,
},
"Goron Tunic" : {'equip_items.goron_tunic' : True},
"Zora Tunic" : {'equip_items.zora_tunic' : True},
"Iron Boots" : {'equip_items.iron_boots' : True},
Expand Down Expand Up @@ -1219,11 +1311,11 @@ def get_save_context_addresses() -> AddressesDict:
},
"Ice Trap" : {'pending_freezes': None},
"Triforce Piece" : {'triforce_pieces': None},
"Ocarina A Button" : {'Ocarina_A_Button': True},
"Ocarina C up Button" : {'Ocarina_C_up_Button': True},
"Ocarina C down Button" : {'Ocarina_C_down_Button': True},
"Ocarina C left Button" : {'Ocarina_C_left_Button': True},
"Ocarina C right Button" : {'Ocarina_C_right_Button': True},
"Ocarina A Button" : {'ocarina_buttons.a': True},
"Ocarina C up Button" : {'ocarina_buttons.c_up': True},
"Ocarina C down Button" : {'ocarina_buttons.c_down': True},
"Ocarina C left Button" : {'ocarina_buttons.c_left': True},
"Ocarina C right Button" : {'ocarina_buttons.c_right': True},
"Boss Key (Forest Temple)" : {'dungeon_items.forest.boss_key': True},
"Boss Key (Fire Temple)" : {'dungeon_items.fire.boss_key': True},
"Boss Key (Water Temple)" : {'dungeon_items.water.boss_key': True},
Expand Down
2 changes: 1 addition & 1 deletion version.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = '8.2.39'
__version__ = '8.2.40'

# This is a supplemental version number for branches based off of main dev.
supplementary_version = 0
Expand Down

0 comments on commit 909bc6d

Please sign in to comment.