diff --git a/worlds/mm_recomp/Items.py b/worlds/mm_recomp/Items.py index 13b42b4c..f81f2966 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, @@ -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, @@ -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=8 # ~ num_exist=6 ), "Red Rupee": MMRItemData( code=0x3469420000004, type=ItemClassification.filler, - num_exist=45 + num_exist=30 # ~ num_exist=29 ), "Purple Rupee": MMRItemData( diff --git a/worlds/mm_recomp/Locations.py b/worlds/mm_recomp/Locations.py index ecd10792..3b6ef08c 100644 --- a/worlds/mm_recomp/Locations.py +++ b/worlds/mm_recomp/Locations.py @@ -283,35 +283,43 @@ 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", - 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", @@ -327,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", @@ -339,11 +349,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", @@ -523,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", @@ -733,7 +747,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)", @@ -777,7 +792,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 +1017,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", @@ -1179,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", @@ -1215,7 +1233,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", @@ -1477,7 +1496,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", @@ -1654,7 +1674,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..1ba2ca1e 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): @@ -167,9 +174,17 @@ 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): @@ -207,6 +222,34 @@ 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. + + 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).""" @@ -295,6 +338,8 @@ 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 start_with_inverted_time: StartWithInvertedTime diff --git a/worlds/mm_recomp/__init__.py b/worlds/mm_recomp/__init__.py index b2696ff3..71ab3352 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,19 @@ 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) + 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) def place(self, location, item): player = self.player @@ -98,12 +108,12 @@ 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: + + if self.options.shuffle_spiderhouse_reward.value != 1: mw.itempool.append(self.create_item("Progressive Wallet")) if self.options.shuffle_regional_maps.value == 1: @@ -120,22 +130,38 @@ 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) + + 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) + 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)): @@ -194,7 +220,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") @@ -204,9 +230,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") @@ -423,6 +448,8 @@ 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), "logic_difficulty": self.options.logic_difficulty.value