Merge branch 'OverworldShuffleDev' into OverworldShuffle

This commit is contained in:
codemann8
2023-03-10 23:57:10 -06:00
17 changed files with 243 additions and 56 deletions

View File

@@ -1,5 +1,12 @@
# Changelog # Changelog
## 0.3.0.2
- \~Merged in DR v1.2.0.12~
- Fixed some door landing issues
- Added Cold Fairy Statue as a new Bonk Location in Bonk Drop Shuffle
- Added Customizer support for enabling OWR Options
- Removed `Arrows (5)` item from Item Table, replaces with `Arrows (10)`
## 0.3.0.1 ## 0.3.0.1
- \~Merged in DR v1.2.0.10~ - \~Merged in DR v1.2.0.10~
- Fixed some door landing issues - Fixed some door landing issues

View File

@@ -538,7 +538,7 @@ def ensure_good_pots(world, write_skips=False):
and (loc.type != LocationType.Pot or loc.item.player != loc.player)): and (loc.type != LocationType.Pot or loc.item.player != loc.player)):
loc.item = ItemFactory(invalid_location_replacement[loc.item.name], loc.item.player) loc.item = ItemFactory(invalid_location_replacement[loc.item.name], loc.item.player)
if (loc.item.name in {'Arrows (5)'} if (loc.item.name in {'Arrows (5)'}
and (loc.type not in [LocationType.Pot, LocationType.Bonk] or loc.item.player != loc.player)): and (loc.type != LocationType.Pot or loc.item.player != loc.player)):
loc.item = ItemFactory(invalid_location_replacement[loc.item.name], loc.item.player) loc.item = ItemFactory(invalid_location_replacement[loc.item.name], loc.item.player)
# # can be placed here by multiworld balancing or shop balancing # # can be placed here by multiworld balancing or shop balancing
# # change it to something normal for the player it got swapped to # # change it to something normal for the player it got swapped to

View File

