From 11f77f78d26f1a9d01d8c440a4c4a43f819f25dc Mon Sep 17 00:00:00 2001 From: codemann8 Date: Wed, 7 Jul 2021 12:01:41 -0500 Subject: [PATCH 01/39] Reduced chance of diagonal flute spot --- OverworldShuffle.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OverworldShuffle.py b/OverworldShuffle.py index a0622ede..03991a47 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -173,7 +173,7 @@ def link_overworld(world, player): or flute_pool[f] - 1 in new_spots \ or flute_pool[f] + 8 in new_spots \ or flute_pool[f] - 8 in new_spots) \ - or (random.randint(0, 9) != 0 \ + or (random.randint(0, 31) != 0 \ and (flute_pool[f] + 7 in new_spots or flute_pool[f] - 7 in new_spots or flute_pool[f] + 9 in new_spots From 8531c1005c2e6089c3ed7d820700103aac2c8c6c Mon Sep 17 00:00:00 2001 From: codemann8 Date: Mon, 2 May 2022 05:56:47 -0500 Subject: [PATCH 02/39] Updated branch suffix --- OverworldShuffle.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OverworldShuffle.py b/OverworldShuffle.py index bd855436..92741142 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -6,7 +6,7 @@ from Regions import mark_dark_world_regions, mark_light_world_regions from OWEdges import OWTileRegions, OWTileGroups, OWEdgeGroups, OWExitTypes, OpenStd, parallel_links, IsParallel version_number = '0.2.7.1' -version_branch = '-u' +version_branch = '' __version__ = '%s%s' % (version_number, version_branch) def link_overworld(world, player): From 58c1a0f4d157a089b84dbc5b18e128e6f12fc5af Mon Sep 17 00:00:00 2001 From: codemann8 Date: Fri, 18 Nov 2022 01:04:28 -0600 Subject: [PATCH 03/39] Corrected formatting in Changelog --- CHANGELOG.md | 50 +++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bfb1bf50..f5d3e076 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,13 +21,13 @@ - Various logic corrections, including the DR Bumper Cave fix for pottery logic ## 0.2.10.1 -- Merged DR v1.0.1.3 +- \~Merged v1.0.1.3~ - Fixed Zelda despawn in TT Prison - Fixed issue with key door usage in rainstate - Added missing modes to example mystery yaml ## 0.2.10.0 -- Merged DR v1.0.1.1-1.0.1.2 +- \~Merged v1.0.1.1-1.0.1.2~ - Removed text color from hint tiles - Removed Good Bee requirement from Mothula - Some keylogic/generation fixes @@ -56,7 +56,7 @@ - Fixed issue with pre-opened pyramid when not expected ### 0.2.8.0 -- ~Merged DR v1.0.1.0 - Pottery options, BPS support, MSU Resume, Collection Rate Counter~ +- \~Merged DR v1.0.1.0 - Pottery options, BPS support, MSU Resume, Collection Rate Counter~ - Various improvements to increase generation success rate and reduce generation time - Fixed issue with playthru recognizing Aga accessibility - Fixed issue with applying rules correctly to Murahdahla, fixing Murahdahla+Beatable issues @@ -81,7 +81,7 @@ - Added proper branch-specific versioning (ie. Dev branch has '-u' suffixing the version number while Release/Main branch does not) ### 0.2.7.0 -- ~Merged DR v1.0.0.3 - MANY changes, major things listed below~ +- \~Merged DR v1.0.0.3 - MANY changes, major things listed below~ - New Item Fills (Districts/Vanilla/Major Location/Dungeon) - New OW Map Prize Indicators (In ER, map checks can spoil dungeon locations with a user setting) - Forbidden Boss Items (Exclude certain dungeon items from dropping on bosses) @@ -132,7 +132,7 @@ - Fixed issue with incorrect Mirror bonking - Fixed issue with old man follower death to Pyramid - Fixed Hera boss music not playing when boss not defeated -- ~Merged DR v0.5.1.7 - TT boss trap door fix/Applied Glitched flag~ +- \~Merged DR v0.5.1.7 - TT boss trap door fix/Applied Glitched flag~ ### 0.2.4.0 - Added Guaranteed OWR Reachability @@ -158,7 +158,7 @@ - Fake flipper damage fix improved to skip the long delay after the scroll - Fixed missing Blue Potion in Lake Shop in Inverted - Added legacy OW Crossed option 'None (Allowed)' to support old behavior when invalid option was used in Mystery -- ~Merged DR v0.5.1.6 - Money balancing fix/Boss logic fixes with Bombbag~ +- \~Merged DR v0.5.1.6 - Money balancing fix/Boss logic fixes with Bombbag~ ### 0.2.3.3 - Added OW Layout validation that reduces the cases where some screens are unreachable @@ -200,7 +200,7 @@ - Fixed music track change to Sanc music when Standard mode is delivering Zelda - Fixed SP flooding issue - Fixed issue with Shuffle Ganon in CLI/GUI -- ~Merged DR v0.5.1.5 - Mystery subweights~ +- \~Merged DR v0.5.1.5 - Mystery subweights~ ### 0.2.1.2 - Fixed issue with whirlpools not changing world when in Crossed OW @@ -221,7 +221,7 @@ - Smith deletion on S+Q only occurs if Blacksmith not reachable from starting locations - Spoiler log improvements to prevent spoiling in the beginning 'meta' section - Various minor fixes and improvements -- ~Merged DR v0.5.1.4 - ROM bug fixes/keylogic improvements~ +- \~Merged DR v0.5.1.4 - ROM bug fixes/keylogic improvements~ ### 0.1.9.4 - Hotfix for bad 0.1.9.3 version @@ -234,11 +234,11 @@ ### 0.1.9.2 - Fixed spoiler log and mystery for new Crossed/Mixed structure - Minor preparations and tweaks to ER framework (added global Entrance/Exit pool) -- ~Merged DR v0.5.1.2 - Blind Prison shuffled outside TT/Keylogic Improvements~ +- \~Merged DR v0.5.1.2 - Blind Prison shuffled outside TT/Keylogic Improvements~ ### 0.1.9.1 - Fixed logic issue with leaving IP entrance not requiring flippers -- ~Merged DR v0.5.1.1 - Map Indicator Fix/Boss Shuffle Bias/Shop Hints~ +- \~Merged DR v0.5.1.1 - Map Indicator Fix/Boss Shuffle Bias/Shop Hints~ ### 0.1.9.0 - Expanded Crossed OW to four separate options, see Readme for details @@ -252,7 +252,7 @@ - Fixed issues with Link/Bunny state in Crossed OW - Fixed issue with Standard+Parallel not using vanilla connections for Escape - Fixed issue with Mystery for OW boolean options -- ~Merged DR v0.5.1.0 - Major Keylogic Update~ +- \~Merged DR v0.5.1.0 - Major Keylogic Update~ ### 0.1.8.1 - Fixed issue with activating flute in DW (OW Mixed) @@ -267,12 +267,12 @@ - Added OW Shuffle support for Plando module (needs user testing) - Fixed issue with Sanc start at TR as bunny when it is LW - Fixed issue with Pyramid Hole not getting shuffled -- ~Merged DR v0.5.0.3 - Minor DR fixes~ +- \~Merged DR v0.5.0.3 - Minor DR fixes~ ### 0.1.7.4 - Fixed issue with Mixed OW failing to generate when HC/Pyramid is swapped - Various fixes to improve generation rates for Mixed OW Shuffle -- ~Merged DR v0.5.0.2 - Shuffle SFX~ +- \~Merged DR v0.5.0.2 - Shuffle SFX~ ### 0.1.7.3 - Fixed minor issue with ambient SFX stopping and starting on OW screen load @@ -292,10 +292,10 @@ ### 0.1.7.0 - Expanded new DR bomb logic to all modes (bomb usage in logic only if there is an unlimited supply of bombs available) -- ~Merged DR v0.5.0.1 - Bombbag mode / Enemizer fixes~ +- \~Merged DR v0.5.0.1 - Bombbag mode / Enemizer fixes~ ### 0.1.6.9 -- ~Merged DR v0.4.0.12 - Secure random update / Credits fix~ +- \~Merged DR v0.4.0.12 - Secure random update / Credits fix~ ### 0.1.6.8 - Implemented a smarter Balanced Flute Shuffle algorithm @@ -309,14 +309,14 @@ - Fixed Boss Music when boss room is entered thru straight stairs - Suppressed in-dungeon music changes when DR is enabled - Fixed issue with Pyramid Exit exiting to wrong location in ER -- ~Merged DR v0.4.0.11 - Various DR changes~ +- \~Merged DR v0.4.0.11 - Various DR changes~ ### 0.1.6.6 -- ~Merged DR v0.4.0.9 - P/C Indicator / Credits fix / CLI Hints Fix~ +- \~Merged DR v0.4.0.9 - P/C Indicator / Credits fix / CLI Hints Fix~ ### 0.1.6.5 - Reduced chance of diagonal flute spot in Balanced -- ~Merged DR v0.4.0.8 - Boss Indicator / Psuedo Boots / Quickswap Update / Credits Updates~ +- \~Merged DR v0.4.0.8 - Boss Indicator / Psuedo Boots / Quickswap Update / Credits Updates~ ### 0.1.6.4 - Fixed Frogsmith and Stumpy and restored progression in these locations @@ -355,15 +355,15 @@ ### 0.1.5.0 - Added OW Tile Swap setting - Fixed horizontal VRAM visual loading glitch on megatiles -- ~~Merged DR v0.4.0.7 - Fast Credits / Reduced Flashing / Sprite Author in Credits~~ Didn't fully merge +- ~\~Merged DR v0.4.0.7 - Fast Credits / Reduced Flashing / Sprite Author in Credits~~ Didn't fully merge ### 0.1.4.3 -- ~Merged DR v0.4.0.6 - TT Maiden Attic Hint / DR Entrance Floor Mat Mods / Hard/Expert Item Pool Fix~ +- \~Merged DR v0.4.0.6 - TT Maiden Attic Hint / DR Entrance Floor Mat Mods / Hard/Expert Item Pool Fix~ ### 0.1.4.2 - Modified various OW map terrain specific to OW Shuffle - Changed World check to table-based vs OW ID-based (should have no effect with current modes) -- ~Merged DR v0.4.0.5 - Mystery Boss Shuffle Fix / Swordless+Hard Item Pool Fix / Insanity+Inverted ER Fixes~ +- \~Merged DR v0.4.0.5 - Mystery Boss Shuffle Fix / Swordless+Hard Item Pool Fix / Insanity+Inverted ER Fixes~ ### 0.1.4.1 - Moved Inverted Pyramid Entrance to top of HC Ledge @@ -377,11 +377,11 @@ - Various logic fixes and region prep for Inverted - Fixed muted MSU-1 music in door rando when descending GT Climb stairs - Fixed Standard + Vanilla (thanks compiling) -- ~Merged DR v0.4.0.4 - Shuffle Link's House / Experimental Bunny Start / 10 Bomb Fix~ +- \~Merged DR v0.4.0.4 - Shuffle Link's House / Experimental Bunny Start / 10 Bomb Fix~ ### 0.1.3.0 - Added OWG Logic for OW Shuffle -- ~Merged DR v0.4.0.2 - OWG Framework / YAML~ +- \~Merged DR v0.4.0.2 - OWG Framework / YAML~ ### 0.1.2.2 - Re-purposed OW Shuffle setting to Layout Shuffle @@ -390,7 +390,7 @@ ### 0.1.2.1 - Made possible fix for Standard -- ~Merged DR v0.3.1.10 - Fixed Standard generation~ +- \~Merged DR v0.3.1.10 - Fixed Standard generation~ ### 0.1.2.0 - Added 'Parallel Worlds' toggle option @@ -400,7 +400,7 @@ ### 0.1.1.2 - If Link's current position fits within the incoming gap, Link will not get re-centered to the incoming gap - Added Rule for Pearl required to drop down back of SW -- ~Merged DR v0.3.1.8 - Improved Shopsanity pricing - Fixed Retro generation~ +- \~Merged DR v0.3.1.8 - Improved Shopsanity pricing - Fixed Retro generation~ ### 0.1.1.1 - Fixed camera unlocking issue From db39f7795bff615fd96efec2b79527d6993a75f1 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sat, 25 May 2024 03:31:24 -0500 Subject: [PATCH 04/39] Version bump --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 12ac61e5..4589f7b7 100644 --- a/README.md +++ b/README.md @@ -214,7 +214,7 @@ As you can see, things get pretty complicated when mixing modes together. Doing ## Whirlpool Shuffle (--ow_whirlpool) -When enabled, the whirlpool connections are shuffled. If Crossed OW is enabled, the whirlpools can also be cross-world as well. For Limited Crossed OW, this doesn't count towards the limited number of crossed edge transitions. +When enabled, the whirlpool connections are shuffled. If Crossed OW is enabled, the whirlpools can also be cross-world as well. When the number of crossed edges are limited thru Customizer, this doesn't count towards the limited number of crossed edge transitions. ## Flute Shuffle (--ow_fluteshuffle) From 32083e66b1651cbea60e553bc4a327484b0fd0ed Mon Sep 17 00:00:00 2001 From: codemann8 Date: Fri, 31 May 2024 01:13:08 -0500 Subject: [PATCH 05/39] Rename release-complete.yml to release-complete.yml-old --- .../workflows/{release-complete.yml => release-complete.yml-old} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{release-complete.yml => release-complete.yml-old} (100%) diff --git a/.github/workflows/release-complete.yml b/.github/workflows/release-complete.yml-old similarity index 100% rename from .github/workflows/release-complete.yml rename to .github/workflows/release-complete.yml-old From 3d9b2a5271f1bcfad882f80ca4694853266be2d5 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sun, 5 Jan 2025 07:48:04 -0600 Subject: [PATCH 06/39] Version bump 0.5.1.2 --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f913b845..071aeafd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 0.5.1.2 +- Many fixes to HMG logic, generation, key collection issues +- Fixed issue with In-Dungeon Prizes getting placed in the same dungeon +- Fixed issue with Old Man getting placed outside of DM in glitched modes +- Fixed issue with Free Terrain water transitions not checking for Pearl requirement + ## 0.5.1.0 (+ Hotfix 0.5.1.1) - New "Nearby" Dungeon Item Shuffle option - Fixed issue with smith follower getting deleted incorrectly on s+q From 265578dca5b9fb284d1e517fabd0f443a0bbe6ff Mon Sep 17 00:00:00 2001 From: theclearmouse <105736589+theclearmouse@users.noreply.github.com> Date: Sun, 19 Jan 2025 22:41:55 -0500 Subject: [PATCH 07/39] display mirror scroll icon on start screen if enabled --- InitialSram.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InitialSram.py b/InitialSram.py index 742e4fe3..d3c2e6e0 100644 --- a/InitialSram.py +++ b/InitialSram.py @@ -228,7 +228,7 @@ class InitialSram: equip[0x343] = min(starting_bombs, equip[0x370]) equip[0x377] = min(starting_arrows, equip[0x371]) - if not startingstate.has('Magic Mirror', player) and world.doorShuffle[player] != 'vanilla': + if not startingstate.has('Magic Mirror', player) and (world.doorShuffle[player] != 'vanilla' or world.mirrorscroll[player]): equip[0x353] = 1 # Assertion and copy equip to initial_sram_bytes From 2af5aad0788cae853649f47ce92a45f49bbabbbd Mon Sep 17 00:00:00 2001 From: KrisDavie Date: Thu, 6 Mar 2025 17:58:29 +0100 Subject: [PATCH 08/39] Fix cavestate dungeon items in non-keysanity --- Rom.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Rom.py b/Rom.py index e4582388..f1d6879a 100644 --- a/Rom.py +++ b/Rom.py @@ -474,6 +474,12 @@ def patch_rom(world, rom, player, team, is_mystery=False): rom.write_byte(location.player_address, location.item.player) else: itemid = 0x5A + + if not location.locked and ((location.item.smallkey and world.keyshuffle[player] == 'none') or ( + location.item.bigkey and world.bigkeyshuffle[player] == 'none') or ( + location.item.map and world.mapshuffle[player] == 'none') or ( + location.item.compass and world.compassshuffle[player] == 'none')): + itemid = handle_native_dungeon(location, itemid) rom.write_byte(location.address, itemid) for dungeon in [d for d in world.dungeons if d.player == player]: if dungeon.prize: From 7efc23b867fb1b0da87d3745a20e186ecafc89bd Mon Sep 17 00:00:00 2001 From: codemann8 Date: Tue, 11 Mar 2025 08:59:26 -0500 Subject: [PATCH 09/39] Fixed error with prizes in starting inventory --- Fill.py | 23 +++++++++++++++++++++++ Rom.py | 45 ++++++++++++++++++++++++++++++--------------- 2 files changed, 53 insertions(+), 15 deletions(-) diff --git a/Fill.py b/Fill.py index 8ffec2ee..b6b793db 100644 --- a/Fill.py +++ b/Fill.py @@ -657,6 +657,29 @@ def ensure_good_items(world, write_skips=False): if loc.type in [LocationType.Pot, LocationType.Bonk] and loc.item.name in valid_pot_items: loc.skip = True + dungeon_pool = collections.defaultdict(list) + prize_pool = collections.defaultdict(list) + from Dungeons import dungeon_table + from Items import prize_item_table + for dungeon in world.dungeons: + if dungeon_table[dungeon.name].prize: + dungeon_pool[dungeon.player].append(dungeon) + prize_set = set(prize_item_table.keys()) + for p in range(1, world.players + 1): + prize_pool[p] = prize_set.copy() + + for player in dungeon_pool: + dungeons = list(dungeon_pool[player]) + random.shuffle(dungeons) + dungeon_pool[player] = dungeons + for dungeon in world.dungeons: + if dungeon.prize: + dungeon_pool[dungeon.player].remove(dungeon) + prize_pool[dungeon.prize.player].remove(dungeon.prize.name) + for p in range(1, world.players + 1): + for dungeon in dungeon_pool[p]: + dungeon.prize = ItemFactory(prize_pool[p].pop(), p) + invalid_location_replacement = {'Arrows (5)': 'Arrows (10)', 'Nothing': 'Rupees (5)', 'Chicken': 'Rupees (5)', 'Big Magic': 'Small Magic', 'Fairy': 'Small Heart'} diff --git a/Rom.py b/Rom.py index f1d6879a..abea18f4 100644 --- a/Rom.py +++ b/Rom.py @@ -1314,6 +1314,17 @@ def patch_rom(world, rom, player, team, is_mystery=False): rom.write_byte(0x18003C, compass_mode) def get_entrance_coords(ent): + if ent is None: + owid_map = [0x1E, 0x30, 0xFF, 0x7B, 0x5E, 0x70, 0x40, 0x75, 0x03, 0x58, 0x47] + x_map_position_generic = [0x03c0, 0x0740, 0xff00, 0x03c0, 0x01c0, 0x0bc0, 0x05c0, 0x09c0, 0x0ac0, 0x07c0, 0x0dc0] + y_map_position_generic = [0xff00, 0xff00, 0xff00, 0x0fc0, 0x0fc0, 0x0fc0, 0x0fc0, 0x0fc0, 0xff00, 0x0fc0, 0x0fc0] + world_indicator = 0x0000 + idx = int((map_index-2)/2) + owid = owid_map[idx] + if owid != 0xFF: + if (owid < 0x40) == (world.is_tile_swapped(owid, player)): + world_indicator = 0x8000 + return [world_indicator | x_map_position_generic[idx], y_map_position_generic[idx]] if type(ent) is Location: from OverworldShuffle import OWTileRegions if ent.name == 'Hobo': @@ -1346,22 +1357,15 @@ def patch_rom(world, rom, player, team, is_mystery=False): # write out dislocated coords if map_index >= 0x02 and map_index < 0x18 and (world.overworld_map[player] != 'default' or world.prizeshuffle[player] not in ['none', 'dungeon', 'nearby']): - owid_map = [0x1E, 0x30, 0xFF, 0x7B, 0x5E, 0x70, 0x40, 0x75, 0x03, 0x58, 0x47] - x_map_position_generic = [0x03c0, 0x0740, 0xff00, 0x03c0, 0x01c0, 0x0bc0, 0x05c0, 0x09c0, 0x0ac0, 0x07c0, 0x0dc0] - y_map_position_generic = [0xff00, 0xff00, 0xff00, 0x0fc0, 0x0fc0, 0x0fc0, 0x0fc0, 0x0fc0, 0xff00, 0x0fc0, 0x0fc0] - world_indicator = 0x0000 - idx = int((map_index-2)/2) - owid = owid_map[idx] - if owid != 0xFF: - if (owid < 0x40) == (world.is_tile_swapped(owid, player)): - world_indicator = 0x8000 - write_int16(rom, snes_to_pc(0x0ABE2E)+(map_index*6)+4, world_indicator | x_map_position_generic[idx]) - write_int16(rom, snes_to_pc(0x0ABE2E)+(map_index*6)+6, y_map_position_generic[idx]) + coords = get_entrance_coords(None) + write_int16s(rom, snes_to_pc(0x0ABE2E)+(map_index*6)+4, coords) # write out icon coord data if world.prizeshuffle[player] not in ['none', 'dungeon', 'nearby'] and dungeon_table[dungeon].prize: dungeon_obj = world.get_dungeon(dungeon, player) - entrance = dungeon_obj.prize.get_map_location() + entrance = None + if dungeon_obj.prize: + entrance = dungeon_obj.prize.get_map_location() coords = get_entrance_coords(entrance) # prize location write_int16s(rom, snes_to_pc(0x0ABE2E)+(map_index*6)+8, coords) @@ -2334,9 +2338,20 @@ def write_strings(rom, world, player, team): silverarrow_hint = f'Did you find the silver arrows {hint_phrase}?' if progressive_silvers else no_silver_text tt['ganon_phase_3_no_silvers_alt'] = silverarrow_hint - crystal5 = world.find_items('Crystal 5', player)[0] - crystal6 = world.find_items('Crystal 6', player)[0] - greenpendant = world.find_items('Green Pendant', player)[0] + crystal5 = world.find_items('Crystal 5', player) + crystal6 = world.find_items('Crystal 6', player) + greenpendant = world.find_items('Green Pendant', player) + def missing_prize(): + from BaseClasses import Dungeon + d = Dungeon('your pocket', [], None, [], [], player, 0) + i = ItemFactory('Nothing', player) + i.dungeon_object = d + r = Region('Nowhere', RegionType.Menu, 'in your pocket', player) + r.dungeon = d + loc = Location(player, 'Nowhere', parent=r, hint_text='in your pocket') + loc.item = i + return loc + (crystal5, crystal6, greenpendant) = tuple([x[0] if x else missing_prize() for x in [crystal5, crystal6, greenpendant]]) if world.prizeshuffle[player] in ['none', 'dungeon']: (crystal5, crystal6, greenpendant) = tuple([x.parent_region.dungeon.name for x in [crystal5, crystal6, greenpendant]]) tt['bomb_shop'] = 'Big Bomb?\nMy supply is blocked until you clear %s and %s.' % (crystal5, crystal6) From acc802dfdf1639728003eac337b6a6aa2206d622 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Tue, 11 Mar 2025 09:07:57 -0500 Subject: [PATCH 10/39] Fixed errors with starting equipment containing bottles --- ItemList.py | 2 +- Main.py | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/ItemList.py b/ItemList.py index 08be1d62..3c879c9f 100644 --- a/ItemList.py +++ b/ItemList.py @@ -1245,7 +1245,7 @@ def modify_pool_for_start_inventory(start_inventory, world, player): world.itempool.remove(alt_item) i = i-1 elif 'Bottle' in item.name: - bottle_item = next((x for x in world.itempool if 'Bottle' in item.name and x.player == player), None) + bottle_item = next((x for x in world.itempool if 'Bottle' in x.name and x.player == player), None) if bottle_item is not None: world.itempool.remove(bottle_item) if item.dungeon: diff --git a/Main.py b/Main.py index e1af57b1..f668e853 100644 --- a/Main.py +++ b/Main.py @@ -429,6 +429,9 @@ def export_yaml(args, fish): for k,v in {"DR":__version__,"OR":ORVersion}.items(): logger.info((k + ' Version:').ljust(16) + '%s' % v) + for player in range(1, world.players + 1): + world.difficulty_requirements[player] = difficulties[world.difficulty[player]] + set_starting_inventory(world, args) world.settings = CustomSettings() From 7cba411e45522e660226fc098eea2c509b63160c Mon Sep 17 00:00:00 2001 From: Kris Davie Date: Sun, 16 Mar 2025 07:30:41 +0100 Subject: [PATCH 11/39] More glitched fixes --- ItemList.py | 12 +++++++++++- Rom.py | 7 +++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/ItemList.py b/ItemList.py index 5889e4d0..3dce2da3 100644 --- a/ItemList.py +++ b/ItemList.py @@ -368,7 +368,17 @@ def generate_itempool(world, player): or (item.map and world.mapshuffle[player]) or (item.compass and world.compassshuffle[player]))]) - + if world.logic[player] == 'hybridglitches' and world.pottery[player] not in ['none', 'cave']: + keys_to_remove = 2 + to_remove = [] + for wix, wi in enumerate(world.itempool): + if wi.name == 'Small Key (Swamp Palace)' and wi.player == player: + to_remove.append(wix) + if keys_to_remove == len(to_remove): + break + for wix in reversed(to_remove): + del world.itempool[wix] + # logic has some branches where having 4 hearts is one possible requirement (of several alternatives) # rather than making all hearts/heart pieces progression items (which slows down generation considerably) # We mark one random heart container as an advancement item (or 4 heart pieces in expert mode) diff --git a/Rom.py b/Rom.py index 4fd43122..984ac066 100644 --- a/Rom.py +++ b/Rom.py @@ -463,6 +463,13 @@ def patch_rom(world, rom, player, team, is_mystery=False): rom.write_byte(location.player_address, location.item.player) else: itemid = 0x5A + + if not location.locked and ((location.item.smallkey and world.keyshuffle[player] == 'none') or ( + location.item.bigkey and world.bigkeyshuffle[player] == 'none') or ( + location.item.map and world.mapshuffle[player] == 'none') or ( + location.item.compass and world.compassshuffle[player] == 'none')): + itemid = handle_native_dungeon(location, itemid) + rom.write_byte(location.address, itemid) else: # crystals From 966bd8d05e8d830ca28a9026ee91c50693ead0ec Mon Sep 17 00:00:00 2001 From: aerinon Date: Fri, 21 Mar 2025 11:07:09 -0600 Subject: [PATCH 12/39] fix: prevent big key door modification while door shuffle is vanilla --- CHANGELOG.md | 15 +++++++++++++++ Main.py | 2 +- RELEASENOTES.md | 19 ++++--------------- Rom.py | 2 +- 4 files changed, 21 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c9f2520..cb0b711a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,21 @@ Changelog archive +* 1.4.8.1 + - Fixed broken doors generation + - Fixed bomb/arrow upgrade ignoring custom pricing + - Extended `money_balance` to apply to price balancing for non-custom shops. +* 1.4.8 + - New option: Mirror Scroll - to add the item to the starting inventory in non-doors modes (Thanks Telethar!) + - Customizer: Ability to customize shop prices and control money balancing. `money_balance` is a percentage betwen 0 and 100 that attempts to ensure you have that much percentage of money available for purchases. (100 is default, 0 essentially ignores money considerations) + - Fixed a key logic bug with decoupled doors when a big key door leads to a small key door (the small key door was missing appropriate logic) + - Fixed an ER bug where Bonk Fairy could be used for a mandatory connector in standard mode (boots could allow escape to be skipped) + - Fixed an issue with flute activation in rain mode. (thanks Codemann!) + - Fixed an issue with enemies in TR Dark Ride room not requiring Somaria. (Refactored the room for decoupled logic better) + - More HMG fixes by Muffins + - Fixed an issue with multi-player HMG + - Fixed an issue limiting number of items specified in the item pool on the GUI + - Minor documentation fixes (thanks Codemann!) * 1.4.7.2 - Fixed an issue with shuffle_ganon/fix_gtower_exit causing a generation failure - More HMG fixes by Muffins diff --git a/Main.py b/Main.py index be7f74ef..fa45699e 100644 --- a/Main.py +++ b/Main.py @@ -38,7 +38,7 @@ from source.enemizer.DamageTables import DamageTable from source.enemizer.Enemizer import randomize_enemies from source.rom.DataTables import init_data_tables -version_number = '1.4.8.1' +version_number = '1.4.9' version_branch = '-u' __version__ = f'{version_number}{version_branch}' diff --git a/RELEASENOTES.md b/RELEASENOTES.md index b912e4f6..04825999 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,17 +1,6 @@ # Patch Notes -* 1.4.8.1 - - Fixed broken doors generation - - Fixed bomb/arrow upgrade ignoring custom pricing - - Extended `money_balance` to apply to price balancing for non-custom shops. -* 1.4.8 - - New option: Mirror Scroll - to add the item to the starting inventory in non-doors modes (Thanks Telethar!) - - Customizer: Ability to customize shop prices and control money balancing. `money_balance` is a percentage betwen 0 and 100 that attempts to ensure you have that much percentage of money available for purchases. (100 is default, 0 essentially ignores money considerations) - - Fixed a key logic bug with decoupled doors when a big key door leads to a small key door (the small key door was missing appropriate logic) - - Fixed an ER bug where Bonk Fairy could be used for a mandatory connector in standard mode (boots could allow escape to be skipped) - - Fixed an issue with flute activation in rain mode. (thanks Codemann!) - - Fixed an issue with enemies in TR Dark Ride room not requiring Somaria. (Refactored the room for decoupled logic better) - - More HMG fixes by Muffins - - Fixed an issue with multi-player HMG - - Fixed an issue limiting number of items specified in the item pool on the GUI - - Minor documentation fixes (thanks Codemann!) +* 1.4.9 + * Mirror scroll will show up on file start screen if enabled (thanks Clearmouse!) + * Fixes for HMG by Muffins + * Vanilla door shuffle prevents big key doors changes from door_type_mode diff --git a/Rom.py b/Rom.py index 984ac066..04b08fb2 100644 --- a/Rom.py +++ b/Rom.py @@ -583,7 +583,7 @@ def patch_rom(world, rom, player, team, is_mystery=False): dr_flags |= DROptions.DarkWorld_Spawns # no longer experimental if world.logic[player] not in ['owglitches', 'hybridglitches', 'nologic']: dr_flags |= DROptions.Fix_EG - if world.door_type_mode[player] in ['big', 'all', 'chaos']: + if world.door_type_mode[player] in ['big', 'all', 'chaos'] and world.doorShuffle[player] != 'vanilla': dr_flags |= DROptions.BigKeyDoor_Shuffle if world.dropshuffle[player] in ['underworld']: dr_flags |= DROptions.EnemyDropIndicator From 58baa412f5cabef6ff61b353175977ed6c9a3c67 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Thu, 27 Mar 2025 02:28:03 -0500 Subject: [PATCH 13/39] Fix extra junk added to pool for some prize shuffles --- ItemList.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ItemList.py b/ItemList.py index 3c879c9f..788ecb48 100644 --- a/ItemList.py +++ b/ItemList.py @@ -459,7 +459,8 @@ def generate_itempool(world, player): world.itempool = [beemizer(item) for item in world.itempool] # increase pool if not enough items - ttl_locations = sum(1 for x in world.get_unfilled_locations(player) if world.prizeshuffle[player] != 'none' or not x.prize) + ttl_locations = sum(1 for x in world.get_unfilled_locations(player) if not x.prize and not x.event) + ttl_locations -= 10 if world.prize_shuffle[player] in ['dungeon', 'nearby'] else 0 # TODO: Fix item pool to include prizes for these modes pool_size = count_player_dungeon_item_pool(world, player) pool_size += sum(1 for x in world.itempool if x.player == player) From fad9c06b056656612fcffb61f53ba9be5dd8d217 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sat, 5 Apr 2025 07:34:56 -0500 Subject: [PATCH 14/39] Remove invalid OW IDs from sprite sheets --- source/enemizer/SpriteSheets.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/source/enemizer/SpriteSheets.py b/source/enemizer/SpriteSheets.py index bb021088..08f3cdd8 100644 --- a/source/enemizer/SpriteSheets.py +++ b/source/enemizer/SpriteSheets.py @@ -701,17 +701,17 @@ def setup_required_overworld_groups(sheets): sheets[6].add_sprite_to_sheet([0x4F, 0x49, 0x4A, 0x50], {0x18, 0x22, 0x28, 0xA8, 0xB2, 0xB8}) sheets[8].add_sprite_to_sheet([None, None, 18, None], {0x30, 0xC0}) # Desert (pre/post-Aga) sheets[10].add_sprite_to_sheet([None, None, None, 17], {0x3A, 0xCA}) # M-rock (pre/post-Aga) - sheets[22].add_sprite_to_sheet([None, None, 24, None], {0x4F, 0xDF}) # Catfish (pre/post-Aga) - sheets[21].add_sprite_to_sheet([21, None, None, 21], {0x62, 0xF2}) # Smith DW (pre/post-Aga) - sheets[27].add_sprite_to_sheet([None, 42, None, None], {0x68, 0xF8}) # Dig Game (pre/post-Aga) + sheets[22].add_sprite_to_sheet([None, None, 24, None], {0x4F}) # Catfish + sheets[21].add_sprite_to_sheet([21, None, None, 21], {0x62}) # Smith DW + sheets[27].add_sprite_to_sheet([None, 42, None, None], {0x68}) # Dig Game sheets[13].add_sprite_to_sheet([None, None, 76, None], {0x16, 0xA6}) # Witch hut (pre/post-Aga) - sheets[29].add_sprite_to_sheet([None, 77, None, 21], {0x69, 0xF9}) # VoO South (pre/post-Aga) + sheets[29].add_sprite_to_sheet([None, 77, None, 21], {0x69}) # VoO South sheets[15].add_sprite_to_sheet([None, None, 78, None], {0x2A, 0xBA}) # Haunted Grove (pre/post-Aga) - sheets[17].add_sprite_to_sheet([None, None, None, 76], {0x6A, 0xFA}) # Stumpy (pre/post-Aga) - sheets[12].add_sprite_to_sheet([None, None, 55, 54], {0x80, 0x110}) # Specials (pre/post-Aga) - sheets[14].add_sprite_to_sheet([None, None, 12, 68], {0x81, 0x111}) # Zora's Domain (pre/post-Aga) + sheets[17].add_sprite_to_sheet([None, None, None, 76], {0x6A}) # Stumpy + sheets[12].add_sprite_to_sheet([None, None, 55, 54], {0x80}) # Specials + sheets[14].add_sprite_to_sheet([None, None, 12, 68], {0x81}) # Zora's Domain sheets[26].add_sprite_to_sheet([15, None, None, None], {0x92}) # Lumberjacks post-Aga - sheets[23].add_sprite_to_sheet([None, None, None, 25], {0x5E, 0xEE}) # PoD pre/post-Aga + sheets[23].add_sprite_to_sheet([None, None, None, 25], {0x5E}) # PoD free_sheet_reqs = [ [None, None, None, 0x14], # bully+pink ball needs this From 4b02a2d5a2c7a4eb42815acc8937eab60ba6ca48 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sat, 5 Apr 2025 08:00:09 -0500 Subject: [PATCH 15/39] Remove unused subgroups and consolidate purple chest/frog sprite sheets --- source/enemizer/SpriteSheets.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/enemizer/SpriteSheets.py b/source/enemizer/SpriteSheets.py index 08f3cdd8..e2342993 100644 --- a/source/enemizer/SpriteSheets.py +++ b/source/enemizer/SpriteSheets.py @@ -702,10 +702,10 @@ def setup_required_overworld_groups(sheets): sheets[8].add_sprite_to_sheet([None, None, 18, None], {0x30, 0xC0}) # Desert (pre/post-Aga) sheets[10].add_sprite_to_sheet([None, None, None, 17], {0x3A, 0xCA}) # M-rock (pre/post-Aga) sheets[22].add_sprite_to_sheet([None, None, 24, None], {0x4F}) # Catfish - sheets[21].add_sprite_to_sheet([21, None, None, 21], {0x62}) # Smith DW + sheets[21].add_sprite_to_sheet([None, None, None, 21], {0x62, 0x69}) # Smith DW/VoO South sheets[27].add_sprite_to_sheet([None, 42, None, None], {0x68}) # Dig Game sheets[13].add_sprite_to_sheet([None, None, 76, None], {0x16, 0xA6}) # Witch hut (pre/post-Aga) - sheets[29].add_sprite_to_sheet([None, 77, None, 21], {0x69}) # VoO South + #sheets[29].add_sprite_to_sheet([None, 77, None, 21], {0x69}) # VoO South sheets[15].add_sprite_to_sheet([None, None, 78, None], {0x2A, 0xBA}) # Haunted Grove (pre/post-Aga) sheets[17].add_sprite_to_sheet([None, None, None, 76], {0x6A}) # Stumpy sheets[12].add_sprite_to_sheet([None, None, 55, 54], {0x80}) # Specials From b6ea50584381abd87e25b7fb2f9f594bee849ac9 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sat, 5 Apr 2025 08:00:40 -0500 Subject: [PATCH 16/39] Fix bat crash sprite gfx in enemizer --- source/enemizer/SpriteSheets.py | 1 + 1 file changed, 1 insertion(+) diff --git a/source/enemizer/SpriteSheets.py b/source/enemizer/SpriteSheets.py index e2342993..08f6152e 100644 --- a/source/enemizer/SpriteSheets.py +++ b/source/enemizer/SpriteSheets.py @@ -712,6 +712,7 @@ def setup_required_overworld_groups(sheets): sheets[14].add_sprite_to_sheet([None, None, 12, 68], {0x81}) # Zora's Domain sheets[26].add_sprite_to_sheet([15, None, None, None], {0x92}) # Lumberjacks post-Aga sheets[23].add_sprite_to_sheet([None, None, None, 25], {0x5E}) # PoD + sheets[19].add_sprite_to_sheet([None, 26, None, None], {0x5B}) # Pyramid post-Aga2 bat crash free_sheet_reqs = [ [None, None, None, 0x14], # bully+pink ball needs this From 9d0404af3947cf3fa3d9f6ee5a56e8a536a2f887 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sat, 5 Apr 2025 08:02:30 -0500 Subject: [PATCH 17/39] Fix swamp drain gfx in enemizer --- source/enemizer/SpriteSheets.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/enemizer/SpriteSheets.py b/source/enemizer/SpriteSheets.py index 08f6152e..1a4cbec6 100644 --- a/source/enemizer/SpriteSheets.py +++ b/source/enemizer/SpriteSheets.py @@ -550,7 +550,7 @@ def setup_required_dungeon_groups(sheets, data_tables): ([None, 77, None, 21], [0x121]), # smithy ([None, None, None, 80], [0x108]), # chicken house ([14, 30, None, None], [0x123]), # mini moldorm (shutter door) - ([None, None, 34, None], [0x36, 0x46, 0x66, 0x76]), # pirogusu spawners + ([None, None, 34, None], [0x36, 0x46, 0x66]), # pirogusu spawners ([None, 32, None, None], [0x9f]), # babasu spawners ([31, None, None, None], [0x7f]), # force baris ([None, None, 35, None], [0x39, 0x49]), # wallmasters @@ -570,7 +570,7 @@ def setup_required_dungeon_groups(sheets, data_tables): ([None, None, (28, 36), 82], [0x2, 0x64]), # pull switches (snakes) ([None, None, None, 82], [0x1a, 0x3d, 0x44, 0x5e, 0x7c, 0x95, 0xc3]), # collapsing bridges ([None, None, None, 83], [0x3f, 0xce]), # pull tongue - ([None, None, None, 83], [0x35, 0x37, 0x76]), # swamp drains + ([None, None, None, 83], [0x35, 0x37]), # swamp drains ([None, None, 34, None], [0x28]), # tektike forced? - spawn chest ([None, None, 37, None], [0x97]), # wizzrobe spawner - in middle of room... From f365267201cb9466186402bc1740e3c51e8e41f2 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sat, 5 Apr 2025 08:03:23 -0500 Subject: [PATCH 18/39] Fix paradox cave and kakariko shop gfx in enemizer --- source/enemizer/SpriteSheets.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/source/enemizer/SpriteSheets.py b/source/enemizer/SpriteSheets.py index 1a4cbec6..2eec5781 100644 --- a/source/enemizer/SpriteSheets.py +++ b/source/enemizer/SpriteSheets.py @@ -527,7 +527,7 @@ def setup_required_dungeon_groups(sheets, data_tables): sheets[did(1)].add_sprite_to_sheet([70, 73, 28, 82], {0xe4, 0xf0}) # old man # various npcs - sheets[did(5)].add_sprite_to_sheet([75, 77, 74, 90], {0xf3, 0x109, 0x10e, 0x10f, 0x110, 0x111, 0x112, + sheets[did(5)].add_sprite_to_sheet([75, 77, 74, 90], {0xf3, 0xff, 0x109, 0x10e, 0x10f, 0x110, 0x111, 0x112, 0x11a, 0x11c, 0x11f, 0x122}) sheets[did(7)].add_sprite_to_sheet([75, 77, 57, 54], {0x8, 0x2c, 0x114, 0x115, 0x116}) # big fairies sheets[did(13)].add_sprite_to_sheet([81, None, None, None], {0x55, 0x102, 0x104}) # uncle, sick kid @@ -546,7 +546,6 @@ def setup_required_dungeon_groups(sheets, data_tables): # not sure 31 is needed above free_sheet_reqs = [ - ([75, None, None, None], [0xff, 0x11f]), # shopkeepers ([None, 77, None, 21], [0x121]), # smithy ([None, None, None, 80], [0x108]), # chicken house ([14, 30, None, None], [0x123]), # mini moldorm (shutter door) From 5c5e5e5428a9383bed0db43b29d2abe54ef1adfa Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sat, 5 Apr 2025 08:04:50 -0500 Subject: [PATCH 19/39] Freeing up unnecessary sprite sheet subgroups for old man screens --- source/enemizer/SpriteSheets.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/enemizer/SpriteSheets.py b/source/enemizer/SpriteSheets.py index 2eec5781..15b339b9 100644 --- a/source/enemizer/SpriteSheets.py +++ b/source/enemizer/SpriteSheets.py @@ -325,7 +325,7 @@ def init_sprite_requirements(): SpriteRequirement(EnemySprite.BlueZirro).no_drop().sub_group(3, 0x1b).exclude(NoFlyingRooms), SpriteRequirement(EnemySprite.Pikit).sub_group(3, 0x1b), SpriteRequirement(EnemySprite.CrystalMaiden).affix(), - SpriteRequirement(EnemySprite.OldMan).affix().sub_group(0, 0x46).sub_group(1, 0x49).sub_group(2, 0x1c), + SpriteRequirement(EnemySprite.OldMan).affix().sub_group(2, 0x1c), SpriteRequirement(EnemySprite.PipeDown).affix(), SpriteRequirement(EnemySprite.PipeUp).affix(), SpriteRequirement(EnemySprite.PipeRight).affix(), @@ -525,7 +525,7 @@ def init_sprite_sheets(requirements): def setup_required_dungeon_groups(sheets, data_tables): - sheets[did(1)].add_sprite_to_sheet([70, 73, 28, 82], {0xe4, 0xf0}) # old man + sheets[did(1)].add_sprite_to_sheet([None, None, 28, None], {0xe4, 0xf0}) # old man # various npcs sheets[did(5)].add_sprite_to_sheet([75, 77, 74, 90], {0xf3, 0xff, 0x109, 0x10e, 0x10f, 0x110, 0x111, 0x112, 0x11a, 0x11c, 0x11f, 0x122}) From d423193aa6bc531bba437af7e7c77ece09372b0f Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sat, 5 Apr 2025 08:10:32 -0500 Subject: [PATCH 20/39] Remove unnecessary sprite sheet subgroup for somaria platforms --- source/enemizer/SpriteSheets.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/source/enemizer/SpriteSheets.py b/source/enemizer/SpriteSheets.py index 15b339b9..e59dd8ae 100644 --- a/source/enemizer/SpriteSheets.py +++ b/source/enemizer/SpriteSheets.py @@ -542,8 +542,7 @@ def setup_required_dungeon_groups(sheets, data_tables): sheets[did(3)].add_sprite_to_sheet([93, None, None, None], {0x51}) # mantle sheets[did(42)].add_sprite_to_sheet([21, None, None, None], {0x11e}) # hype cave sheets[did(10)].add_sprite_to_sheet([47, None, 46, None], {0x5c, 0x75, 0xb9, 0xd9}) # cannonballs - sheets[did(37)].add_sprite_to_sheet([31, None, 39, 82], {0x24, 0xb4, 0xb5, 0xc6, 0xc7, 0xd6}) # somaria platforms - # not sure 31 is needed above + sheets[did(37)].add_sprite_to_sheet([None, None, 39, 82], {0x24, 0xb4, 0xb5, 0xc6, 0xc7, 0xd6}) # somaria platforms free_sheet_reqs = [ ([None, 77, None, 21], [0x121]), # smithy From 813caa894ef0083132b5be85e6c76b9cd82fdf45 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sat, 5 Apr 2025 08:12:30 -0500 Subject: [PATCH 21/39] Fixed enemizer sprite gfx for soldier enemies falling down pits --- source/enemizer/SpriteSheets.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/source/enemizer/SpriteSheets.py b/source/enemizer/SpriteSheets.py index e59dd8ae..3dd8cb29 100644 --- a/source/enemizer/SpriteSheets.py +++ b/source/enemizer/SpriteSheets.py @@ -123,6 +123,9 @@ LenientTrapsForTesting = {0x16, 0x26, 0x3f, 0x40, 0x42, 0x46, 0x49, 0x4e, 0x57, 0x65, 0x6a, 0x74, 0x76, 0x7d, 0x98, 0x9e, 0xaf, 0xba, 0xc6, 0xcb, 0xce, 0xd2, 0xd5, 0xd8, 0xdf, 0xe4, 0xe7, 0xee, 0xfd, 0x10c} +PitRooms = {0x17, 0x1a, 0x2a, 0x31, 0x3c, 0x3d, 0x40, 0x44, 0x49, 0x4e, 0x56, 0x58, 0x5c, 0x67, 0x72, + 0x7b, 0x7c, 0x7d, 0x7f, 0x82, 0x8b, 0x8d, 0x95, 0x96, 0x9b, 0x9c, 0x9d, 0x9e, 0xa0, 0xa5, + 0xaf, 0xbc, 0xc0, 0xc5, 0xc6, 0xd1, 0xd5, 0xe7, 0xe8, 0xee, 0xf0, 0xf1, 0xfb, 0x123} # wallmasters must not be on tiles near spiral staircases. Unknown if other stairs have issues WallmasterInvalidRooms = { @@ -222,9 +225,12 @@ def init_sprite_requirements(): SpriteRequirement(EnemySprite.Hoarder2).sub_group(3, 0x11).exclude({0x10c}), SpriteRequirement(EnemySprite.TutorialGuard).affix(), SpriteRequirement(EnemySprite.LightningGate).affix().sub_group(3, 0x3f), - SpriteRequirement(EnemySprite.BlueGuard).aquaphobia().sub_group(1, [0xd, 0x49]), - SpriteRequirement(EnemySprite.GreenGuard).aquaphobia().sub_group(1, 0x49), - SpriteRequirement(EnemySprite.RedSpearGuard).aquaphobia().sub_group(1, [0xd, 0x49]), + SpriteRequirement(EnemySprite.BlueGuard).aquaphobia().sub_group(1, [0xd, 0x49]).exclude(PitRooms), + SpriteRequirement(EnemySprite.BlueGuard).aquaphobia().sub_group(1, [0xd, 0x49]).sub_group(2, [0x29, 0x13]), + SpriteRequirement(EnemySprite.GreenGuard).aquaphobia().sub_group(1, 0x49).exclude(PitRooms), + SpriteRequirement(EnemySprite.GreenGuard).aquaphobia().sub_group(1, 0x49).sub_group(2, 0x13), + SpriteRequirement(EnemySprite.RedSpearGuard).aquaphobia().sub_group(1, [0xd, 0x49]).exclude(PitRooms), + SpriteRequirement(EnemySprite.RedSpearGuard).aquaphobia().sub_group(1, [0xd, 0x49]).sub_group(2, [0x29, 0x13]), SpriteRequirement(EnemySprite.BluesainBolt).aquaphobia().sub_group(0, 0x46).sub_group(1, [0xd, 0x49]), SpriteRequirement(EnemySprite.UsainBolt).aquaphobia().sub_group(1, [0xd, 0x49]), SpriteRequirement(EnemySprite.BlueArcher).sub_group(0, 0x48).sub_group(1, 0x49), From 65f84a1c55806a2b67d24f7bc28e24ea66a2d319 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Wed, 16 Apr 2025 01:01:27 -0500 Subject: [PATCH 22/39] Added documentation for little-known start_inventory items --- docs/Customizer.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/Customizer.md b/docs/Customizer.md index 5173fccb..e7c5738c 100644 --- a/docs/Customizer.md +++ b/docs/Customizer.md @@ -289,6 +289,12 @@ start_inventory: To start with multiple copies of progressive items, list them more than once. +There are some additional non-standard keywords available that can be added as starting inventory: + +* `RandomWeapon` - This grants the player with the same random weapon options that Uncle gives in standard starts, including ammo for that weapon. +* `Beat Agahnim 1` - This enables post-Agahnim world state by default and flags Agahnim 1 as defeated. +* `Return Old Man` - This enables the Mountain Cave starting location by default. This also removes one item location from the game. + ##### Known Issue This conflicts with the mystery yaml, if specified. These start inventory items will be added after those are added. From bce49b9e76eea2ca9f60295689bb7c928572fd7f Mon Sep 17 00:00:00 2001 From: codemann8 Date: Wed, 16 Apr 2025 01:18:58 -0500 Subject: [PATCH 23/39] Minor documentation and error fixes --- InitialSram.py | 2 +- ItemList.py | 2 +- README.md | 10 ++++++++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/InitialSram.py b/InitialSram.py index 7fbb0b3b..0aa25bc2 100644 --- a/InitialSram.py +++ b/InitialSram.py @@ -124,7 +124,7 @@ class InitialSram: if startingstate.has('Beat Agahnim 1', player): self.pre_open_lumberjack() if world.mode[player] == 'standard': - self.set_progress_indicator(0x80) # todo: probably missing some code rom side for this + self.set_progress_indicator(0x80) else: self.set_progress_indicator(0x03) diff --git a/ItemList.py b/ItemList.py index 788ecb48..45c1df2d 100644 --- a/ItemList.py +++ b/ItemList.py @@ -460,7 +460,7 @@ def generate_itempool(world, player): # increase pool if not enough items ttl_locations = sum(1 for x in world.get_unfilled_locations(player) if not x.prize and not x.event) - ttl_locations -= 10 if world.prize_shuffle[player] in ['dungeon', 'nearby'] else 0 # TODO: Fix item pool to include prizes for these modes + ttl_locations -= 10 if world.prizeshuffle[player] in ['dungeon', 'nearby'] else 0 # TODO: Fix item pool to include prizes for these modes pool_size = count_player_dungeon_item_pool(world, player) pool_size += sum(1 for x in world.itempool if x.player == player) diff --git a/README.md b/README.md index a332ce01..707b7b75 100644 --- a/README.md +++ b/README.md @@ -272,7 +272,7 @@ As far as map trackers, Bonk Locations are supported on `CodeTracker` when the B This is a new option in addition to the traditional wild vs non-wild (keysanity/non-keysanity) options for all the dungeon item types (maps, compasses, small keys, big keys, prizes). This new option shuffles dungeon items into locations somewhere either within the dungeon that it is assigned to or within the surrounding district of that dungeon. -## Prize Shuffle +## Prize Shuffle (--prizeshuffle) A new option has been added to shuffle the 10 dungeon prizes in ways that they haven't been shuffled before. This means that dungeon prizes can be found in other item locations, such as chests or free-standing item locations. This also means that bosses are able to drop a 2nd item in place of the shuffled prize. @@ -292,7 +292,7 @@ This option shuffles the prize into a location somewhere either within the dunge This option freely shuffles the prizes throughout the world. While the dungeon prizes can end up anywhere, they still are assigned to a specific dungeon. When you defeat the boss of a certain dungeon, checking the map on the overworld will reveal the location WHERE you can find the prize, an example shown [here](https://zelda.codemann8.com/images/shared/prizemap-all.gif). Finding the map will still reveal WHAT the prize is. If you defeated a boss but haven't collected the map for that dungeon, the prize will be indicated by a red X, example shown [here](https://zelda.codemann8.com/images/shared/prizemap-boss.gif). If you collected a map but haven't defeated the boss yet, the icon indicator on the map will be shown on the top edge (for LW dungeons) or the bottom edge (for DW dungeons), but it will show you WHAT the prize is for that dungeon, an example of that is shown [here](https://zelda.codemann8.com/images/shared/prizemap-map.gif). -- It is important to note that the overworld map check has changed: the numbered icons that are displayed are NO LONGER indicating the crystal number like they have in the past. They are now indicating the dungeon that it belongs to; a blue 1-3 indicates the 3 LW dungeons (EP, DP, and ToH) and a red 1-7 indicate the 7 DW dungeons +- It is important to note that the overworld map check has changed: the numbered icons that are displayed are NO LONGER indicating the crystal number like they have in the past. They are now indicating the dungeon that it belongs to; a blue E/D/T indicates the 3 LW dungeons (EP, DP, and ToH) and a red 1-7 indicate the 7 DW dungeons ## New Goal Options (--goal) @@ -408,3 +408,9 @@ For randomizing the flute spots around the overworld ``` This extends the item pool to bonk locations and makes them additional item locations + +``` +--prizeshuffle +``` + +This allows prizes (crystals/pendants) to shuffle outside their usual boss location. From 63f39c5c0580b6d53707c9523d5010cd3cee9c08 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Wed, 16 Apr 2025 01:19:51 -0500 Subject: [PATCH 24/39] Possibly fix false positive error message for python package requirements --- source/meta/check_requirements.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source/meta/check_requirements.py b/source/meta/check_requirements.py index 6976f707..4a93be72 100644 --- a/source/meta/check_requirements.py +++ b/source/meta/check_requirements.py @@ -11,8 +11,9 @@ def check_requirements(console=False): 'pyyaml': 'yaml'} missing = [] for package, import_name in check_packages.items(): - spec = importlib.util.find_spec(import_name) - if spec is None: + try: + __import__(import_name) + except ImportError: missing.append(package) if len(missing) > 0: packages = ','.join(missing) From 267552bfeed139ede754815dd078a9a7b4fa2aa1 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Wed, 16 Apr 2025 01:24:59 -0500 Subject: [PATCH 25/39] Improved Retro button in GUI --- resources/app/gui/lang/en.json | 2 +- resources/app/gui/randomize/item/widgets.json | 17 ++++---- source/gui/bottom.py | 2 +- source/gui/randomize/item.py | 40 +++++++++++++++++-- 4 files changed, 47 insertions(+), 14 deletions(-) diff --git a/resources/app/gui/lang/en.json b/resources/app/gui/lang/en.json index bf4dfa93..8affe105 100644 --- a/resources/app/gui/lang/en.json +++ b/resources/app/gui/lang/en.json @@ -294,7 +294,7 @@ "randomizer.item.worldstate.open": "Open", "randomizer.item.worldstate.inverted": "Inverted", "randomizer.item.worldstate.retro": "Retro", - "randomizer.item.retro": "Enable Retro", + "randomizer.item.retro": "Retro", "randomizer.item.logiclevel": "Logic Level", "randomizer.item.logiclevel.noglitches": "No Glitches", diff --git a/resources/app/gui/randomize/item/widgets.json b/resources/app/gui/randomize/item/widgets.json index 8531cf75..402fde7c 100644 --- a/resources/app/gui/randomize/item/widgets.json +++ b/resources/app/gui/randomize/item/widgets.json @@ -6,7 +6,7 @@ "collection_rate": {"type": "checkbox"}, "race": { "type": "checkbox" } }, - "leftItemFrame": { + "worldstateFrame": { "worldstate": { "type": "selectbox", "default": "open", @@ -14,8 +14,13 @@ "standard", "open", "inverted" - ] - }, + ], + "config": { + "width": 13 + } + } + }, + "leftItemFrame": { "logiclevel": { "type": "selectbox", "options": [ @@ -64,12 +69,6 @@ } }, "rightItemFrame": { - "retro": { - "type": "button", - "config": { - "command": "retro" - } - }, "sortingalgo": { "type": "selectbox", "default": "balanced", diff --git a/source/gui/bottom.py b/source/gui/bottom.py index 1cd99e0a..7faf3402 100644 --- a/source/gui/bottom.py +++ b/source/gui/bottom.py @@ -272,7 +272,7 @@ def create_guiargs(parent): arg = options[mainpage][subpage][widget] if subpage != "" else options[mainpage][widget] page = parent.pages[mainpage].pages[subpage] if subpage != "" else parent.pages[mainpage] pagewidgets = page.content.customWidgets if mainpage == "custom" else page.content.startingWidgets if mainpage == "startinventory" else page.widgets - if hasattr(pagewidgets[widget], 'storageVar'): + if widget in pagewidgets and hasattr(pagewidgets[widget], 'storageVar'): setattr(guiargs, arg, pagewidgets[widget].storageVar.get()) # Get Multiworld Worlds count diff --git a/source/gui/randomize/item.py b/source/gui/randomize/item.py index 63a96997..bdb47747 100644 --- a/source/gui/randomize/item.py +++ b/source/gui/randomize/item.py @@ -1,5 +1,6 @@ -from tkinter import ttk, font, Frame, E, W, NW, TOP, LEFT, RIGHT, Y, Label +from tkinter import messagebox, ttk, font, Button, Frame, E, W, TOP, LEFT, RIGHT, X, Y, Label import source.gui.widgets as widgets +from source.classes.Empty import Empty import json import os @@ -28,6 +29,16 @@ def item_page(parent): self.frames["leftItemFrame"] = Frame(self.frames["mainFrame"]) self.frames["leftItemFrame"].pack(side=LEFT) + self.frames["worldstateFrame"] = Frame(self.frames["leftItemFrame"]) + self.frames["worldstateFrame"].pack(side=TOP, fill=X) + + ## Retro Button + widget = Empty() + widget.pieces = {} + widget.type = "button" + widget.pieces["button"] = Button(self.frames["worldstateFrame"], text="Retro", command=lambda: retro(widget)) + widget.pieces["button"].pack(side=RIGHT, padx=(1, 2)) + self.frames["rightItemFrame"] = Frame(self.frames["mainFrame"]) self.frames["rightItemFrame"].pack(side=RIGHT) @@ -65,8 +76,6 @@ def item_page(parent): for key in dictWidgets: self.widgets[key] = dictWidgets[key] packAttrs = {"anchor":E} - if key == "retro": - packAttrs["side"] = RIGHT if self.widgets[key].type == "checkbox" or framename.startswith("leftPoolFrame"): packAttrs["anchor"] = W if framename == "checkboxes": @@ -75,7 +84,32 @@ def item_page(parent): elif framename == "leftPoolHeader": packAttrs["side"] = LEFT packAttrs["padx"] = (0, 20) + elif framename == "rightItemFrame" and self.widgets[key].type == "checkbox": + packAttrs["side"] = LEFT + packAttrs["padx"] = (118, 0) packAttrs = widgets.add_padding_from_config(packAttrs, theseWidgets[key]) self.widgets[key].pack(packAttrs) return self + +def retro(baseWidget): + widget = baseWidget.pieces['button'] + root = widget.winfo_toplevel() + text_output = "" + temp_widget = root.pages["randomizer"].pages["dungeon"].widgets["smallkeyshuffle"] + text_output += f'\n {temp_widget.label.cget("text")}' + temp_widget.storageVar.set('universal') + + temp_widget = root.pages["randomizer"].pages["item"].widgets["bow_mode"] + text_output += f'\n {temp_widget.label.cget("text")}' + if temp_widget.storageVar.get() == 'progressive': + temp_widget.storageVar.set('retro') + elif temp_widget.storageVar.get() == 'silvers': + temp_widget.storageVar.set('retro_silvers') + + temp_widget = root.pages["randomizer"].pages["item"].widgets["take_any"] + text_output += f'\n {temp_widget.label.cget("text")}' + if temp_widget.storageVar.get() == 'none': + temp_widget.storageVar.set('random') + + messagebox.showinfo('', f'The following settings were changed:{text_output}') From fe0cfe8b3aac9b27a41f1a8276432bef34fa6147 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sat, 5 Apr 2025 07:34:56 -0500 Subject: [PATCH 26/39] fix: various Enemizer fixes Fixed enemizer sprite gfx for soldier enemies falling down pits Remove unnecessary sprite sheet subgroup for somaria platforms Freeing up unnecessary sprite sheet subgroups for old man screens Fix paradox cave and kakariko shop gfx in enemizer Fix swamp drain gfx in enemizer Fix bat crash sprite gfx in enemizer Remove unused subgroups and consolidate purple chest/frog sprite sheets Remove invalid OW IDs from sprite sheets --- RELEASENOTES.md | 1 + source/enemizer/SpriteSheets.py | 43 ++++++++++++++++++--------------- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 04825999..02cfeef6 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -3,4 +3,5 @@ * 1.4.9 * Mirror scroll will show up on file start screen if enabled (thanks Clearmouse!) * Fixes for HMG by Muffins + * Various fixes for Enemizer by Codemann (gfx fixes, more randomization options) * Vanilla door shuffle prevents big key doors changes from door_type_mode diff --git a/source/enemizer/SpriteSheets.py b/source/enemizer/SpriteSheets.py index bb021088..3dd8cb29 100644 --- a/source/enemizer/SpriteSheets.py +++ b/source/enemizer/SpriteSheets.py @@ -123,6 +123,9 @@ LenientTrapsForTesting = {0x16, 0x26, 0x3f, 0x40, 0x42, 0x46, 0x49, 0x4e, 0x57, 0x65, 0x6a, 0x74, 0x76, 0x7d, 0x98, 0x9e, 0xaf, 0xba, 0xc6, 0xcb, 0xce, 0xd2, 0xd5, 0xd8, 0xdf, 0xe4, 0xe7, 0xee, 0xfd, 0x10c} +PitRooms = {0x17, 0x1a, 0x2a, 0x31, 0x3c, 0x3d, 0x40, 0x44, 0x49, 0x4e, 0x56, 0x58, 0x5c, 0x67, 0x72, + 0x7b, 0x7c, 0x7d, 0x7f, 0x82, 0x8b, 0x8d, 0x95, 0x96, 0x9b, 0x9c, 0x9d, 0x9e, 0xa0, 0xa5, + 0xaf, 0xbc, 0xc0, 0xc5, 0xc6, 0xd1, 0xd5, 0xe7, 0xe8, 0xee, 0xf0, 0xf1, 0xfb, 0x123} # wallmasters must not be on tiles near spiral staircases. Unknown if other stairs have issues WallmasterInvalidRooms = { @@ -222,9 +225,12 @@ def init_sprite_requirements(): SpriteRequirement(EnemySprite.Hoarder2).sub_group(3, 0x11).exclude({0x10c}), SpriteRequirement(EnemySprite.TutorialGuard).affix(), SpriteRequirement(EnemySprite.LightningGate).affix().sub_group(3, 0x3f), - SpriteRequirement(EnemySprite.BlueGuard).aquaphobia().sub_group(1, [0xd, 0x49]), - SpriteRequirement(EnemySprite.GreenGuard).aquaphobia().sub_group(1, 0x49), - SpriteRequirement(EnemySprite.RedSpearGuard).aquaphobia().sub_group(1, [0xd, 0x49]), + SpriteRequirement(EnemySprite.BlueGuard).aquaphobia().sub_group(1, [0xd, 0x49]).exclude(PitRooms), + SpriteRequirement(EnemySprite.BlueGuard).aquaphobia().sub_group(1, [0xd, 0x49]).sub_group(2, [0x29, 0x13]), + SpriteRequirement(EnemySprite.GreenGuard).aquaphobia().sub_group(1, 0x49).exclude(PitRooms), + SpriteRequirement(EnemySprite.GreenGuard).aquaphobia().sub_group(1, 0x49).sub_group(2, 0x13), + SpriteRequirement(EnemySprite.RedSpearGuard).aquaphobia().sub_group(1, [0xd, 0x49]).exclude(PitRooms), + SpriteRequirement(EnemySprite.RedSpearGuard).aquaphobia().sub_group(1, [0xd, 0x49]).sub_group(2, [0x29, 0x13]), SpriteRequirement(EnemySprite.BluesainBolt).aquaphobia().sub_group(0, 0x46).sub_group(1, [0xd, 0x49]), SpriteRequirement(EnemySprite.UsainBolt).aquaphobia().sub_group(1, [0xd, 0x49]), SpriteRequirement(EnemySprite.BlueArcher).sub_group(0, 0x48).sub_group(1, 0x49), @@ -325,7 +331,7 @@ def init_sprite_requirements(): SpriteRequirement(EnemySprite.BlueZirro).no_drop().sub_group(3, 0x1b).exclude(NoFlyingRooms), SpriteRequirement(EnemySprite.Pikit).sub_group(3, 0x1b), SpriteRequirement(EnemySprite.CrystalMaiden).affix(), - SpriteRequirement(EnemySprite.OldMan).affix().sub_group(0, 0x46).sub_group(1, 0x49).sub_group(2, 0x1c), + SpriteRequirement(EnemySprite.OldMan).affix().sub_group(2, 0x1c), SpriteRequirement(EnemySprite.PipeDown).affix(), SpriteRequirement(EnemySprite.PipeUp).affix(), SpriteRequirement(EnemySprite.PipeRight).affix(), @@ -525,9 +531,9 @@ def init_sprite_sheets(requirements): def setup_required_dungeon_groups(sheets, data_tables): - sheets[did(1)].add_sprite_to_sheet([70, 73, 28, 82], {0xe4, 0xf0}) # old man + sheets[did(1)].add_sprite_to_sheet([None, None, 28, None], {0xe4, 0xf0}) # old man # various npcs - sheets[did(5)].add_sprite_to_sheet([75, 77, 74, 90], {0xf3, 0x109, 0x10e, 0x10f, 0x110, 0x111, 0x112, + sheets[did(5)].add_sprite_to_sheet([75, 77, 74, 90], {0xf3, 0xff, 0x109, 0x10e, 0x10f, 0x110, 0x111, 0x112, 0x11a, 0x11c, 0x11f, 0x122}) sheets[did(7)].add_sprite_to_sheet([75, 77, 57, 54], {0x8, 0x2c, 0x114, 0x115, 0x116}) # big fairies sheets[did(13)].add_sprite_to_sheet([81, None, None, None], {0x55, 0x102, 0x104}) # uncle, sick kid @@ -542,15 +548,13 @@ def setup_required_dungeon_groups(sheets, data_tables): sheets[did(3)].add_sprite_to_sheet([93, None, None, None], {0x51}) # mantle sheets[did(42)].add_sprite_to_sheet([21, None, None, None], {0x11e}) # hype cave sheets[did(10)].add_sprite_to_sheet([47, None, 46, None], {0x5c, 0x75, 0xb9, 0xd9}) # cannonballs - sheets[did(37)].add_sprite_to_sheet([31, None, 39, 82], {0x24, 0xb4, 0xb5, 0xc6, 0xc7, 0xd6}) # somaria platforms - # not sure 31 is needed above + sheets[did(37)].add_sprite_to_sheet([None, None, 39, 82], {0x24, 0xb4, 0xb5, 0xc6, 0xc7, 0xd6}) # somaria platforms free_sheet_reqs = [ - ([75, None, None, None], [0xff, 0x11f]), # shopkeepers ([None, 77, None, 21], [0x121]), # smithy ([None, None, None, 80], [0x108]), # chicken house ([14, 30, None, None], [0x123]), # mini moldorm (shutter door) - ([None, None, 34, None], [0x36, 0x46, 0x66, 0x76]), # pirogusu spawners + ([None, None, 34, None], [0x36, 0x46, 0x66]), # pirogusu spawners ([None, 32, None, None], [0x9f]), # babasu spawners ([31, None, None, None], [0x7f]), # force baris ([None, None, 35, None], [0x39, 0x49]), # wallmasters @@ -570,7 +574,7 @@ def setup_required_dungeon_groups(sheets, data_tables): ([None, None, (28, 36), 82], [0x2, 0x64]), # pull switches (snakes) ([None, None, None, 82], [0x1a, 0x3d, 0x44, 0x5e, 0x7c, 0x95, 0xc3]), # collapsing bridges ([None, None, None, 83], [0x3f, 0xce]), # pull tongue - ([None, None, None, 83], [0x35, 0x37, 0x76]), # swamp drains + ([None, None, None, 83], [0x35, 0x37]), # swamp drains ([None, None, 34, None], [0x28]), # tektike forced? - spawn chest ([None, None, 37, None], [0x97]), # wizzrobe spawner - in middle of room... @@ -701,17 +705,18 @@ def setup_required_overworld_groups(sheets): sheets[6].add_sprite_to_sheet([0x4F, 0x49, 0x4A, 0x50], {0x18, 0x22, 0x28, 0xA8, 0xB2, 0xB8}) sheets[8].add_sprite_to_sheet([None, None, 18, None], {0x30, 0xC0}) # Desert (pre/post-Aga) sheets[10].add_sprite_to_sheet([None, None, None, 17], {0x3A, 0xCA}) # M-rock (pre/post-Aga) - sheets[22].add_sprite_to_sheet([None, None, 24, None], {0x4F, 0xDF}) # Catfish (pre/post-Aga) - sheets[21].add_sprite_to_sheet([21, None, None, 21], {0x62, 0xF2}) # Smith DW (pre/post-Aga) - sheets[27].add_sprite_to_sheet([None, 42, None, None], {0x68, 0xF8}) # Dig Game (pre/post-Aga) + sheets[22].add_sprite_to_sheet([None, None, 24, None], {0x4F}) # Catfish + sheets[21].add_sprite_to_sheet([None, None, None, 21], {0x62, 0x69}) # Smith DW/VoO South + sheets[27].add_sprite_to_sheet([None, 42, None, None], {0x68}) # Dig Game sheets[13].add_sprite_to_sheet([None, None, 76, None], {0x16, 0xA6}) # Witch hut (pre/post-Aga) - sheets[29].add_sprite_to_sheet([None, 77, None, 21], {0x69, 0xF9}) # VoO South (pre/post-Aga) + #sheets[29].add_sprite_to_sheet([None, 77, None, 21], {0x69}) # VoO South sheets[15].add_sprite_to_sheet([None, None, 78, None], {0x2A, 0xBA}) # Haunted Grove (pre/post-Aga) - sheets[17].add_sprite_to_sheet([None, None, None, 76], {0x6A, 0xFA}) # Stumpy (pre/post-Aga) - sheets[12].add_sprite_to_sheet([None, None, 55, 54], {0x80, 0x110}) # Specials (pre/post-Aga) - sheets[14].add_sprite_to_sheet([None, None, 12, 68], {0x81, 0x111}) # Zora's Domain (pre/post-Aga) + sheets[17].add_sprite_to_sheet([None, None, None, 76], {0x6A}) # Stumpy + sheets[12].add_sprite_to_sheet([None, None, 55, 54], {0x80}) # Specials + sheets[14].add_sprite_to_sheet([None, None, 12, 68], {0x81}) # Zora's Domain sheets[26].add_sprite_to_sheet([15, None, None, None], {0x92}) # Lumberjacks post-Aga - sheets[23].add_sprite_to_sheet([None, None, None, 25], {0x5E, 0xEE}) # PoD pre/post-Aga + sheets[23].add_sprite_to_sheet([None, None, None, 25], {0x5E}) # PoD + sheets[19].add_sprite_to_sheet([None, 26, None, None], {0x5B}) # Pyramid post-Aga2 bat crash free_sheet_reqs = [ [None, None, None, 0x14], # bully+pink ball needs this From 2c1ecd70ff101efc86138162a0f048e508e6d945 Mon Sep 17 00:00:00 2001 From: aerinon Date: Fri, 18 Apr 2025 12:51:00 -0600 Subject: [PATCH 27/39] fix: various Enemizer fixes --- RELEASENOTES.md | 1 + source/enemizer/enemy_deny.yaml | 58 ++++++++++++++++++--------------- 2 files changed, 32 insertions(+), 27 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 02cfeef6..3fbbb257 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -5,3 +5,4 @@ * Fixes for HMG by Muffins * Various fixes for Enemizer by Codemann (gfx fixes, more randomization options) * Vanilla door shuffle prevents big key doors changes from door_type_mode + * Various enemizer bans for blocked paths (thanks to all the reports, Q1 2025) diff --git a/source/enemizer/enemy_deny.yaml b/source/enemizer/enemy_deny.yaml index 069bb668..ea92264d 100644 --- a/source/enemizer/enemy_deny.yaml +++ b/source/enemizer/enemy_deny.yaml @@ -31,8 +31,8 @@ UwGeneralDeny: - [ 0x001a, 7, [ "RollerHorizontalRight", "RollerHorizontalLeft" ]] # Too long - [ 0x001b, 3, [ "Beamos", "AntiFairyCircle", "Bumper" ] ] #"Palace of Darkness - Mimics 2 - Red Eyegore" - [ 0x001b, 4, [ "RollerVerticalUp" ] ] #"Palace of Darkness - Mimics 2 - Green Eyegore L" - - [ 0x001e, 3, [ "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft", "BigSpike", "Bumper" ] ] #"Ice Palace - Blob Ambush - Red Bari 3" - - [ 0x001e, 4, [ "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft", "BigSpike", "Bumper" ] ] #"Ice Palace - Blob Ambush - Red Bari 4" + - [ 0x001e, 3, [ "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft", "BigSpike", "Bumper", "AntiFairyCircle" ] ] #"Ice Palace - Blob Ambush - Red Bari 3" + - [ 0x001e, 4, [ "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft", "BigSpike", "Bumper", "AntiFairyCircle" ] ] #"Ice Palace - Blob Ambush - Red Bari 4" - [ 0x001e, 5, [ "SparkCW", "SparkCCW", "RollerVerticalDown", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ice Palace - Blob Ambush - Zol 1" - [ 0x001e, 6, [ "SparkCW", "SparkCCW", "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ice Palace - Blob Ambush - Zol 2" - [0x001f, 0, ["RollerHorizontalRight", "RollerHorizontalLeft"]] #"Ice Palace - Big Key View - Pengator 1" @@ -82,10 +82,10 @@ UwGeneralDeny: - [ 0x0038, 4, [ "RollerHorizontalRight" ] ] #"Swamp Palace - Long Hall - Kyameron 2" - [ 0x0039, 3, [ "RollerVerticalUp", "RollerHorizontalLeft" ] ] #"Skull Woods - Play Pen - Mini Helmasaur" - [ 0x0039, 4, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "FirebarCW", "FirebarCCW" ] ] #"Skull Woods - Play Pen - Spike Trap 1" - - [0x0039, 5, ["RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "Bumper"]] #"Skull Woods - Play Pen - Hardhat Beetle" + - [0x0039, 5, ["RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "Bumper", "AntiFairyCircle"]] #"Skull Woods - Play Pen - Hardhat Beetle" - [ 0x0039, 6, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "FirebarCW", "FirebarCCW" ] ] #"Skull Woods - Play Pen - Spike Trap 2" - [0x003a, 1, ["RollerVerticalUp"]] - - [ 0x003b, 1, [ "Bumper" ]] + - [ 0x003b, 1, [ "Bumper", "AntiFairyCircle" ]] - [ 0x003b, 4, ["RollerVerticalUp", "RollerVerticalDown"]] - [ 0x003c, 0, ["BigSpike"]] - [ 0x003c, 1, [ "SparkCW", "SparkCCW", "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Hookshot Cave - Blue Bari 1" @@ -129,8 +129,8 @@ UwGeneralDeny: - [0x004b, 0, ["Beamos", "AntiFairyCircle", "Bumper", "BigSpike"]] #"Palace of Darkness - Mimics 1 - Red Eyegore" - [ 0x004b, 1, [ "RollerHorizontalRight" ] ] #"Palace of Darkness - Warp Hint - Antifairy 1" - [ 0x004b, 5, [ "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Palace of Darkness - Jelly Hall - Blue Bari 1" - - [ 0x004b, 6, [ "AntiFairyCircle", "BigSpike" ] ] #"Palace of Darkness - Jelly Hall - Blue Bari 2" - - [ 0x004b, 7, [ "AntiFairyCircle", "BigSpike" ] ] #"Palace of Darkness - Jelly Hall - Blue Bari 3" + - [ 0x004b, 6, [ "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Palace of Darkness - Jelly Hall - Blue Bari 2" + - [ 0x004b, 7, [ "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Palace of Darkness - Jelly Hall - Blue Bari 3" - [ 0x004e, 0, [ "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Ice Palace - Blob Alley - Zol 1" - [ 0x004e, 1, [ "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Ice Palace - Blob Alley - Zol 2" - [ 0x004e, 2, [ "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Ice Palace - Blob Alley - Zol 3" @@ -138,9 +138,9 @@ UwGeneralDeny: - [ 0x0050, 1, [ "RollerVerticalUp", "RollerVerticalDown" ] ] #"Hyrule Castle - North West Passage - Green Knife Guard 1" - [ 0x0050, 2, [ "RollerVerticalUp", "RollerVerticalDown" ] ] #"Hyrule Castle - North West Passage - Green Knife Guard 2" - [0x0051, 2, ["Zoro"]] # Zoro clips off and doesn't return - - [ 0x0052, 0, [ "RollerVerticalUp", "RollerVerticalDown", "AntiFairyCircle", "Bumper" ] ] #"Hyrule Castle - North East Passage - Green Guard" - - [ 0x0052, 1, [ "RollerVerticalUp", "RollerVerticalDown", "AntiFairyCircle", "Bumper" ] ] #"Hyrule Castle - North East Passage - Green Knife Guard 1" - - [ 0x0052, 2, [ "RollerVerticalUp", "RollerVerticalDown", "AntiFairyCircle", "Bumper" ] ] #"Hyrule Castle - North East Passage - Green Knife Guard 2" + - [ 0x0052, 0, [ "RollerVerticalUp", "RollerVerticalDown", "AntiFairyCircle", "Bumper", "Zoro"]] #"Hyrule Castle - North East Passage - Green Guard" + - [ 0x0052, 1, [ "RollerVerticalUp", "RollerVerticalDown", "AntiFairyCircle", "Bumper", "Zoro"]] #"Hyrule Castle - North East Passage - Green Knife Guard 1" + - [ 0x0052, 2, [ "RollerVerticalUp", "RollerVerticalDown", "AntiFairyCircle", "Bumper", "Zoro"]] #"Hyrule Castle - North East Passage - Green Knife Guard 2" - [ 0x0053, 1, [ "AntiFairyCircle", "Bumper" ] ] #"Desert Palace - Bridge - Beamos 1" - [ 0x0053, 5, [ "RollerVerticalDown" ] ] #"Desert Palace - Popo Genocide - Popo TL" - [ 0x0053, 7, ["Beamos", "AntiFairyCircle", "Bumper", "RollerVerticalUp", "RollerVerticalDown"]] #"Desert Palace - Bridge - Popo 5" @@ -166,7 +166,7 @@ UwGeneralDeny: - [ 0x0058, 4, ["Statue"]] - [ 0x0058, 6, ["Statue"]] - [ 0x0058, 7, [ "RollerHorizontalLeft", "Statue" ] ] #"Skull Woods - Lever Room - Hardhat Beetle 2" - - [ 0x0058, 8, ["Statue"]] + - [ 0x0058, 8, ["Statue", "AntiFairyCircle", "Bumper"]] - [ 0x0059, 0, [ "RollerVerticalUp", "RollerVerticalDown", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Skull Woods - Bridge Room - Mini Moldorm 1" - [ 0x0059, 1, [ "RollerVerticalUp", "RollerVerticalDown", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Skull Woods - Bridge Room - Mini Moldorm 2" - [0x0059, 5, ["RollerVerticalUp", "RollerVerticalDown", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper"]] @@ -177,7 +177,7 @@ UwGeneralDeny: - [ 0x005f, 1, [ "RollerVerticalDown", "RollerHorizontalRight" ] ] #"Ice Palace - Bari University - Blue Bari 2" - [ 0x0060, 0, [ "RollerVerticalUp", "RollerHorizontalLeft", "AntiFairyCircle", "BigSpike", "Bumper", "Beamos", "SpikeBlock" ] ] #"Hyrule Castle - West - Blue Guard" - [ 0x0062, 0, [ "RollerVerticalUp", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Hyrule Castle - East - Blue Guard" - - [ 0x0064, 2, [ "Bumper" , "Beamos" ] ] #"Thieves' Town - Attic Hall Left - Keese 2" + - [ 0x0064, 2, [ "Bumper", "AntiFairyCircle", "Beamos" ] ] #"Thieves' Town - Attic Hall Left - Keese 2" - [ 0x0064, 3, [ "Wizzrobe", "Statue" ] ] # Wizzrobes can't spawn on pots - [ 0x0064, 4, [ "RollerHorizontalLeft", "RollerHorizontalRight" ] ] #"Thieves' Town - Attic Hall Left - Rat 1" - [ 0x0065, 0, [ "RollerVerticalUp", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Thieves' Town - Attic Window - Rat 1" @@ -186,9 +186,9 @@ UwGeneralDeny: - [ 0x0066, 0, [ "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Swamp Palace - Waterfall Room - Hover 1" - [ 0x0066, 2, [ "AntiFairyCircle", "Bumper"]] - [ 0x0067, 1, [ "RollerVerticalUp", "RollerVerticalDown", "AntiFairyCircle", "Bumper"]] #"Skull Woods - Firebar Pits - Blue Bari 1" - - [ 0x0067, 2, ["Bumper"]] #"Skull Woods - Firebar Pits - Blue Bari 2" + - [ 0x0067, 2, ["Bumper", "AntiFairyCircle"]] #"Skull Woods - Firebar Pits - Blue Bari 2" - [ 0x0067, 3, [ "RollerVerticalUp", "RollerVerticalDown" ] ] #"Skull Woods - Firebar Pits - Hardhat Beetle 1" - - [ 0x0067, 4, [ "AntiFairyCircle", "Bumper" ]] + - [0x0067, 4, [ "AntiFairyCircle", "Bumper", "RollerVerticalUp"]] - [ 0x0067, 5, ["RollerVerticalDown", "Beamos"]] #"Skull Woods - Firebar Pits - Hardhat Beetle 3" - [ 0x0067, 6, [ "RollerVerticalDown" ] ] #"Skull Woods - Firebar Pits - Hardhat Beetle 4" - [ 0x0067, 7, [ "Beamos", "AntiFairyCircle", "Bumper", "BunnyBeam" ] ] #"Skull Woods - Firebar Pits - Fire Bar (Clockwise)" @@ -209,6 +209,7 @@ UwGeneralDeny: - [ 0x0076, 3, [ "RollerVerticalUp", "RollerVerticalDown", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Swamp Palace - Toilet Left - Hover 2" - [ 0x0076, 4, [ "RollerVerticalUp", "RollerVerticalDown", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Swamp Palace - Toilet Left - Zol" - [ 0x0076, 6, [ "RollerVerticalDown", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Swamp Palace - Toilet Left - Blue Bari" + - [0x0077, 0, [ "AntiFairyCircle", "Bumper"]] - [ 0x007b, 0, [ "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ganon's Tower - DMs Room - Blue Bari 1" - [ 0x007b, 1, [ "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ganon's Tower - DMs Room - Blue Bari 2" - [ 0x007b, 6, [ "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Ganon's Tower - DMs Room - Statue" @@ -239,6 +240,7 @@ UwGeneralDeny: - [ 0x0084, 1, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Desert Palace - Main Room - Left - Leever 2" - [ 0x0085, 2, [ "RollerHorizontalRight" ] ] #"Desert Palace - Compass Room - Popo TL" - [ 0x0085, 7, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Desert Palace - Right Hallway - Leever 2" + - [0x0087, 0, ["RollerHorizontalLeft"]] # First moldorm in Tri-dorm room - [ 0x008b, 3, ["RollerHorizontalRight"]] - [ 0x008b, 4, [ "Statue", "RollerVerticalUp", "RollerVerticalDown", "Beamos", "AntiFairyCircle", "Bumper", "BigSpike"]] #"Ganon's Tower - Map Room - Spike Trap" - [ 0x008b, 6, [ "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ganon's Tower - Map Room - Fire Bar (Clockwise)" @@ -254,10 +256,10 @@ UwGeneralDeny: - [ 0x0092, 8, [ "RollerVerticalUp", "Beamos", "AntiFairyCircle", "Bumper" ] ] #"Misery Mire - Dark Weave - Spike Trap" - [ 0x0092, 9, [ "RollerHorizontalRight" ] ] #"Misery Mire - Dark Weave - Antifairy 3" - [ 0x0092, 10, [ "RollerHorizontalLeft" ] ] #"Misery Mire - Dark Weave - Stalfos" - - [ 0x0095, 0, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "SpikeBlock" ] ] #"Ganon's Tower - Conveyer Falling Bridge - Red Spear Guard 1" + - [ 0x0095, 0, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalRight", "AntiFairyCircle", "Bumper", "BigSpike", "SpikeBlock" ] ] #"Ganon's Tower - Conveyer Falling Bridge - Red Spear Guard 1" - [ 0x0095, 1, [ "Statue", "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Ganon's Tower - Conveyer Falling Bridge - Red Spear Guard 2" - [ 0x0095, 2, [ "Statue", "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Ganon's Tower - Conveyer Falling Bridge - Red Spear Guard 3" - - [ 0x0095, 3, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "AntiFairyCircle", "BigSpike", "SpikeBlock" ] ] #"Ganon's Tower - Conveyer Falling Bridge - Red Spear Guard 4" + - [ 0x0095, 3, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "AntiFairyCircle", "Bumper", "BigSpike", "SpikeBlock" ] ] #"Ganon's Tower - Conveyer Falling Bridge - Red Spear Guard 4" - [ 0x0096, 0, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Ganon's Tower - Torches 1 - Fire Bar (Clockwise)" - [ 0x0098, 0, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Misery Mire - Entrance - Zol 1" - [ 0x0098, 1, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Misery Mire - Entrance - Zol 2" @@ -278,7 +280,7 @@ UwGeneralDeny: - [ 0x009c, 4, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ganon's Tower - Invisible Floor Maze - Hardhat Beetle 4" - [ 0x009c, 5, [ "RollerVerticalUp", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ganon's Tower - Invisible Floor Maze - Hardhat Beetle 5" - [0x009c, 6, ["AntiFairyCircle", "Bumper"]] - - [0x009d, 2, ["AntiFairyCircle"]] + - [0x009d, 2, ["AntiFairyCircle", "Bumper"]] - [ 0x009d, 3, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Ganon's Tower - Compass Room - Gibdo 2" - [ 0x009d, 6, [ "RollerHorizontalLeft", "RollerHorizontalRight" ] ] #"Ganon's Tower - Compass Room - Blue Bari 1" - [ 0x009d, 7, [ "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ganon's Tower - Compass Room - Blue Bari 2" @@ -305,7 +307,7 @@ UwGeneralDeny: - [0x00b0, 8, [ "StalfosKnight", "Blob", "Stal", "Wizzrobe"]] # blocked, but Geldmen are probably okay - [ 0x00b1, 2, [ "RollerVerticalUp", "RollerVerticalDown" ] ] #"Misery Mire - Hourglass - Spike Trap 1" - [ 0x00b1, 3, [ "RollerVerticalUp", "RollerVerticalDown" ] ] #"Misery Mire - Hourglass - Spike Trap 2" - - [ 0x00b1, 4, ["Bumper", "BigSpike", "AntiFairyCircle" ]] + - [0x00b1, 4, ["Bumper", "BigSpike", "AntiFairyCircle", "Statue"]] # Wizzrobe near door - [ 0x00b2, 1, [ "Wizzrobe", "Statue" ] ] # Wizzrobes can't spawn on pots - [ 0x00b2, 3, [ "Wizzrobe", "Statue" ] ] # Wizzrobes can't spawn on pots - [ 0x00b2, 6, [ "RollerVerticalUp", "RollerHorizontalLeft" ] ] #"Misery Mire - Sluggula Cross - Sluggula TR" @@ -332,12 +334,12 @@ UwGeneralDeny: - [ 0x00bc, 7, [ "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Thieves' Town - Toilet - Stalfos 3" - [ 0x00bc, 8, [ "RollerVerticalUp", "RollerVerticalDown" ] ] #"Thieves' Town - Toilet - Stalfos 4" - [ 0x00bf, 0, [ "Wizzrobe", "Statue" ] ] # Wizzrobes can't spawn on collision - - [ 0x00c1, 3, [ "RollerVerticalUp", "RollerHorizontalLeft", "Bumper" ] ] #"Misery Mire - 4 Rails - Stalfos 1" + - [ 0x00c1, 3, [ "RollerVerticalUp", "RollerHorizontalLeft", "Bumper", "AntiFairyCircle" ] ] #"Misery Mire - 4 Rails - Stalfos 1" - [ 0x00c2, 0, [ "RollerHorizontalLeft", "RollerHorizontalRight" ] ] #"Misery Mire - Main Lobby - blue - Fire Snake 1" - [ 0x00c2, 5, [ "Wizzrobe", "Statue" ] ] # Wizzrobes can't spawn on pots - [ 0x00c5, 6, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Turtle Rock - Catwalk - Mini Helmasaur" - [ 0x00c5, 7, [ "Statue" ] ] #"Turtle Rock - Catwalk - Laser Eye (Left) 4" - - [0x00c6, 5, ["Bumper"]] + - [0x00c6, 5, ["Bumper", "AntiFairyCircle"]] - [ 0x00cb, 0, [ "Wizzrobe", "Statue" ] ] # Wizzrobes can't spawn on pots - [ 0x00cb, 3, [ "RollerVerticalUp", "RollerVerticalDown", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Thieves' Town - Grand Room NW - Zol 1" - [ 0x00cb, 5, [ "RollerVerticalUp", "RollerVerticalDown", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Thieves' Town - Grand Room NW - Zol 2" @@ -385,11 +387,11 @@ UwGeneralDeny: - [ 0x00d8, 8, [ "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Eastern Palace - Kill Room 1 - Red Eyegore" - [ 0x00d9, 1, [ "RollerHorizontalRight" ] ] #"Eastern Palace - Dodgeball - Green Eyegore 1" - [ 0x00db, 0, [ "Wizzrobe", "Statue" ] ] # Wizzrobes can't spawn on pots - - [ 0x00db, 3, [ "Bumper" ] ] # Okay in vanilla + - [ 0x00db, 3, [ "Bumper", "AntiFairyCircle" ] ] # Okay in vanilla - [ 0x00dc, 2, [ "AntiFairyCircle", "BigSpike", "Bumper" ] ] - [ 0x00dc, 9, [ "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Thieves' Town - Grand Room SE - Fire Snake 2" - [ 0x00df, 0, [ "RollerVerticalDown", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Paradox Cave - Top - Mini Moldorm 1" - - [ 0x00df, 1, [ "RollerVerticalDown", "RollerHorizontalRight", "AntiFairyCircle" ] ] #"Paradox Cave - Top - Mini Moldorm 2" + - [ 0x00df, 1, [ "RollerVerticalDown", "RollerHorizontalRight", "AntiFairyCircle", "Bumper" ] ] #"Paradox Cave - Top - Mini Moldorm 2" - [ 0x00e4, 0, [ "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Old Man Home - Keese 1" - [ 0x00e4, 1, [ "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Old Man Home - Keese 2" - [ 0x00e4, 2, [ "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Old Man Home - Keese 3" @@ -420,8 +422,8 @@ UwGeneralDeny: - [0x0107, 1, ["Beamos", "Bumper", "BigSpike", "AntiFairyCircle"]] - [0x0107, 2, ["Beamos", "Bumper", "BigSpike", "AntiFairyCircle"]] - [0x010b, 6, ["RollerHorizontalRight"]] - - [0x010c, 4, ["AntiFairyCircle"]] - - [0x010c, 5, ["AntiFairyCircle"]] + - [0x010c, 4, ["AntiFairyCircle", "Bumper"]] + - [0x010c, 5, ["AntiFairyCircle", "Bumper"]] - [0x010c, 6, ["StalfosKnight", "Geldman", "Blob", "Stal", "Wizzrobe"]] - [0x010c, 7, ["StalfosKnight", "Geldman", "Blob", "Stal", "Wizzrobe"]] - [0x011e, 0, ["RollerVerticalDown"]] @@ -450,6 +452,7 @@ OwGeneralDeny: - [0x40, 16, ["RollerVerticalUp", "RollerVerticalDown"]] # Ropa near back hole is really large as a roller - [0x55, 6, ["BigSpike"]] - [0x57, 5, ["RollerVerticalUp", "RollerVerticalDown"]] + - [0x5b, 0, ["AntiFairyCircle", "Bumper"]] # ropa on pyramid - [0x5e, 0, ["Gibo"]] # kiki eating Gibo - [0x5e, 1, ["Gibo", "RollerVerticalUp", "RollerVerticalDown"]] # kiki eating Gibo - [0x5e, 2, ["Gibo"]] # kiki eating Gibo @@ -473,9 +476,9 @@ OwGeneralDeny: - [0x5e, 20, ["Gibo"]] # kiki eating Gibo - [0x62, 1, ["RollerVerticalUp", "RollerVerticalDown"]] # hard to avoid roller around hammer pegs - [0x62, 3, ["RollerVerticalUp", "RollerVerticalDown"]] # hard to avoid roller around hammer pegs - - [0x6d, 3, ["Bumper"]] # can block path with multiple bumpers - - [0x77, 1, ["Bumper"]] # soft-lock potential near ladder - - [0x7f, 1, ["Bumper"]] # soft-lock potential near ladder + - [0x6d, 3, ["Bumper", "AntiFairyCircle"]] # can block path with multiple bumpers + - [0x77, 1, ["Bumper", "AntiFairyCircle"]] # soft-lock potential near ladder + - [0x7f, 1, ["Bumper", "AntiFairyCircle"]] # soft-lock potential near ladder UwEnemyDrop: - [0x0085, 9, ["Babasu"]] # ran off the edge and didn't return - [0x00cb, 3, ["Zoro"]] # layer issues @@ -576,7 +579,7 @@ UwEnemyDrop: "BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]] - [0x00c6, 5, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard", "Hover", "BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard", - "BombGuard", "GreenKnifeGuard", "Bumper", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]] + "BombGuard", "GreenKnifeGuard", "Bumper", "AntiFairyCircle", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]] - [0x00c6, 6, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard", "Hover", "BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard", "BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]] @@ -621,6 +624,7 @@ UwEnemyDrop: - [0x0067, 6, ["Wizzrobe"]] - [0x0067, 7, ["Wizzrobe", "Stal"]] - [0x0067, 8, ["Wizzrobe", "Stal"]] + - [0x006b, 4, ["Wizzrobe"]] # crystal switch interaction? - [0x0074, 5, ["Wizzrobe"]] - [0x007c, 1, ["Wizzrobe", "Stal"]] - [0x007c, 3, ["Wizzrobe", "Stal"]] From f3b774ad7f67411fe6781da9c184f39119651433 Mon Sep 17 00:00:00 2001 From: aerinon Date: Mon, 28 Apr 2025 12:34:19 -0600 Subject: [PATCH 28/39] fix: attempt at fixing moth conveyor room timing --- RELEASENOTES.md | 1 + Rom.py | 2 +- data/base2current.bps | Bin 117954 -> 117959 bytes source/enemizer/Bossmizer.py | 4 ++-- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 3fbbb257..fc754596 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,6 +1,7 @@ # Patch Notes * 1.4.9 + * Attempted fix for Moth conveyor room timing. THank for many people's input. Unsure if Helmacopter is still acceptable. * Mirror scroll will show up on file start screen if enabled (thanks Clearmouse!) * Fixes for HMG by Muffins * Various fixes for Enemizer by Codemann (gfx fixes, more randomization options) diff --git a/Rom.py b/Rom.py index 04b08fb2..0961df7c 100644 --- a/Rom.py +++ b/Rom.py @@ -42,7 +42,7 @@ from source.enemizer.Enemizer import write_enemy_shuffle_settings JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '403d349584246fd845c3a9c78a55b3d4' +RANDOMIZERBASEHASH = '54eaa40cc69c54b9d790b9c4ea107f4d' class JsonRom(object): diff --git a/data/base2current.bps b/data/base2current.bps index 0292d6f7bd5188d22f912d6816b65e3388782b64..d0cdd7d679a902d0d1b30607297ef54cbdf0ebed 100644 GIT binary patch delta 1291 zcmWNNYfO`87>1t*YALqVic~7dp$Nh_h?Q9nsKA(rb0```L;_53tH-MI00GAP0Ts&p z5cpPK0in?{h*pBJLC`9Na{NFC`fKxtbD43D7{L&xZfMtk_jTv`ap$(zyA9X7-Ewgi zocfOyScI+u1OxEC$pa$-A$bFpTRLi4r+VahE(|ojX^Hfnd%EhQY$4-kz6}t(aa4p(Y zd}^81nq4r$a`jY@00%7tXRo_pQrYo>uHyxGAQ5Njj+u`tYq z7~)_9gn?c57bja>-sZLWZO4{4AXFlzslDipAym_g2R(|?M(Zj&s`T&)+KTDZUR>dp z>>(jWaWP%chXtsn`aV=)F17aI<#3x|bKH#C9@t~mG+%?f|S#ydCI zs|`RP0alt8(qcR6Fq69W<8~~hyZUjN=k_li+WnLDb@PhOGiy!TNTZxq^y5Ld`O%9= zA~{B9`f;r+-p7j=3r=0u%c9;Lit=1|@RaL)KGoR3e!~e8i z;PR-?Ao}@dYtx8<0XsYd`-Qq=1%}!LC;fb5S%|wS_8_S7F3(E>C`aB zxUUEs*DGLyC4okaU^#}xzZ+t!rzQexYlDJAyAc{e%t3>wMfCM=>ycvSinpAZw8 z?}V(?3GMbE!l`I0kJ*dT_T6J8;1Bj11GvEtz?$|_#VCG-c{FzvqnG&# zy@@^>9Ij0I?#09&8eUbm?iA0=aN#z#AIiY!5lTBpv1rGxC{JRqw))<^C~Lb>!|mC> zm>3o6A=Vpw!M69X)tD0~Ax$&z0e*#7V9Rw9^*SmhmqJ!q4IiNp-o3xHUhzkxtFvnq zC@2|2xp09x#c9#TF^s?%Iy{DJwqzaYW=c3MF&AEGy=-#d7fskt-~hT?U4Q#0P9l?& zi@{d9wVat73;D9DOTDp52Vh&GkrEnwP)eGW-<36FO?%VL5AlpB#@5xWvRQ-w2RxPx AH2?qr delta 1290 zcmWNPdrXsO7{#BbR4!7Wa%%;-qacb>QA8Ahp#hv2G>QV7#0!ET)C(#I!uxU2mRUr; zl~+LMMjcKncCk?ywOoo^3OdlmWLp+=(M&W(Fbu^_{nr1^?<6OAa-K6(Z)L2v`iW=3 zkLG$nXKBF~_qJWXNKW{l$#t>^p{!HiS>5G`6 zTjLdGX>&$)=T!~n__A#N;=A~al`L6_FLnEtsOMuRJ5Lgf{cNaYHQv-^N!D+~QTD1d z34hhiN;N$6*L{E7myg}Ld#A4RFseMSup_S!_s8NJ`tU9uTkt2ChBf?hWeS>>j=QQ@ z15GiY_jctTG~F2YP+d@JkqMg?wCwx3y6Me~pzJM}EcL%D{LwU_p$a*eu4?8KmS|d} z47=kA9BPU)(o( z#>;Ex6`y0m)nAfED|(?HGpveNIFVSAPUreDT)4{3nW%D(-5#v&h{(RJ4yDoe@Sgjb z%$LnJF5j>LQXf)P)o-6QpU{}>cdZxLWa>459=M%G4xq>~ydar0?xU##=!aWr$p8l7 zQhI#=4=+#6=#m3OHRfEY%P-Pa3Iuhfxwo6wxohjP9T-W~DWv69hUiA792789b zxsblu*`w2Qb5}k-TJagd+~zC2SNR`>)#~l^pCJsj@eUl5i(!KTiUsK*Fy!DN~>f-C*(EJZ|~ z4x9zEWv44K1_V{rt~+jGX4s$}ML(2-s&onM8o}c1O~H=DSgm*e`J(VzTMZkR=1NrJ zut9|g+@WW8wqCWv+q~-;_yE7bB=qbu6SX{IOX?P{(knkf5xk$PixB_ScrwS9G@cTf z51xQ}uwo-fv(v$=7yZxG%G4N^Xb#cuMsXP~ruRp2ZCp}LCsWEwiKggE>t%J(o|Q!L z+5BX>GpzpBw`_@n3%Tg8rwJ9z$5GLys*b?Os!D(!+bnxRT{G-SvrlGu!`|soy5&Be Pv|j!E)~3fT`40aB&|e%t diff --git a/source/enemizer/Bossmizer.py b/source/enemizer/Bossmizer.py index 85b8a3c2..6c262e38 100644 --- a/source/enemizer/Bossmizer.py +++ b/source/enemizer/Bossmizer.py @@ -110,8 +110,8 @@ def add_kholdstare_to_list(sprite_list, room_id): def add_vitreous_to_list(sprite_list, room_id): - sprite_list.clear() # vitreous does not play nice which other sprites on the tile, just kill them - sprite_list.append(create_sprite(room_id, EnemySprite.Vitreous, 0x00, 0, 0x07, 0x05)) + sprite_list[:] = [x for x in sprite_list if x.sub_type == SpriteType.Overlord] # vitreous does not play nice which other sprites on the tile, just kill them + sprite_list.insert(0, create_sprite(room_id, EnemySprite.Vitreous, 0x00, 0, 0x07, 0x05)) def add_trinexx_to_list(sprite_list, room_id): From 4657aaf0b68e92a464bbc916083b2f188d957d06 Mon Sep 17 00:00:00 2001 From: aerinon Date: Mon, 28 Apr 2025 14:16:31 -0600 Subject: [PATCH 29/39] fix: some customizer generation issues --- DoorShuffle.py | 5 ++++- DungeonGenerator.py | 9 +++++---- RELEASENOTES.md | 1 + 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/DoorShuffle.py b/DoorShuffle.py index 0369ff5c..e2e25390 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -1062,8 +1062,11 @@ def handle_split_dungeons(dungeon_builders, recombinant_builders, entrances_map, for name, split_list in split_dungeon_entrances.items(): builder = dungeon_builders.pop(name) - recombinant_builders[name] = builder + if all(len(sector.outstanding_doors) <= 0 for sector in builder.sectors): + dungeon_builders[name] = builder + continue + recombinant_builders[name] = builder split_builders = split_dungeon_builder(builder, split_list, builder_info) dungeon_builders.update(split_builders) for sub_name, split_entrances in split_list.items(): diff --git a/DungeonGenerator.py b/DungeonGenerator.py index 2cae4254..58b86adf 100644 --- a/DungeonGenerator.py +++ b/DungeonGenerator.py @@ -1342,10 +1342,6 @@ def create_dungeon_builders(all_sectors, connections_tuple, world, player, dunge if not sector: sector = find_sector(r_name, all_sectors) reverse_d_map[sector] = key - if world.mode[player] == 'standard': - if 'Hyrule Castle' in dungeon_map: - current_dungeon = dungeon_map['Hyrule Castle'] - standard_stair_check(dungeon_map, current_dungeon, candidate_sectors, global_pole) complete_dungeons = {x: y for x, y in dungeon_map.items() if sum(len(sector.outstanding_doors) for sector in y.sectors) <= 0} [dungeon_map.pop(key) for key in complete_dungeons.keys()] @@ -1354,6 +1350,11 @@ def create_dungeon_builders(all_sectors, connections_tuple, world, player, dunge dungeon_map.update(complete_dungeons) return dungeon_map + if world.mode[player] == 'standard': + if 'Hyrule Castle' in dungeon_map: + current_dungeon = dungeon_map['Hyrule Castle'] + standard_stair_check(dungeon_map, current_dungeon, candidate_sectors, global_pole) + # categorize sectors identify_destination_sectors(accessible_sectors, reverse_d_map, dungeon_map, connections, dungeon_entrances, split_dungeon_entrances) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index fc754596..a0e3ee1c 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -6,4 +6,5 @@ * Fixes for HMG by Muffins * Various fixes for Enemizer by Codemann (gfx fixes, more randomization options) * Vanilla door shuffle prevents big key doors changes from door_type_mode + * Couple of minor fixes to custom generation. Deals with a complete specification of all dungeons * Various enemizer bans for blocked paths (thanks to all the reports, Q1 2025) From fcaaab30a4a3c7569920ab9ea6a334224ab49186 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Wed, 30 Apr 2025 06:41:43 -0500 Subject: [PATCH 30/39] Initial Follower Shuffle Implementation --- BaseClasses.py | 25 +++-- CLI.py | 3 +- Doors.py | 2 +- DungeonGenerator.py | 6 +- InitialSram.py | 23 +++- ItemList.py | 104 +++++++++++++++--- Items.py | 3 + Main.py | 14 ++- OWEdges.py | 2 + OverworldShuffle.py | 1 + README.md | 27 +++++ Regions.py | 16 ++- Rom.py | 47 ++++++-- Rules.py | 8 +- data/base2current.bps | Bin 133998 -> 136345 bytes docs/Customizer.md | 10 ++ docs/customizer_example.yaml | 1 + resources/app/cli/args.json | 4 + resources/app/cli/lang/en.json | 3 + resources/app/gui/lang/en.json | 5 +- resources/app/gui/randomize/item/widgets.json | 4 + source/classes/CustomSettings.py | 2 + source/classes/constants.py | 1 + source/dungeon/DungeonStitcher.py | 3 +- source/dungeon/RoomHeader.py | 1 + source/enemizer/Bossmizer.py | 5 +- source/enemizer/Enemizer.py | 17 ++- source/enemizer/SpriteSheets.py | 28 +++++ source/tools/MysteryUtils.py | 1 + 29 files changed, 316 insertions(+), 50 deletions(-) diff --git a/BaseClasses.py b/BaseClasses.py index 4691ef4b..a82f3093 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -1662,18 +1662,21 @@ class Entrance(object): self.temp_path = [] def can_reach(self, state): - # Destination Pickup OW Only No Ledges Can S&Q Allow Mirror - multi_step_locations = { 'Pyramid Crack': ('Big Bomb', True, True, False, True), - 'Missing Smith': ('Frog', True, False, True, True), - 'Middle Aged Man': ('Dark Blacksmith Ruins', True, False, True, True), - 'Old Man Drop Off': ('Lost Old Man', True, False, False, False), - 'Revealing Light': ('Suspicious Maiden', False, False, False, False) + # Destination Pickup OW Only No Ledges Can S&Q Allow Mirror + multi_step_locations = { 'Pyramid Crack': ('Big Bomb', True, True, False, True), + 'Missing Smith': ('Frog', True, False, True, True), + 'Middle Aged Man': ('Dark Blacksmith Ruins', True, False, True, True), + 'Dark Palace Button':('Kiki', True, False, False, False), + 'Old Man Drop Off': ('Lost Old Man', True, False, False, False), + 'Revealing Light': ('Suspicious Maiden', False, False, False, False) } if self.name in multi_step_locations: if self not in state.path: world = self.parent_region.world multi_step_loc = multi_step_locations[self.name] + if world.shuffle_followers[self.player]: + multi_step_loc = (multi_step_loc[0], self.name == 'Pyramid Crack', multi_step_loc[2], True, True) step_location = world.get_location(multi_step_loc[0], self.player) if step_location.can_reach(state) and self.can_reach_thru(state, step_location, multi_step_loc[1], multi_step_loc[2], multi_step_loc[3], multi_step_loc[4]) and self.access_rule(state): if not self in state.path: @@ -2952,7 +2955,7 @@ class Spoiler(object): self.settings = {} - self.suppress_spoiler_locations = ['Big Bomb', 'Frog', 'Dark Blacksmith Ruins', 'Middle Aged Man', 'Lost Old Man', 'Old Man Drop Off'] + self.suppress_spoiler_locations = ['Lost Old Man', 'Big Bomb', 'Frog', 'Dark Blacksmith Ruins', 'Middle Aged Man', 'Kiki'] def set_overworld(self, entrance, exit, direction, player): if self.world.players == 1: @@ -3018,6 +3021,7 @@ class Spoiler(object): 'ow_whirlpool': self.world.owWhirlpoolShuffle, 'ow_fluteshuffle': self.world.owFluteShuffle, 'bonk_drops': self.world.shuffle_bonk_drops, + 'shuffle_followers': self.world.shuffle_followers, 'shuffle': self.world.shuffle, 'shuffleganon': self.world.shuffle_ganon, 'shufflelinks': self.world.shufflelinks, @@ -3259,6 +3263,7 @@ class Spoiler(object): outfile.write('\n') outfile.write('Shopsanity:'.ljust(line_width) + '%s\n' % yn(self.metadata['shopsanity'][player])) outfile.write('Bonk Drops:'.ljust(line_width) + '%s\n' % yn(self.metadata['bonk_drops'][player])) + outfile.write('Followers:'.ljust(line_width) + '%s\n' % yn(self.metadata['shuffle_followers'][player])) outfile.write('Pottery Mode:'.ljust(line_width) + '%s\n' % self.metadata['pottery'][player]) outfile.write('Pot Shuffle (Legacy):'.ljust(line_width) + '%s\n' % yn(self.metadata['potshuffle'][player])) outfile.write('Enemy Drop Shuffle:'.ljust(line_width) + '%s\n' % self.metadata['dropshuffle'][player]) @@ -3670,7 +3675,7 @@ boss_mode = {"none": 0, "simple": 1, "full": 2, "chaos": 3, 'random': 3, 'unique or_mode = {"vanilla": 0, "parallel": 1, "full": 2} orcrossed_mode = {"none": 0, "polar": 1, "grouped": 2, "unrestricted": 4} -# byte 12: KMB? FF?? (keep similar, mixed/tile flip, bonk drops, flute spots) +# byte 12: KMBQ FF?? (keep similar, mixed/tile flip, bonk drops, follower quests, flute spots) flutespot_mode = {"vanilla": 0, "balanced": 1, "random": 2} # byte 13: FBBB TTPP (flute_mode, bow_mode, take_any, prize shuffle) @@ -3737,7 +3742,8 @@ class Settings(object): | (0x08 if w.owWhirlpoolShuffle[p] else 0) | orcrossed_mode[w.owCrossed[p]], (0x80 if w.owKeepSimilar[p] else 0) | (0x40 if w.owMixed[p] else 0) - | (0x20 if w.shuffle_bonk_drops[p] else 0) | (flutespot_mode[w.owFluteShuffle[p]] << 4), + | (0x20 if w.shuffle_bonk_drops[p] else 0) | (0x10 if w.shuffle_followers[p] else 0) + | (flutespot_mode[w.owFluteShuffle[p]] << 4), (flute_mode[w.flute_mode[p]] << 7 | bow_mode[w.bow_mode[p]] << 4 | take_any_mode[w.take_any[p]] << 2 | prizeshuffle_mode[w.prizeshuffle[p]]), @@ -3822,6 +3828,7 @@ class Settings(object): args.ow_keepsimilar[p] = True if settings[12] & 0x80 else False args.ow_mixed[p] = True if settings[12] & 0x40 else False args.bonk_drops[p] = True if settings[12] & 0x20 else False + args.shuffle_followers[p] = True if settings[12] & 0x10 else False args.ow_fluteshuffle[p] = r(flutespot_mode)[(settings[12] & 0x0C) >> 2] if len(settings) > 13: diff --git a/CLI.py b/CLI.py index 8fc7263e..c6ae7d9f 100644 --- a/CLI.py +++ b/CLI.py @@ -132,7 +132,7 @@ def parse_cli(argv, no_defaults=False): for name in ['logic', 'mode', 'swords', 'goal', 'difficulty', 'item_functionality', 'ow_shuffle', 'ow_terrain', 'ow_crossed', 'ow_keepsimilar', 'ow_mixed', 'ow_whirlpool', 'ow_fluteshuffle', - 'flute_mode', 'bow_mode', 'take_any', 'boots_hint', + 'flute_mode', 'bow_mode', 'take_any', 'boots_hint', 'shuffle_followers', 'shuffle', 'door_shuffle', 'intensity', 'crystals_ganon', 'crystals_gt', 'openpyramid', 'mapshuffle', 'compassshuffle', 'keyshuffle', 'bigkeyshuffle', 'prizeshuffle', 'startinventory', 'usestartinventory', 'bombbag', 'shuffleganon', 'overworld_map', 'restrict_boss_items', @@ -200,6 +200,7 @@ def parse_settings(): "ow_mixed": False, "ow_whirlpool": False, "ow_fluteshuffle": "vanilla", + "shuffle_followers": False, "bonk_drops": False, "shuffle": "vanilla", "shufflelinks": False, diff --git a/Doors.py b/Doors.py index af83f6fc..aa55cf0c 100644 --- a/Doors.py +++ b/Doors.py @@ -1301,7 +1301,7 @@ def create_doors(world, player): world.get_door('Swamp Drain Right Switch', player).event('Swamp Drain') world.get_door('Swamp Flooded Room Ladder', player).event('Swamp Drain') - if world.mode[player] == 'standard': + if world.mode[player] == 'standard' and 'Zelda Herself' not in [i.name for i in world.precollected_items if i.player == player]: world.get_door('Hyrule Castle Throne Room Tapestry', player).event('Zelda Pickup') world.get_door('Hyrule Castle Tapestry Backwards', player).event('Zelda Pickup') diff --git a/DungeonGenerator.py b/DungeonGenerator.py index f8297aff..d5c65621 100644 --- a/DungeonGenerator.py +++ b/DungeonGenerator.py @@ -602,7 +602,8 @@ def determine_paths_for_dungeon(world, player, all_regions, name): paths.append(boss) if 'Thieves Boss' in all_r_names: paths.append('Thieves Boss') - if world.get_dungeon("Thieves Town", player).boss.enemizer_name == 'Blind': + if world.get_dungeon("Thieves Town", player).boss.enemizer_name == 'Blind' \ + and not world.shuffle_followers[player]: paths.append(('Thieves Blind\'s Cell', 'Thieves Boss')) for drop_check in drop_path_checks: if drop_check in all_r_names: @@ -1324,7 +1325,8 @@ def create_dungeon_builders(all_sectors, connections_tuple, world, player, dunge for r_name in ['Hyrule Dungeon Cellblock', 'Sanctuary', 'Hyrule Castle Throne Room']: # need to deliver zelda assign_sector(find_sector(r_name, candidate_sectors), current_dungeon, candidate_sectors, global_pole) - if key == 'Thieves Town' and world.get_dungeon("Thieves Town", player).boss.enemizer_name == 'Blind': + if key == 'Thieves Town' and (world.get_dungeon("Thieves Town", player).boss.enemizer_name == 'Blind' + and not world.shuffle_followers[player]): assign_sector(find_sector("Thieves Blind's Cell", candidate_sectors), current_dungeon, candidate_sectors, global_pole) entrances_map, potentials, connections = connections_tuple diff --git a/InitialSram.py b/InitialSram.py index 0aa25bc2..f360236a 100644 --- a/InitialSram.py +++ b/InitialSram.py @@ -128,6 +128,25 @@ class InitialSram: else: self.set_progress_indicator(0x03) + if startingstate.has('Zelda Herself', player): + self._initial_sram_bytes[0x3CC] = 0x01 + elif startingstate.has('Escort Old Man', player): + self._initial_sram_bytes[0x3CC] = 0x04 + elif startingstate.has('Maiden Rescued', player): + self._initial_sram_bytes[0x3CC] = 0x06 + elif startingstate.has('Get Frog', player): + self._initial_sram_bytes[0x3CC] = 0x07 + elif startingstate.has('Sign Vandalized', player): + self._initial_sram_bytes[0x3CC] = 0x09 + elif startingstate.has('Pick Up Kiki', player): + self._initial_sram_bytes[0x3CC] = 0x0A + elif startingstate.has('Pick Up Purple Chest', player): + self._initial_sram_bytes[0x3CC] = 0x0C + elif startingstate.has('Pick Up Big Bomb', player): + self._initial_sram_bytes[0x3CC] = 0x0D + if self._initial_sram_bytes[0x3CC] > 0x01 and world.mode[player] == 'standard': + self._initial_sram_bytes[0x3D3] = 0x80 + for item in world.precollected_items: if item.player != player: continue @@ -138,7 +157,9 @@ class InitialSram: 'Mirror Shield', 'Red Shield', 'Blue Shield', 'Progressive Shield', 'Red Mail', 'Blue Mail', 'Progressive Armor', 'Magic Upgrade (1/4)', 'Magic Upgrade (1/2)', - 'Return Old Man', 'Beat Agahnim 1']: + 'Return Old Man', 'Beat Agahnim 1', 'Zelda Herself', 'Escort Old Man', + 'Maiden Rescued', 'Get Frog', 'Sign Vandalized', 'Pick Up Kiki', + 'Pick Up Purple Chest', 'Pick Up Big Bomb']: continue set_table = {'Book of Mudora': (0x34E, 1), 'Hammer': (0x34B, 1), 'Bug Catching Net': (0x34D, 1), 'Hookshot': (0x342, 1), 'Magic Mirror': (0x353, 2), diff --git a/ItemList.py b/ItemList.py index 45c1df2d..e690d83a 100644 --- a/ItemList.py +++ b/ItemList.py @@ -129,6 +129,40 @@ difficulties = { ), } + +follower_quests = { + 'Zelda Pickup': ['Zelda Herself', 'Zelda Drop Off', 'Zelda Delivered'], + 'Lost Old Man': ['Escort Old Man', 'Old Man Drop Off', 'Return Old Man'], + 'Locksmith': ['Sign Vandalized', None, None], + 'Kiki': ['Pick Up Kiki', 'Kiki Assistance', 'Dark Palace Opened'], + 'Suspicious Maiden': ['Maiden Rescued', 'Revealing Light', 'Maiden Unmasked'], + 'Frog': ['Get Frog', 'Missing Smith', 'Return Smith'], + 'Dark Blacksmith Ruins': ['Pick Up Purple Chest', 'Middle Aged Man', 'Deliver Purple Chest'], + 'Big Bomb': ['Pick Up Big Bomb', 'Pyramid Crack', 'Detonate Big Bomb'], +} + +follower_locations = { + 'Zelda Pickup': 0x1802C0, + 'Lost Old Man': 0x1802C3, + 'Suspicious Maiden': 0x1802C6, + 'Frog': 0x1802C9, + 'Locksmith': 0x1802CC, + 'Kiki': 0x1802CF, + 'Dark Blacksmith Ruins': 0x1802D2, + 'Big Bomb': 0x1802D5, +} + +follower_pickups = { + 'Zelda Herself': 0x01, + 'Escort Old Man': 0x04, + 'Maiden Rescued': 0x06, + 'Get Frog': 0x07, + 'Sign Vandalized': 0x09, + 'Pick Up Kiki': 0x0A, + 'Pick Up Purple Chest': 0x0C, + 'Pick Up Big Bomb': 0x0D, +} + # Translate between Mike's label array and YAML/JSON keys def get_custom_array_key(item): label_switcher = { @@ -194,17 +228,10 @@ def generate_itempool(world, player): if world.timer in ['ohko', 'timed-ohko']: world.can_take_damage = False - def set_event_item(location_name, item_name=None): - location = world.get_location(location_name, player) - if item_name: - world.push_item(location, ItemFactory(item_name, player), False) - location.event = True - location.locked = True - if world.goal[player] in ['pedestal', 'triforcehunt']: - set_event_item('Ganon', 'Nothing') + set_event_item(world, player, 'Ganon', 'Nothing') else: - set_event_item('Ganon', 'Triforce') + set_event_item(world, player, 'Ganon', 'Triforce') if world.goal[player] in ['triforcehunt', 'trinity']: region = world.get_region('Hyrule Castle Courtyard', player) @@ -241,12 +268,17 @@ def generate_itempool(world, player): old_man.skip = True for loc, item in location_events.items(): - if item: - set_event_item(loc, item) - + if loc in follower_quests and world.shuffle_followers[player]: + item = None + set_event_item(world, player, loc, item) + + zelda_pickup, zelda_dropoff = None, None if world.mode[player] == 'standard': - set_event_item('Zelda Pickup', 'Zelda Herself') - set_event_item('Zelda Drop Off', 'Zelda Delivered') + if not world.shuffle_followers[player]: + zelda_pickup = 'Zelda Herself' + zelda_dropoff = 'Zelda Delivered' + set_event_item(world, player, 'Zelda Pickup', zelda_pickup) + set_event_item(world, player, 'Zelda Drop Off', zelda_dropoff) # set up item pool skip_pool_adjustments = False @@ -1642,6 +1674,50 @@ def fill_specific_items(world): world.item_pool_config.verify_target += len(placement['locations']) +def set_event_item(world, player, location_name, item_name=None): + location = world.get_location(location_name, player) + if item_name: + world.push_item(location, ItemFactory(item_name, player), False) + location.event = True + if location_name not in follower_quests or not world.shuffle_followers[player]: + location.locked = True + + +def shuffle_event_items(world, player): + if (world.shuffle_followers[player]): + available_quests = follower_quests.copy() + available_pickups = [quests[0] for quests in available_quests.values()] + + for loc_name in follower_quests.keys(): + loc = world.get_location(loc_name, player) + if loc.item: + set_event_item(world, player, loc_name) + available_quests.pop(loc_name) + available_pickups.remove(loc.item.name) + + + if world.mode[player] == 'standard': + if 'Zelda Herself' in available_pickups: + zelda_pickup = available_quests.pop('Zelda Pickup')[0] + available_pickups.remove(zelda_pickup) + set_event_item(world, player, 'Zelda Pickup', zelda_pickup) + + random.shuffle(available_pickups) + + restricted_pickups = { 'Get Frog': 'Dark Blacksmith Ruins'} + for pickup in restricted_pickups: + restricted_quests = [q for q in available_quests.keys() if q not in restricted_pickups[pickup]] + random.shuffle(restricted_quests) + quest = restricted_quests.pop() + available_quests.pop(quest) + available_pickups.remove(pickup) + set_event_item(world, player, quest, pickup) + + for pickup in available_pickups: + quest, _ = available_quests.popitem() + set_event_item(world, player, quest, pickup) + + def get_item_and_event_flag(item, world, player, dungeon_pool, prize_set, prize_pool): item_parts = item.split('#') item_player = player if len(item_parts) < 2 else int(item_parts[1]) diff --git a/Items.py b/Items.py index 5b24b17a..ec6a18b8 100644 --- a/Items.py +++ b/Items.py @@ -180,6 +180,8 @@ item_table = {'Bow': (True, False, None, 0x0B, 200, 'Bow!\nJoin the archer class 'Beat Boss': (True, False, 'Event', 999, None, None, None, None, None, None, None, None), 'Beat Agahnim 1': (True, False, 'Event', 999, None, None, None, None, None, None, None, None), 'Beat Agahnim 2': (True, False, 'Event', 999, None, None, None, None, None, None, None, None), + 'Pick Up Kiki': (True, False, 'Event', 999, None, None, None, None, None, None, None, None), + 'Dark Palace Opened': (True, False, 'Event', 999, None, None, None, None, None, None, None, None), 'Get Frog': (True, False, 'Event', 999, None, None, None, None, None, None, None, None), 'Return Smith': (True, False, 'Event', 999, None, None, None, None, None, None, None, None), 'Pick Up Purple Chest': (True, False, 'Event', 999, None, None, None, None, None, None, None, None), @@ -198,6 +200,7 @@ item_table = {'Bow': (True, False, None, 0x0B, 200, 'Bow!\nJoin the archer class 'Hidden Pits': (True, False, 'Event', 999, None, None, None, None, None, None, None, None), 'Zelda Herself': (True, False, 'Event', 999, None, None, None, None, None, None, None, None), 'Zelda Delivered': (True, False, 'Event', 999, None, None, None, None, None, None, None, None), + 'Sign Vandalized': (True, False, 'Event', 999, None, None, None, None, None, None, None, None), 'Escort Old Man': (True, False, 'Event', 999, None, None, None, None, None, None, None, None), 'Return Old Man': (True, False, 'Event', 999, None, None, None, None, None, None, None, None), 'Farmable Bombs': (True, False, 'Event', 999, None, None, None, None, None, None, None, None), diff --git a/Main.py b/Main.py index f668e853..6029ee30 100644 --- a/Main.py +++ b/Main.py @@ -27,7 +27,7 @@ from Dungeons import create_dungeons from Fill import distribute_items_restrictive, promote_dungeon_items, fill_dungeons_restrictive, ensure_good_items from Fill import dungeon_tracking from Fill import sell_potions, sell_keys, balance_multiworld_progression, balance_money_progression, lock_shop_locations, set_prize_drops -from ItemList import generate_itempool, difficulties, fill_prizes, customize_shops, fill_specific_items, create_farm_locations +from ItemList import generate_itempool, difficulties, fill_prizes, customize_shops, fill_specific_items, create_farm_locations, shuffle_event_items, follower_pickups from UnderworldGlitchRules import connect_hmg_entrances_regions, create_hmg_entrances_regions from Utils import output_path, parse_player_names @@ -35,6 +35,7 @@ from source.item.District import init_districts from source.item.FillUtil import create_item_pool_config, massage_item_pool, district_item_pool_config, verify_item_pool_config from source.overworld.EntranceShuffle2 import link_entrances_new from source.tools.BPS import create_bps_from_data +from source.tools.GraphExporter import GephiStreamer from source.classes.CustomSettings import CustomSettings from source.enemizer.DamageTables import DamageTable from source.enemizer.Enemizer import randomize_enemies @@ -244,6 +245,7 @@ def main(args, seed=None, fish=None): sell_keys(world, player) else: lock_shop_locations(world, player) + shuffle_event_items(world, player) massage_item_pool(world) logger.info(world.fish.translate("cli", "cli", "placing.dungeon.prizes")) @@ -476,6 +478,7 @@ def init_world(args, fish): world.owKeepSimilar = args.ow_keepsimilar.copy() world.owWhirlpoolShuffle = args.ow_whirlpool.copy() world.owFluteShuffle = args.ow_fluteshuffle.copy() + world.shuffle_followers = args.shuffle_followers.copy() world.shuffle_bonk_drops = args.bonk_drops.copy() world.open_pyramid = args.openpyramid.copy() world.boss_shuffle = args.shufflebosses.copy() @@ -530,6 +533,7 @@ def set_starting_inventory(world, args): if world.customizer and world.customizer.get_start_inventory(): for p, inv_list in world.customizer.get_start_inventory().items(): if inv_list: + follower_added = False for inv_item in inv_list: name = inv_item.strip() if inv_item == 'RandomWeapon': @@ -543,7 +547,13 @@ def set_starting_inventory(world, args): item = ItemFactory(e, p) if item: world.push_precollected(item) + elif inv_item == 'RandomFollower': + name = random.choice([f for f in follower_pickups if f != 'Zelda Herself' or world.mode[p] == 'standard']) name = name if name != 'Ocarina' or world.flute_mode[p] != 'active' else 'Ocarina (Activated)' + if name in follower_pickups: + if not world.shuffle_followers[p] or follower_added: + continue + follower_added = True item = ItemFactory(name, p) if item: world.push_precollected(item) @@ -591,6 +601,7 @@ def copy_world(world): ret.owKeepSimilar = world.owKeepSimilar.copy() ret.owWhirlpoolShuffle = world.owWhirlpoolShuffle.copy() ret.owFluteShuffle = world.owFluteShuffle.copy() + ret.shuffle_followers = world.shuffle_followers.copy() ret.shuffle_bonk_drops = world.shuffle_bonk_drops.copy() ret.open_pyramid = world.open_pyramid.copy() ret.shufflelinks = world.shufflelinks.copy() @@ -811,6 +822,7 @@ def copy_world_premature(world, player): ret.owKeepSimilar = world.owKeepSimilar.copy() ret.owWhirlpoolShuffle = world.owWhirlpoolShuffle.copy() ret.owFluteShuffle = world.owFluteShuffle.copy() + ret.shuffle_followers = world.shuffle_followers.copy() ret.shuffle_bonk_drops = world.shuffle_bonk_drops.copy() ret.open_pyramid = world.open_pyramid.copy() ret.shufflelinks = world.shufflelinks.copy() diff --git a/OWEdges.py b/OWEdges.py index ef9c9182..645e05ad 100644 --- a/OWEdges.py +++ b/OWEdges.py @@ -1241,6 +1241,7 @@ OWTileRegions = bidict({ 'Broken Bridge Water': 0x5d, 'Palace of Darkness Area': 0x5e, + 'Dark Palace Button': 0x5e, 'Hammer Pegs Area': 0x62, 'Hammer Pegs Entry': 0x62, @@ -1580,6 +1581,7 @@ OWExitTypes = { 'Middle Aged Man', 'Desert Pass Ladder (South)', 'Desert Pass Ladder (North)', + 'Kiki Assistance', 'GT Approach', 'GT Leave', ], diff --git a/OverworldShuffle.py b/OverworldShuffle.py index 6934829e..6118b731 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -1833,6 +1833,7 @@ mandatory_connections = [ ('Broken Bridge Water Drop', 'Broken Bridge Water'), #flippers ('Broken Bridge Northeast Water Drop', 'Broken Bridge Water'), #flippers ('Broken Bridge West Water Drop', 'Broken Bridge Water'), #flippers + ('Kiki Assistance', 'Dark Palace Button'), ('Peg Area Rocks (West)', 'Hammer Pegs Area'), #mitts ('Peg Area Rocks (East)', 'Hammer Pegs Entry'), #mitts ('Dig Game To Ledge Drop', 'Dig Game Ledge'), #mitts diff --git a/README.md b/README.md index 707b7b75..f5c6572a 100644 --- a/README.md +++ b/README.md @@ -234,6 +234,27 @@ New flute spots are chosen at random, with restrictions that limit the promixity New flute spots are chosen at random with minimum bias. +## Follower Shuffle (--shuffle_followers) + +This shuffles the follower companions throughout the world. Here is a full list of followers in the game: + +- Princess Zelda +- Old Man +- Blind Maiden +- Frog/Blacksmith +- Locksmith (Guy who unlocks Purple Chest) +- Kiki the Monkey +- Purple Chest +- Super Bomb + +When followers are shuffled, you must still fulfill the original requirements of the follower location. For example, if the Super Bomb Shop now contains the Frog, you must have crystals 5 and 6 and 100 rupees to unlock the Frog. It is also important to note that Purple Chest still needs to be delivered to the usual spot. Also, since it isn't useful normally, many people might not know that the Locksmith (the Purple Chest unlocking guy) can follow you, you must remove his sign to get him to follow. + +Most of the limitations of followers in the vanilla game have been lifted for this shuffle to work. For instance, you are able to mirror, flute, die, collect a crystal, and save/quit in most situations and still retain the follower. You are also able to enter caves/dungeons and complete dig game while you have a follower. + +In the scenario where you are forced down a narrow path and a follower is in your way and you already have a different follower. Running into that follower will switch the followers rather than overwriting, this gives you the opportunity to proceed with either one of the followers. Note that if you leave the screen, you lose this option to switch and you will need to go back to the original place you found the first follower. + +Optionally, thru the customizer, you can add a follower to your starting inventory, and you will be given that follower and it will stay with you until you complete their quest. + ## Bonk Drop Shuffle (--bonk_drops) This adds 42 new item locations to the game. These bonk locations are limited to the ones that drop a static item in the vanilla game. @@ -403,6 +424,12 @@ This gives each OW tile a random chance to be flipped to the opposite world For randomizing the flute spots around the overworld +``` +--shuffle_followers +``` + +This shuffles the follower companion locations, ie. Purple Chest, Old Man, etc. + ``` --bonk_drops ``` diff --git a/Regions.py b/Regions.py index 7068f0f6..d539cb86 100644 --- a/Regions.py +++ b/Regions.py @@ -133,7 +133,7 @@ def create_regions(world, player): create_lw_region(player, 'Ice Cave Area', None, ['Ice Rod Cave', 'Good Bee Cave', '20 Rupee Cave', 'Ice Cave Water Drop', 'Ice Cave SE']), create_lw_region(player, 'Ice Cave Water', None, ['Ice Cave Pier', 'Ice Cave SW'], 'Light World', Terrain.Water), create_lw_region(player, 'Desert Pass Area', ['Middle Aged Man'], ['Desert Fairy', '50 Rupee Cave', 'Middle Aged Man', 'Desert Pass Ladder (South)', 'Desert Pass Rocks (North)', 'Desert Pass WS', 'Desert Pass EC']), - create_lw_region(player, 'Middle Aged Man', ['Purple Chest'], None), + create_lw_region(player, 'Middle Aged Man', ['Purple Chest', 'Locksmith'], None), create_lw_region(player, 'Desert Pass Southeast', None, ['Desert Pass Rocks (South)', 'Desert Pass ES']), create_lw_region(player, 'Desert Pass Ledge', None, ['Desert Pass Ladder (North)', 'Desert Pass Ledge Drop', 'Desert Pass WC']), create_lw_region(player, 'Dam Area', ['Sunken Treasure'], ['Dam', 'Dam WC', 'Dam WS', 'Dam NC', 'Dam EC']), @@ -197,7 +197,8 @@ def create_regions(world, player): create_dw_region(player, 'Broken Bridge Northeast', None, ['Broken Bridge Hammer Rock (North)', 'Broken Bridge Hookshot Gap', 'Broken Bridge Northeast Water Drop', 'Broken Bridge NE']), create_dw_region(player, 'Broken Bridge West', None, ['Broken Bridge West Water Drop', 'Broken Bridge NW']), create_dw_region(player, 'Broken Bridge Water', None, ['Broken Bridge NC'], 'Dark World', Terrain.Water), - create_dw_region(player, 'Palace of Darkness Area', None, ['Palace of Darkness Hint', 'Palace of Darkness', 'Palace of Darkness SW', 'Palace of Darkness SE']), + create_dw_region(player, 'Palace of Darkness Area', ['Kiki'], ['Palace of Darkness Hint', 'Palace of Darkness', 'Kiki Assistance', 'Palace of Darkness SW', 'Palace of Darkness SE']), + create_dw_region(player, 'Dark Palace Button', ['Kiki Assistance'], None), create_dw_region(player, 'Darkness Cliff', None, ['Dark Dunes Cliff Ledge Drop', 'Hammer Bridge North Cliff Ledge Drop', 'Dark Tree Line Cliff Ledge Drop', 'Palace of Darkness Cliff Ledge Drop']), create_dw_region(player, 'Hammer Pegs Area', ['Dark Blacksmith Ruins'], ['Hammer Peg Cave', 'Peg Area Rocks (East)']), create_dw_region(player, 'Hammer Pegs Entry', None, ['Peg Area Rocks (West)', 'Hammer Pegs WS']), @@ -436,7 +437,6 @@ def create_dungeon_regions(world, player): create_dungeon_region(player, 'Hyrule Dungeon Staircase', 'Hyrule Castle', None, ['Hyrule Dungeon Staircase Up Stairs', 'Hyrule Dungeon Staircase Down Stairs']), create_dungeon_region(player, 'Hyrule Dungeon Cellblock', 'Hyrule Castle', ['Hyrule Castle - Big Key Drop'], ['Hyrule Dungeon Cellblock Up Stairs', 'Hyrule Dungeon Cellblock Door']), create_dungeon_region(player, 'Hyrule Dungeon Cell', 'Hyrule Castle', - ["Hyrule Castle - Zelda's Chest"] if not std_flag else ["Hyrule Castle - Zelda's Chest", 'Zelda Pickup'], ['Hyrule Dungeon Cell Exit']), @@ -1255,7 +1255,9 @@ def adjust_locations(world, player): location.type = LocationType.Logical location.real = False if l not in ['Ganon', 'Agahnim 1', 'Agahnim 2']: - location.skip = True + from ItemList import follower_quests + if not world.shuffle_followers[player] or l not in follower_quests: + location.skip = True def valid_pot_location(pot, pot_set, world, player): @@ -1413,9 +1415,12 @@ location_events = { 'Ice Palace - Boss Kill': 'Beat Boss', 'Misery Mire - Boss Kill': 'Beat Boss', 'Turtle Rock - Boss Kill': 'Beat Boss', + 'Locksmith': 'Sign Vandalized', 'Lost Old Man': 'Escort Old Man', 'Old Man Drop Off': 'Return Old Man', 'Floodgate': 'Open Floodgate', + 'Kiki': 'Pick Up Kiki', + 'Kiki Assistance': 'Dark Palace Opened', 'Big Bomb': 'Pick Up Big Bomb', 'Pyramid Crack': 'Detonate Big Bomb', 'Frog': 'Get Frog', @@ -1671,9 +1676,12 @@ location_table = {'Mushroom': (0x180013, 0x186df8, False, 'in the woods'), 'Ice Palace - Boss Kill': (None, None, False, None), 'Misery Mire - Boss Kill': (None, None, False, None), 'Turtle Rock - Boss Kill': (None, None, False, None), + 'Locksmith': (None, None, False, None), 'Lost Old Man': (None, None, False, None), 'Old Man Drop Off': (None, None, False, None), 'Floodgate': (None, None, False, None), + 'Kiki': (None, None, False, None), + 'Kiki Assistance': (None, None, False, None), 'Frog': (None, None, False, None), 'Missing Smith': (None, None, False, None), 'Dark Blacksmith Ruins': (None, None, False, None), diff --git a/Rom.py b/Rom.py index abea18f4..c102dfec 100644 --- a/Rom.py +++ b/Rom.py @@ -43,7 +43,7 @@ from source.enemizer.Enemizer import write_enemy_shuffle_settings JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '80e0a4f8bd5cc6f83ac9f7f46c01bf4f' +RANDOMIZERBASEHASH = '7ce0f9fc9db08644ff77fb41993d9e34' class JsonRom(object): @@ -638,10 +638,6 @@ def patch_rom(world, rom, player, team, is_mystery=False): write_int16(rom, 0x150002, owMode) write_int16(rom, 0x150004, owFlags) - from OverworldShuffle import can_reach_smith - if not can_reach_smith(world, player): - rom.write_byte(0x180043, 0x01) # patch for deleting smith on S+Q - # patch entrance/exits/holes for region in world.regions: for exit in region.exits: @@ -1545,9 +1541,44 @@ def patch_rom(world, rom, player, team, is_mystery=False): rom.write_byte(snes_to_pc(0x0DB810), 0x8A) # allows heart pieces to travel across water # rom.write_byte(snes_to_pc(0x0DB730), 0x08) # allows chickens to travel across water - # allow smith into multi-entrance caves in appropriate shuffles - if world.shuffle[player] in ['restricted', 'simple', 'full', 'lite', 'lean', 'district', 'swapped', 'crossed', 'insanity']: - rom.write_byte(0x18004C, 0x01) + + if world.shuffle_followers[player]: + from ItemList import follower_locations, follower_pickups + + for loc_name, address in follower_locations.items(): + loc = world.get_location(loc_name, player) + rom.write_byte(address, follower_pickups[loc.item.name]) + + rom.write_byte(0x18004C, 0x02) # enable follower shuffle + rom.write_byte(snes_to_pc(0x1BBD3A), 0x80) # allow all followers thru entrances + rom.write_bytes(snes_to_pc(0x1DFC70), [0xEA, 0xEA]) # allow followers at dig game + rom.write_byte(snes_to_pc(0x02823B), 0x80) # allow super bomb indoors + rom.write_byte(snes_to_pc(0x0283FB), 0x80) # allow maiden to go outside + rom.write_bytes(snes_to_pc(0x02D6F2), [0xEA, 0xEA]) # disable old man checkpoint + rom.write_byte(snes_to_pc(0x05DEFA), 0xAF) # no follower despawn at uncle + rom.write_byte(snes_to_pc(0x05DF3C), 0xAF) # no follower despawn at uncle + rom.write_bytes(snes_to_pc(0x079448), [0xEA, 0xEA]) # dont draw super bomb while falling into holes + rom.write_byte(snes_to_pc(0x079595), 0x80) # allow super bomb to follow into OW holes + rom.write_bytes(snes_to_pc(0x07A132), [0xEA, 0xEA]) # allow bomb use with super bomb + rom.write_byte(snes_to_pc(0x07A4B4), 0x80) # allow ether use with super bomb + rom.write_byte(snes_to_pc(0x07A589), 0x80) # allow bombos use with super bomb + rom.write_byte(snes_to_pc(0x07A66B), 0x80) # allow quake use with super bomb + rom.write_byte(snes_to_pc(0x07A919), 0x80) # disable kiki dialogue during mirror + rom.write_byte(snes_to_pc(0x07AAC5), 0xAF) # keep all followers after mirroring + rom.write_byte(snes_to_pc(0x08DED6), 0x80) # allow locksmith to follow with flute + rom.write_bytes(snes_to_pc(0x09A045), [0xEA, 0xEA]) # allow super bomb to follow into UW holes + rom.write_byte(snes_to_pc(0x09ACDF), 0x6B) # allow kiki/locksmith to follow after screen transition + + if world.enemy_shuffle[player] != 'none': + # informs zelda and maiden to draw over gfx slots that are guaranteed unused + rom.write_bytes(0x1802C1, world.data_tables[player].room_headers[0x80].free_gfx[0:2]) + rom.write_bytes(0x1802C7, world.data_tables[player].room_headers[0x45].free_gfx[0:2]) + else: + from OverworldShuffle import can_reach_smith + if not can_reach_smith(world, player): + rom.write_byte(0x180043, 0x01) # patch for deleting smith on S+Q + if world.shuffle[player] in ['restricted', 'simple', 'full', 'lite', 'lean', 'district', 'swapped', 'crossed', 'insanity']: + rom.write_byte(0x18004C, 0x01) # allow smith into multi-entrance caves in appropriate shuffles # set correct flag for hera basement item hera_basement = world.get_location('Tower of Hera - Basement Cage', player) diff --git a/Rules.py b/Rules.py index 29c95a9b..68dfda95 100644 --- a/Rules.py +++ b/Rules.py @@ -252,6 +252,7 @@ def global_rules(world, player): set_rule(world.get_location('Zora\'s Ledge', player), lambda state: state.has('Flippers', player)) set_rule(world.get_location('Flute Spot', player), lambda state: state.has('Shovel', player)) set_rule(world.get_location('Bombos Tablet', player), lambda state: state.has('Book of Mudora', player) and state.has_beam_sword(player)) + set_rule(world.get_location('Kiki Assistance', player), lambda state: state.has('Pick Up Kiki', player)) # Can S&Q with chest set_rule(world.get_location('Middle Aged Man', player), lambda state: state.has('Pick Up Purple Chest', player)) # Can S&Q with chest set_rule(world.get_location('Purple Chest', player), lambda state: state.has('Deliver Purple Chest', player)) # Can S&Q with chest set_rule(world.get_location('Sunken Treasure', player), lambda state: state.has('Open Floodgate', player)) @@ -406,6 +407,7 @@ def global_rules(world, player): set_rule(world.get_entrance('Bonk Fairy (Dark)', player), lambda state: state.has_Boots(player)) set_rule(world.get_entrance('Dark Lake Hylia Ledge Spike Cave', player), lambda state: state.can_lift_rocks(player)) + set_rule(world.get_entrance('Palace of Darkness', player), lambda state: state.has('Dark Palace Opened', player)) set_rule(world.get_entrance('Skull Woods Final Section', player), lambda state: state.has('Fire Rod', player)) set_rule(world.get_entrance('Misery Mire', player), lambda state: state.has_sword(player) and state.has_misery_mire_medallion(player)) # sword required to cast magic (!) set_rule(world.get_entrance('Turtle Rock', player), lambda state: state.has('Turtle Opened', player)) @@ -1128,6 +1130,8 @@ def ow_bunny_rules(world, player): add_bunny_rule(world.get_location('Maze Race', player), player) add_bunny_rule(world.get_location('Flute Spot', player), player) add_bunny_rule(world.get_location('Catfish', player), player) + add_bunny_rule(world.get_location('Kiki', player), player) + add_bunny_rule(world.get_location('Locksmith', player), player) # entrances add_bunny_rule(world.get_entrance('Lost Woods Hideout Drop', player), player) @@ -1148,7 +1152,6 @@ def ow_bunny_rules(world, player): add_bunny_rule(world.get_entrance('Skull Woods Final Section', player), player) # bunny cannot use fire rod add_bunny_rule(world.get_entrance('Hookshot Cave', player), player) add_bunny_rule(world.get_entrance('Thieves Town', player), player) # bunny cannot pull - add_bunny_rule(world.get_entrance('Palace of Darkness', player), player) # kiki needs pearl add_bunny_rule(world.get_entrance('Hammer Peg Cave', player), player) add_bunny_rule(world.get_entrance('Bonk Fairy (Dark)', player), player) add_bunny_rule(world.get_entrance('Misery Mire', player), player) @@ -1639,7 +1642,6 @@ def standard_rules(world, player): else: add_rule(loc, lambda state: standard_escape_rule(state)) - set_rule(world.get_location('Zelda Pickup', player), lambda state: state.has('Big Key (Escape)', player)) set_rule(world.get_entrance('Hyrule Castle Tapestry Backwards', player), lambda state: state.has('Zelda Herself', player)) def check_rule_list(state, r_list): @@ -1702,7 +1704,7 @@ def set_bunny_rules(world, player, inverted): bunny_accessible_locations = ['Link\'s Uncle', 'Sahasrahla', 'Sick Kid', 'Lost Woods Hideout', 'Lumberjack Tree', 'Checkerboard Cave', 'Potion Shop', 'Spectacle Rock Cave', 'Pyramid', 'Old Man', 'Hype Cave - Generous Guy', 'Peg Cave', 'Bumper Cave Ledge', 'Dark Blacksmith Ruins', - 'Spectacle Rock', 'Bombos Tablet', 'Ether Tablet', 'Purple Chest', 'Blacksmith', + 'Spectacle Rock', 'Bombos Tablet', 'Ether Tablet', 'Kiki Assistance', 'Purple Chest', 'Blacksmith', 'Missing Smith', 'Master Sword Pedestal', 'Bottle Merchant', 'Sunken Treasure', 'Desert Ledge', 'Pyramid Crack', 'Big Bomb', 'Stumpy', 'Lost Old Man', 'Old Man Drop Off', 'Murahdahla', 'Kakariko Shop - Left', 'Kakariko Shop - Middle', 'Kakariko Shop - Right', diff --git a/data/base2current.bps b/data/base2current.bps index db46c22a6aaf24c4317e0d06e25a5acb3590b983..84b14dd60ee8f4971aa260ec8bde9ec35c33c7ce 100644 GIT binary patch delta 18728 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 PD88n1`7 Date: Wed, 30 Apr 2025 06:49:42 -0500 Subject: [PATCH 31/39] Fixed incorrect bunny music issue --- Rom.py | 2 +- data/base2current.bps | Bin 136345 -> 136347 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/Rom.py b/Rom.py index c102dfec..7309db3c 100644 --- a/Rom.py +++ b/Rom.py @@ -43,7 +43,7 @@ from source.enemizer.Enemizer import write_enemy_shuffle_settings JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '7ce0f9fc9db08644ff77fb41993d9e34' +RANDOMIZERBASEHASH = '2ccee3f731044db154e0608f2a4e32a9' class JsonRom(object): diff --git a/data/base2current.bps b/data/base2current.bps index 84b14dd60ee8f4971aa260ec8bde9ec35c33c7ce..c343873dfcdd2ca320c1be257de450657397c602 100644 GIT binary patch delta 2100 zcmW+#YgALm8a;FJ4v$2Pzy-x{0EL2rKt)k0FIyCRYprcWYL%uQuS+djsSjqN0n=*; zVT1z&$U#I+5n+*PY8ALr3q(-UYF%ot%G*Gdn=a|X)>`l3uKDrJe6#mj``fdp+#)tv z#7%bqXvKFyELdZekTU`QMU8u=HG;R81QpiL1QR59fIk*56w4m5qZvpSiBE~+z;ygj zi~--eOQPk0D|p=f1lVsy9vT25t$dkK3Yx8M|2Ra(mkqI_qkkc&MyM(Z=@t*O^;1me z5Og4TPS-KSMnI&k&XFSB=;)|}*(XMo43UH?>!?2KHGeTbjTq+mMOrEhQ}7!jq@2~d zZ&B4%R5cyysT3!B(y*zPNj+T>ZUN;*qF`vL{+o5nqS~HvG}pyC|7C!y-qbr-u1q4+ zFkYt&mHg`DF3;S!1T9u2_vBdkw7AQ`>NG&~54Y z5w-{A-!Gvi@arI@B5;(gG-altGNi3!7Hvo8^;EWXUU0S?xU6NdPgB8TE6lwooYw!8 zZK~Nf#1=^?Zzo&2`|Za@Y8Iwpg2>`zi*!^EZi4=cRZh0oyfv=sG=hl;>7Su|l?K6Y zb;1$07iqhYHVW3K?fgCi;s6aNS}}5EYVLoFjQK@VsX#13^L;o^Pfh~$XAdVmK*QgQ z7xdn*qQ1lH(Hsz9)u1LR7{xIs^1!IodZI6G#{0#UNMZ8ch#I2oOI;E6_gtZ;B(P8f z3xjhZzHq%WB4TF$XON}_ud!5o0cw|@VcU35*nT-xSpe5PV%I-n2OhC|AG6>IOX8Xz zvR0J};9Gvr+vY^~ zyo*$GS}*=v>JT-!^X*LL;Ke1NqBho|~i%Tc9dfGe5|$$*{z|IRTc6GwKX zyGsThwky*rq%kIwKhEz;Q*flThhN{Q6ADBwfypL>{I*`)-<1HeaiD!V2*(NbTyG9! zC=I-B^rBu2u(nk3qr#O9W*>aht^^zKnB6aK!yxO+C_G0R++B)E%_zpJjkzItsW^qnAW27w0~pXgWtIk03vYajiq^Rv*2Y{pH}TlbK^Vss>;E9 zlXncXME;iVOV_cStAVB%W0e;*HpmtM8XwRb)#~x(&q|{=w=ldzsLoE(l%7kdLTpOT zLk-fup+_i(c=?PDHO&@iesIXuYO0JQ^T$7ZPLFSSPBU`}jd}esJ~M)472B(j6MGW{~By|2$%@wY6&F>Ee(ABxI&&%wAe^A=2Z(9));&vJ-XP zK9G!;^h5*+o#wX@y2G5QQoZ~opCDeoF~=lyqp{kpiQRZ#C}a-F@rj<`uoH$OP+RFV zoK$7-$( zR{lY%I1@|hkfPEr1wYqTlu%t9N`O5IOe;!?bF=@07a6X|&y^cSIJ3+nrb2YndKlU^ z1UpN!b4=x)o&>i%OP55Li$92af(RyOu2V~R;LU|7q%u$CM(}Ag>BsdeeJ} z>cdgwkAse5FU0(F*PzAS#UBr9p~q*n(4~7;JT%e#7W&v4)R$VZg!T zcFYRfEdhuN<45#kUz;QnM7a5fC+dIX5tdk@h-dL44XulgWXYh6Yz}8~Y^&qJR?2U$ z`^(}3ih?Tb*u(ayQ+J8_X$PUsvU_EH0@I@cZ-H>zgbE~*()sBx^^QLHn^|Q`+5(aQ zklBuAfn_r|z|F%T82B8D{_EPZuTE3ZeQYBio(&^i?v3kAo{TsT4EQd1|IdrU#(%*k z7ip2x7MZrhWIzhW+s1=n3n|kzHSuwF5Y$S)Vh(I5v+dD)%d6DtSgY&%cLI%`-O^wkjdR?>pTu7gwlkNiA(C~ z7lNS7)@1-A00h~ZjerM$x9w6f=;DDLOkOEB;Ue4DrQi$zKFpdjumfZ=SIa=Tc*@6B z+HE2x$+o#1`~(CU{`XDkwpbI`!2_!pb2XR`d~Nrtfm0y#j)QJp3AXE}0Xa(`h&hJe svvuD9^JD_y<~}CF1|EWia{$3C5|REO(za1V#(Ris$?8oTqqa=@9|)(S0{{R3 delta 2123 zcmW+#YgAKL7QW}^bqN8&L!h7-FQ8~q5fB8cMO28DY8T+BEedU|O}*OHsgDtSa85Kp z90LglxL|->M6?;CFb2Kt>Htcs5(G`Fb}1dIJPoKcj&!M`wR4$ue(dx3_SxV5_TFYI zRb{1GZUWGWZ-H2_!RAKJ1mfK4f{$&HqPIv;Yx_*{j0FAoLn?vt?dQhRkUj>Vq~d`J z_fZ&7w$I&kBG7>+6~{rI4S8q*h_Q*iq;hb<=KjV(GO>Du8y|m#pa!9uD5OssBq;%9qe8TRkOqjRNX+2*e(TA;#Bdd;BVB?^DzxuO^|lh z>c2rX|3Wp>p@B|ya%Cl(>)BPO%HOntDx)k6>S|w?rW`Xo5WHOH8-mvW!TQrHvA1dk zxxWx+sv_Kea|(}V^>m6&r#eEq<&LmXm4+O;4tt0C0u2riy&-QI<9blRopSmmejTdv z3m@mI&0E!|66vbhrJta)26~4rI&8ZVOxmhqAFKj{HkA9bblT_xuB9$_gfqI)K~ApX zi^ad1=y`Z2TrO*Jaz;Jv!2g87AP4utfH3(OcOU7xkS+=~s&{^$262d1AQd?Fop0`M zMpJ>&mk!4iiVF}VE1LqE&Kz2C7ma>TExCWEhHl3j(0oAKj-VDfn82~e^TC9z_4q)1 z(EFv;NNM)pi0WePt6fp{R9EEb1*44v#Kf` zX6$}|Bu|<5eoBN=C0q%kgC2J*j_yf8S@YY^Uz9s!O$xEy$3+I_L$2$HID`+CSK)^0X&7+}ol&9e(tGhPf6JDg=PgR1&MA zM(L$_sCh`Mhqxt-W>6K#Xf!$MK~F8j!&cd zi`O+-X5t%m71)ej_MrI9!(1Ti=Q-A-aQRJPZuAIhvFkq>{Z{EBp*)aT!c64=#r2ys zV^s&#Q?Xhtxp+l)2#Ccw-K+C`XTxt@13FD0BdFpKXH^dum_uTqb>WkOK&F8cYBb9n zW2*6)(#{ANyx(BbXeQrzR1v+UjdeeW8tf!Pn}pW(qs;H*qbB)l=n)|xok}RGn3hm88(j4S~8EKAS{76?Ana{&^V~G0#+RlQKI<+)9=w%PDf2q z-RJP>R9TOX>ZDeJ(782V(zZaQ<*l;2WuwCBs!??ipwiKqEB2yY(h@`By*5aeH6bplG~QDMsP73Gw&z3Ri%6tyGJAPW&Co+2FL%lHD&W^4{$$S9)YoZ3X6S z?~kKk99o2Z5W5$D*ZW35Ix}pY8Y}na9&L+VQR?0_F*B>o9Y5@yaQj;%OpfTDX?o8# zcwOQjynk!QxujdAf8AEzFpZ#zS;Q)09nraGTRCQIx?>ii)fs2 z0P3w@tZPhRuV;aIAclXD1(Hbl^0m(mjsf_@lF6^k1}gyY<#jn=%?z-Rzi|kJfdFyL zt4nK+oucCgxMndtGnaHJnlsE&R-O-rKoUEV5Bz~AFM%MN^lE5n5ubE}%6oS=W8*(b^2*>*7|GLh&X0bcicZGT7T1-p2A5qKt*r-VPdpqc)4C=B4cOTZWa!F;O;h=36Fn^Mpv0$;MILda+(f3^ag z2EdEWs02H}U)c6aP(`_YSfkq}W7qK6Rp2Ke$qc?@&fw$BV222#vURl}4k-CMwZJKn zhQvent~mb6DL~Ga9Ev`Q*YmyIV3C)^bISm`iWl{Pg!zDCm&wRr5YKOxk%=DEBfoRm IY_hEPe<%v9H~;_u From 3f930c095c6ec6148c077f0e6f20fbcd27c88859 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Wed, 30 Apr 2025 13:47:49 -0500 Subject: [PATCH 32/39] Version bump 0.6.0.0 --- CHANGELOG.md | 9 +++++++++ OverworldShuffle.py | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a9e21869..4b1a10a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## 0.6.0.0 +- New Follower Shuffle option (See Readme) +- HMG fixes for key pickup behavior +- Fixed some errors with starting equipment +- Added documentation for some unknown/obscure starting inventory options +- Possible fix for ignorable error message for EXE users +- \~Merged in DR v1.4.9~ + - Fixed Moth conveyor issue + ## 0.5.1.5 - Fixed rare overworld map check VRAM crash - Fixed cavestate dark room hidden item issue diff --git a/OverworldShuffle.py b/OverworldShuffle.py index 6118b731..f0ab938e 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -8,7 +8,7 @@ from OWEdges import OWTileRegions, OWEdgeGroups, OWEdgeGroupsTerrain, OWExitType from OverworldGlitchRules import create_owg_connections from Utils import bidict -version_number = '0.5.1.5' +version_number = '0.6.0.0' # branch indicator is intentionally different across branches version_branch = '-u' From dee0a25f421bb44b4655936ec6b1edd0458449c7 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Thu, 1 May 2025 04:31:47 -0500 Subject: [PATCH 33/39] oopsie --- Main.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Main.py b/Main.py index ac9faaf9..2165c669 100644 --- a/Main.py +++ b/Main.py @@ -35,7 +35,6 @@ from source.item.District import init_districts from source.item.FillUtil import create_item_pool_config, massage_item_pool, district_item_pool_config, verify_item_pool_config from source.overworld.EntranceShuffle2 import link_entrances_new from source.tools.BPS import create_bps_from_data -from source.tools.GraphExporter import GephiStreamer from source.classes.CustomSettings import CustomSettings from source.enemizer.DamageTables import DamageTable from source.enemizer.Enemizer import randomize_enemies From 8309b1cf9cd2d1662f3cb5265b5535df5e2d1d7e Mon Sep 17 00:00:00 2001 From: codemann8 Date: Thu, 1 May 2025 08:11:00 -0500 Subject: [PATCH 34/39] Error when follower shuffle not enabled --- Regions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Regions.py b/Regions.py index d539cb86..6b276d8f 100644 --- a/Regions.py +++ b/Regions.py @@ -456,7 +456,7 @@ def create_dungeon_regions(world, player): create_dungeon_region(player, 'Sewers Yet More Rats', 'Hyrule Castle', None, ['Sewers Pull Switch Down Stairs', 'Sewers Yet More Rats S']), create_dungeon_region(player, 'Sewers Pull Switch', 'Hyrule Castle', None, ['Sewers Pull Switch N', 'Sewers Pull Switch S']), create_dungeon_region(player, 'Sanctuary', 'Hyrule Castle', - ['Sanctuary'] if not std_flag else ['Sanctuary', 'Zelda Drop Off'], + ['Sanctuary', 'Zelda Drop Off'], ['Sanctuary S', 'Sanctuary N', 'Sanctuary Mirror Route']), # Eastern Palace From a1eee9f0746ac7ad8b09f3174303f666052ddd35 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Thu, 1 May 2025 08:12:24 -0500 Subject: [PATCH 35/39] Version bump 0.6.0.1 --- CHANGELOG.md | 3 +++ OverworldShuffle.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b1a10a0..71b95a8a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +## 0.6.0.1 +- Emergency fix for generation errors + ## 0.6.0.0 - New Follower Shuffle option (See Readme) - HMG fixes for key pickup behavior diff --git a/OverworldShuffle.py b/OverworldShuffle.py index f0ab938e..fff137d4 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -8,7 +8,7 @@ from OWEdges import OWTileRegions, OWEdgeGroups, OWEdgeGroupsTerrain, OWExitType from OverworldGlitchRules import create_owg_connections from Utils import bidict -version_number = '0.6.0.0' +version_number = '0.6.0.1' # branch indicator is intentionally different across branches version_branch = '-u' From 20c9bb0f565eecd38f3f30cda4f792a6d5f89e4b Mon Sep 17 00:00:00 2001 From: codemann8 Date: Thu, 1 May 2025 08:12:40 -0500 Subject: [PATCH 36/39] h --- Regions.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Regions.py b/Regions.py index 6b276d8f..b5acf6b9 100644 --- a/Regions.py +++ b/Regions.py @@ -456,6 +456,7 @@ def create_dungeon_regions(world, player): create_dungeon_region(player, 'Sewers Yet More Rats', 'Hyrule Castle', None, ['Sewers Pull Switch Down Stairs', 'Sewers Yet More Rats S']), create_dungeon_region(player, 'Sewers Pull Switch', 'Hyrule Castle', None, ['Sewers Pull Switch N', 'Sewers Pull Switch S']), create_dungeon_region(player, 'Sanctuary', 'Hyrule Castle', + #['Sanctuary'] if not std_flag else ['Sanctuary', 'Zelda Drop Off'], ['Sanctuary S', 'Sanctuary N', 'Sanctuary Mirror Route']), From 40bff27e6b4f9135ab032a2d25f02fef890bc93d Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sun, 4 May 2025 09:27:29 -0500 Subject: [PATCH 37/39] Various bug fixes for Follower Shuffle post-launch - Fix issue with infinite purple chest item get - Fix issue with Kiki running away on iframe ledge hops - Fix issue with bad follower gfx on screens with followers - Fix issue with Zelda appearing in conditional follower locations --- Rom.py | 2 +- data/base2current.bps | Bin 136351 -> 136392 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/Rom.py b/Rom.py index ac9d46d6..efda6e30 100644 --- a/Rom.py +++ b/Rom.py @@ -43,7 +43,7 @@ from source.enemizer.Enemizer import write_enemy_shuffle_settings JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '1143daca64a1dbdb151339830dca37df' +RANDOMIZERBASEHASH = 'a1d6e5902d2e33a3c440aca3983897a3' class JsonRom(object): diff --git a/data/base2current.bps b/data/base2current.bps index f29dabbd6595664bf6f56583b4b124fb8ee72046..0915c9814eb1110334356a6a6ea93fb985f392de 100644 GIT binary patch delta 10312 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 X<}t}_cbvJ``2y|C;2ZJb*Tnx1Ut1EG delta 10377 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 Date: Sun, 4 May 2025 09:31:36 -0500 Subject: [PATCH 38/39] Fixed issue with item pool placing items on Zelda Drop Off --- ItemList.py | 8 -------- Regions.py | 6 +++--- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/ItemList.py b/ItemList.py index e690d83a..de36b74a 100644 --- a/ItemList.py +++ b/ItemList.py @@ -272,14 +272,6 @@ def generate_itempool(world, player): item = None set_event_item(world, player, loc, item) - zelda_pickup, zelda_dropoff = None, None - if world.mode[player] == 'standard': - if not world.shuffle_followers[player]: - zelda_pickup = 'Zelda Herself' - zelda_dropoff = 'Zelda Delivered' - set_event_item(world, player, 'Zelda Pickup', zelda_pickup) - set_event_item(world, player, 'Zelda Drop Off', zelda_dropoff) - # set up item pool skip_pool_adjustments = False if world.customizer and world.customizer.get_item_pool() and player in world.customizer.get_item_pool(): diff --git a/Regions.py b/Regions.py index 6b276d8f..d634fbb8 100644 --- a/Regions.py +++ b/Regions.py @@ -1249,7 +1249,7 @@ def adjust_locations(world, player): location.prize = prize_on_boss location.real = not prize_on_boss # unreal events: - for l in ['Ganon', 'Zelda Pickup', 'Zelda Drop Off'] + list(location_events): + for l in ['Ganon'] + list(location_events): location = world.get_location_unsafe(l, player) if location: location.type = LocationType.Logical @@ -1436,8 +1436,8 @@ location_events = { 'Revealing Light': 'Maiden Unmasked', 'Ice Block Drop': 'Convenient Block', 'Skull Star Tile': 'Hidden Pits', - 'Zelda Pickup': None, - 'Zelda Drop Off': None + 'Zelda Pickup': 'Zelda Herself', + 'Zelda Drop Off': 'Zelda Delivered' } From 73ee8a9942094b446fc3c094a0ef7bd61f2d8293 Mon Sep 17 00:00:00 2001 From: codemann8 Date: Sun, 4 May 2025 09:33:32 -0500 Subject: [PATCH 39/39] Version bump 0.6.0.2 --- CHANGELOG.md | 7 +++++++ OverworldShuffle.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 71b95a8a..c1abe383 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## 0.6.0.2 +- Fixed issue with item pool placing items on Zelda Drop Off +- Fix issue with infinite purple chest item get +- Fix issue with Kiki running away on i-frame ledge hops +- Fix issue with bad follower gfx on screens with followers +- Fix issue with Zelda appearing in conditional follower locations + ## 0.6.0.1 - Emergency fix for generation errors diff --git a/OverworldShuffle.py b/OverworldShuffle.py index fff137d4..433707cb 100644 --- a/OverworldShuffle.py +++ b/OverworldShuffle.py @@ -8,7 +8,7 @@ from OWEdges import OWTileRegions, OWEdgeGroups, OWEdgeGroupsTerrain, OWExitType from OverworldGlitchRules import create_owg_connections from Utils import bidict -version_number = '0.6.0.1' +version_number = '0.6.0.2' # branch indicator is intentionally different across branches version_branch = '-u'