diff --git a/worlds/mm_recomp/Items.py b/worlds/mm_recomp/Items.py index 88b0dcb97967..9628208ea2b6 100644 --- a/worlds/mm_recomp/Items.py +++ b/worlds/mm_recomp/Items.py @@ -63,15 +63,10 @@ class MMRItemData(NamedTuple): ), "Heart Container": MMRItemData( code=0x3476942000000D, - type=ItemClassification.useful, + type=ItemClassification.filler, num_exist=12 #num_exist=4 ), - "Heart Container (Filler)": MMRItemData( - code=0x3476942000000D, - type=ItemClassification.filler, - num_exist=2 - ), "Swamp Skulltula Token": MMRItemData( code=0x34769420000052, type=ItemClassification.progression, @@ -246,7 +241,6 @@ class MMRItemData(NamedTuple): code=0x34769420000037, type=ItemClassification.progression, num_exist=2 - #num_exist=3 ), "Great Fairy Sword": MMRItemData( code=0x3476942000003B, diff --git a/worlds/mm_recomp/Locations.py b/worlds/mm_recomp/Locations.py index 73abed3a67df..16e57595ab1a 100644 --- a/worlds/mm_recomp/Locations.py +++ b/worlds/mm_recomp/Locations.py @@ -15,6 +15,10 @@ class MMRLocationData(NamedTuple): location_data_table: Dict[str, MMRLocationData] = { + "Link's Inventory (Kokiri Sword)": MMRLocationData( + region="Clock Town", + address=0x34769420000037 + ), "Keaton Quiz": MMRLocationData( region="Clock Town", address=0x3476942007028C @@ -91,7 +95,7 @@ class MMRLocationData(NamedTuple): region="Clock Town", address=0x347694200700B5 ), - "East Clock Town Treasure Game Chest": MMRLocationData( + "East Clock Town Treasure Game Chest (Goron)": MMRLocationData( region="Clock Town", address=0x34769420061700 ), diff --git a/worlds/mm_recomp/Options.py b/worlds/mm_recomp/Options.py index 99de230eb048..3d71352b5ee1 100644 --- a/worlds/mm_recomp/Options.py +++ b/worlds/mm_recomp/Options.py @@ -1,6 +1,8 @@ +from dataclasses import dataclass + from typing import Dict -from Options import Choice, Option, Toggle, StartInventoryPool, DeathLink +from Options import Choice, Option, Toggle, StartInventoryPool, DeathLink, PerGameCommonOptions #class HardMode(Toggle): @@ -29,10 +31,18 @@ class LogicDifficulty(Choice): """Set the logic difficulty used when generating.""" display_name = "Logic Difficulty" option_easy = 0 + #option_normal = 1 + #option_obscure_glitchless = 2 + #option_glitched = 3 option_no_logic = 4 default = 0 +class Swordless(Toggle): + """Start the game without a sword, and shuffle an extra Progressive Sword into the pool.""" + display_name = "Swordless" + + class ShuffleSwamphouseReward(Toggle): """Choose whether to shuffle the Mask of Truth given at the end of the Southern Swamphouse.""" display_name = "Shuffle Swamphouse Reward" @@ -61,12 +71,13 @@ class Fairysanity(Toggle): display_name = "Fairysanity" -mmr_options: Dict[str, type(Option)] = { - "start_inventory_from_pool": StartInventoryPool, - "logic_difficulty": LogicDifficulty, - "shuffle_swamphouse_reward": ShuffleSwamphouseReward, - "skullsanity": Skullsanity, - "shuffle_great_fairy_rewards": ShuffleGreatFairyRewards, - "fairysanity": Fairysanity, - "death_link": DeathLink -} +@dataclass +class MMROptions(PerGameCommonOptions): + start_inventory_from_pool: StartInventoryPool + logic_difficulty: LogicDifficulty + swordless: Swordless + shuffle_swamphouse_reward: ShuffleSwamphouseReward + skullsanity: Skullsanity + shuffle_great_fairy_rewards: ShuffleGreatFairyRewards + fairysanity: Fairysanity + death_link: DeathLink diff --git a/worlds/mm_recomp/Rules.py b/worlds/mm_recomp/Rules.py index 7d26c350b7a1..bb78cf7b3331 100644 --- a/worlds/mm_recomp/Rules.py +++ b/worlds/mm_recomp/Rules.py @@ -17,8 +17,11 @@ def has_bombchus(state, player): def has_explosives(state, player): return state.has("Progressive Bomb Bag", player) or has_bombchus(state, player) +def has_hard_projectiles(state, player): + return state.has("Progressive Bow", player) or state.has("Zora Mask", player) or state.has("Hookshot", player) + def has_projectiles(state, player): - return state.has("Progressive Bow", player) or (state.has("Deku Mask", player) and state.has("Progressive Magic Upgrade", player)) or state.has("Zora Mask", player) or state.has("Hookshot", player) + return (state.has("Deku Mask", player) and state.has("Progressive Magic Upgrade", player)) or has_hard_projectiles(state, player) def can_smack_hard(state, player): return state.has("Progressive Sword", player) or state.has("Fierce Deity's Mask", player) or state.has("Great Fairy Sword", player) or state.has("Goron Mask", player) or state.has("Zora Mask", player) @@ -70,7 +73,7 @@ def get_region_rules(player): "Clock Town -> The Moon": lambda state: state.has("Ocarina of Time", player) and state.has("Oath to Order", player) and state.has("Odolwa's Remains", player) and state.has("Goht's Remains", player) and state.has("Gyorg's Remains", player) and state.has("Twinmold's Remains", player), "Southern Swamp -> Southern Swamp (Deku Palace)": - lambda state: state.has("Bottle of Red Potion", player) or (has_projectiles(state, player) and state.has("Deku Mask", player)), # or state.has("Pictograph Box", player) + lambda state: state.has("Bottle of Red Potion", player) or (has_hard_projectiles(state, player) and state.has("Deku Mask", player)), # or state.has("Pictograph Box", player) "Southern Swamp (Deku Palace) -> Swamphouse": lambda state: state.has("Deku Mask", player) and can_use_fire_arrows(state, player), "Southern Swamp (Deku Palace) -> Deku Palace": @@ -143,7 +146,7 @@ def get_location_rules(player): lambda state: state.has("Progressive Bow", player) or state.has("Progressive Bomb Bag", player) or has_bombchus(state, player), "East Clock Town Honey and Darling All Days": lambda state: state.has("Progressive Bow", player) and state.has("Progressive Bomb Bag", player) and has_bombchus(state, player), - "East Clock Town Treasure Game Chest": + "East Clock Town Treasure Game Chest (Goron)": lambda state: state.has("Goron Mask", player), "East Clock Town Sewer Chest": lambda state: state.can_reach("Clock Town Hide-and-Seek", 'Location', player) and has_explosives(state, player), diff --git a/worlds/mm_recomp/__init__.py b/worlds/mm_recomp/__init__.py index c1d38d4fa547..790b2580964e 100644 --- a/worlds/mm_recomp/__init__.py +++ b/worlds/mm_recomp/__init__.py @@ -5,7 +5,7 @@ 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 -from .Options import mmr_options +from .Options import MMROptions from .Regions import region_data_table, get_exit from .Rules import * @@ -31,7 +31,8 @@ class MMRWorld(World): game = "Majora's Mask Recompiled" data_version = 1 web = MMRWebWorld() - option_definitions = mmr_options + options_dataclass = MMROptions + options = MMROptions location_name_to_id = location_table item_name_to_id = item_table @@ -57,7 +58,9 @@ def create_items(self) -> None: mw.push_precollected(self.create_item("Ocarina of Time")) mw.push_precollected(self.create_item("Song of Time")) - mw.push_precollected(self.create_item("Progressive Sword")) + + if self.options.swordless.value: + mw.itempool.append(self.create_item("Progressive Sword")) def create_regions(self) -> None: player = self.player @@ -120,6 +123,9 @@ def create_regions(self) -> None: mw.get_location("Woodfall Temple Final Room Left Upper Platform SF", player).place_locked_item(self.create_item("Stray Fairy (Woodfall)")) mw.get_location("Woodfall Temple Final Room Bubble SF", player).place_locked_item(self.create_item("Stray Fairy (Woodfall)")) + if not self.options.swordless.value: + mw.get_location("Link's Inventory (Kokiri Sword)", player).place_locked_item(self.create_item("Progressive Sword")) + # TODO: check options to see what player starts with mw.get_location("Top of Clock Tower (Ocarina of Time)", player).place_locked_item(self.create_item(self.get_filler_item_name())) mw.get_location("Top of Clock Tower (Song of Time)", player).place_locked_item(self.create_item(self.get_filler_item_name()))