From 7389a55cd20465c89cc87dff3f998b2c61c5ede9 Mon Sep 17 00:00:00 2001 From: G4M3R L1F3 Date: Sun, 16 Nov 2025 22:07:55 -0400 Subject: [PATCH 1/9] shuffle_great_fairy_rewards: Conversion from "Toggle" to "Choice" --- worlds/mm_recomp/Items.py | 14 +++++++------- worlds/mm_recomp/Locations.py | 18 ++++++++++++------ worlds/mm_recomp/Options.py | 11 +++++++++-- worlds/mm_recomp/__init__.py | 33 +++++++++++++++++++++------------ 4 files changed, 49 insertions(+), 27 deletions(-) diff --git a/worlds/mm_recomp/Items.py b/worlds/mm_recomp/Items.py index 13b42b4c..7d573163 100644 --- a/worlds/mm_recomp/Items.py +++ b/worlds/mm_recomp/Items.py @@ -23,18 +23,18 @@ class MMRItemData(NamedTuple): "Progressive Magic": MMRItemData( code=0x3469420020000, type=ItemClassification.progression, - can_create=lambda options: options.shuffle_great_fairy_rewards.value, + can_create=lambda options: options.shuffle_great_fairy_rewards.value != 1, num_exist=2 ), "Great Spin Attack": MMRItemData( code=0x3469420020001, type=ItemClassification.useful, - can_create=lambda options: options.shuffle_great_fairy_rewards.value + can_create=lambda options: options.shuffle_great_fairy_rewards.value != 1 ), "Double Defense": MMRItemData( code=0x3469420020003, type=ItemClassification.useful, - can_create=lambda options: options.shuffle_great_fairy_rewards.value + can_create=lambda options: options.shuffle_great_fairy_rewards.value != 1 ), "Bomber's Notebook": MMRItemData( code=0x3469420000050, @@ -195,7 +195,7 @@ class MMRItemData(NamedTuple): "Great Fairy Mask": MMRItemData( code=0x3469420000086, type=ItemClassification.progression, - can_create=lambda options: options.shuffle_great_fairy_rewards.value + can_create=lambda options: options.shuffle_great_fairy_rewards.value != 1 ), "Gibdo Mask": MMRItemData( code=0x3469420000087, @@ -271,7 +271,7 @@ class MMRItemData(NamedTuple): "Great Fairy Sword": MMRItemData( code=0x346942000003B, type=ItemClassification.progression, - can_create=lambda options: options.shuffle_great_fairy_rewards.value + can_create=lambda options: options.shuffle_great_fairy_rewards.value != 1 ), "Progressive Bow": MMRItemData( code=0x3469420000022, @@ -508,13 +508,13 @@ class MMRItemData(NamedTuple): "Blue Rupee": MMRItemData( code=0x3469420000002, type=ItemClassification.filler, - num_exist=14 + num_exist=12 # ~ num_exist=6 ), "Red Rupee": MMRItemData( code=0x3469420000004, type=ItemClassification.filler, - num_exist=45 + num_exist=41 # ~ num_exist=29 ), "Purple Rupee": MMRItemData( diff --git a/worlds/mm_recomp/Locations.py b/worlds/mm_recomp/Locations.py index ecd10792..9686d965 100644 --- a/worlds/mm_recomp/Locations.py +++ b/worlds/mm_recomp/Locations.py @@ -339,11 +339,13 @@ def can_create_heart_location(shp, c_or_p, loc_index): ), "North Clock Town Great Fairy Reward": MMRLocationData( region="Clock Town", - address=0x3469420030000 + address=0x3469420030000, + can_create=lambda options: options.shuffle_great_fairy_rewards.value != 0 ), "North Clock Town Great Fairy Reward (Has Transformation Mask)": MMRLocationData( region="Clock Town", - address=0x3469420000086 + address=0x3469420000086, + can_create=lambda options: options.shuffle_great_fairy_rewards.value != 0 ), "West Clock Town Lottery Any Day": MMRLocationData( region="Clock Town", @@ -777,7 +779,8 @@ def can_create_heart_location(shp, c_or_p, loc_index): ), "Woodfall Great Fairy Reward": MMRLocationData( region="Woodfall", - address=0x3469420030001 + address=0x3469420030001, + can_create=lambda options: options.shuffle_great_fairy_rewards.value != 0 ), "Woodfall Temple Entrance Chest SF": MMRLocationData( region="Woodfall Temple", @@ -1001,7 +1004,8 @@ def can_create_heart_location(shp, c_or_p, loc_index): ), "Snowhead Great Fairy Reward": MMRLocationData( region="Snowhead Temple", - address=0x3469420030002 + address=0x3469420030002, + can_create=lambda options: options.shuffle_great_fairy_rewards.value != 0 ), "Snowhead Temple Elevator Room Invisible Platform Chest SF": MMRLocationData( region="Snowhead Temple", @@ -1215,7 +1219,8 @@ def can_create_heart_location(shp, c_or_p, loc_index): ), "Great Bay Great Fairy Reward": MMRLocationData( region="Zora Cape", - address=0x3469420030003 + address=0x3469420030003, + can_create=lambda options: options.shuffle_great_fairy_rewards.value != 0 ), "Zora Hall Shop Item 1": MMRLocationData( region="Zora Hall", @@ -1654,7 +1659,8 @@ def can_create_heart_location(shp, c_or_p, loc_index): ), "Stone Tower Great Fairy Reward": MMRLocationData( region="Ikana Canyon", - address=0x3469420030004 + address=0x3469420030004, + can_create=lambda options: options.shuffle_great_fairy_rewards.value != 0 ), "Ikana Well Final Chest": MMRLocationData( region="Beneath the Well", diff --git a/worlds/mm_recomp/Options.py b/worlds/mm_recomp/Options.py index 04cc77eb..b9f1b2c4 100644 --- a/worlds/mm_recomp/Options.py +++ b/worlds/mm_recomp/Options.py @@ -167,9 +167,16 @@ class Cowsanity(Toggle): display_name = "Shuffle Cows" -class ShuffleGreatFairyRewards(Toggle): - """Choose whether to shuffle Great Fairy rewards.""" +class ShuffleGreatFairyRewards(Choice): + """Choose how Great Fairy rewards are shuffled. + disabled: Great Fairy rewards won't be shuffled into the pool. + vanilla: Great Fairy rewards will be vanilla. For example, Magic will be behind Clock Town and Snowhead rewards. + enabled: Great Fairy rewards will be shuffled. Any item can be shuffled at their locations.""" display_name = "Shuffle Great Fairy Rewards" + option_disabled = 0 + option_vanilla = 1 + option_enabled = 2 + default = 0 class RequiredStrayFairies(Range): diff --git a/worlds/mm_recomp/__init__.py b/worlds/mm_recomp/__init__.py index b2696ff3..b3291fa3 100644 --- a/worlds/mm_recomp/__init__.py +++ b/worlds/mm_recomp/__init__.py @@ -2,7 +2,7 @@ from typing import Dict from typing import TextIO -from BaseClasses import Region, Tutorial +from BaseClasses import Region, Tutorial, ItemClassification from worlds.AutoWorld import WebWorld, World from .Items import MMRItem, item_data_table, item_table, code_to_item_table from .Locations import MMRLocation, location_data_table, location_table, code_to_location_table, locked_locations @@ -37,7 +37,7 @@ class MMRWorld(World): options = MMROptions location_name_to_id = location_table item_name_to_id = item_table - + prices_ints: List[int] prices: str @@ -66,9 +66,16 @@ def generate_early(self): self.prices += str(price) + " " self.prices = self.prices[:-1] - + def create_item(self, name: str) -> MMRItem: - return MMRItem(name, item_data_table[name].type, item_data_table[name].code, self.player) + if (name == "Stray Fairy (Clock Town)" or + name == "Stray Fairy (Woodfall)" or + name == "Stray Fairy (Snowhead)" or + name == "Stray Fairy (Great Bay)" or + name == "Stray Fairy (Stone Tower)") and self.options.shuffle_great_fairy_rewards == 0: + return MMRItem(name, ItemClassification.filler, item_data_table[name].code, self.player) + else: + return MMRItem(name, item_data_table[name].type, item_data_table[name].code, self.player) def place(self, location, item): player = self.player @@ -98,11 +105,11 @@ def create_items(self) -> None: if self.options.shieldless.value: mw.itempool.append(self.create_item("Progressive Shield")) - + if self.options.start_with_soaring.value: mw.push_precollected(self.create_item("Song of Soaring")) self.create_and_add_filler_items() - + if self.options.shuffle_spiderhouse_reward.value: mw.itempool.append(self.create_item("Progressive Wallet")) @@ -120,22 +127,25 @@ def create_items(self) -> None: mw.itempool.append(self.create_item("Red Rupee")) mw.itempool.append(self.create_item("Purple Rupee")) mw.itempool.append(self.create_item("Gold Rupee")) - + if self.options.scrubsanity.value != 0: self.create_and_add_filler_items(4) - + if self.options.shopsanity.value != 0: self.create_and_add_filler_items(27) if self.options.shopsanity.value == 2: self.create_and_add_filler_items(11) - + if self.options.cowsanity.value != 0: self.create_and_add_filler_items(8) - + if self.options.intro_checks.value: self.create_and_add_filler_items(1) + if self.options.shuffle_great_fairy_rewards.value != 0: + self.create_and_add_filler_items(6) + shp = self.options.starting_hearts.value if self.options.starting_hearts_are_containers_or_pieces.value == 0: for i in range(0, int((12 - shp)/4)): @@ -204,9 +214,8 @@ def create_regions(self) -> None: self.place(code_to_location_table[0x3469420062700 | i], "Swamp Skulltula Token") if i != 0: self.place(code_to_location_table[0x3469420062800 | i], "Ocean Skulltula Token") - - if not self.options.shuffle_great_fairy_rewards.value: + if self.options.shuffle_great_fairy_rewards.value == 1: #vanilla self.place("North Clock Town Great Fairy Reward", "Progressive Magic") self.place("North Clock Town Great Fairy Reward (Has Transformation Mask)", "Great Fairy Mask") self.place("Woodfall Great Fairy Reward", "Great Spin Attack") From 51d06dafb963357b9c5ef97275338290b752b522 Mon Sep 17 00:00:00 2001 From: G4M3R L1F3 Date: Sat, 20 Dec 2025 01:09:19 -0400 Subject: [PATCH 2/9] Add spacing to ShuffleGreatFairyRewards description --- worlds/mm_recomp/Options.py | 1 + 1 file changed, 1 insertion(+) diff --git a/worlds/mm_recomp/Options.py b/worlds/mm_recomp/Options.py index b9f1b2c4..4e52a708 100644 --- a/worlds/mm_recomp/Options.py +++ b/worlds/mm_recomp/Options.py @@ -169,6 +169,7 @@ class Cowsanity(Toggle): class ShuffleGreatFairyRewards(Choice): """Choose how Great Fairy rewards are shuffled. + disabled: Great Fairy rewards won't be shuffled into the pool. vanilla: Great Fairy rewards will be vanilla. For example, Magic will be behind Clock Town and Snowhead rewards. enabled: Great Fairy rewards will be shuffled. Any item can be shuffled at their locations.""" From 256c6b93729b71b71bbcf7f5f5a01397ad8d335e Mon Sep 17 00:00:00 2001 From: G4M3R L1F3 Date: Wed, 21 Jan 2026 21:55:03 -0400 Subject: [PATCH 3/9] Added the option to disable ShuffleSpiderhouseReward Tokens will be filler items when disabled --- worlds/mm_recomp/Items.py | 4 ++-- worlds/mm_recomp/Locations.py | 6 ++++-- worlds/mm_recomp/Options.py | 11 +++++++++-- worlds/mm_recomp/__init__.py | 10 ++++++++-- 4 files changed, 23 insertions(+), 8 deletions(-) diff --git a/worlds/mm_recomp/Items.py b/worlds/mm_recomp/Items.py index 7d573163..57297ed3 100644 --- a/worlds/mm_recomp/Items.py +++ b/worlds/mm_recomp/Items.py @@ -212,7 +212,7 @@ class MMRItemData(NamedTuple): "Mask of Truth": MMRItemData( code=0x346942000008A, type=ItemClassification.progression, - can_create=lambda options: options.shuffle_spiderhouse_reward.value + can_create=lambda options: options.shuffle_spiderhouse_reward.value != 1 ), "Stone Mask": MMRItemData( code=0x346942000008B, @@ -514,7 +514,7 @@ class MMRItemData(NamedTuple): "Red Rupee": MMRItemData( code=0x3469420000004, type=ItemClassification.filler, - num_exist=41 + num_exist=39 # ~ num_exist=29 ), "Purple Rupee": MMRItemData( diff --git a/worlds/mm_recomp/Locations.py b/worlds/mm_recomp/Locations.py index 9686d965..16af7921 100644 --- a/worlds/mm_recomp/Locations.py +++ b/worlds/mm_recomp/Locations.py @@ -735,7 +735,8 @@ def can_create_heart_location(shp, c_or_p, loc_index): ), "Swamp Spider House Reward": MMRLocationData( region="Swamp Spider House", - address=0x346942000008A + address=0x346942000008A, + can_create=lambda options: options.shuffle_spiderhouse_reward.value != 0 ), "Southern Swamp Grotto Chest": MMRLocationData( region="Southern Swamp (Deku Palace)", @@ -1482,7 +1483,8 @@ def can_create_heart_location(shp, c_or_p, loc_index): ), "Ocean Spider House Reward": MMRLocationData( region="Ocean Spider House", - address=0x3469420000009 + address=0x3469420000009, + can_create=lambda options: options.shuffle_spiderhouse_reward.value != 0 ), "Great Bay Temple Blender Pot SF": MMRLocationData( region="Great Bay Temple", diff --git a/worlds/mm_recomp/Options.py b/worlds/mm_recomp/Options.py index 4e52a708..cecdaf72 100644 --- a/worlds/mm_recomp/Options.py +++ b/worlds/mm_recomp/Options.py @@ -98,9 +98,16 @@ class BossWarpsWithRemains(DefaultOnToggle): display_name = "Warp to Bosses Using Remains" -class ShuffleSpiderHouseReward(Toggle): - """Choose whether to shuffle the Mask of Truth given at the end of the Southern Spider House and the Wallet Upgrade at the end of the Ocean Spider House.""" +class ShuffleSpiderHouseReward(Choice): + """Choose how Swamp Spider House and Ocean Spider House rewards are shuffled. + + disabled: Spider House rewards won't be shuffled into the pool. + vanilla: Spider House rewards will be vanilla. Mask of Truth will be in Swamp and a wallet upgrade in Ocean. + enabled: Spider House rewards will be shuffled. Any item can be shuffled at their locations.""" display_name = "Shuffle Spider House Rewards" + option_disabled = 0 + option_vanilla = 1 + option_enabled = 2 class RequiredSkullTokens(Range): diff --git a/worlds/mm_recomp/__init__.py b/worlds/mm_recomp/__init__.py index b3291fa3..da86fcab 100644 --- a/worlds/mm_recomp/__init__.py +++ b/worlds/mm_recomp/__init__.py @@ -74,6 +74,9 @@ def create_item(self, name: str) -> MMRItem: name == "Stray Fairy (Great Bay)" or name == "Stray Fairy (Stone Tower)") and self.options.shuffle_great_fairy_rewards == 0: return MMRItem(name, ItemClassification.filler, item_data_table[name].code, self.player) + elif (name == "Swamp Skulltula Token" or + name == "Ocean Skulltula Token") and self.options.shuffle_spiderhouse_reward == 0: + return MMRItem(name, ItemClassification.filler, item_data_table[name].code, self.player) else: return MMRItem(name, item_data_table[name].type, item_data_table[name].code, self.player) @@ -110,7 +113,7 @@ def create_items(self) -> None: mw.push_precollected(self.create_item("Song of Soaring")) self.create_and_add_filler_items() - if self.options.shuffle_spiderhouse_reward.value: + if self.options.shuffle_spiderhouse_reward.value != 1: mw.itempool.append(self.create_item("Progressive Wallet")) if self.options.shuffle_regional_maps.value == 1: @@ -146,6 +149,9 @@ def create_items(self) -> None: if self.options.shuffle_great_fairy_rewards.value != 0: self.create_and_add_filler_items(6) + if self.options.shuffle_spiderhouse_reward.value != 0: + self.create_and_add_filler_items(2) + shp = self.options.starting_hearts.value if self.options.starting_hearts_are_containers_or_pieces.value == 0: for i in range(0, int((12 - shp)/4)): @@ -204,7 +210,7 @@ def create_regions(self) -> None: self.place("Great Bay Temple Gyorg's Remains", remains_list.pop(self.random.randint(0, 1))) self.place("Stone Tower Temple Inverted Twinmold's Remains", remains_list[0]) - if not self.options.shuffle_spiderhouse_reward.value: + if self.options.shuffle_spiderhouse_reward.value == 1: self.place("Swamp Spider House Reward", "Mask of Truth") self.place("Ocean Spider House Reward", "Progressive Wallet") From 41762d092b355911dcd78894ccbb5cd260623b0c Mon Sep 17 00:00:00 2001 From: G4M3R L1F3 Date: Thu, 22 Jan 2026 23:59:03 -0400 Subject: [PATCH 4/9] Added ShuffleTreasureChestGame option Allows to disable or enable all chests, or to only enable Goron chest. --- worlds/mm_recomp/Items.py | 4 ++-- worlds/mm_recomp/Locations.py | 12 ++++++++---- worlds/mm_recomp/Options.py | 13 +++++++++++++ worlds/mm_recomp/__init__.py | 6 ++++++ 4 files changed, 29 insertions(+), 6 deletions(-) diff --git a/worlds/mm_recomp/Items.py b/worlds/mm_recomp/Items.py index 57297ed3..7cded359 100644 --- a/worlds/mm_recomp/Items.py +++ b/worlds/mm_recomp/Items.py @@ -508,13 +508,13 @@ class MMRItemData(NamedTuple): "Blue Rupee": MMRItemData( code=0x3469420000002, type=ItemClassification.filler, - num_exist=12 + num_exist=11 # ~ num_exist=6 ), "Red Rupee": MMRItemData( code=0x3469420000004, type=ItemClassification.filler, - num_exist=39 + num_exist=36 # ~ num_exist=29 ), "Purple Rupee": MMRItemData( diff --git a/worlds/mm_recomp/Locations.py b/worlds/mm_recomp/Locations.py index 16af7921..39bc9073 100644 --- a/worlds/mm_recomp/Locations.py +++ b/worlds/mm_recomp/Locations.py @@ -299,19 +299,23 @@ def can_create_heart_location(shp, c_or_p, loc_index): ), "East Clock Town Treasure Game Chest (Human)": MMRLocationData( region="Clock Town", - address=0x3469420061705 + address=0x3469420061705, + can_create=lambda options: options.shuffle_treasure_chest_game.value == 2 ), "East Clock Town Treasure Game Chest (Deku)": MMRLocationData( region="Clock Town", - address=0x346942006172A + address=0x346942006172A, + can_create=lambda options: options.shuffle_treasure_chest_game.value == 2 ), "East Clock Town Treasure Game Chest (Goron)": MMRLocationData( region="Clock Town", - address=0x346942006170C + address=0x346942006170C, + can_create=lambda options: options.shuffle_treasure_chest_game.value != 0 ), "East Clock Town Treasure Game Chest (Zora)": MMRLocationData( region="Clock Town", - address=0x3469420061704 + address=0x3469420061704, + can_create=lambda options: options.shuffle_treasure_chest_game.value == 2 ), "Bomber's Hideout Chest": MMRLocationData( region="Clock Town", diff --git a/worlds/mm_recomp/Options.py b/worlds/mm_recomp/Options.py index cecdaf72..36a60f26 100644 --- a/worlds/mm_recomp/Options.py +++ b/worlds/mm_recomp/Options.py @@ -222,6 +222,18 @@ class IntroChecks(Toggle): A way backwards through these areas has been added through the stone door at the bottom of the Clock Tower Interior.""" display_name = "Enable Intro Checks" +class ShuffleTreasureChestGame(Choice): + """Choose which chests in the Treasure Chest minigame are shuffled. + + disabled: Chests are not shuffled. + goron_only: Only the reward as Goron is shuffled. + everything: Rewards for human, Deku, Goron, and Zora are shuffled.""" + display_name = "Treasure Chest Minigame Shuffle" + option_disabled = 0 + option_goron_only = 1 + option_everything = 2 + default = 1 + class StartWithConsumables(DefaultOnToggle): """Choose whether to start with basic consumables (99 rupees, 10 deku sticks, 20 deku nuts).""" @@ -310,6 +322,7 @@ class MMROptions(PerGameCommonOptions): bosskeysanity: BossKeysanity curiostity_shop_trades: CuriostityShopTrades intro_checks: IntroChecks + shuffle_treasure_chest_game: ShuffleTreasureChestGame start_with_consumables: StartWithConsumables permanent_chateau_romani: PermanentChateauRomani start_with_inverted_time: StartWithInvertedTime diff --git a/worlds/mm_recomp/__init__.py b/worlds/mm_recomp/__init__.py index da86fcab..04c7014e 100644 --- a/worlds/mm_recomp/__init__.py +++ b/worlds/mm_recomp/__init__.py @@ -152,6 +152,11 @@ def create_items(self) -> None: if self.options.shuffle_spiderhouse_reward.value != 0: self.create_and_add_filler_items(2) + if self.options.shuffle_treasure_chest_game.value == 1: + self.create_and_add_filler_items(1) + elif self.options.shuffle_treasure_chest_game.value == 2: + self.create_and_add_filler_items(4) + shp = self.options.starting_hearts.value if self.options.starting_hearts_are_containers_or_pieces.value == 0: for i in range(0, int((12 - shp)/4)): @@ -438,6 +443,7 @@ def fill_slot_data(self): "shuffle_regional_maps": self.options.shuffle_regional_maps.value, "shuffle_spiderhouse_reward": self.options.shuffle_spiderhouse_reward.value, "shuffle_great_fairy_rewards": self.options.shuffle_great_fairy_rewards.value, + "shuffle_treasure_chest_game": self.options.shuffle_treasure_chest_game.value, "link_tunic_color": ((self.options.link_tunic_color.value[0] & 0xFF) << 16) | ((self.options.link_tunic_color.value[1] & 0xFF) << 8) | (self.options.link_tunic_color.value[2] & 0xFF), "random_seed": self.random.getrandbits(32), "logic_difficulty": self.options.logic_difficulty.value From 00f40ec94ccca48e4751e7113550d95a54474ce6 Mon Sep 17 00:00:00 2001 From: G4M3R L1F3 Date: Sun, 1 Feb 2026 18:13:42 -0400 Subject: [PATCH 5/9] Added ShuffleMinigames option --- worlds/mm_recomp/Items.py | 4 ++-- worlds/mm_recomp/Locations.py | 27 ++++++++++++++++++--------- worlds/mm_recomp/Options.py | 17 +++++++++++++++++ worlds/mm_recomp/__init__.py | 6 ++++++ 4 files changed, 43 insertions(+), 11 deletions(-) diff --git a/worlds/mm_recomp/Items.py b/worlds/mm_recomp/Items.py index 7cded359..f81f2966 100644 --- a/worlds/mm_recomp/Items.py +++ b/worlds/mm_recomp/Items.py @@ -508,13 +508,13 @@ class MMRItemData(NamedTuple): "Blue Rupee": MMRItemData( code=0x3469420000002, type=ItemClassification.filler, - num_exist=11 + num_exist=8 # ~ num_exist=6 ), "Red Rupee": MMRItemData( code=0x3469420000004, type=ItemClassification.filler, - num_exist=36 + num_exist=30 # ~ num_exist=29 ), "Purple Rupee": MMRItemData( diff --git a/worlds/mm_recomp/Locations.py b/worlds/mm_recomp/Locations.py index 39bc9073..3b6ef08c 100644 --- a/worlds/mm_recomp/Locations.py +++ b/worlds/mm_recomp/Locations.py @@ -283,19 +283,23 @@ def can_create_heart_location(shp, c_or_p, loc_index): ), "East Clock Town Shooting Gallery 40-49 Points": MMRLocationData( region="Clock Town", - address=0x3469420000023 + address=0x3469420000023, + can_create=lambda options: options.shuffle_minigames.value != 0 ), "East Clock Town Shooting Gallery Perfect 50 Points": MMRLocationData( region="Clock Town", - address=0x346942007011D + address=0x346942007011D, + can_create=lambda options: options.shuffle_minigames.value == 2 ), "East Clock Town Honey and Darling Any Day": MMRLocationData( region="Clock Town", - address=0x34694200800B5 + address=0x34694200800B5, + can_create=lambda options: options.shuffle_minigames.value != 0 ), "East Clock Town Honey and Darling All Days": MMRLocationData( region="Clock Town", - address=0x34694200700B5 + address=0x34694200700B5, + can_create=lambda options: options.shuffle_minigames.value == 2 ), "East Clock Town Treasure Game Chest (Human)": MMRLocationData( region="Clock Town", @@ -331,11 +335,13 @@ def can_create_heart_location(shp, c_or_p, loc_index): ), "North Clock Town Deku Playground Any Day": MMRLocationData( region="Clock Town", - address=0x34694200801C9 + address=0x34694200801C9, + can_create=lambda options: options.shuffle_minigames.value != 0 ), "North Clock Town Deku Playground All Days": MMRLocationData( region="Clock Town", - address=0x34694200701C9 + address=0x34694200701C9, + can_create=lambda options: options.shuffle_minigames.value == 2 ), "North Clock Town Save Old Lady": MMRLocationData( region="Clock Town", @@ -529,11 +535,13 @@ def can_create_heart_location(shp, c_or_p, loc_index): ), "Swamp Shooting Gallery 2120 Points": MMRLocationData( region="Southern Swamp", - address=0x3469420000024 + address=0x3469420000024, + can_create=lambda options: options.shuffle_minigames.value != 0 ), "Swamp Shooting Gallery 2180 Points": MMRLocationData( region="Southern Swamp", - address=0x346942008011D + address=0x346942008011D, + can_create=lambda options: options.shuffle_minigames.value == 2 ), "Southern Swamp Deku Trade": MMRLocationData( region="Southern Swamp", @@ -1188,7 +1196,8 @@ def can_create_heart_location(shp, c_or_p, loc_index): ), "Great Bay Fisherman Game": MMRLocationData( region="Great Bay", - address=0x3469420070292 + address=0x3469420070292, + can_create=lambda options: options.shuffle_minigames.value != 0 ), "Zora Cape Underwater Like-Like HP": MMRLocationData( region="Zora Cape", diff --git a/worlds/mm_recomp/Options.py b/worlds/mm_recomp/Options.py index 36a60f26..1ba2ca1e 100644 --- a/worlds/mm_recomp/Options.py +++ b/worlds/mm_recomp/Options.py @@ -222,6 +222,22 @@ class IntroChecks(Toggle): A way backwards through these areas has been added through the stone door at the bottom of the Clock Tower Interior.""" display_name = "Enable Intro Checks" +class ShuffleMinigames(Choice): + """Choose whether the minigames are shuffled or not. The minigames affected are: + - Town and Swamp Shooting Galleries; + - Honey & Darling; + - Deku Playground; + - Great Bay Fisherman Game. + + disabled: Listed minigames are not shuffled. + single: Listed minigames only have one location. Where applicable, the easier locations (any day/lowest points requirements) are shuffled. + everything: Listed minigames are fully shuffled.""" + display_name = "Shuffle Minigames" + option_disabled = 0 + option_single = 1 + option_everything = 2 + default = 1 + class ShuffleTreasureChestGame(Choice): """Choose which chests in the Treasure Chest minigame are shuffled. @@ -322,6 +338,7 @@ class MMROptions(PerGameCommonOptions): bosskeysanity: BossKeysanity curiostity_shop_trades: CuriostityShopTrades intro_checks: IntroChecks + shuffle_minigames: ShuffleMinigames shuffle_treasure_chest_game: ShuffleTreasureChestGame start_with_consumables: StartWithConsumables permanent_chateau_romani: PermanentChateauRomani diff --git a/worlds/mm_recomp/__init__.py b/worlds/mm_recomp/__init__.py index 04c7014e..71ab3352 100644 --- a/worlds/mm_recomp/__init__.py +++ b/worlds/mm_recomp/__init__.py @@ -151,6 +151,11 @@ def create_items(self) -> None: if self.options.shuffle_spiderhouse_reward.value != 0: self.create_and_add_filler_items(2) + + if self.options.shuffle_minigames.value == 1: + self.create_and_add_filler_items(5) + elif self.options.shuffle_minigames.value == 2: + self.create_and_add_filler_items(9) if self.options.shuffle_treasure_chest_game.value == 1: self.create_and_add_filler_items(1) @@ -443,6 +448,7 @@ def fill_slot_data(self): "shuffle_regional_maps": self.options.shuffle_regional_maps.value, "shuffle_spiderhouse_reward": self.options.shuffle_spiderhouse_reward.value, "shuffle_great_fairy_rewards": self.options.shuffle_great_fairy_rewards.value, + "shuffle_minigames": self.options.shuffle_minigames.value, "shuffle_treasure_chest_game": self.options.shuffle_treasure_chest_game.value, "link_tunic_color": ((self.options.link_tunic_color.value[0] & 0xFF) << 16) | ((self.options.link_tunic_color.value[1] & 0xFF) << 8) | (self.options.link_tunic_color.value[2] & 0xFF), "random_seed": self.random.getrandbits(32), From 10d448628b3d87f14fe2ac94e4678d8a22db8bcc Mon Sep 17 00:00:00 2001 From: G4M3R L1F3 Date: Sat, 16 May 2026 14:37:37 -0300 Subject: [PATCH 6/9] Changed keysanity, bosskeysanity and fairysanity, and added maps & compass shuffle - keysanity and bosskeysanity have been changed to shuffle_small_keys and shuffle_boss_keys, respectively. Added options to start with them or have them be placed locally. - fairysanity changed to shuffle_stray_fairies. Added option to have them be placed locally. *** This PR has features that were cut out due to lack of knowledge. On top of the options I added, I also wanted to add options that would shuffle items in either their own dungeons or any of the four. I will likely revisit this someday. --- worlds/mm_recomp/Items.py | 52 +++--- worlds/mm_recomp/Options.py | 86 ++++++++-- worlds/mm_recomp/__init__.py | 297 +++++++++++++++++++++++++++++++++-- 3 files changed, 392 insertions(+), 43 deletions(-) diff --git a/worlds/mm_recomp/Items.py b/worlds/mm_recomp/Items.py index f81f2966..73dd5e46 100644 --- a/worlds/mm_recomp/Items.py +++ b/worlds/mm_recomp/Items.py @@ -8,6 +8,7 @@ class MMRItem(Item): class MMRItemData(NamedTuple): + category: str = "Item" code: Optional[int] = None type: ItemClassification = ItemClassification.filler num_exist: int = 1 @@ -16,9 +17,10 @@ class MMRItemData(NamedTuple): item_data_table: Dict[str, MMRItemData] = { "Stray Fairy (Clock Town)": MMRItemData( + category="Stray Fairy", code=0x346942001007F, type=ItemClassification.progression, - can_create=lambda options: options.fairysanity.value + can_create=lambda options: options.shuffle_stray_fairies.value == 4 or 5 ), "Progressive Magic": MMRItemData( code=0x3469420020000, @@ -356,101 +358,109 @@ class MMRItemData(NamedTuple): code=0x3469420010000, type=ItemClassification.progression, num_exist=15, - can_create=lambda options: options.fairysanity.value + can_create=lambda options: options.shuffle_stray_fairies.value == 4 or options.shuffle_stray_fairies.value == 5 ), "Stray Fairy (Snowhead)": MMRItemData( code=0x3469420010001, type=ItemClassification.progression, num_exist=15, - can_create=lambda options: options.fairysanity.value + can_create=lambda options: options.shuffle_stray_fairies.value == 4 or options.shuffle_stray_fairies.value == 5 ), "Stray Fairy (Great Bay)": MMRItemData( code=0x3469420010002, type=ItemClassification.progression, num_exist=15, - can_create=lambda options: options.fairysanity.value + can_create=lambda options: options.shuffle_stray_fairies.value == 4 or options.shuffle_stray_fairies.value == 5 ), "Stray Fairy (Stone Tower)": MMRItemData( code=0x3469420010003, type=ItemClassification.progression, num_exist=15, - can_create=lambda options: options.fairysanity.value + can_create=lambda options: options.shuffle_stray_fairies.value == 4 or options.shuffle_stray_fairies.value == 5 ), "Small Key (Woodfall)": MMRItemData( code=0x3469420090078, type=ItemClassification.progression, num_exist=1, - can_create=lambda options: options.keysanity.value + can_create=lambda options: options.shuffle_small_keys.value == 4 or options.shuffle_small_keys.value == 5 ), "Small Key (Snowhead)": MMRItemData( code=0x3469420090178, type=ItemClassification.progression, num_exist=3, - can_create=lambda options: options.keysanity.value + can_create=lambda options: options.shuffle_small_keys.value == 4 or options.shuffle_small_keys.value == 5 ), "Small Key (Great Bay)": MMRItemData( code=0x3469420090278, type=ItemClassification.progression, num_exist=1, - can_create=lambda options: options.keysanity.value + can_create=lambda options: options.shuffle_small_keys.value == 4 or options.shuffle_small_keys.value == 5 ), "Small Key (Stone Tower)": MMRItemData( code=0x3469420090378, type=ItemClassification.progression, num_exist=4, - can_create=lambda options: options.keysanity.value + can_create=lambda options: options.shuffle_small_keys.value == 4 or options.shuffle_small_keys.value == 5 ), "Dungeon Map (Woodfall)": MMRItemData( code=0x3469420090076, - type=ItemClassification.useful + type=ItemClassification.useful, + can_create=lambda options: options.shuffle_maps_and_compasses.value == 4 or options.shuffle_maps_and_compasses.value == 5 ), "Dungeon Map (Snowhead)": MMRItemData( code=0x3469420090176, - type=ItemClassification.useful + type=ItemClassification.useful, + can_create=lambda options: options.shuffle_maps_and_compasses.value == 4 or options.shuffle_maps_and_compasses.value == 5 ), "Dungeon Map (Great Bay)": MMRItemData( code=0x3469420090276, - type=ItemClassification.useful + type=ItemClassification.useful, + can_create=lambda options: options.shuffle_maps_and_compasses.value == 4 or options.shuffle_maps_and_compasses.value == 5 ), "Dungeon Map (Stone Tower)": MMRItemData( code=0x3469420090376, - type=ItemClassification.useful + type=ItemClassification.useful, + can_create=lambda options: options.shuffle_maps_and_compasses.value == 4 or options.shuffle_maps_and_compasses.value == 5 ), "Compass (Woodfall)": MMRItemData( code=0x3469420090075, - type=ItemClassification.useful + type=ItemClassification.useful, + can_create=lambda options: options.shuffle_maps_and_compasses.value == 4 or options.shuffle_maps_and_compasses.value == 5 ), "Compass (Snowhead)": MMRItemData( code=0x3469420090175, - type=ItemClassification.useful + type=ItemClassification.useful, + can_create=lambda options: options.shuffle_maps_and_compasses.value == 4 or options.shuffle_maps_and_compasses.value == 5 ), "Compass (Great Bay)": MMRItemData( code=0x3469420090275, - type=ItemClassification.useful + type=ItemClassification.useful, + can_create=lambda options: options.shuffle_maps_and_compasses.value == 4 or options.shuffle_maps_and_compasses.value == 5 ), "Compass (Stone Tower)": MMRItemData( code=0x3469420090375, - type=ItemClassification.useful + type=ItemClassification.useful, + can_create=lambda options: options.shuffle_maps_and_compasses.value == 4 or options.shuffle_maps_and_compasses.value == 5 ), "Boss Key (Woodfall)": MMRItemData( code=0x3469420090074, type=ItemClassification.progression, - can_create=lambda options: options.bosskeysanity.value + can_create=lambda options: options.shuffle_boss_keys.value == 4 or options.shuffle_boss_keys.value == 5 ), "Boss Key (Snowhead)": MMRItemData( code=0x3469420090174, type=ItemClassification.progression, - can_create=lambda options: options.bosskeysanity.value + can_create=lambda options: options.shuffle_boss_keys.value == 4 or options.shuffle_boss_keys.value == 5 ), "Boss Key (Great Bay)": MMRItemData( code=0x3469420090274, type=ItemClassification.progression, - can_create=lambda options: options.bosskeysanity.value + can_create=lambda options: options.shuffle_boss_keys.value == 4 or options.shuffle_boss_keys.value == 5 ), "Boss Key (Stone Tower)": MMRItemData( code=0x3469420090374, type=ItemClassification.progression, - can_create=lambda options: options.bosskeysanity.value + can_create=lambda options: options.shuffle_boss_keys.value == 4 or options.shuffle_boss_keys.value == 5 ), "Odolwa's Remains": MMRItemData( code=0x3469420000055, diff --git a/worlds/mm_recomp/Options.py b/worlds/mm_recomp/Options.py index 1ba2ca1e..d4b25e07 100644 --- a/worlds/mm_recomp/Options.py +++ b/worlds/mm_recomp/Options.py @@ -196,19 +196,80 @@ class RequiredStrayFairies(Range): range_end = 15 default = 15 +class DungeonItems(Choice): + """Base class for shuffle options for dungeon items (keys, maps, compasses).""" + value: int + option_vanilla = 1 + #option_dungeon = 2 + #option_any_dungeon = 3 + option_local = 4 + option_keysanity = 5 + default = 4 + + @property + def in_dungeon(self) -> bool: + """ + Return whether the item should be shuffled into a dungeon. + + :return: Whether the item is shuffled into a dungeon. + """ + return self.value in (2, 3) + -class Fairysanity(Toggle): - """Choose whether Stray Fairies are shuffled into the pool.""" - display_name = "Fairysanity" +class ShuffleStrayFairies(DungeonItems): + """ + Choose how stray fairies will be shuffled in the pool. + Vanilla: Stray fairies will be places where they can be found in vanilla. + Local: Stray fairies will be placed anywhere in your own world. + Fairysanity: Stray fairies will be placed in any world. + """ + item_name_group = "Stray Fairies" + display_name = "Shuffle Stray Fairies" + option_fairysanity = 5 + default = 4 -class Keysanity(Toggle): - """Choose whether Small Keys are shuffled into the pool or placed in their vanilla locations.""" - display_name = "Keysanity" +class ShuffleMapsAndCompasses(DungeonItems): + """ + Choose how dungeon maps and compasses will be shuffled in the pool. + + Start With: Start the seed with dungeon maps and compasses. + Vanilla: Dungeon maps and compasses will be placed where they can be found in vanilla. + Local: Dungeon maps and compasses will be placed anywhere in your own world. + Keysanity: Dungeon maps and compasses will be placed in any world. + """ + item_name_group = "Maps and Compasses" + display_name = "Shuffle Maps and Compasses" + option_start_with = 0 + default = 4 -class BossKeysanity(Toggle): - """Choose whether Boss Keys are shuffled into the pool or placed in their vanilla locations.""" - display_name = "BossKeysanity" +class ShuffleSmallKeys(DungeonItems): + """ + Choose how small keys will be shuffled in the pool. + + Start With: Start the seed with small keys. + Vanilla: Small keys will be placed where they can be found in vanilla. + Local: Small keys will be placed anywhere in your own world. + Keysanity: Small keys will be placed in any world. + """ + item_name_group = "Small Keys" + display_name = "Shuffle Small Keys" + option_start_with = 0 + default = 4 + +class ShuffleBossKeys(DungeonItems): + """ + Choose how boss keys will be shuffled in the pool. + + Start With: Start the seed with boss keys. + Vanilla: Boss keys will be placed where they can be found in vanilla. + Local: Boss keys will be placed anywhere in your own world. + Keysanity: Boss keys will be placed in any world. + """ + item_name_group = "Boss Keys" + display_name = "Shuffle Boss Keys" + option_start_with = 0 + default = 4 class CuriostityShopTrades(Toggle): @@ -333,9 +394,10 @@ class MMROptions(PerGameCommonOptions): cowsanity: Cowsanity shuffle_great_fairy_rewards: ShuffleGreatFairyRewards required_stray_fairies: RequiredStrayFairies - fairysanity: Fairysanity - keysanity: Keysanity - bosskeysanity: BossKeysanity + shuffle_stray_fairies: ShuffleStrayFairies + shuffle_maps_and_compasses: ShuffleMapsAndCompasses + shuffle_small_keys: ShuffleSmallKeys + shuffle_boss_keys: ShuffleBossKeys curiostity_shop_trades: CuriostityShopTrades intro_checks: IntroChecks shuffle_minigames: ShuffleMinigames diff --git a/worlds/mm_recomp/__init__.py b/worlds/mm_recomp/__init__.py index 71ab3352..41db6126 100644 --- a/worlds/mm_recomp/__init__.py +++ b/worlds/mm_recomp/__init__.py @@ -1,6 +1,6 @@ from typing import List from typing import Dict -from typing import TextIO +from typing import TextIO, ClassVar from BaseClasses import Region, Tutorial, ItemClassification from worlds.AutoWorld import WebWorld, World @@ -41,7 +41,56 @@ class MMRWorld(World): prices_ints: List[int] prices: str + #item_name_groups: ClassVar[dict[str, set[str]]] = item_name_groups + + #def __init__(self, *args, **kwargs): + # super().__init__(*args, **kwargs) + # + # self.dungeon_local_item_names: set[str] = set() + # self.dungeon_specific_item_names: set[str] = set() + def generate_early(self): + + #for dungeon_item in ["shuffle_small_keys", "shuffle_boss_keys", "shuffle_maps_and_compasses", "shuffle_stray_fairies"]: + # option = getattr(self.options, dungeon_item) + # if option == "local": + # self.options.local_items.value |= self.item_name_groups[option.item_name_group] + # elif option.in_dungeon: + # self.dungeon_local_item_names |= self.item_name_groups[option.item_name_group] + # if option == "dungeon": + # self.dungeon_specific_item_names |= self.item_name_groups[option.item_name_group] + # else: + # self.options.local_items.value |= self.dungeon_local_item_names + + if self.options.shuffle_stray_fairies.value == 4: + self.options.local_items.value.add("Stray Fairy (Clock Town)") + self.options.local_items.value.add("Stray Fairy (Woodfall)") + self.options.local_items.value.add("Stray Fairy (Snowhead)") + self.options.local_items.value.add("Stray Fairy (Great Bay)") + self.options.local_items.value.add("Stray Fairy (Stone Tower)") + + if self.options.shuffle_maps_and_compasses.value == 4: + self.options.local_items.value.add("Dungeon Map (Woodfall)") + self.options.local_items.value.add("Dungeon Map (Snowhead)") + self.options.local_items.value.add("Dungeon Map (Great Bay)") + self.options.local_items.value.add("Dungeon Map (Stone Tower)") + self.options.local_items.value.add("Compass (Woodfall)") + self.options.local_items.value.add("Compass (Snowhead)") + self.options.local_items.value.add("Compass (Great Bay)") + self.options.local_items.value.add("Compass (Stone Tower)") + + if self.options.shuffle_small_keys.value == 4: + self.options.local_items.value.add("Small Key (Woodfall)") + self.options.local_items.value.add("Small Key (Snowhead)") + self.options.local_items.value.add("Small Key (Great Bay)") + self.options.local_items.value.add("Small Key (Stone Tower)") + + if self.options.shuffle_boss_keys.value == 4: + self.options.local_items.value.add("Boss Key (Woodfall)") + self.options.local_items.value.add("Boss Key (Snowhead)") + self.options.local_items.value.add("Boss Key (Great Bay)") + self.options.local_items.value.add("Boss Key (Stone Tower)") + # Create shop prices. self.prices_ints = [] self.prices = "" @@ -125,6 +174,33 @@ def create_items(self) -> None: mw.push_precollected(self.create_item("Stone Tower Map")) self.create_and_add_filler_items(6) + if self.options.shuffle_maps_and_compasses.value == 0: + mw.push_precollected(self.create_item("Dungeon Map (Woodfall)")) + mw.push_precollected(self.create_item("Compass (Woodfall)")) + mw.push_precollected(self.create_item("Dungeon Map (Snowhead)")) + mw.push_precollected(self.create_item("Compass (Snowhead)")) + mw.push_precollected(self.create_item("Dungeon Map (Great Bay)")) + mw.push_precollected(self.create_item("Compass (Great Bay)")) + mw.push_precollected(self.create_item("Dungeon Map (Stone Tower)")) + mw.push_precollected(self.create_item("Compass (Stone Tower)")) + + if self.options.shuffle_small_keys.value == 0: + mw.push_precollected(self.create_item("Small Key (Woodfall)")) + mw.push_precollected(self.create_item("Small Key (Snowhead)")) + mw.push_precollected(self.create_item("Small Key (Snowhead)")) + mw.push_precollected(self.create_item("Small Key (Snowhead)")) + mw.push_precollected(self.create_item("Small Key (Great Bay)")) + mw.push_precollected(self.create_item("Small Key (Stone Tower)")) + mw.push_precollected(self.create_item("Small Key (Stone Tower)")) + mw.push_precollected(self.create_item("Small Key (Stone Tower)")) + mw.push_precollected(self.create_item("Small Key (Stone Tower)")) + + if self.options.shuffle_boss_keys == 0: + mw.push_precollected(self.create_item("Boss Key (Woodfall)")) + mw.push_precollected(self.create_item("Boss Key (Snowhead)")) + mw.push_precollected(self.create_item("Boss Key (Great Bay)")) + mw.push_precollected(self.create_item("Boss Key (Stone Tower)")) + if self.options.curiostity_shop_trades.value: mw.itempool.append(self.create_item("Blue Rupee")) mw.itempool.append(self.create_item("Red Rupee")) @@ -162,6 +238,15 @@ def create_items(self) -> None: elif self.options.shuffle_treasure_chest_game.value == 2: self.create_and_add_filler_items(4) + if self.options.shuffle_maps_and_compasses.value == 0: + self.create_and_add_filler_items(8) + + if self.options.shuffle_small_keys.value == 0: + self.create_and_add_filler_items(9) + + if self.options.shuffle_boss_keys == 0: + self.create_and_add_filler_items(4) + shp = self.options.starting_hearts.value if self.options.starting_hearts_are_containers_or_pieces.value == 0: for i in range(0, int((12 - shp)/4)): @@ -175,6 +260,19 @@ def create_items(self) -> None: def create_regions(self) -> None: player = self.player mw = self.multiworld + + available_dungeon_locations = [ + "Woodfall Temple Dinolfos Chest", + "Snowhead Temple Lower Wizzrobe Chest", + "Great Bay Temple Behind Locked Door Chest", + "Stone Tower Temple Garo Master Chest", + "Stone Tower Temple Inverted Eyegore Chest" + ] + available_wft_locations = ["Woodfall Temple Dinolfos Chest"] + available_sht_locations = ["Snowhead Temple Lower Wizzrobe Chest"] + available_gbt_locations = ["Great Bay Temple Behind Locked Door Chest"] + available_stt_locations = ["Stone Tower Temple Garo Master Chest", "Stone Tower Temple Inverted Eyegore Chest"] + item_name_groups_to_shuffle = [] # Create regions. for region_name in region_data_table.keys(): @@ -239,7 +337,53 @@ def create_regions(self) -> None: self.place("Great Bay Great Fairy Reward", "Double Defense") self.place("Stone Tower Great Fairy Reward", "Great Fairy Sword") - if not self.options.keysanity.value: + if self.options.shuffle_maps_and_compasses.value == "vanilla": + self.place("Woodfall Temple Turtle Chest", "Dungeon Map (Woodfall)") + self.place("Woodfall Temple Dragonfly Chest", "Compass (Woodfall)") + self.place("Snowhead Temple Elevator Room Lower Chest", "Dungeon Map (Snowhead)") + self.place("Snowhead Temple Frozen Block Chest", "Compass (Snowhead)") + self.place("Great Bay Temple Before Red Valve Room Chest", "Dungeon Map (Great Bay)") + self.place("Great Bay Temple Caged Chest Room Upper Chest", "Compass (Great Bay)") + self.place("Stone Tower Temple Armos Room Back Chest", "Dungeon Map (Stone Tower)") + self.place("Stone Tower Temple Eastern Water Room Sun Block Chest", "Compass (Stone Tower)") +# elif self.options.shuffle_maps_and_compasses.value == "dungeon": +# available_wft_locations.append("Woodfall Temple Turtle Chest") +# available_wft_locations.append("Woodfall Temple Dragonfly Chest") +# available_sht_locations.append("Snowhead Temple Elevator Room Lower Chest") +# available_sht_locations.append("Snowhead Temple Frozen Block Chest") +# available_gbt_locations.append("Great Bay Temple Before Red Valve Room Chest") +# available_gbt_locations.append("Great Bay Temple Caged Chest Room Upper Chest") +# available_stt_locations.append("Stone Tower Temple Armos Room Back Chest") +# available_stt_locations.append("Stone Tower Temple Eastern Water Room Sun Block Chest") +# +# available_wft_locations.append("Dungeon Map (Woodfall)") +# available_wft_locations.append("Compass (Woodfall)") +# available_sht_locations.append("Dungeon Map (Snowhead)") +# available_sht_locations.append("Compass (Snowhead)") +# available_gbt_locations.append("Dungeon Map (Great Bay)") +# available_gbt_locations.append("Compass (Great Bay)") +# available_stt_locations.append("Dungeon Map (Stone Tower)") +# available_stt_locations.append("Compass (Stone Tower)") +# elif self.options.shuffle_maps_and_compasses.value == "any_dungeon": +# available_dungeon_locations.append("Woodfall Temple Turtle Chest") +# available_dungeon_locations.append("Woodfall Temple Dragonfly Chest") +# available_dungeon_locations.append("Snowhead Temple Elevator Room Lower Chest") +# available_dungeon_locations.append("Snowhead Temple Frozen Block Chest") +# available_dungeon_locations.append("Great Bay Temple Before Red Valve Room Chest") +# available_dungeon_locations.append("Great Bay Temple Caged Chest Room Upper Chest") +# available_dungeon_locations.append("Stone Tower Temple Armos Room Back Chest") +# available_dungeon_locations.append("Stone Tower Temple Eastern Water Room Sun Block Chest") +# +# item_name_groups_to_shuffle.append("Dungeon Map (Woodfall)") +# item_name_groups_to_shuffle.append("Compass (Woodfall)") +# item_name_groups_to_shuffle.append("Dungeon Map (Snowhead)") +# item_name_groups_to_shuffle.append("Compass (Snowhead)") +# item_name_groups_to_shuffle.append("Dungeon Map (Great Bay)") +# item_name_groups_to_shuffle.append("Compass (Great Bay)") +# item_name_groups_to_shuffle.append("Dungeon Map (Stone Tower)") +# item_name_groups_to_shuffle.append("Compass (Stone Tower)") + + if self.options.shuffle_small_keys.value == 1: self.place("Woodfall Temple Ledge Chest", "Small Key (Woodfall)") self.place("Snowhead Temple Behind Stacked Block Chest", "Small Key (Snowhead)") @@ -252,14 +396,74 @@ def create_regions(self) -> None: self.place("Stone Tower Temple Eyegore Room Dexi Hand Ledge Chest", "Small Key (Stone Tower)") self.place("Stone Tower Temple Inverted Eastern Air Gust Room Switch Chest", "Small Key (Stone Tower)") self.place("Stone Tower Temple Inverted Death Armos Maze Chest", "Small Key (Stone Tower)") +# elif self.options.shuffle_small_keys.value == "dungeon": +# available_wft_locations.append("Woodfall Temple Ledge Chest") +# available_sht_locations.append("Snowhead Temple Behind Stacked Block Chest") +# available_sht_locations.append("Snowhead Temple Icicle Room Snowball Chest") +# available_sht_locations.append("Snowhead Temple Bridge Room Freezard Chest") +# available_gbt_locations.append("Great Bay Temple Caged Chest Room Underwater Chest") +# available_stt_locations.append("Stone Tower Temple Armos Room Lava Chest") +# available_stt_locations.append("Stone Tower Temple Eyegore Room Dexi Hand Ledge Chest") +# available_stt_locations.append("Stone Tower Temple Inverted Eastern Air Gust Room Switch Chest") +# available_stt_locations.append("Stone Tower Temple Inverted Death Armos Maze Chest") +# +# available_wft_locations.append("Small Key (Woodfall)") +# available_sht_locations.append("Small Key (Snowhead)") +# available_sht_locations.append("Small Key (Snowhead)") +# available_sht_locations.append("Small Key (Snowhead)") +# available_gbt_locations.append("Small Key (Great Bay)") +# available_sst_locations.append("Small Key (Stone Tower)") +# available_sst_locations.append("Small Key (Stone Tower)") +# available_sst_locations.append("Small Key (Stone Tower)") +# available_sst_locations.append("Small Key (Stone Tower)") +# elif self.options.shuffle_small_keys.value == "any_dungeon": +# available_dungeon_locations.append("Woodfall Temple Ledge Chest") +# available_dungeon_locations.append("Snowhead Temple Behind Stacked Block Chest") +# available_dungeon_locations.append("Snowhead Temple Icicle Room Snowball Chest") +# available_dungeon_locations.append("Snowhead Temple Bridge Room Freezard Chest") +# available_dungeon_locations.append("Great Bay Temple Caged Chest Room Underwater Chest") +# available_dungeon_locations.append("Stone Tower Temple Armos Room Lava Chest") +# available_dungeon_locations.append("Stone Tower Temple Eyegore Room Dexi Hand Ledge Chest") +# available_dungeon_locations.append("Stone Tower Temple Inverted Eastern Air Gust Room Switch Chest") +# available_dungeon_locations.append("Stone Tower Temple Inverted Death Armos Maze Chest") +# +# item_name_groups_to_shuffle.append("Small Key (Woodfall)") +# item_name_groups_to_shuffle.append("Small Key (Snowhead)") +# item_name_groups_to_shuffle.append("Small Key (Snowhead)") +# item_name_groups_to_shuffle.append("Small Key (Snowhead)") +# item_name_groups_to_shuffle.append("Small Key (Great Bay)") +# item_name_groups_to_shuffle.append("Small Key (Stone Tower)") +# item_name_groups_to_shuffle.append("Small Key (Stone Tower)") +# item_name_groups_to_shuffle.append("Small Key (Stone Tower)") +# item_name_groups_to_shuffle.append("Small Key (Stone Tower)") - if not self.options.bosskeysanity.value: + if self.options.shuffle_boss_keys.value == "vanilla": self.place("Woodfall Temple Gekko Chest", "Boss Key (Woodfall)") self.place("Snowhead Temple Upper Wizzrobe Chest", "Boss Key (Snowhead)") self.place("Great Bay Temple Mad Jellied Gekko Chest", "Boss Key (Great Bay)") self.place("Stone Tower Temple Inverted Gomess Chest", "Boss Key (Stone Tower)") - - if not self.options.fairysanity.value: +# elif self.options.shuffle_boss_keys.value == "dungeon": +# available_wft_locations.append("Woodfall Temple Gekko Chest") +# available_sht_locations.append("Snowhead Temple Upper Wizzrobe Chest") +# available_gbt_locations.append("Great Bay Temple Mad Jellied Gekko Chest") +# available_stt_locations.append("Stone Tower Temple Inverted Gomess Chest") +# +# available_wft_locations.append("Boss Key (Woodfall)") +# available_sht_locations.append("Boss Key (Snowhead)") +# available_gbt_locations.append("Boss Key (Great Bay)") +# available_stt_locations.append("Boss Key (Stone Tower)") +# elif self.options.shuffle_boss_keys.value == "any_dungeon": +# available_dungeon_locations.append("Woodfall Temple Gekko Chest") +# available_dungeon_locations.append("Snowhead Temple Upper Wizzrobe Chest") +# available_dungeon_locations.append("Great Bay Temple Mad Jellied Gekko Chest") +# available_dungeon_locations.append("Stone Tower Temple Inverted Gomess Chest") +# +# item_name_groups_to_shuffle.append("Boss Key (Woodfall)") +# item_name_groups_to_shuffle.append("Boss Key (Snowhead)") +# item_name_groups_to_shuffle.append("Boss Key (Great Bay)") +# item_name_groups_to_shuffle.append("Boss Key (Stone Tower)") + + if self.options.shuffle_stray_fairies.value == "vanilla": self.place("Laundry Pool Stray Fairy (Clock Town)", "Stray Fairy (Clock Town)") self.place("Woodfall Temple Entrance Chest SF", "Stray Fairy (Woodfall)") @@ -277,7 +481,7 @@ def create_regions(self) -> None: self.place("Woodfall Temple Pre-Boss Upper Right Bubble SF", "Stray Fairy (Woodfall)") self.place("Woodfall Temple Pre-Boss Upper Left Bubble SF", "Stray Fairy (Woodfall)") self.place("Woodfall Temple Pre-Boss Pillar Bubble SF", "Stray Fairy (Woodfall)") - + self.place("Snowhead Temple Basement Switch Chest SF", "Stray Fairy (Snowhead)") self.place("Snowhead Temple Elevator Room Invisible Platform Chest SF", "Stray Fairy (Snowhead)") self.place("Snowhead Temple Stacked Block Upper Chest SF", "Stray Fairy (Snowhead)") @@ -325,7 +529,79 @@ def create_regions(self) -> None: self.place("Stone Tower Temple Inverted Eastern Air Gust Room Fire Chest", "Stray Fairy (Stone Tower)") self.place("Stone Tower Temple Entrance Room Lower Chest", "Stray Fairy (Stone Tower)") self.place("Stone Tower Temple After Garo Upside Down Chest", "Stray Fairy (Stone Tower)") - +# else: +# available_dungeon_locations.append("Woodfall Temple Entrance Chest SF") +# available_dungeon_locations.append("Woodfall Temple Switch Chest SF") +# available_dungeon_locations.append("Woodfall Temple Dark Room Chest SF") +# available_dungeon_locations.append("Woodfall Temple Entrance Freestanding SF") +# available_dungeon_locations.append("Woodfall Temple Deku Baba SF") +# available_dungeon_locations.append("Woodfall Temple Pot SF") +# available_dungeon_locations.append("Woodfall Temple Platform Hive SF") +# available_dungeon_locations.append("Woodfall Temple Main Room Bubble SF") +# available_dungeon_locations.append("Woodfall Temple Skulltula SF") +# available_dungeon_locations.append("Woodfall Temple Bridge Room Bubble SF") +# available_dungeon_locations.append("Woodfall Temple Bridge Room Hive SF") +# available_dungeon_locations.append("Woodfall Temple Pre-Boss Lower Right Bubble SF") +# available_dungeon_locations.append("Woodfall Temple Pre-Boss Upper Right Bubble SF") +# available_dungeon_locations.append("Woodfall Temple Pre-Boss Upper Left Bubble SF") +# available_dungeon_locations.append("Woodfall Temple Pre-Boss Pillar Bubble SF") +# +# available_dungeon_locations.append("Snowhead Temple Basement Switch Chest SF") +# available_dungeon_locations.append("Snowhead Temple Elevator Room Invisible Platform Chest SF") +# available_dungeon_locations.append("Snowhead Temple Stacked Block Upper Chest SF") +# available_dungeon_locations.append("Snowhead Temple Freezard Torch Room Chest SF") +# available_dungeon_locations.append("Snowhead Temple Frozen Block Upper Chest SF") +# available_dungeon_locations.append("Snowhead Temple Icicle Room Hidden Chest SF") +# available_dungeon_locations.append("Snowhead Temple Main Room Wall Chest SF") +# available_dungeon_locations.append("Snowhead Temple Bridge Room Pillar Bubble SF") +# available_dungeon_locations.append("Snowhead Temple Bridge Room Under Platform Bubble SF") +# available_dungeon_locations.append("Snowhead Temple Elevator Freestanding SF") +# available_dungeon_locations.append("Snowhead Temple Bombable Stairs Crate SF") +# available_dungeon_locations.append("Snowhead Temple Timed Switch Room Bubble SF") +# available_dungeon_locations.append("Snowhead Temple Snowmen Bubble SF") +# available_dungeon_locations.append("Snowhead Temple Dinolfos Room First SF") +# available_dungeon_locations.append("Snowhead Temple Dinolfos Room Second SF") +# +# available_dungeon_locations.append("Great Bay Temple Entrance Torches Chest SF") +# available_dungeon_locations.append("Great Bay Temple Bio-Baba Hall Chest SF") +# available_dungeon_locations.append("Great Bay Temple Freezable Waterwheel Upper Chest SF") +# available_dungeon_locations.append("Great Bay Temple Freezable Waterwheel Lower Chest SF") +# available_dungeon_locations.append("Great Bay Temple Seesaw Room Chest SF") +# available_dungeon_locations.append("Great Bay Temple Room Behind Waterfall Ceiling Chest SF") +# available_dungeon_locations.append("Great Bay Temple Waterwheel Room Skulltula SF") +# available_dungeon_locations.append("Great Bay Temple Waterwheel Room Bubble SF") +# available_dungeon_locations.append("Great Bay Temple Blender Pot SF") +# available_dungeon_locations.append("Great Bay Temple Blender Room Barrel SF") +# available_dungeon_locations.append("Great Bay Temple Before Red Valve Room Pot SF") +# available_dungeon_locations.append("Great Bay Temple Caged Chest Room Pot SF") +# available_dungeon_locations.append("Great Bay Temple Seesaw Room Underwater Barrel SF") +# available_dungeon_locations.append("Great Bay Temple Pre-Boss Room Platform Bubble SF") +# available_dungeon_locations.append("Great Bay Temple Pre-Boss Room Tunnel Bubble SF") +# +# available_dungeon_locations.append("Stone Tower Temple Entrance Room Eye Switch Chest") +# available_dungeon_locations.append("Stone Tower Temple Armos Room Upper Chest") +# available_dungeon_locations.append("Stone Tower Temple Eyegore Room Switch Chest") +# available_dungeon_locations.append("Stone Tower Temple Mirror Room Sun Face Chest") +# available_dungeon_locations.append("Stone Tower Temple Mirror Room Sun Block Chest") +# available_dungeon_locations.append("Stone Tower Temple Air Gust Room Side Chest") +# available_dungeon_locations.append("Stone Tower Temple Air Gust Room Goron Switch Chest") +# available_dungeon_locations.append("Stone Tower Temple Eyegore Chest") +# available_dungeon_locations.append("Stone Tower Temple Eastern Water Room Underwater Chest") +# available_dungeon_locations.append("Stone Tower Temple Inverted Entrance Room Sun Face Chest") +# available_dungeon_locations.append("Stone Tower Temple Inverted Eastern Air Gust Room Frozen Switch Chest") +# available_dungeon_locations.append("Stone Tower Temple Inverted Wizzrobe Chest") +# available_dungeon_locations.append("Stone Tower Temple Inverted Eastern Air Gust Room Fire Chest") +# available_dungeon_locations.append("Stone Tower Temple Entrance Room Lower Chest") +# available_dungeon_locations.append("Stone Tower Temple After Garo Upside Down Chest") +# for i in range(1, 15, 1): +# item_name_groups_to_shuffle.append("Stray Fairy (Woodfall)") +# for i in range(1, 15, 1): +# item_name_groups_to_shuffle.append("Stray Fairy (Snowhead)") +# for i in range(1, 15, 1): +# item_name_groups_to_shuffle.append("Stray Fairy (Great Bay)") +# for i in range(1, 15, 1): +# item_name_groups_to_shuffle.append("Stray Fairy (Stone Tower)") + sword_location = mw.get_location("Link's Inventory (Kokiri Sword)", player) if self.options.swordless.value: sword_location.item_rule = lambda item: item.name != "Progressive Sword" @@ -420,14 +696,15 @@ def fill_slot_data(self): shuffled_pieces = (12 - shp) % 4 return { "skullsanity": self.options.skullsanity.value, - "fairysanity": self.options.fairysanity.value, + "shuffle_stray_fairies": self.options.shuffle_stray_fairies.value, "shopsanity": self.options.shopsanity.value, "scrubsanity": self.options.scrubsanity.value, "shop_prices": self.prices, "shop_prices_ints": self.prices_ints, "cowsanity": self.options.cowsanity.value, - "keysanity": self.options.keysanity.value, - "bosskeysanity": self.options.bosskeysanity.value, + "shuffle_maps_and_compasses": self.options.shuffle_maps_and_compasses.value, + "shuffle_small_keys": self.options.shuffle_small_keys.value, + "shuffle_boss_keys": self.options.shuffle_boss_keys.value, "intro_checks": self.options.intro_checks.value, "curiostity_shop_trades": self.options.curiostity_shop_trades.value, "damage_multiplier": self.options.damage_multiplier.value, From 67fa1fe6e5f6b0bded371022c5f1117c1b28d244 Mon Sep 17 00:00:00 2001 From: G4M3R L1F3 Date: Sun, 17 May 2026 12:37:07 -0300 Subject: [PATCH 7/9] Added lottery shuffle option Currently untested --- worlds/mm_recomp/Items.py | 2 +- worlds/mm_recomp/Locations.py | 3 ++- worlds/mm_recomp/Options.py | 5 +++++ worlds/mm_recomp/__init__.py | 4 ++++ 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/worlds/mm_recomp/Items.py b/worlds/mm_recomp/Items.py index 73dd5e46..2be8d94d 100644 --- a/worlds/mm_recomp/Items.py +++ b/worlds/mm_recomp/Items.py @@ -524,7 +524,7 @@ class MMRItemData(NamedTuple): "Red Rupee": MMRItemData( code=0x3469420000004, type=ItemClassification.filler, - num_exist=30 + num_exist=29 # ~ num_exist=29 ), "Purple Rupee": MMRItemData( diff --git a/worlds/mm_recomp/Locations.py b/worlds/mm_recomp/Locations.py index 3b6ef08c..dfd81e81 100644 --- a/worlds/mm_recomp/Locations.py +++ b/worlds/mm_recomp/Locations.py @@ -359,7 +359,8 @@ def can_create_heart_location(shp, c_or_p, loc_index): ), "West Clock Town Lottery Any Day": MMRLocationData( region="Clock Town", - address=0x3469420080239 + address=0x3469420080239, + can_create=lambda options: options.shuffle_lottery.value ), "West Clock Town Swordsman Expert Course": MMRLocationData( region="Clock Town", diff --git a/worlds/mm_recomp/Options.py b/worlds/mm_recomp/Options.py index d4b25e07..527590d4 100644 --- a/worlds/mm_recomp/Options.py +++ b/worlds/mm_recomp/Options.py @@ -311,6 +311,10 @@ class ShuffleTreasureChestGame(Choice): option_everything = 2 default = 1 +class ShuffleLottery(Toggle): + """Choose whether to shuffle lottery reward or not.""" + display_name = "Shuffle Lottery" + class StartWithConsumables(DefaultOnToggle): """Choose whether to start with basic consumables (99 rupees, 10 deku sticks, 20 deku nuts).""" @@ -402,6 +406,7 @@ class MMROptions(PerGameCommonOptions): intro_checks: IntroChecks shuffle_minigames: ShuffleMinigames shuffle_treasure_chest_game: ShuffleTreasureChestGame + shuffle_lottery: ShuffleLottery start_with_consumables: StartWithConsumables permanent_chateau_romani: PermanentChateauRomani start_with_inverted_time: StartWithInvertedTime diff --git a/worlds/mm_recomp/__init__.py b/worlds/mm_recomp/__init__.py index 41db6126..8806d0e3 100644 --- a/worlds/mm_recomp/__init__.py +++ b/worlds/mm_recomp/__init__.py @@ -238,6 +238,9 @@ def create_items(self) -> None: elif self.options.shuffle_treasure_chest_game.value == 2: self.create_and_add_filler_items(4) + if self.options.shuffle_lottery.value: + self.create_and_add_filler_items(1) + if self.options.shuffle_maps_and_compasses.value == 0: self.create_and_add_filler_items(8) @@ -727,6 +730,7 @@ def fill_slot_data(self): "shuffle_great_fairy_rewards": self.options.shuffle_great_fairy_rewards.value, "shuffle_minigames": self.options.shuffle_minigames.value, "shuffle_treasure_chest_game": self.options.shuffle_treasure_chest_game.value, + "shuffle_lottery": self.options.shuffle_lottery.value, "link_tunic_color": ((self.options.link_tunic_color.value[0] & 0xFF) << 16) | ((self.options.link_tunic_color.value[1] & 0xFF) << 8) | (self.options.link_tunic_color.value[2] & 0xFF), "random_seed": self.random.getrandbits(32), "logic_difficulty": self.options.logic_difficulty.value From 26c5af849391c7918781f1bc6166d9b68bcda8df Mon Sep 17 00:00:00 2001 From: G4M3R L1F3 Date: Sun, 17 May 2026 13:52:17 -0300 Subject: [PATCH 8/9] Added beaver race shuffle option Currently untested. --- worlds/mm_recomp/Items.py | 2 +- worlds/mm_recomp/Locations.py | 6 ++++-- worlds/mm_recomp/Options.py | 12 ++++++++++++ worlds/mm_recomp/__init__.py | 6 ++++++ 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/worlds/mm_recomp/Items.py b/worlds/mm_recomp/Items.py index 2be8d94d..199919fe 100644 --- a/worlds/mm_recomp/Items.py +++ b/worlds/mm_recomp/Items.py @@ -518,7 +518,7 @@ class MMRItemData(NamedTuple): "Blue Rupee": MMRItemData( code=0x3469420000002, type=ItemClassification.filler, - num_exist=8 + num_exist=6 # ~ num_exist=6 ), "Red Rupee": MMRItemData( diff --git a/worlds/mm_recomp/Locations.py b/worlds/mm_recomp/Locations.py index dfd81e81..a719f532 100644 --- a/worlds/mm_recomp/Locations.py +++ b/worlds/mm_recomp/Locations.py @@ -1226,11 +1226,13 @@ def can_create_heart_location(shp, c_or_p, loc_index): ), "Beaver Bros. Race 1": MMRLocationData( region="Zora Cape", - address=0x346942009018D + address=0x346942009018D, + can_create=lambda options: options.shuffle_beaver_races.value ), "Beaver Bros. Race 2 HP": MMRLocationData( region="Zora Cape", - address=0x346942007018D + address=0x346942007018D, + can_create=lambda options: options.shuffle_beaver_races.value == 2 ), "Great Bay Great Fairy Reward": MMRLocationData( region="Zora Cape", diff --git a/worlds/mm_recomp/Options.py b/worlds/mm_recomp/Options.py index 527590d4..0050702d 100644 --- a/worlds/mm_recomp/Options.py +++ b/worlds/mm_recomp/Options.py @@ -311,6 +311,17 @@ class ShuffleTreasureChestGame(Choice): option_everything = 2 default = 1 +class ShuffleBeaverRace(Range): + """ + Choose how many beaver race rewards are shuffled. + + Valid amounts are within the range 0-2. + """ + display_name = "Shuffle Beaver Race" + range_start = 0 + range_end = 2 + default = 0 + class ShuffleLottery(Toggle): """Choose whether to shuffle lottery reward or not.""" display_name = "Shuffle Lottery" @@ -406,6 +417,7 @@ class MMROptions(PerGameCommonOptions): intro_checks: IntroChecks shuffle_minigames: ShuffleMinigames shuffle_treasure_chest_game: ShuffleTreasureChestGame + shuffle_beaver_races: ShuffleBeaverRace shuffle_lottery: ShuffleLottery start_with_consumables: StartWithConsumables permanent_chateau_romani: PermanentChateauRomani diff --git a/worlds/mm_recomp/__init__.py b/worlds/mm_recomp/__init__.py index 8806d0e3..0159f3f4 100644 --- a/worlds/mm_recomp/__init__.py +++ b/worlds/mm_recomp/__init__.py @@ -238,6 +238,11 @@ def create_items(self) -> None: elif self.options.shuffle_treasure_chest_game.value == 2: self.create_and_add_filler_items(4) + if self.options.shuffle_beaver_races.value: + self.create_and_add_filler_items(1) + if self.options.shuffle_beaver_races.value == 2: + self.create_and_add_filler_items(1) + if self.options.shuffle_lottery.value: self.create_and_add_filler_items(1) @@ -730,6 +735,7 @@ def fill_slot_data(self): "shuffle_great_fairy_rewards": self.options.shuffle_great_fairy_rewards.value, "shuffle_minigames": self.options.shuffle_minigames.value, "shuffle_treasure_chest_game": self.options.shuffle_treasure_chest_game.value, + "shuffle_beaver_races": self.options.shuffle_beaver_races.value, "shuffle_lottery": self.options.shuffle_lottery.value, "link_tunic_color": ((self.options.link_tunic_color.value[0] & 0xFF) << 16) | ((self.options.link_tunic_color.value[1] & 0xFF) << 8) | (self.options.link_tunic_color.value[2] & 0xFF), "random_seed": self.random.getrandbits(32), From 26cc6e1ac8184c39c3cdc91a8f8885ac25a5efe6 Mon Sep 17 00:00:00 2001 From: G4M3R L1F3 Date: Mon, 18 May 2026 15:40:11 -0300 Subject: [PATCH 9/9] Added picture rewards shuffle option --- worlds/mm_recomp/Items.py | 4 ++-- worlds/mm_recomp/Locations.py | 15 ++++++++++----- worlds/mm_recomp/Options.py | 15 +++++++++++++++ worlds/mm_recomp/__init__.py | 6 ++++++ 4 files changed, 33 insertions(+), 7 deletions(-) diff --git a/worlds/mm_recomp/Items.py b/worlds/mm_recomp/Items.py index 199919fe..52389f32 100644 --- a/worlds/mm_recomp/Items.py +++ b/worlds/mm_recomp/Items.py @@ -524,13 +524,13 @@ class MMRItemData(NamedTuple): "Red Rupee": MMRItemData( code=0x3469420000004, type=ItemClassification.filler, - num_exist=29 + num_exist=25 # ~ num_exist=29 ), "Purple Rupee": MMRItemData( code=0x3469420000005, type=ItemClassification.filler, - num_exist=11 + num_exist=10 ), "Silver Rupee": MMRItemData( code=0x3469420000006, diff --git a/worlds/mm_recomp/Locations.py b/worlds/mm_recomp/Locations.py index a719f532..8375ef80 100644 --- a/worlds/mm_recomp/Locations.py +++ b/worlds/mm_recomp/Locations.py @@ -571,15 +571,18 @@ def can_create_heart_location(shp, c_or_p, loc_index): ), "Southern Swamp Winning Picture": MMRLocationData( region="Southern Swamp", - address=0x34694200701C5 + address=0x34694200701C5, + can_create=lambda options: options.shuffle_picture_rewards ), "Southern Swamp Good Picture": MMRLocationData( region="Southern Swamp", - address=0x3469420071C54 + address=0x3469420071C54, + can_create=lambda options: options.shuffle_picture_rewards == 2 ), "Southern Swamp Okay Picture": MMRLocationData( region="Southern Swamp", - address=0x3469420071C52 + address=0x3469420071C52, + can_create=lambda options: options.shuffle_picture_rewards == 2 ), "Southern Swamp Witch Shop Item 1": MMRLocationData( region="Southern Swamp", @@ -1277,11 +1280,13 @@ def can_create_heart_location(shp, c_or_p, loc_index): ), "Zora Hall Good Picture of Lulu": MMRLocationData( region="Zora Hall", - address=0x3469420082284 + address=0x3469420082284, + can_create=lambda options: options.shuffle_picture_rewards == 2 ), "Zora Hall Bad Picture of Lulu": MMRLocationData( region="Zora Hall", - address=0x3469420082282 + address=0x3469420082282, + can_create=lambda options: options.shuffle_picture_rewards == 2 ), "Pirates' Fortress Sewers Cage HP": MMRLocationData( region="Pirates' Fortress Sewers", diff --git a/worlds/mm_recomp/Options.py b/worlds/mm_recomp/Options.py index 0050702d..371f9064 100644 --- a/worlds/mm_recomp/Options.py +++ b/worlds/mm_recomp/Options.py @@ -326,6 +326,20 @@ class ShuffleLottery(Toggle): """Choose whether to shuffle lottery reward or not.""" display_name = "Shuffle Lottery" +class ShufflePictureRewards(Choice): + """ + Choose whether the rewards for the Tourist Center picture contest and the Lulu fan are shuffled or not. + + disabled: Picture rewards will be disabled. + winning_only: Only the winning picture for the Tourist Center reward will be shuffled. + all_pictures: All picture rewards will be shuffled. + """ + display_name = "Shuffle Picture Rewards" + option_disabled = 0 + option_winning_only = 1 + option_all_pictures = 2 + default = 1 + class StartWithConsumables(DefaultOnToggle): """Choose whether to start with basic consumables (99 rupees, 10 deku sticks, 20 deku nuts).""" @@ -419,6 +433,7 @@ class MMROptions(PerGameCommonOptions): shuffle_treasure_chest_game: ShuffleTreasureChestGame shuffle_beaver_races: ShuffleBeaverRace shuffle_lottery: ShuffleLottery + shuffle_picture_rewards: ShufflePictureRewards start_with_consumables: StartWithConsumables permanent_chateau_romani: PermanentChateauRomani start_with_inverted_time: StartWithInvertedTime diff --git a/worlds/mm_recomp/__init__.py b/worlds/mm_recomp/__init__.py index 0159f3f4..b71ee92b 100644 --- a/worlds/mm_recomp/__init__.py +++ b/worlds/mm_recomp/__init__.py @@ -246,6 +246,11 @@ def create_items(self) -> None: if self.options.shuffle_lottery.value: self.create_and_add_filler_items(1) + if self.options.shuffle_picture_rewards.value: + self.create_and_add_filler_items(1) + if self.options.shuffle_picture_rewards.value == 2: + self.create_and_add_filler_items(4) + if self.options.shuffle_maps_and_compasses.value == 0: self.create_and_add_filler_items(8) @@ -736,6 +741,7 @@ def fill_slot_data(self): "shuffle_minigames": self.options.shuffle_minigames.value, "shuffle_treasure_chest_game": self.options.shuffle_treasure_chest_game.value, "shuffle_beaver_races": self.options.shuffle_beaver_races.value, + "shuffle_picture_rewards": self.options.shuffle_picture_rewards.value, "shuffle_lottery": self.options.shuffle_lottery.value, "link_tunic_color": ((self.options.link_tunic_color.value[0] & 0xFF) << 16) | ((self.options.link_tunic_color.value[1] & 0xFF) << 8) | (self.options.link_tunic_color.value[2] & 0xFF), "random_seed": self.random.getrandbits(32),