@@ -392,20 +392,6 @@ def generate_itempool(world, player):
for i in range(4): for i in range(4):
next(adv_heart_pieces).advancement = True next(adv_heart_pieces).advancement = True
beeweights = {'0': {None: 100},
'1': {None: 75, 'trap': 25},
'2': {None: 40, 'trap': 40, 'bee': 20},
'3': {'trap': 50, 'bee': 50},
'4': {'trap': 100}}
def beemizer(item):
if world.beemizer[item.player] and not item.advancement and not item.priority and not item.type:
choice = random.choices(list(beeweights[world.beemizer[item.player]].keys()), weights=list(beeweights[world.beemizer[item.player]].values()))[0]
return item if not choice else ItemFactory("Bee Trap", player) if choice == 'trap' else ItemFactory("Bee", player)
return item
if not skip_pool_adjustments:
world.itempool += [beemizer(item) for item in items]
else:
world.itempool += items world.itempool += items
# shuffle medallions # shuffle medallions
@@ -463,6 +449,20 @@ def generate_itempool(world, player):
# modfiy based on start inventory, if any # modfiy based on start inventory, if any
modify_pool_for_start_inventory(start_inventory, world, player) modify_pool_for_start_inventory(start_inventory, world, player)
beeweights = {'0': {None: 100},
'1': {None: 75, 'trap': 25},
'2': {None: 40, 'trap': 40, 'bee': 20},
'3': {'trap': 50, 'bee': 50},
'4': {'trap': 100}}
def beemizer(item):
if world.beemizer[item.player] and not item.advancement and not item.priority and not item.type:
choice = random.choices(list(beeweights[world.beemizer[item.player]].keys()), weights=list(beeweights[world.beemizer[item.player]].values()))[0]
return item if not choice else ItemFactory("Bee Trap", player) if choice == 'trap' else ItemFactory("Bee", player)
return item
if not skip_pool_adjustments:
world.itempool = [beemizer(item) for item in world.itempool]
# increase pool if not enough items # increase pool if not enough items
ttl_locations = sum(1 for x in world.get_unfilled_locations(player) if '- Prize' not in x.name) ttl_locations = sum(1 for x in world.get_unfilled_locations(player) if '- Prize' not in x.name)
pool_size = count_player_dungeon_item_pool(world, player) pool_size = count_player_dungeon_item_pool(world, player)
@@ -1104,6 +1104,8 @@ def get_pool_core(world, player, progressive, shuffle, difficulty, treasure_hunt
pool.remove('Fighter Sword') pool.remove('Fighter Sword')
pool.extend(['Rupees (50)']) pool.extend(['Rupees (50)'])
#TODO: Remove test placements
#place_item('Purple Chest', 'Magic Mirror')
if timer in ['timed', 'timed-countdown']: if timer in ['timed', 'timed-countdown']:
pool.extend(diff.timedother) pool.extend(diff.timedother)
clock_mode = 'stopwatch' if timer == 'timed' else 'countdown' clock_mode = 'stopwatch' if timer == 'timed' else 'countdown'

View File

@@ -80,7 +80,7 @@ item_table = {'Bow': (True, False, None, 0x0B, 200, 'You have\nchosen the\narche
'Arrow Upgrade (+10)': (False, False, None, 0x54, 100, 'Increase arrow\nstorage, low\nlow price', 'and the quiver', 'quiver-enlarging kid', 'arrow boost for sale', 'witch and more skewers', 'upgrade boy sews more again', 'arrow capacity'), 'Arrow Upgrade (+10)': (False, False, None, 0x54, 100, 'Increase arrow\nstorage, low\nlow price', 'and the quiver', 'quiver-enlarging kid', 'arrow boost for sale', 'witch and more skewers', 'upgrade boy sews more again', 'arrow capacity'),
'Arrow Upgrade (+5)': (False, False, None, 0x53, 100, 'Increase arrow\nstorage, low\nlow price', 'and the quiver', 'quiver-enlarging kid', 'arrow boost for sale', 'witch and more skewers', 'upgrade boy sews more again', 'arrow capacity'), 'Arrow Upgrade (+5)': (False, False, None, 0x53, 100, 'Increase arrow\nstorage, low\nlow price', 'and the quiver', 'quiver-enlarging kid', 'arrow boost for sale', 'witch and more skewers', 'upgrade boy sews more again', 'arrow capacity'),
'Single Bomb': (False, False, None, 0x27, 5, 'I make things\ngo BOOM! But\njust once.', 'and the explosion', 'the bomb-holding kid', 'firecracker for sale', 'blend fungus into bomb', '\'splosion boy explodes again', 'a bomb'), 'Single Bomb': (False, False, None, 0x27, 5, 'I make things\ngo BOOM! But\njust once.', 'and the explosion', 'the bomb-holding kid', 'firecracker for sale', 'blend fungus into bomb', '\'splosion boy explodes again', 'a bomb'),
'Arrows (5)': (False, False, None, 0xB5, 15, 'This will give\nyou five shots\nwith your bow!', 'and the arrow pack', 'stick-collecting kid', 'sewing kit for sale', 'fungus for arrows', 'archer boy sews again', 'five arrows'), 'Arrows (5)': (False, False, None, 0x5A, 15, 'This will give\nyou five shots\nwith your bow!', 'and the arrow pack', 'stick-collecting kid', 'sewing kit for sale', 'fungus for arrows', 'archer boy sews again', 'five arrows'),
'Small Magic': (False, False, None, 0x45, 5, 'A bit of magic', 'and the bit of magic', 'bit-o-magic kid', 'magic bit for sale', 'fungus for magic', 'magic boy conjures again', 'a bit of magic'), 'Small Magic': (False, False, None, 0x45, 5, 'A bit of magic', 'and the bit of magic', 'bit-o-magic kid', 'magic bit for sale', 'fungus for magic', 'magic boy conjures again', 'a bit of magic'),
'Big Magic': (False, False, None, 0xB4, 40, 'A lot of magic', 'and lots of magic', 'lot-o-magic kid', 'magic refill for sale', 'fungus for magic', 'magic boy conjures again', 'a magic refill'), 'Big Magic': (False, False, None, 0xB4, 40, 'A lot of magic', 'and lots of magic', 'lot-o-magic kid', 'magic refill for sale', 'fungus for magic', 'magic boy conjures again', 'a magic refill'),
'Chicken': (False, False, None, 0xB3, 5, 'Cucco of Legend', 'and the legendary cucco', 'chicken kid', 'fried chicken for sale', 'fungus for chicken', 'cucco boy clucks again', 'a cucco'), 'Chicken': (False, False, None, 0xB3, 5, 'Cucco of Legend', 'and the legendary cucco', 'chicken kid', 'fried chicken for sale', 'fungus for chicken', 'cucco boy clucks again', 'a cucco'),
@@ -175,6 +175,7 @@ item_table = {'Bow': (True, False, None, 0x0B, 200, 'You have\nchosen the\narche
'Green Potion': (False, False, None, 0x2F, 60, 'Refreshing green goop!', 'and the green goo', 'the liquid kid', 'potion for sale', 'free samples', 'bottle boy has green goo again', 'a green potion'), 'Green Potion': (False, False, None, 0x2F, 60, 'Refreshing green goop!', 'and the green goo', 'the liquid kid', 'potion for sale', 'free samples', 'bottle boy has green goo again', 'a green potion'),
'Blue Potion': (False, False, None, 0x30, 160, 'Delicious blue goop!', 'and the blue goo', 'the liquid kid', 'potion for sale', 'free samples', 'bottle boy has blue goo again', 'a blue potion'), 'Blue Potion': (False, False, None, 0x30, 160, 'Delicious blue goop!', 'and the blue goo', 'the liquid kid', 'potion for sale', 'free samples', 'bottle boy has blue goo again', 'a blue potion'),
'Bee': (False, False, None, 0x0E, 10, 'I will sting your foes a few times', 'and the sting buddy', 'the beekeeper kid', 'insect for sale', 'shroom pollenation', 'bottle boy has mad bee again', 'a bee'), 'Bee': (False, False, None, 0x0E, 10, 'I will sting your foes a few times', 'and the sting buddy', 'the beekeeper kid', 'insect for sale', 'shroom pollenation', 'bottle boy has mad bee again', 'a bee'),
'Good Bee': (False, False, None, 0xB5, 10, 'I will sting your foes a lot', 'and the cold buddy', 'the beekeeper kid', 'cold insect for sale', 'shroom pollenation', 'bottle boy has cold bee again', 'a good bee'),
'Small Heart': (False, False, None, 0x42, 10, 'Just a little\npiece of love!', 'and the heart', 'the life-giving kid', 'little love for sale', 'fungus for life', 'life boy feels some love again', 'a heart'), 'Small Heart': (False, False, None, 0x42, 10, 'Just a little\npiece of love!', 'and the heart', 'the life-giving kid', 'little love for sale', 'fungus for life', 'life boy feels some love again', 'a heart'),
'Apples': (False, False, None, 0xB1, 30, 'Just a few pieces of fruit!', 'and the juicy fruit', 'the fruity kid', 'the fruit stand', 'expired fruit', 'bottle boy has fruit again', 'an apple hoard'), 'Apples': (False, False, None, 0xB1, 30, 'Just a few pieces of fruit!', 'and the juicy fruit', 'the fruity kid', 'the fruit stand', 'expired fruit', 'bottle boy has fruit again', 'an apple hoard'),
'Fairy': (False, False, None, 0xB2, 50, 'Just a pixie!', 'and the pixie', 'the pixie kid', 'pixie for sale', 'pixie fungus', 'bottle boy has pixie again', 'a pixie'), 'Fairy': (False, False, None, 0xB2, 50, 'Just a pixie!', 'and the pixie', 'the pixie kid', 'pixie for sale', 'pixie fungus', 'bottle boy has pixie again', 'a pixie'),

View File

@@ -36,7 +36,7 @@ from source.overworld.EntranceShuffle2 import link_entrances_new
from source.tools.BPS import create_bps_from_data from source.tools.BPS import create_bps_from_data
from source.classes.CustomSettings import CustomSettings from source.classes.CustomSettings import CustomSettings
__version__ = '1.2.0.10u' __version__ = '1.2.0.12u'
from source.classes.BabelFish import BabelFish from source.classes.BabelFish import BabelFish

View File

@@ -7,7 +7,7 @@ from OWEdges import OWTileRegions, OWEdgeGroups, OWEdgeGroupsTerrain, OWExitType
from OverworldGlitchRules import create_owg_connections from OverworldGlitchRules import create_owg_connections
from Utils import bidict from Utils import bidict
version_number = '0.3.0.1' version_number = '0.3.0.2'
# branch indicator is intentionally different across branches # branch indicator is intentionally different across branches
version_branch = '' version_branch = ''

View File

@@ -108,6 +108,16 @@ These are now independent of retro mode and have three options: None, Random, an
* Bonk Fairy (Dark) * Bonk Fairy (Dark)
# Bug Fixes and Notes # Bug Fixes and Notes
* 1.2.0.12u
* Fix for mirror portal in inverted
* Yet another fix for blocked door in Standard ER
* 1.2.0.11u
* Fixed an issue with lower layer doors in Standard
* Fix for doors in cave state (will no longer be vanilla)
* Added a logic rule for th murderdactyl near bumper ledge for OHKO purposes
* Enemizer alteration for Hovers and normal enemies in shallow water
* Fix for beemizer including modes with an increased item pool
* Fix for district algorithm
* 1.2.0.10u * 1.2.0.10u
* Fixed overrun issues with edge transitions * Fixed overrun issues with edge transitions
* Better support for customized start_inventory with dungeon items * Better support for customized start_inventory with dungeon items

View File

@@ -688,6 +688,8 @@ def create_dungeon_regions(world, player):
create_dungeon_region(player, 'Thieves Big Chest Nook', 'Thieves\' Town', ['Thieves\' Town - Big Key Chest'], ['Thieves Big Chest Nook ES Edge']), create_dungeon_region(player, 'Thieves Big Chest Nook', 'Thieves\' Town', ['Thieves\' Town - Big Key Chest'], ['Thieves Big Chest Nook ES Edge']),
create_dungeon_region(player, 'Thieves Hallway', 'Thieves\' Town', ['Thieves\' Town - Hallway Pot Key'], ['Thieves Hallway SE', 'Thieves Hallway NE', 'Thieves Hallway WN', 'Thieves Hallway WS']), create_dungeon_region(player, 'Thieves Hallway', 'Thieves\' Town', ['Thieves\' Town - Hallway Pot Key'], ['Thieves Hallway SE', 'Thieves Hallway NE', 'Thieves Hallway WN', 'Thieves Hallway WS']),
create_dungeon_region(player, 'Thieves Boss', 'Thieves\' Town', ['Revealing Light', 'Thieves\' Town - Boss', 'Thieves\' Town - Prize'], ['Thieves Boss SE']), create_dungeon_region(player, 'Thieves Boss', 'Thieves\' Town', ['Revealing Light', 'Thieves\' Town - Boss', 'Thieves\' Town - Prize'], ['Thieves Boss SE']),
#create_dungeon_region(player, 'Thieves Boss', 'Thieves\' Town', ['Thieves\' Town - Boss', 'Thieves\' Town - Prize'], ['Revealing Light', 'Thieves Boss SE']),
#create_dungeon_region(player, 'Thieves Revealing Light', 'Thieves\' Town', ['Revealing Light'], ['Thieves Boss Room']),
create_dungeon_region(player, 'Thieves Pot Alcove Mid', 'Thieves\' Town', None, ['Thieves Pot Alcove Mid ES', 'Thieves Pot Alcove Mid WS']), create_dungeon_region(player, 'Thieves Pot Alcove Mid', 'Thieves\' Town', None, ['Thieves Pot Alcove Mid ES', 'Thieves Pot Alcove Mid WS']),
create_dungeon_region(player, 'Thieves Pot Alcove Bottom', 'Thieves\' Town', None, ['Thieves Pot Alcove Bottom SW']), create_dungeon_region(player, 'Thieves Pot Alcove Bottom', 'Thieves\' Town', None, ['Thieves Pot Alcove Bottom SW']),
create_dungeon_region(player, 'Thieves Pot Alcove Top', 'Thieves\' Town', None, ['Thieves Pot Alcove Top NW']), create_dungeon_region(player, 'Thieves Pot Alcove Top', 'Thieves\' Town', None, ['Thieves Pot Alcove Top NW']),
@@ -1304,7 +1306,8 @@ bonk_prize_table = {
'Dark Tree Line Tree 2': (0x26, 0x10, False, '', 'Dark Tree Line Area', 'in a tree'), 'Dark Tree Line Tree 2': (0x26, 0x10, False, '', 'Dark Tree Line Area', 'in a tree'),
'Dark Tree Line Tree 3': (0x27, 0x08, False, '', 'Dark Tree Line Area', 'in a tree'), 'Dark Tree Line Tree 3': (0x27, 0x08, False, '', 'Dark Tree Line Area', 'in a tree'),
'Dark Tree Line Tree 4': (0x28, 0x04, False, '', 'Dark Tree Line Area', 'in a tree'), 'Dark Tree Line Tree 4': (0x28, 0x04, False, '', 'Dark Tree Line Area', 'in a tree'),
'Hype Cave Statue': (0x29, 0x10, False, '', 'Hype Cave Area', 'encased in stone') 'Hype Cave Statue': (0x29, 0x10, False, '', 'Hype Cave Area', 'encased in stone'),
'Cold Fairy Statue': (0x2a, 0x02, False, '', 'Good Bee Cave', 'encased in stone')
} }
bonk_table_by_location_id = {0x2ABB00+(data[0]*6)+3: name for name, data in bonk_prize_table.items()} bonk_table_by_location_id = {0x2ABB00+(data[0]*6)+3: name for name, data in bonk_prize_table.items()}

21
Rom.py
View File

@@ -38,7 +38,7 @@ from source.dungeon.RoomList import Room0127
JAP10HASH = '03a63945398191337e896e5771f77173' JAP10HASH = '03a63945398191337e896e5771f77173'
RANDOMIZERBASEHASH = '7043e64e74b2452367de7cc146873524' RANDOMIZERBASEHASH = '4458a348e3040d79d0e28d572579fcb5'
class JsonRom(object): class JsonRom(object):
@@ -686,7 +686,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
flute_spots = default_flute_connections flute_spots = default_flute_connections
else: else:
flute_spots = world.owflutespots[player] flute_spots = world.owflutespots[player]
owFlags |= 0x100 owFlags |= 0x0100
for o in range(0, len(flute_spots)): for o in range(0, len(flute_spots)):
owslot = flute_spots[o] owslot = flute_spots[o]
@@ -740,12 +740,12 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
owMode = 2 owMode = 2
if world.owKeepSimilar[player] and (world.owShuffle[player] != 'vanilla' or world.owCrossed[player] in ['limited', 'chaos']): if world.owKeepSimilar[player] and (world.owShuffle[player] != 'vanilla' or world.owCrossed[player] in ['limited', 'chaos']):
owMode |= 0x100 owMode |= 0x0100
if world.owCrossed[player] != 'none' and (world.owCrossed[player] != 'polar' or world.owMixed[player]): if world.owCrossed[player] != 'none' and (world.owCrossed[player] != 'polar' or world.owMixed[player]):
owMode |= 0x200 owMode |= 0x0200
world.fix_fake_world[player] = True world.fix_fake_world[player] = True
if world.owMixed[player]: if world.owMixed[player]:
owMode |= 0x400 owMode |= 0x0400
# patches map data specific for OW Shuffle # patches map data specific for OW Shuffle
#inverted_buffer[0x03] = inverted_buffer[0x03] | 0x2 # convenient portal on WDM #inverted_buffer[0x03] = inverted_buffer[0x03] | 0x2 # convenient portal on WDM
@@ -793,7 +793,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
# for prize, address in zip(bonk_prizes, bonk_addresses): # for prize, address in zip(bonk_prizes, bonk_addresses):
# rom.write_byte(address, prize) # rom.write_byte(address, prize)
owFlags |= 0x200 owFlags |= 0x0200
# setting spriteID to D8, a placeholder sprite we use to inform ROM to spawn a dynamic item # setting spriteID to D8, a placeholder sprite we use to inform ROM to spawn a dynamic item
#for address in bonk_addresses: #for address in bonk_addresses:
@@ -803,6 +803,8 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
rom.write_byte(snes_to_pc(0x09AE32), 0xD8) rom.write_byte(snes_to_pc(0x09AE32), 0xD8)
rom.write_byte(snes_to_pc(0x09AE35), 0xD8) rom.write_byte(snes_to_pc(0x09AE35), 0xD8)
rom.write_byte(snes_to_pc(0x06918E), 0x80) # skip good bee bottle check
write_int16(rom, 0x150002, owMode) write_int16(rom, 0x150002, owMode)
write_int16(rom, 0x150004, owFlags) write_int16(rom, 0x150004, owFlags)
@@ -1649,6 +1651,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
if world.shuffle_bonk_drops[player]: if world.shuffle_bonk_drops[player]:
# warning, this temporary patch might cause fairies to respawn differently?, limiting this to bonk drop mode only # warning, this temporary patch might cause fairies to respawn differently?, limiting this to bonk drop mode only
rom.write_byte(snes_to_pc(0x0DB808), 0x03) # patch fairies sprites to not permadeath like enemies rom.write_byte(snes_to_pc(0x0DB808), 0x03) # patch fairies sprites to not permadeath like enemies
rom.write_byte(snes_to_pc(0x1DF6D8), 0) # allows sprites to travel across water / same flag as write_enemizer_tweaks
# allow smith into multi-entrance caves in appropriate shuffles # allow smith into multi-entrance caves in appropriate shuffles
if world.shuffle[player] in ['restricted', 'full', 'lite', 'lean', 'crossed', 'insanity'] or (world.shuffle[player] == 'simple' and world.mode[player] == 'inverted'): if world.shuffle[player] in ['restricted', 'full', 'lite', 'lean', 'crossed', 'insanity'] or (world.shuffle[player] == 'simple' and world.mode[player] == 'inverted'):
@@ -1695,6 +1698,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
raise Exception('Pot table is too big for current area') raise Exception('Pot table is too big for current area')
world.pot_contents[player].write_pot_data_to_rom(rom, colorize_pots) world.pot_contents[player].write_pot_data_to_rom(rom, colorize_pots)
write_enemizer_tweaks(rom, world, player)
write_strings(rom, world, player, team) write_strings(rom, world, player, team)
# write initial sram # write initial sram
@@ -1785,6 +1789,11 @@ def write_custom_shops(rom, world, player):
rom.write_bytes(0x184900, items_data) rom.write_bytes(0x184900, items_data)
def write_enemizer_tweaks(rom, world, player):
if world.enemy_shuffle[player] != 'none':
rom.write_byte(snes_to_pc(0x1DF6D8), 0) # lets enemies walk on water instead of clipping into infinity?
rom.write_byte(snes_to_pc(0x0DB6B3), 0x82) # hovers don't need water necessarily?
def hud_format_text(text): def hud_format_text(text):
output = bytes() output = bytes()
for char in text.lower(): for char in text.lower():

View File

@@ -862,7 +862,9 @@ def default_rules(world, player):
from Regions import bonk_prize_table from Regions import bonk_prize_table
for location_name, (_, _, aga_required, _, _, _) in bonk_prize_table.items(): for location_name, (_, _, aga_required, _, _, _) in bonk_prize_table.items():
loc = world.get_location(location_name, player) loc = world.get_location(location_name, player)
if not aga_required: if location_name == 'Cold Fairy Statue':
set_rule(loc, lambda state: state.can_use_bombs(player) and state.can_collect_bonkdrops(player))
elif not aga_required:
set_rule(loc, lambda state: state.can_collect_bonkdrops(player)) set_rule(loc, lambda state: state.can_collect_bonkdrops(player))
else: else:
set_rule(loc, lambda state: state.can_collect_bonkdrops(player) and state.has_beaten_aga(player)) set_rule(loc, lambda state: state.can_collect_bonkdrops(player) and state.has_beaten_aga(player))
@@ -921,6 +923,8 @@ def default_rules(world, player):
set_rule(world.get_entrance('Desert Pass Rocks (South)', player), lambda state: state.can_lift_rocks(player)) set_rule(world.get_entrance('Desert Pass Rocks (South)', player), lambda state: state.can_lift_rocks(player))
set_rule(world.get_entrance('Skull Woods Bush Rock (West)', player), lambda state: state.can_lift_rocks(player)) set_rule(world.get_entrance('Skull Woods Bush Rock (West)', player), lambda state: state.can_lift_rocks(player))
set_rule(world.get_entrance('Skull Woods Bush Rock (East)', player), lambda state: state.can_lift_rocks(player)) set_rule(world.get_entrance('Skull Woods Bush Rock (East)', player), lambda state: state.can_lift_rocks(player))
# this more like an ohko rule - dependent on bird being present too - so enemizer could turn this off?
set_rule(world.get_entrance('Bumper Cave Ledge Drop', player), lambda state: (state.has('Cape', player) or state.has('Cane of Byrna', player) or state.has_sword(player)))
set_rule(world.get_entrance('Bumper Cave Entrance Rock', player), lambda state: state.can_lift_rocks(player)) set_rule(world.get_entrance('Bumper Cave Entrance Rock', player), lambda state: state.can_lift_rocks(player))
set_rule(world.get_entrance('Skull Woods Pass Rock (North)', player), lambda state: state.can_lift_heavy_rocks(player)) set_rule(world.get_entrance('Skull Woods Pass Rock (North)', player), lambda state: state.can_lift_heavy_rocks(player))
set_rule(world.get_entrance('Skull Woods Pass Rock (South)', player), lambda state: state.can_lift_heavy_rocks(player)) set_rule(world.get_entrance('Skull Woods Pass Rock (South)', player), lambda state: state.can_lift_heavy_rocks(player))
@@ -1157,6 +1161,7 @@ def ow_bunny_rules(world, player):
add_bunny_rule(world.get_entrance('Skull Woods Forgotten Bush (East)', player), player) add_bunny_rule(world.get_entrance('Skull Woods Forgotten Bush (East)', player), player)
add_bunny_rule(world.get_entrance('Skull Woods Second Section Hole', player), player) add_bunny_rule(world.get_entrance('Skull Woods Second Section Hole', player), player)
add_bunny_rule(world.get_entrance('East Dark Death Mountain Bushes', player), player) add_bunny_rule(world.get_entrance('East Dark Death Mountain Bushes', player), player)
add_bunny_rule(world.get_entrance('Bumper Cave Ledge Drop', player), player)
add_bunny_rule(world.get_entrance('Bumper Cave Entrance Rock', player), player) add_bunny_rule(world.get_entrance('Bumper Cave Entrance Rock', player), player)
add_bunny_rule(world.get_entrance('Skull Woods Pass Bush Row (West)', player), player) add_bunny_rule(world.get_entrance('Skull Woods Pass Bush Row (West)', player), player)
add_bunny_rule(world.get_entrance('Skull Woods Pass Bush Row (East)', player), player) add_bunny_rule(world.get_entrance('Skull Woods Pass Bush Row (East)', player), player)

View File

@@ -130,6 +130,7 @@ bonk_prize_lookup = {
'Chicken': (0x0b, 0, None), 'Chicken': (0x0b, 0, None),
'Bee Trap': (0x79, 6, None), 'Bee Trap': (0x79, 6, None),
'Apples': (0xac, 8, None), 'Apples': (0xac, 8, None),
'Good Bee': (0xb2, 1, None),
'Small Heart': (0xd8, 2, None), 'Small Heart': (0xd8, 2, None),
'Rupee (1)': (0xd9, 0, None), 'Rupee (1)': (0xd9, 0, None),
'Rupees (5)': (0xda, 3, None), # TODO: add in murahdahla tree rupee 'Rupees (5)': (0xda, 3, None), # TODO: add in murahdahla tree rupee

View File

@@ -157,6 +157,14 @@ and #$7f : eor #$40 : nop #2
org $06AD4C org $06AD4C
jsl.l OWBonkDrops : nop #4 jsl.l OWBonkDrops : nop #4
org $1EDE6F
jsl.l OWBonkGoodBeeDrop : bra +
GoldBee_SpawnSelf_SetProperties:
phb : lda.b #$1E : pha : plb ; switch to bank 1E
jsr GoldBee_SpawnSelf+12
plb : rtl
nop #3
+
;Code ;Code
org $aa8800 org $aa8800
@@ -395,6 +403,112 @@ LoadMapDarkOrMixed:
dw $0400+$0210 ; bottom right dw $0400+$0210 ; bottom right
} }
OWBonkGoodBeeDrop:
{
LDA.l OWFlags+1 : AND.b #$02 : BNE .shuffled
.vanilla ; what we wrote over
STZ.w $0DD0,X
LDA.l BottleContentsOne : ORA.l BottleContentsTwo
ORA.l BottleContentsThree : ORA.l BottleContentsFour
RTL
.shuffled
PHY : TXY
LDA.l RoomDataWRAM[$0120].high : AND.b #$02 : PHA : BNE + ; check if collected
LDA.b #$1B : STA $12F ; JSL Sound_SetSfx3PanLong ; seems that when you bonk, there is a pending bonk sfx, so we clear that out and replace with reveal secret sfx
+
LDA.l OWBonkPrizeData+(42*6+4) : BEQ + ; multiworld item
LDA.l OWBonkPrizeData+(42*6+3)
JMP .spawn_item
+
.determine_type ; S = Collected, FlagBitmask, X (row + 2)
LDA.l OWBonkPrizeData+(42*6+3) ; A = item id
CMP.b #$B0 : BNE +
LDA.b #$79 : JMP .sprite_transform ; transform to bees
+ CMP.b #$42 : BNE +
JSL.l Sprite_TransmuteToBomb ; transform a heart to bomb, vanilla behavior
JMP .mark_collected
+ CMP.b #$34 : BNE +
LDA.b #$D9 : JMP .sprite_transform ; transform to single rupee
+ CMP.b #$35 : BNE +
LDA.b #$DA : JMP .sprite_transform ; transform to blue rupee
+ CMP.b #$36 : BNE +
LDA.b #$DB : BRA .sprite_transform ; transform to red rupee
+ CMP.b #$27 : BNE +
LDA.b #$DC : BRA .sprite_transform ; transform to 1 bomb
+ CMP.b #$28 : BNE +
LDA.b #$DD : BRA .sprite_transform ; transform to 4 bombs
+ CMP.b #$31 : BNE +
LDA.b #$DE : BRA .sprite_transform ; transform to 8 bombs
+ CMP.b #$45 : BNE +
LDA.b #$DF : BRA .sprite_transform ; transform to small magic
+ CMP.b #$B4 : BNE +
LDA.b #$E0 : BRA .sprite_transform ; transform to big magic
+ CMP.b #$B5 : BNE +
LDA.b #$79 : JSL.l OWBonkSpritePrep
JSL.l GoldBee_SpawnSelf_SetProperties ; transform to good bee
BRA .mark_collected
+ CMP.b #$44 : BNE +
LDA.b #$E2 : BRA .sprite_transform ; transform to 10 arrows
+ CMP.b #$B1 : BNE +
LDA.b #$AC : BRA .sprite_transform ; transform to apples
+ CMP.b #$B2 : BNE +
LDA.b #$E3 : BRA .sprite_transform ; transform to fairy
+ CMP.b #$B3 : BNE .spawn_item
INX : INX : LDA.l OWBonkPrizeData+(42*6+5)
CLC : ADC.b #$08 : PHA
LDA.w $0D00,Y : SEC : SBC.b 1,S : STA.w $0D00,Y
LDA.w $0D20,Y : SBC.b #$00 : STA.w $0D20,Y : PLX
LDA.b #$0B : SEC ; BRA .sprite_transform ; transform to chicken
.sprite_transform
JSL.l OWBonkSpritePrep
.mark_collected ; S = Collected
PLA : BNE .return
LDA.l RoomDataWRAM[$0120].high : ORA.b #$02 : STA.l RoomDataWRAM[$0120].high
REP #$20
LDA.l TotalItemCounter : INC : STA.l TotalItemCounter
SEP #$20
BRA .return
; spawn itemget item
.spawn_item ; A = item id ; Y = bonk sprite slot ; S = Collected
PLX : BEQ + : LDA.b #$00 : STA.w $0DD0,Y : BRA .return
+ LDA.l OWBonkPrizeData+(42*6+4) : STA.l !MULTIWORLD_SPRITEITEM_PLAYER_ID
LDA.b #$01 : STA !REDRAW
LDA.b #$EB : STA.l $7FFE00
JSL Sprite_SpawnDynamically+15 ; +15 to skip finding a new slot, use existing sprite
; affects the rate the item moves in the Y/X direction
LDA.b #$00 : STA.w $0D40,Y
LDA.b #$0A : STA.w $0D50,Y
LDA.b #$20 : STA.w $0F80,Y ; amount of force (gives height to the arch)
LDA.b #$FF : STA.w $0B58,Y ; stun timer
LDA.b #$30 : STA.w $0F10,Y ; aux delay timer 4 ?? dunno what that means
LDA.b #$00 : STA.w $0F20,Y ; layer the sprite is on
; sets OW event bitmask flag, uses free RAM
LDA.l OWBonkPrizeData+(42*6+2) : STA.w $0ED0,Y
; determines the initial spawn point of item
LDA.w $0D00,Y : SEC : SBC.l OWBonkPrizeData+(42*6+5) : STA.w $0D00,Y
LDA.w $0D20,Y : SBC #$00 : STA.w $0D20,Y
LDA.b #$01 : STA !REDRAW : STA !FORCE_HEART_SPAWN
.return
PLY
LDA #$08 ; makes original good bee not spawn
RTL
nop #20
}
; Y = sprite slot index of bonk sprite ; Y = sprite slot index of bonk sprite
OWBonkDrops: OWBonkDrops:
{ {
@@ -439,7 +553,7 @@ OWBonkDrops:
+ CMP.b #$34 : BNE + + CMP.b #$34 : BNE +
LDA.b #$D9 : CLC : JMP .sprite_transform ; transform to single rupee LDA.b #$D9 : CLC : JMP .sprite_transform ; transform to single rupee
+ CMP.b #$35 : BNE + + CMP.b #$35 : BNE +
LDA.b #$DA : CLC : BRA .sprite_transform ; transform to blue rupee LDA.b #$DA : CLC : JMP .sprite_transform ; transform to blue rupee
+ CMP.b #$36 : BNE + + CMP.b #$36 : BNE +
LDA.b #$DB : CLC : BRA .sprite_transform ; transform to red rupee LDA.b #$DB : CLC : BRA .sprite_transform ; transform to red rupee
+ CMP.b #$27 : BNE + + CMP.b #$27 : BNE +
@@ -453,7 +567,9 @@ OWBonkDrops:
+ CMP.b #$B4 : BNE + + CMP.b #$B4 : BNE +
LDA.b #$E0 : CLC : BRA .sprite_transform ; transform to big magic LDA.b #$E0 : CLC : BRA .sprite_transform ; transform to big magic
+ CMP.b #$B5 : BNE + + CMP.b #$B5 : BNE +
LDA.b #$E1 : CLC : BRA .sprite_transform ; transform to 5 arrows LDA.b #$79 : JSL.l OWBonkSpritePrep
JSL.l GoldBee_SpawnSelf_SetProperties ; transform to good bee
BRA .mark_collected
+ CMP.b #$44 : BNE + + CMP.b #$44 : BNE +
LDA.b #$E2 : CLC : BRA .sprite_transform ; transform to 10 arrows LDA.b #$E2 : CLC : BRA .sprite_transform ; transform to 10 arrows
+ CMP.b #$B1 : BNE + + CMP.b #$B1 : BNE +
@@ -468,14 +584,7 @@ OWBonkDrops:
LDA.b #$0B : SEC ; BRA .sprite_transform ; transform to chicken LDA.b #$0B : SEC ; BRA .sprite_transform ; transform to chicken
.sprite_transform .sprite_transform
STA.w $0E20,Y JSL.l OWBonkSpritePrep
TYX : JSL.l Sprite_LoadProperties
BEQ +
; these are sprite properties that make it fall out of the tree to the east
LDA #$30 : STA $0F80,Y ; amount of force (related to speed)
LDA #$10 : STA $0D50,Y ; eastward rate of speed
LDA #$FF : STA $0B58,Y ; expiration timer
+
.mark_collected ; S = Collected, FlagBitmask, X (row + 2) .mark_collected ; S = Collected, FlagBitmask, X (row + 2)
PLA : BNE + ; S = FlagBitmask, X (row + 2) PLA : BNE + ; S = FlagBitmask, X (row + 2)
@@ -495,8 +604,7 @@ OWBonkDrops:
LDA.b #$01 : STA !REDRAW LDA.b #$01 : STA !REDRAW
LDA.b #$EB LDA.b #$EB : STA.l $7FFE00
STA.l $7FFE00
JSL Sprite_SpawnDynamically+15 ; +15 to skip finding a new slot, use existing sprite JSL Sprite_SpawnDynamically+15 ; +15 to skip finding a new slot, use existing sprite
; affects the rate the item moves in the Y/X direction ; affects the rate the item moves in the Y/X direction
@@ -525,6 +633,19 @@ OWBonkDrops:
PLA : PLA : PLB : RTL PLA : PLA : PLB : RTL
} }
; A = SpriteID, Y = Sprite Slot Index, X = free/overwritten
OWBonkSpritePrep:
{
STA.w $0E20,Y
TYX : JSL.l Sprite_LoadProperties
BEQ +
; these are sprite properties that make it fall out of the tree to the east
LDA #$30 : STA $0F80,Y ; amount of force (related to speed)
LDA #$10 : STA $0D50,Y ; eastward rate of speed
LDA #$FF : STA $0B58,Y ; expiration timer
+ RTL
}
org $aa9000 org $aa9000
OWDetectEdgeTransition: OWDetectEdgeTransition:
{ {
@@ -1539,6 +1660,7 @@ db $6e, $8c, $10, $35, $00, $10
db $6e, $90, $08, $b0, $00, $10 db $6e, $90, $08, $b0, $00, $10
db $6e, $a4, $04, $b1, $00, $10 db $6e, $a4, $04, $b1, $00, $10
db $74, $4e, $10, $b1, $00, $1c db $74, $4e, $10, $b1, $00, $1c
db $ff, $00, $02, $b5, $00, $08
; temporary fix - murahdahla replaces one of the bonk tree prizes ; temporary fix - murahdahla replaces one of the bonk tree prizes
; so we copy the sprite table here and update the pointer ; so we copy the sprite table here and update the pointer

Binary file not shown.

View File

@@ -17,6 +17,13 @@ settings:
shopsanity: true shopsanity: true
shuffle: crossed shuffle: crossed
shufflelinks: true shufflelinks: true
ow_shuffle: parallel
ow_terrain: true
ow_crossed: grouped
ow_keepsimilar: true
ow_mixed: true
ow_whirlpool: true
ow_fluteshuffle: balanced
shufflebosses: unique shufflebosses: unique
item_pool: item_pool:
1: 1:

View File

@@ -72,7 +72,13 @@ class CustomSettings(object):
args.mystery = True args.mystery = True
else: else:
settings = defaultdict(lambda: None, player_setting) settings = defaultdict(lambda: None, player_setting)
args.ow_shuffle[p] = get_setting(settings['ow_shuffle'], args.ow_shuffle[p])
args.ow_terrain[p] = get_setting(settings['ow_terrain'], args.ow_terrain[p])
args.ow_crossed[p] = get_setting(settings['ow_crossed'], args.ow_crossed[p])
args.ow_keepsimilar[p] = get_setting(settings['ow_keepsimilar'], args.ow_keepsimilar[p])
args.ow_mixed[p] = get_setting(settings['ow_mixed'], args.ow_mixed[p]) args.ow_mixed[p] = get_setting(settings['ow_mixed'], args.ow_mixed[p])
args.ow_whirlpool[p] = get_setting(settings['ow_whirlpool'], args.ow_whirlpool[p])
args.ow_fluteshuffle[p] = get_setting(settings['ow_fluteshuffle'], args.ow_fluteshuffle[p])
args.shuffle[p] = get_setting(settings['shuffle'], args.shuffle[p]) args.shuffle[p] = get_setting(settings['shuffle'], args.shuffle[p])
args.door_shuffle[p] = get_setting(settings['door_shuffle'], args.door_shuffle[p]) args.door_shuffle[p] = get_setting(settings['door_shuffle'], args.door_shuffle[p])
args.logic[p] = get_setting(settings['logic'], args.logic[p]) args.logic[p] = get_setting(settings['logic'], args.logic[p])
@@ -130,8 +136,8 @@ class CustomSettings(object):
args.mapshuffle[p] = True args.mapshuffle[p] = True
args.compassshuffle[p] = True args.compassshuffle[p] = True
args.shufflebosses[p] = get_setting(settings['shufflebosses'], args.shufflebosses[p]) args.shufflebosses[p] = get_setting(settings['boss_shuffle'], args.shufflebosses[p])
args.shuffleenemies[p] = get_setting(settings['shuffleenemies'], args.shuffleenemies[p]) args.shuffleenemies[p] = get_setting(settings['enemy_shuffle'], args.shuffleenemies[p])
args.enemy_health[p] = get_setting(settings['enemy_health'], args.enemy_health[p]) args.enemy_health[p] = get_setting(settings['enemy_health'], args.enemy_health[p])
args.enemy_damage[p] = get_setting(settings['enemy_damage'], args.enemy_damage[p]) args.enemy_damage[p] = get_setting(settings['enemy_damage'], args.enemy_damage[p])
args.shufflepots[p] = get_setting(settings['shufflepots'], args.shufflepots[p]) args.shufflepots[p] = get_setting(settings['shufflepots'], args.shufflepots[p])

View File

@@ -426,7 +426,8 @@ def filter_locations(item_to_place, locations, world, vanilla_skip=False, potion
return filtered if len(filtered) > 0 else locations return filtered if len(filtered) > 0 else locations
if world.algorithm == 'district': if world.algorithm == 'district':
config = world.item_pool_config config = world.item_pool_config
if item_to_place == 'Placeholder' or item_to_place.name in config.item_pool[item_to_place.player]: if ((isinstance(item_to_place,str) and item_to_place == 'Placeholder')
or item_to_place.name in config.item_pool[item_to_place.player]):
restricted = config.location_groups[0].locations restricted = config.location_groups[0].locations
filtered = [l for l in locations if l.name in restricted and l.player in restricted[l.name]] filtered = [l for l in locations if l.name in restricted and l.player in restricted[l.name]]
return filtered if len(filtered) > 0 else locations return filtered if len(filtered) > 0 else locations
@@ -820,7 +821,7 @@ trash_items = {
'Nothing': -1, 'Nothing': -1,
'Bee Trap': 0, 'Bee Trap': 0,
'Rupee (1)': 1, 'Rupees (5)': 1, 'Small Heart': 1, 'Bee': 1, 'Arrows (5)': 1, 'Chicken': 1, 'Single Bomb': 1, 'Rupee (1)': 1, 'Rupees (5)': 1, 'Small Heart': 1, 'Bee': 1, 'Arrows (5)': 1, 'Chicken': 1, 'Single Bomb': 1,
'Rupees (20)': 2, 'Small Magic': 2, 'Rupees (20)': 2, 'Small Magic': 2, 'Good Bee': 2,
'Bombs (3)': 3, 'Arrows (10)': 3, 'Bombs (10)': 3, 'Apples': 3, 'Bombs (3)': 3, 'Arrows (10)': 3, 'Bombs (10)': 3, 'Apples': 3,
'Fairy': 4, 'Big Magic': 4, 'Red Potion': 4, 'Blue Shield': 4, 'Rupees (50)': 4, 'Rupees (100)': 4, 'Fairy': 4, 'Big Magic': 4, 'Red Potion': 4, 'Blue Shield': 4, 'Rupees (50)': 4, 'Rupees (100)': 4,
'Rupees (300)': 5, 'Rupees (300)': 5,

View File

@@ -444,10 +444,12 @@ def do_holes_and_linked_drops(entrances, exits, avail, cross_world, keep_togethe
random.shuffle(hole_entrances) random.shuffle(hole_entrances)
if not cross_world and 'Sanctuary Grave' in holes_to_shuffle: if not cross_world and 'Sanctuary Grave' in holes_to_shuffle:
hc = avail.world.get_entrance('Hyrule Castle Exit (South)', avail.player) hc = avail.world.get_entrance('Hyrule Castle Exit (South)', avail.player)
chosen_entrance = None
if hc.connected_region and hc.connected_region.type == RegionType.DarkWorld: if hc.connected_region and hc.connected_region.type == RegionType.DarkWorld:
chosen_entrance = next(entrance for entrance in hole_entrances if entrance[0] in DW_Entrances) chosen_entrance = next(entrance for entrance in hole_entrances if entrance[0] in DW_Entrances)
if not chosen_entrance: if not chosen_entrance:
chosen_entrance = next(entrance for entrance in hole_entrances if entrance[0] in LW_Entrances) chosen_entrance = next(entrance for entrance in hole_entrances if entrance[0] in LW_Entrances)
if chosen_entrance:
hole_entrances.remove(chosen_entrance) hole_entrances.remove(chosen_entrance)
sanc_interior = next(target for target in hole_targets if target[0] == 'Sanctuary Exit') sanc_interior = next(target for target in hole_targets if target[0] == 'Sanctuary Exit')
hole_targets.remove(sanc_interior) hole_targets.remove(sanc_interior)
@@ -1132,6 +1134,9 @@ def do_vanilla_connect(pool_def, avail):
elif pool_def['condition'] == 'takeany': elif pool_def['condition'] == 'takeany':
if avail.world.take_any[avail.player] == 'fixed': if avail.world.take_any[avail.player] == 'fixed':
return return
elif pool_def['condition'] == 'bonk':
if avail.world.shuffle_bonk_drops[avail.player]:
return
defaults = {**default_connections, **(inverted_default_connections if avail.inverted != avail.world.is_tile_swapped(0x1b, avail.player) else open_default_connections)} defaults = {**default_connections, **(inverted_default_connections if avail.inverted != avail.world.is_tile_swapped(0x1b, avail.player) else open_default_connections)}
for entrance in pool_def['entrances']: for entrance in pool_def['entrances']:
if entrance in avail.entrances: if entrance in avail.entrances:
@@ -1548,7 +1553,7 @@ modes = {
'condition': '', 'condition': '',
'entrances': ['Dark Desert Fairy', 'Archery Game', 'Fortune Teller (Dark)', 'Dark Sanctuary Hint', 'entrances': ['Dark Desert Fairy', 'Archery Game', 'Fortune Teller (Dark)', 'Dark Sanctuary Hint',
'Dark Lake Hylia Ledge Hint', 'Dark Lake Hylia Fairy', 'Dark Lake Hylia Shop', 'Dark Lake Hylia Ledge Hint', 'Dark Lake Hylia Fairy', 'Dark Lake Hylia Shop',
'East Dark World Hint', 'Kakariko Gamble Game', 'Good Bee Cave', 'Long Fairy Cave', 'East Dark World Hint', 'Kakariko Gamble Game', 'Long Fairy Cave',
'Bush Covered House', 'Fortune Teller (Light)', 'Lost Woods Gamble', 'Bush Covered House', 'Fortune Teller (Light)', 'Lost Woods Gamble',
'Lake Hylia Fortune Teller', 'Lake Hylia Fairy', 'Bonk Fairy (Light)', 'Inverted Dark Sanctuary'], 'Lake Hylia Fortune Teller', 'Lake Hylia Fairy', 'Bonk Fairy (Light)', 'Inverted Dark Sanctuary'],
}, },
@@ -1572,7 +1577,11 @@ modes = {
'Light World Bomb Hut', '20 Rupee Cave', '50 Rupee Cave', 'Hookshot Fairy', 'Light World Bomb Hut', '20 Rupee Cave', '50 Rupee Cave', 'Hookshot Fairy',
'Palace of Darkness Hint', 'Dark Lake Hylia Ledge Spike Cave', 'Palace of Darkness Hint', 'Dark Lake Hylia Ledge Spike Cave',
'Dark Desert Hint'] 'Dark Desert Hint']
},
'fixed_bonk': {
'special': 'vanilla',
'condition': 'bonk',
'entrances': ['Good Bee Cave']
}, },
'item_caves': { # shuffles shops/pottery if they weren't fixed in the last steps 'item_caves': { # shuffles shops/pottery if they weren't fixed in the last steps
'entrances': ['Mimic Cave', 'Spike Cave', 'Mire Shed', 'Dark World Hammer Peg Cave', 'Chest Game', 'entrances': ['Mimic Cave', 'Spike Cave', 'Mire Shed', 'Dark World Hammer Peg Cave', 'Chest Game',
@@ -1580,7 +1589,7 @@ modes = {
'Ice Rod Cave', 'Dam', 'Bonk Rock Cave', 'Library', 'Potion Shop', 'Mini Moldorm Cave', 'Ice Rod Cave', 'Dam', 'Bonk Rock Cave', 'Library', 'Potion Shop', 'Mini Moldorm Cave',
'Checkerboard Cave', 'Graveyard Cave', 'Cave 45', 'Sick Kids House', 'Blacksmiths Hut', 'Checkerboard Cave', 'Graveyard Cave', 'Cave 45', 'Sick Kids House', 'Blacksmiths Hut',
'Sahasrahlas Hut', 'Aginahs Cave', 'Chicken House', 'Kings Grave', 'Blinds Hideout', 'Sahasrahlas Hut', 'Aginahs Cave', 'Chicken House', 'Kings Grave', 'Blinds Hideout',
'Waterfall of Wishing', 'Cave Shop (Dark Death Mountain)', 'Waterfall of Wishing', 'Cave Shop (Dark Death Mountain)', 'Good Bee Cave',
'Dark World Potion Shop', 'Dark World Lumberjack Shop', 'Dark World Shop', 'Dark World Potion Shop', 'Dark World Lumberjack Shop', 'Dark World Shop',
'Red Shield Shop', 'Kakariko Shop', 'Capacity Upgrade', 'Cave Shop (Lake Hylia)', 'Red Shield Shop', 'Kakariko Shop', 'Capacity Upgrade', 'Cave Shop (Lake Hylia)',
'Lumberjack House', 'Snitch Lady (West)', 'Snitch Lady (East)', 'Tavern (Front)', 'Lumberjack House', 'Snitch Lady (West)', 'Snitch Lady (East)', 'Tavern (Front)',
@@ -1635,7 +1644,7 @@ modes = {
'condition': '', 'condition': '',
'entrances': ['Dark Desert Fairy', 'Archery Game', 'Fortune Teller (Dark)', 'Dark Sanctuary Hint', 'entrances': ['Dark Desert Fairy', 'Archery Game', 'Fortune Teller (Dark)', 'Dark Sanctuary Hint',
'Dark Lake Hylia Ledge Hint', 'Dark Lake Hylia Fairy', 'Dark Lake Hylia Shop', 'Dark Lake Hylia Ledge Hint', 'Dark Lake Hylia Fairy', 'Dark Lake Hylia Shop',
'East Dark World Hint', 'Kakariko Gamble Game', 'Good Bee Cave', 'Long Fairy Cave', 'East Dark World Hint', 'Kakariko Gamble Game', 'Long Fairy Cave',
'Bush Covered House', 'Fortune Teller (Light)', 'Lost Woods Gamble', 'Bush Covered House', 'Fortune Teller (Light)', 'Lost Woods Gamble',
'Lake Hylia Fortune Teller', 'Lake Hylia Fairy', 'Bonk Fairy (Light)', 'Inverted Dark Sanctuary'], 'Lake Hylia Fortune Teller', 'Lake Hylia Fairy', 'Bonk Fairy (Light)', 'Inverted Dark Sanctuary'],
}, },
@@ -1659,7 +1668,11 @@ modes = {
'Light World Bomb Hut', '20 Rupee Cave', '50 Rupee Cave', 'Hookshot Fairy', 'Light World Bomb Hut', '20 Rupee Cave', '50 Rupee Cave', 'Hookshot Fairy',
'Palace of Darkness Hint', 'Dark Lake Hylia Ledge Spike Cave', 'Palace of Darkness Hint', 'Dark Lake Hylia Ledge Spike Cave',
'Dark Desert Hint'] 'Dark Desert Hint']
},
'fixed_bonk': {
'special': 'vanilla',
'condition': 'bonk',
'entrances': ['Good Bee Cave']
}, },
'item_caves': { # shuffles shops/pottery if they weren't fixed in the last steps 'item_caves': { # shuffles shops/pottery if they weren't fixed in the last steps
'entrances': ['Mimic Cave', 'Spike Cave', 'Mire Shed', 'Dark World Hammer Peg Cave', 'Chest Game', 'entrances': ['Mimic Cave', 'Spike Cave', 'Mire Shed', 'Dark World Hammer Peg Cave', 'Chest Game',
@@ -1667,7 +1680,7 @@ modes = {
'Ice Rod Cave', 'Dam', 'Bonk Rock Cave', 'Library', 'Potion Shop', 'Mini Moldorm Cave', 'Ice Rod Cave', 'Dam', 'Bonk Rock Cave', 'Library', 'Potion Shop', 'Mini Moldorm Cave',
'Checkerboard Cave', 'Graveyard Cave', 'Cave 45', 'Sick Kids House', 'Blacksmiths Hut', 'Checkerboard Cave', 'Graveyard Cave', 'Cave 45', 'Sick Kids House', 'Blacksmiths Hut',
'Sahasrahlas Hut', 'Aginahs Cave', 'Chicken House', 'Kings Grave', 'Blinds Hideout', 'Sahasrahlas Hut', 'Aginahs Cave', 'Chicken House', 'Kings Grave', 'Blinds Hideout',
'Waterfall of Wishing', 'Cave Shop (Dark Death Mountain)', 'Waterfall of Wishing', 'Cave Shop (Dark Death Mountain)', 'Good Bee Cave',
'Dark World Potion Shop', 'Dark World Lumberjack Shop', 'Dark World Shop', 'Dark World Potion Shop', 'Dark World Lumberjack Shop', 'Dark World Shop',
'Red Shield Shop', 'Kakariko Shop', 'Capacity Upgrade', 'Cave Shop (Lake Hylia)', 'Red Shield Shop', 'Kakariko Shop', 'Capacity Upgrade', 'Cave Shop (Lake Hylia)',
'Lumberjack House', 'Snitch Lady (West)', 'Snitch Lady (East)', 'Tavern (Front)', 'Lumberjack House', 'Snitch Lady (West)', 'Snitch Lady (East)', 'Tavern (Front)',