From 445674ec74db6b0d54b086112ed90ad9a7dd2235 Mon Sep 17 00:00:00 2001 From: Seatori <92278897+Seatori@users.noreply.github.com> Date: Tue, 10 Feb 2026 19:05:53 -0500 Subject: [PATCH 1/4] Initial Rulebuilder-based rules rewrite --- worlds/minecraft/Rules.py | 1081 +++++++++------------ worlds/minecraft/__init__.py | 4 +- worlds/minecraft/archipelago.json | 2 +- worlds/minecraft/test/TestAdvancements.py | 15 +- 4 files changed, 453 insertions(+), 649 deletions(-) diff --git a/worlds/minecraft/Rules.py b/worlds/minecraft/Rules.py index fa3a0e6045e0..9136967d1de7 100644 --- a/worlds/minecraft/Rules.py +++ b/worlds/minecraft/Rules.py @@ -1,6 +1,12 @@ from BaseClasses import CollectionState from worlds.generic.Rules import exclusion_rules +from Options import ExcludeLocations +from .Options import CombatDifficulty, DeathLink, HardAdvancements, StructureCompasses + +from rule_builder.options import OptionFilter +from rule_builder.rules import Has, CanReachRegion + from . import Constants from typing import TYPE_CHECKING @@ -8,651 +14,442 @@ from . import MinecraftWorld -# Helper functions -# moved from logicmixin - -def has_iron_ingots(world: "MinecraftWorld", state: CollectionState, player: int) -> bool: - return state.has('Progressive Tools', player) and state.has('Progressive Resource Crafting', player) - - -def has_copper_ingots(world: "MinecraftWorld", state: CollectionState, player: int) -> bool: - return state.has('Progressive Tools', player) and state.has('Progressive Resource Crafting', player) - - -def has_gold_ingots(world: "MinecraftWorld", state: CollectionState, player: int) -> bool: - return (state.has('Progressive Resource Crafting', player) - and ( - state.has('Progressive Tools', player, 2) - or state.can_reach_region('The Nether', player) - ) - ) - - -def has_diamond_pickaxe(world: "MinecraftWorld", state: CollectionState, player: int) -> bool: - return state.has('Progressive Tools', player, 3) and has_iron_ingots(world, state, player) - - -def craft_crossbow(world: "MinecraftWorld", state: CollectionState, player: int) -> bool: - return state.has('Archery', player) and has_iron_ingots(world, state, player) - - -def has_bottle(world: "MinecraftWorld", state: CollectionState, player: int) -> bool: - return state.has('Bottles', player) and state.has('Progressive Resource Crafting', player) - - -def has_spyglass(world: "MinecraftWorld", state: CollectionState, player: int) -> bool: - return (has_copper_ingots(world, state, player) - and state.has('Spyglass', player) - and can_adventure(world, state, player) - ) - - -def can_enchant(world: "MinecraftWorld", state: CollectionState, player: int) -> bool: - return state.has('Enchanting', player) and has_diamond_pickaxe(world, state, player) # mine obsidian and lapis - - -def can_use_anvil(world: "MinecraftWorld", state: CollectionState, player: int) -> bool: - return (state.has('Enchanting', player) - and state.has('Progressive Resource Crafting', player,2) - and has_iron_ingots(world, state, player) - ) - - -def fortress_loot(world: "MinecraftWorld", state: CollectionState, player: int) -> bool: # blaze rods, wither skulls - return state.can_reach_region('Nether Fortress', player) and basic_combat(world, state, player) - - -def can_excavate(world: "MinecraftWorld", state: CollectionState, player: int) -> bool: - return (has_copper_ingots(world, state, player) and state.has('Brush', player) - and can_adventure(world, state, player) - ) - - -def can_brew_potions(world: "MinecraftWorld", state: CollectionState, player: int) -> bool: - return state.has('Blaze Rods', player) and state.has('Brewing', player) and has_bottle(world, state, player) - -def can_piglin_trade(world: "MinecraftWorld", state: CollectionState, player: int) -> bool: - return (has_gold_ingots(world, state, player) - and ( - state.can_reach_region('The Nether', player) - or state.can_reach_region('Bastion Remnant', player) - )) - - -def overworld_villager(world: "MinecraftWorld", state: CollectionState, player: int) -> bool: - village_region = state.multiworld.get_region('Village', player).entrances[0].parent_region.name - if village_region == 'The Nether': # 2 options: cure zombie villager or build portal in village - return (state.can_reach_location('Zombie Doctor', player) - or ( - has_diamond_pickaxe(world, state, player) - and state.can_reach_region('Village', player) - )) - elif village_region == 'The End': - return state.can_reach_location('Zombie Doctor', player) - return state.can_reach_region('Village', player) - - -def enter_stronghold(world: "MinecraftWorld", state: CollectionState, player: int) -> bool: - return state.has('Blaze Rods', player) and state.has('Brewing', player) and state.has('3 Ender Pearls', player) - - -# Difficulty-dependent functions -def combat_difficulty(world: "MinecraftWorld", state: CollectionState, player: int) -> str: - return world.options.combat_difficulty.current_key - - -def can_adventure(world: "MinecraftWorld", state: CollectionState, player: int) -> bool: - death_link_check = not world.options.death_link or state.has('Bed', player) - if combat_difficulty(world, state, player) == 'easy': - return state.has('Progressive Weapons', player, 2) and has_iron_ingots(world, state, player) and death_link_check - elif combat_difficulty(world, state, player) == 'hard': - return True - return (state.has('Progressive Weapons', player) and death_link_check and - (state.has('Progressive Resource Crafting', player) or state.has('Campfire', player))) - - -def basic_combat(world: "MinecraftWorld", state: CollectionState, player: int) -> bool: - if combat_difficulty(world, state, player) == 'easy': - return (state.has('Progressive Weapons', player, 2) - and state.has('Progressive Armor', player) - and state.has('Shield', player) - and has_iron_ingots(world, state, player) - ) - elif combat_difficulty(world, state, player) == 'hard': - return True - return (state.has('Progressive Weapons', player) - and ( - state.has('Progressive Armor', player) - or state.has('Shield', player) - ) - and has_iron_ingots(world, state, player) - ) - - -def ominous_vaults(world: "MinecraftWorld", state: CollectionState, player: int) -> bool: - if combat_difficulty(world, state, player) == 'easy': - return (state.can_reach_region("Pillager Outpost", player) - and state.has('Progressive Weapons', player, 3) - and state.has('Progressive Armor', player, 2) - and state.has('Shield', player) - and state.has('Progressive Tools', player, 2) - and has_iron_ingots(world, state, player) - ) - elif combat_difficulty(world, state, player) == 'hard': - return (state.can_reach_region("Pillager Outpost", player) - and state.has('Progressive Weapons', player, 2) - and has_iron_ingots(world, state, player) - and ( - state.has('Progressive Armor', player) - or state.has('Shield', player) - ) - ) - return (state.can_reach_region("Pillager Outpost", player) - and state.has('Progressive Weapons', player, 2) - and has_iron_ingots(world, state, player) - and state.has('Progressive Armor', player) - and state.has('Shield', player) - ) - - -def complete_raid(world: "MinecraftWorld", state: CollectionState, player: int) -> bool: - reach_regions = (state.can_reach_region('Village', player) - and state.can_reach_region('Pillager Outpost', player)) - if combat_difficulty(world, state, player) == 'easy': - return (reach_regions - and state.has('Progressive Weapons', player, 3) - and state.has('Progressive Armor', player, 2) - and state.has('Shield', player) - and state.has('Archery', player) - and state.has('Progressive Tools', player, 2) - and has_iron_ingots(world, state, player) - ) - elif combat_difficulty(world, state, player) == 'hard': # might be too hard? - return (reach_regions - and state.has('Progressive Weapons', player, 2) - and has_iron_ingots(world, state, player) - and ( - state.has('Progressive Armor', player) - or state.has('Shield', player) - ) - ) - return (reach_regions - and state.has('Progressive Weapons', player, 2) - and has_iron_ingots(world, state, player) - and state.has('Progressive Armor', player) - and state.has('Shield', player) - ) - - -def can_kill_wither(world: "MinecraftWorld", state: CollectionState, player: int) -> bool: - normal_kill = (state.has("Progressive Weapons", player, 3) - and state.has("Progressive Armor", player, 2) - and can_brew_potions(world, state, player) - and can_enchant(world, state, player) - ) - if combat_difficulty(world, state, player) == 'easy': - return (fortress_loot(world, state, player) - and normal_kill - and state.has('Archery', player) - ) - elif combat_difficulty(world, state, player) == 'hard': # cheese kill using bedrock ceilings - return (fortress_loot(world, state, player) - and ( - normal_kill - or state.can_reach_region('The Nether', player) - or state.can_reach_region('The End', player) - ) - ) - - return fortress_loot(world, state, player) and normal_kill - - -def can_respawn_ender_dragon(world: "MinecraftWorld", state: CollectionState, player: int) -> bool: - return (state.can_reach_region('The Nether', player) - and state.can_reach_region('The End', player) - and state.has('Progressive Resource Crafting', player) # smelt sand into glass - ) - - -def can_kill_ender_dragon(world: "MinecraftWorld", state: CollectionState, player: int) -> bool: - if combat_difficulty(world, state, player) == 'easy': - return (state.has("Progressive Weapons", player, 3) - and state.has("Progressive Armor", player, 2) - and state.has('Archery', player) - and can_brew_potions(world, state, player) - and can_enchant(world, state, player) - ) - if combat_difficulty(world, state, player) == 'hard': - return ( - ( - state.has('Progressive Weapons', player, 2) - and state.has('Progressive Armor', player) - ) or ( - state.has('Progressive Weapons', player, 1) - and state.has('Bed', player) # who needs armor when you can respawn right outside the chamber - ) - ) - return (state.has('Progressive Weapons', player, 2) - and state.has('Progressive Armor', player) - and state.has('Archery', player) - ) - - -def has_structure_compass(world: "MinecraftWorld", state: CollectionState, entrance_name: str, player: int) -> bool: - if not world.options.structure_compasses: - return True - return state.has(f"Structure Compass ({state.multiworld.get_entrance(entrance_name, player).connected_region.name})", player) - - -def get_rules_lookup(world, player: int): - rules_lookup = { - "entrances": { - "Nether Portal": lambda state: state.has('Flint and Steel', player) - and ( - state.has('Bucket', player) - or state.has('Progressive Tools', player, 3) - ) - and has_iron_ingots(world, state, player), - "End Portal": lambda state: enter_stronghold(world, state, player) - and state.has('3 Ender Pearls', player, 4), - "Overworld Structure 1": lambda state: can_adventure(world, state, player) - and has_structure_compass(world, state, "Overworld Structure 1", player), - "Overworld Structure 2": lambda state: can_adventure(world, state, player) - and has_structure_compass(world, state, "Overworld Structure 2", player), - "Nether Structure 1": lambda state: can_adventure(world, state, player) - and has_structure_compass(world, state, "Nether Structure 1", player), - "Nether Structure 2": lambda state: can_adventure(world, state, player) - and has_structure_compass(world, state, "Nether Structure 2", player), - "The End Structure": lambda state: can_adventure(world, state, player) - and has_structure_compass(world, state, "The End Structure", player), - "Ocean": lambda state: can_adventure(world, state, player) - and has_structure_compass(world, state, "Ocean", player), - "Dark Forest": lambda state: can_adventure(world, state, player) - and has_structure_compass(world, state, "Dark Forest", player), - "Deep Dark": lambda state: can_adventure(world, state, player) - and has_iron_ingots(world, state, player) - and state.has("Progressive Tools", player, 2) - and has_structure_compass(world, state, "Deep Dark", player), - "Ruins": lambda state: can_adventure(world, state, player) - and has_structure_compass(world, state, "Ruins", player), - "Underground": lambda state: can_adventure(world, state, player) and state.has("Progressive Tools", player) - and has_structure_compass(world, state, "Underground", player) - }, - "locations": { - "Ender Dragon": lambda state: can_respawn_ender_dragon(world, state, player) - and can_kill_ender_dragon(world, state, player), - "Wither": lambda state: can_kill_wither(world, state, player), - "Blaze Rods": lambda state: fortress_loot(world, state, player), - "Who is Cutting Onions?": lambda state: can_piglin_trade(world, state, player), - "Oh Shiny": lambda state: can_piglin_trade(world, state, player), - "Suit Up": lambda state: state.has("Progressive Armor", player) - and has_iron_ingots(world, state, player), - "Very Very Frightening": lambda state: state.has("Channeling Book", player) - and can_use_anvil(world, state, player) - and can_enchant(world, state, player) - and overworld_villager(world, state, player), - "Hot Stuff": lambda state: state.has("Bucket", player) - and has_iron_ingots(world, state, player), - "Free the End": lambda state: can_respawn_ender_dragon(world, state, player) - and can_kill_ender_dragon(world, state, player), - "A Furious Cocktail": lambda state: (can_brew_potions(world, state, player) - and state.has("Fishing Rod", player) # Water Breathing - and state.can_reach_region("The Nether", player) # Regeneration, Fire Resistance, gold nuggets - and state.can_reach_region("Village", player) # Night Vision, Invisibility - and state.can_reach_location("Bring Home the Beacon", player) # Resistance - and can_adventure(world, state, player) - and state.can_reach_region("Trial Chambers", player) # Wind Charged - ), - "Bring Home the Beacon": lambda state: can_kill_wither(world, state, player) - and has_diamond_pickaxe(world, state, player) - and state.has("Progressive Resource Crafting", player, 2), - "Not Today, Thank You": lambda state: state.has("Shield", player) - and has_iron_ingots(world, state, player), - "Isn't It Iron Pick": lambda state: state.has("Progressive Tools", player, 2) - and has_iron_ingots(world, state, player), - "Local Brewery": lambda state: can_brew_potions(world, state, player), - "The Next Generation": lambda state: can_respawn_ender_dragon(world, state, player) - and can_kill_ender_dragon(world, state, player), - "Fishy Business": lambda state: state.has("Fishing Rod", player), - "This Boat Has Legs": lambda state: has_iron_ingots(world, state, player) - and state.has("Saddle", player) - and state.has("Fishing Rod", player), - "Sniper Duel": lambda state: state.has("Archery", player), - "Great View From Up Here": lambda state: basic_combat(world, state, player), - "How Did We Get Here?": lambda state: (can_brew_potions(world, state, player) - and has_gold_ingots(world, state, player) # Absorption - and state.can_reach_region('End City', player) # Levitation - and state.can_reach_region('The Nether', player) # potion ingredients - and state.can_reach_region('Ocean Monument', player) # Heart of the Sea, Dolphin's Grace, Mining Fatigue - and state.can_reach_region('Ancient City', player) # Darkness - and state.has("Fishing Rod", player) # Pufferfish, Nautilus Shells - and state.has("Archery", player) # Spectral Arrows - and state.can_reach_location("Bring Home the Beacon", player) # Haste - and state.can_reach_location("Hero of the Village", player)), # Bad Omen, Hero of the Village - "Bullseye": lambda state: state.has("Archery", player) - and state.has("Progressive Tools", player, 2) - and has_iron_ingots(world, state, player), - "Spooky Scary Skeleton": lambda state: basic_combat(world, state, player), - "Two by Two": lambda state: can_excavate(world, state, player) - and state.can_reach_region("Ocean Monument", player) # Sniffers - and state.has("Bucket", player) - and state.can_reach_region("Village", player) # Axolotls, Cats - and state.has("Brush", player), - "Two Birds, One Arrow": lambda state: craft_crossbow(world, state, player) - and can_enchant(world, state, player), - "Who's the Pillager Now?": lambda state: craft_crossbow(world, state, player), - "Getting an Upgrade": lambda state: state.has("Progressive Tools", player), - "Tactical Fishing": lambda state: state.has("Bucket", player) - and has_iron_ingots(world, state, player), - "Zombie Doctor": lambda state: can_brew_potions(world, state, player) - and has_gold_ingots(world, state, player), - "Ice Bucket Challenge": lambda state: has_diamond_pickaxe(world, state, player), - "Into Fire": lambda state: basic_combat(world, state, player), - "War Pigs": lambda state: basic_combat(world, state, player), - "Take Aim": lambda state: state.has("Archery", player), - "Total Beelocation": lambda state: state.has("Silk Touch Book", player) - and can_use_anvil(world, state, player) - and can_enchant(world, state, player), - "Arbalistic": lambda state: (craft_crossbow(world, state, player) - and state.has("Piercing IV Book", player) - and can_use_anvil(world, state, player) - and can_enchant(world, state, player) - ), - "The End... Again...": lambda state: can_respawn_ender_dragon(world, state, player) - and can_kill_ender_dragon(world, state, player), - "Acquire Hardware": lambda state: has_iron_ingots(world, state, player), - "Not Quite \"Nine\" Lives": lambda state: can_piglin_trade(world, state, player) - and state.has("Progressive Resource Crafting", player, 2), - "Cover Me with Diamonds": lambda state: state.has("Progressive Armor", player, 2) - and state.has("Progressive Tools", player, 2) - and has_iron_ingots(world, state, player), - "Sky's the Limit": lambda state: basic_combat(world, state, player), - "Hired Help": lambda state: state.has("Progressive Resource Crafting", player, 2) - and has_iron_ingots(world, state, player), - "Sweet Dreams": lambda state: state.has("Bed", player) - or state.can_reach_region('Village', player), - "You Need a Mint": lambda state: can_respawn_ender_dragon(world, state, player) - and has_bottle(world, state, player), - "Monsters Hunted": lambda state: can_respawn_ender_dragon(world, state, player) # Ghast, Hoglin, Magma Cube, Piglin - and can_kill_ender_dragon(world, state, player) # Ender Dragon, Enderman, Endermite, Silverfish - and can_kill_wither(world, state, player) # Blaze, Wither, Wither Skeleton, Zombified Piglin - and complete_raid(world, state, player) # Ravagers; Pillager Outposts - and state.can_reach_region('Bastion Remnant', player) - and state.can_reach_region('End City', player) # Piglin Brute; Shulker - and state.has("Lead", player) # Zoglins - and state.can_reach_region('Ocean Monument', player) # Drowned - and ( - (can_brew_potions(world, state, player) and state.has("Fishing Rod", player)) # Water Breathing Potions for Elder Guardian, Guardian - or (can_enchant(world, state, player) and state.has("Bucket", player)) # Aqua Affinity/Respiration and Milk/Axolotls for Elder Guardian, Guardian - ), - "Enchanter": lambda state: can_enchant(world, state, player), - "Voluntary Exile": lambda state: basic_combat(world, state, player), - "Eye Spy": lambda state: enter_stronghold(world, state, player), - "Serious Dedication": lambda state: (state.can_reach_location("Hidden in the Depths", player) - and state.has("8 Netherite Scrap", player) - and has_gold_ingots(world, state, player)), - "Postmortal": lambda state: complete_raid(world, state, player), - "Adventuring Time": lambda state: can_adventure(world, state, player) - and has_iron_ingots(world, state, player) - and state.has("Progressive Tools", player, 2) - and state.can_reach_region('Ocean Monument', player) # Most Oceans - and state.can_reach_region('Woodland Mansion', player) # Dark Forest - and state.can_reach_region('Ancient City', player) # Deep Dark - and state.can_reach_region('Trail Ruins', player), # Jungle, Birch Forest, Old Growth Birch Forest, all Taiga variants - "Hero of the Village": lambda state: complete_raid(world, state, player), - "Hidden in the Depths": lambda state: can_brew_potions(world, state, player) - and state.has("Bed", player) - and has_diamond_pickaxe(world, state, player), - "Beaconator": lambda state: (can_kill_wither(world, state, player) - and has_diamond_pickaxe(world, state, player) - and state.has("Progressive Resource Crafting", player, 2)), - "Withering Heights": lambda state: can_kill_wither(world, state, player), - "A Balanced Diet": lambda state: (has_bottle(world, state, player) # honey bottle - and state.has("Campfire", player) # honey bottle - and state.has("Fishing Rod", player) - and state.can_reach_location("Overpowered", player) # gapple, notch apple - and state.can_reach_region('The End', player)), # chorus fruit - "Subspace Bubble": lambda state: has_diamond_pickaxe(world, state, player), - "Country Lode, Take Me Home": lambda state: state.has("Progressive Tools", player, 2) - and has_iron_ingots(world, state, player), - "Bee Our Guest": lambda state: state.has("Campfire", player) - and has_bottle(world, state, player), - "Uneasy Alliance": lambda state: has_diamond_pickaxe(world, state, player) - and state.has('Fishing Rod', player), - "Diamonds!": lambda state: state.has("Progressive Tools", player, 2) - and has_iron_ingots(world, state, player), - "A Throwaway Joke": lambda state: basic_combat(world, state, player), - "Sticky Situation": lambda state: state.has("Campfire", player) - and has_bottle(world, state, player), - "Ol' Betsy": lambda state: craft_crossbow(world, state, player), - "Cover Me in Debris": lambda state: state.has("Progressive Armor", player, 2) - and state.has("8 Netherite Scrap", player, 2) - and state.can_reach_location("Hidden in the Depths", player), - "Hot Topic": lambda state: state.has("Progressive Resource Crafting", player), - "The Lie": lambda state: has_iron_ingots(world, state, player) - and state.has("Bucket", player), - "On a Rail": lambda state: has_iron_ingots(world, state, player) - and state.has('Progressive Tools', player, 2), - "When Pigs Fly": lambda state: has_iron_ingots(world, state, player) - and state.has("Saddle", player) - and state.has("Fishing Rod", player) - and can_adventure(world, state, player), - "Overkill": lambda state: ( - can_brew_potions(world, state, player) - and ( - state.has("Progressive Weapons", player) - or state.can_reach_region('The Nether', player) - ) - ) - or ( - state.can_reach_location("Over-Overkill", player) - and world.options.include_hard_advancements - and "Over-Overkill" not in world.options.exclude_locations.value - ), - "Librarian": lambda state: state.has("Enchanting", player), - "Overpowered": lambda state: has_iron_ingots(world, state, player) - and state.has('Progressive Tools', player, 2) - and basic_combat(world, state, player), - "Wax On": lambda state: state.has('Campfire', player) - and has_copper_ingots(world, state, player), - "Wax Off": lambda state: ( - has_copper_ingots(world, state, player) - and state.has('Campfire', player) - ) - or state.can_reach_region("Trial Chambers", player), - "The Cutest Predator": lambda state: can_adventure(world, state, player) - and has_iron_ingots(world, state, player) - and state.has('Bucket', player), - "The Healing Power of Friendship": lambda state: can_adventure(world, state, player) - and has_iron_ingots(world, state, player) - and state.has('Bucket', player), - "Is It a Bird?": lambda state: has_spyglass(world, state, player), - "Is It a Balloon?": lambda state: has_spyglass(world, state, player), - "Is It a Plane?": lambda state: has_spyglass(world, state, player) - and can_respawn_ender_dragon(world, state, player), - "Surge Protector": lambda state: state.has("Channeling Book", player) - and can_use_anvil(world, state, player) - and can_enchant(world, state, player) - and overworld_villager(world, state, player), - "Light as a Rabbit": lambda state: can_adventure(world, state, player) - and has_iron_ingots(world, state, player) - and state.has('Bucket', player), - "Glow and Behold!": lambda state: can_adventure(world, state, player), - "Whatever Floats Your Goat!": lambda state: can_adventure(world, state, player), - "Caves & Cliffs": lambda state: has_iron_ingots(world, state, player) - and state.has('Bucket', player) - and state.has('Progressive Tools', player, 2), - "Feels Like Home": lambda state: has_iron_ingots(world, state, player) - and state.has('Bucket', player) - and state.has('Fishing Rod', player) - and state.has("Saddle", player), - "Sound of Music": lambda state: state.has("Progressive Tools", player, 2) - and has_iron_ingots(world, state, player) - and basic_combat(world, state, player), - "Star Trader": lambda state: has_iron_ingots(world, state, player) - and state.has('Bucket', player) - and ( - state.can_reach_region("The Nether", player) # soul sand in nether - or state.can_reach_region("Nether Fortress", player) # soul sand in fortress if not in nether for water elevator - or can_piglin_trade(world, state, player) # piglins give soul sand - ) - and overworld_villager(world, state, player), - "Birthday Song": lambda state: state.can_reach_location("The Lie", player) - and state.has("Progressive Tools", player, 2) - and has_iron_ingots(world, state, player) - and ( - state.can_reach_region('Pillager Outpost', player) - or state.can_reach_region('Woodland Mansion', player) - ), - "Bukkit Bukkit": lambda state: state.has("Bucket", player) - and has_iron_ingots(world, state, player) - and can_adventure(world, state, player), - "It Spreads": lambda state: can_adventure(world, state, player) - and has_iron_ingots(world, state, player) - and state.has("Progressive Tools", player, 2), - "Sneak 100": lambda state: can_adventure(world, state, player) - and has_iron_ingots(world, state, player) - and state.has("Progressive Tools", player, 2), - "When the Squad Hops into Town": lambda state: can_adventure(world, state, player) - and state.has("Lead", player) - and state.has("Bucket", player) - and has_iron_ingots(world, state, player), - "With Our Powers Combined!": lambda state: can_adventure(world, state, player) - and state.has("Lead", player) - and state.has("Bucket", player) - and has_iron_ingots(world, state, player), - "You've Got a Friend in Me": lambda state: state.can_reach_region('Pillager Outpost', player) - or ( - basic_combat(world, state, player) - and state.can_reach_region('Woodland Mansion', player) - ), - "Smells Interesting": lambda state: can_excavate(world, state, player), - "Little Sniffs": lambda state: can_excavate(world, state, player), - "Planting the Past": lambda state: can_excavate(world, state, player), - "Crafting a New Look": lambda state: has_iron_ingots(world, state, player) # Maybe streamline this one - and ( - fortress_loot(world, state, player) - or ( - state.can_reach_region("Pillager Outpost", player) - and basic_combat(world, state, player) - ) - or ( - state.can_reach_region("Bastion Remnant", player) - and basic_combat(world, state, player) - ) - or ( - state.can_reach_region("End City", player) - and basic_combat(world, state, player) - ) - or ( - state.can_reach_region("Ocean Monument", player) - and basic_combat(world, state, player) - and ( - ( - state.has("Fishing Rod", player) - and can_enchant(world, state, player) - ) - or ( - state.has("Bucket", player) - and can_brew_potions(world, state, player) - ) - ) - ) - or ( - state.can_reach_region("Woodland Mansion", player) - and basic_combat(world, state, player) - ) - or state.can_reach_region("Ancient City", player) - or ( - state.can_reach_region("Trail Ruins", player) - and state.has("Brush", player) - ) - ), - "Smithing with Style": lambda state: can_excavate(world, state, player) # Wayfinder Armor Trim - and fortress_loot(world, state, player) # Rib Armor Trim - and state.can_reach_region("Bastion Remnant", player) # Snout Armor Trim - and state.can_reach_region("End City", player) # Spire Armor Trim - and ( - ( # Water Breathing Potions - state.has("Fishing Rod", player) - and can_brew_potions(world, state, player) - ) - or ( - state.has("Bucket", player) # Milk/Axolotls - and can_enchant(world, state, player) # Respiration - ) - ) - and state.can_reach_region("Woodland Mansion", player) # Vex Armor Trim - and state.can_reach_region("Ancient City", player) # Ward and Silence Armor Trims - and state.can_reach_region("Trail Ruins", player) - and state.can_reach_region("Ocean Monument", player), # Tide Armor Trim - "Respecting the Remnants": lambda state: can_excavate(world, state, player) - and ( - state.can_reach_region("Ocean Monument", player) - or state.can_reach_region("Trail Ruins", player) - ), - "Careful Restoration": lambda state: can_excavate(world, state, player) - and ( - state.can_reach_region("Ocean Monument", player) - or state.can_reach_region("Trail Ruins", player) - ), - "The Power of Books": lambda state: state.has("Progressive Tools", player, 2), - "Isn't It Scute?": lambda state: can_adventure(world, state, player) - and has_copper_ingots(world, state, player) - and state.has("Brush", player), - "Shear Brilliance": lambda state: can_adventure(world, state, player) - and has_copper_ingots(world, state, player) - and state.has("Brush", player), - "Good as New": lambda state: can_adventure(world, state, player) - and has_copper_ingots(world, state, player) - and state.has("Brush", player), - "The Whole Pack": lambda state: can_adventure(world, state, player), - "Under Lock and Key": lambda state: basic_combat(world, state, player), - "Blowback": lambda state: basic_combat(world, state, player), - "Who Needs Rockets?": lambda state: basic_combat(world, state, player), - "Crafters Crafting Crafters": lambda state: has_iron_ingots(world, state, player) - and state.has("Progressive Tools", player, 2), - "Lighten Up": lambda state: ( - fortress_loot(world, state, player) - and state.has("Progressive Tools", player, 2) - and state.has("Progressive Resource Crafting", player, 2) - ) - or state.can_reach_region("Trial Chambers", player), - "Over-Overkill": lambda state: ominous_vaults(world, state, player), - "Revaulting": lambda state: ominous_vaults(world, state, player), - "Stay Hydrated!": lambda state: state.can_reach_region("The Nether", player) - or can_piglin_trade(world, state, player), - "Heart Transplanter": lambda state: can_adventure(world, state, player) - and ( - ( - basic_combat(world, state, player) - and state.has("Progressive Resource Crafting", player, 2) - ) - or ( - state.has("Silk Touch Book", player) - and can_use_anvil(world, state, player) - and can_enchant(world, state, player) - ) - ) - } - } - return rules_lookup - - -def set_rules(self: "MinecraftWorld") -> None: +def set_all_rules(self: "MinecraftWorld") -> None: + set_main_rules(self) + set_special_rules(self) + + +def set_main_rules(self: "MinecraftWorld") -> None: + # new_world = self.get_entrance("New World") + nether_portal = self.get_entrance("Nether Portal") + end_portal = self.get_entrance("End Portal") + overworld_structure_1 = self.get_entrance("Overworld Structure 1") + overworld_structure_2 = self.get_entrance("Overworld Structure 2") + nether_structure_1 = self.get_entrance("Nether Structure 1") + nether_structure_2 = self.get_entrance("Nether Structure 2") + the_end_structure = self.get_entrance("The End Structure") + ocean = self.get_entrance("Ocean") + dark_forest = self.get_entrance("Dark Forest") + deep_dark = self.get_entrance("Deep Dark") + ruins = self.get_entrance("Ruins") + underground = self.get_entrance("Underground") + + nether = CanReachRegion("The Nether") + the_end = CanReachRegion("The End") + village = CanReachRegion("Village") + outpost = CanReachRegion("Pillager Outpost") + fortress = CanReachRegion("Nether Fortress") + bastion = CanReachRegion("Bastion Remnant") + end_city = CanReachRegion("End City") + monument = CanReachRegion("Ocean Monument") + mansion = CanReachRegion("Woodland Mansion") + ancient_city = CanReachRegion("Ancient City") + trail_ruins = CanReachRegion("Trail Ruins") + trial_chambers = CanReachRegion("Trial Chambers") + + stone_tools = Has("Progressive Tools") + furnace = Has("Progressive Resource Crafting") + iron_ingots = stone_tools & furnace + copper_ingots = iron_ingots + + iron_tools = Has("Progressive Tools", count=2) & iron_ingots + diamond_tools = Has("Progressive Tools", count=3) & iron_ingots + + stone_weapons = Has("Progressive Weapons") + iron_weapons = Has("Progressive Weapons", count=2) & iron_ingots + diamond_weapons = Has("Progressive Weapons", count=3) & iron_tools + + iron_armor = Has("Progressive Armor") & iron_ingots + diamond_armor = Has("Progressive Armor", count=2) & iron_tools + + bow = Has("Archery") + resource_blocks = Has("Progressive Resource Crafting", count=2) + crossbow = bow & iron_ingots + blaze_rods = Has("Blaze Rods") + brewing = Has("Brewing") & blaze_rods + can_enchant = Has("Enchanting") & diamond_tools + anvil = Has("Enchanting") & resource_blocks & iron_ingots + enchanted_books = can_enchant & anvil + bucket = Has("Bucket") & iron_ingots + flint_and_steel = Has("Flint and Steel") & iron_ingots + bed = Has("Bed") + bottles = Has("Bottles") & furnace + potions = brewing & bottles + shield = Has("Shield") & iron_ingots + fishing_rod = Has("Fishing Rod") + campfire = Has("Campfire") + netherite_scrap = Has("8 Netherite Scrap") + channeling = Has("Channeling Book") & enchanted_books + silk_touch = Has("Silk Touch Book") & enchanted_books + piercing_iv = Has("Piercing IV Book") & enchanted_books + ender_pearls = Has("3 Ender Pearls") + saddle = Has("Saddle") & iron_ingots + brush = Has("Brush") & copper_ingots + + gold_ingots = iron_tools | nether & Has("Progressive Resource Crafting") + ancient_debris = potions & bed & diamond_tools + eye_of_ender = ender_pearls & brewing + + piglin_bartering = gold_ingots & (nether | bastion) + + cure_zombie = potions & gold_ingots + + village_dimension = self.get_region("Village").entrances[0].parent_region.name + + if village_dimension == "The Nether": + overworld_villagers = cure_zombie | (village & diamond_tools) + elif village_dimension == "The End": + overworld_villagers = cure_zombie + else: + overworld_villagers = village | cure_zombie + + no_death_link = OptionFilter(DeathLink, False) + death_link_check = no_death_link | bed + + easy = OptionFilter(CombatDifficulty, CombatDifficulty.option_easy) + normal = OptionFilter(CombatDifficulty, CombatDifficulty.option_normal) + hard = OptionFilter(CombatDifficulty, CombatDifficulty.option_hard) + + easy_adventure = easy & iron_weapons & death_link_check + normal_adventure = normal & stone_weapons & (furnace | campfire) & death_link_check + can_adventure = easy_adventure | normal_adventure | hard + + spyglass = Has("Spyglass") & copper_ingots & can_adventure + lead = Has("Lead") & can_adventure + stronghold = eye_of_ender & can_adventure + + easy_combat = easy & iron_weapons & iron_armor & shield + normal_combat = normal & stone_weapons & (iron_armor | shield) + combat = easy_combat | normal_combat | hard + + loot_fortress = fortress & combat + enchanted_golden_apple = iron_tools & combat & bastion + + easy_ominous_vaults = easy & diamond_weapons & diamond_armor & shield + normal_ominous_vaults = normal & iron_weapons & iron_armor & shield + hard_ominous_vaults = hard & iron_weapons & (iron_armor | shield) + ominous_vaults = trial_chambers & outpost & (easy_ominous_vaults | normal_ominous_vaults | hard_ominous_vaults) + + hard_advancements = OptionFilter(HardAdvancements, True) + exclude_mace = [OptionFilter(ExcludeLocations, ExcludeLocations("Over-Overkill"))] + mace = ominous_vaults & hard_advancements & exclude_mace + + easy_raid = easy & diamond_weapons & diamond_armor & shield & bow + normal_raid = normal & iron_weapons & iron_armor & shield + hard_raid = hard & iron_weapons & (iron_armor | shield) + beat_raid = village & outpost & (easy_raid | normal_raid | hard_raid) + + basic_wither_kill = diamond_weapons & diamond_armor & potions & can_enchant + easy_wither = easy & basic_wither_kill & bow + normal_wither = normal & basic_wither_kill + hard_wither = hard & (basic_wither_kill | nether | the_end) + kill_wither = loot_fortress & (easy_wither | normal_wither | hard_wither) + + beacon = kill_wither & diamond_tools & resource_blocks + + respawn_dragon = the_end & nether & furnace + easy_dragon = easy & diamond_weapons & diamond_armor & bow & potions & can_enchant + normal_dragon = normal & iron_weapons & iron_armor & bow + hard_dragon = hard & ((iron_weapons & iron_armor) | (stone_weapons & bed)) + kill_dragon = respawn_dragon & (easy_dragon | normal_dragon | hard_dragon) + + no_compasses = OptionFilter(StructureCompasses, False) + + # entrances + + overworld_compass_1 = Has(f"Structure Compass ({overworld_structure_1.connected_region.name})") + overworld_compass_2 = Has(f"Structure Compass ({overworld_structure_2.connected_region.name})") + nether_compass_1 = Has(f"Structure Compass ({nether_structure_1.connected_region.name})") + nether_compass_2 = Has(f"Structure Compass ({nether_structure_2.connected_region.name})") + the_end_compass = Has(f"Structure Compass ({the_end_structure.connected_region.name})") + ocean_compass = Has(f"Structure Compass ({ocean.connected_region.name})") + dark_forest_compass = Has(f"Structure Compass ({dark_forest.connected_region.name})") + deep_dark_compass = Has(f"Structure Compass ({deep_dark.connected_region.name})") + ruins_compass = Has(f"Structure Compass ({ruins.connected_region.name})") + underground_compass = Has(f"Structure Compass ({underground.connected_region.name})") + + # self.set_rule(new_world, True_) + self.set_rule(nether_portal, flint_and_steel & (diamond_tools | bucket)) + self.set_rule(end_portal, stronghold & Has("3 Ender Pearls", count=4)) + self.set_rule(overworld_structure_1, can_adventure & (no_compasses | overworld_compass_1)) + self.set_rule(overworld_structure_2, can_adventure & (no_compasses | overworld_compass_2)) + self.set_rule(nether_structure_1, can_adventure & (no_compasses | nether_compass_1)) + self.set_rule(nether_structure_2, can_adventure & (no_compasses | nether_compass_2)) + self.set_rule(the_end_structure, can_adventure & (no_compasses | the_end_compass)) + self.set_rule(ocean, can_adventure & (no_compasses | ocean_compass)) + self.set_rule(dark_forest, can_adventure & (no_compasses | dark_forest_compass)) + self.set_rule(deep_dark, can_adventure & iron_tools & (no_compasses | deep_dark_compass)) + self.set_rule(ruins, can_adventure & (no_compasses | ruins_compass)) + self.set_rule(underground, can_adventure & stone_tools & (no_compasses | underground_compass)) + + # events + + defeat_ender_dragon = self.get_location("Ender Dragon") + defeat_wither = self.get_location("Wither") + obtain_blaze_rods = self.get_location("Blaze Rods") + + # locations + + who_is_cutting_onions = self.get_location("Who is Cutting Onions?") + oh_shiny = self.get_location("Oh Shiny") + suit_up = self.get_location("Suit Up") + very_very_frightening = self.get_location("Very Very Frightening") + hot_stuff = self.get_location("Hot Stuff") + free_the_end = self.get_location("Free the End") + a_furious_cocktail = self.get_location("A Furious Cocktail") + # best_friends_forever = self.get_location("Best Friends Forever") + bring_home_the_beacon = self.get_location("Bring Home the Beacon") + not_today_thank_you = self.get_location("Not Today, Thank You") + isnt_it_iron_pick = self.get_location("Isn't It Iron Pick") + local_brewery = self.get_location("Local Brewery") + the_next_generation = self.get_location("The Next Generation") + fishy_business = self.get_location("Fishy Business") + # hot_tourist_destinations = self.get_location("Hot Tourist Destinations") + this_boat_has_legs = self.get_location("This Boat Has Legs") + sniper_duel = self.get_location("Sniper Duel") + # enter_the_nether = self.get_location("Nether") + great_view_from_up_here = self.get_location("Great View From Up Here") + how_did_we_get_here = self.get_location("How Did We Get Here?") + bullseye = self.get_location("Bullseye") + spooky_scary_skeleton = self.get_location("Spooky Scary Skeleton") + two_by_two = self.get_location("Two by Two") + # stone_age = self.get_location("Stone Age") + two_birds_one_arrow = self.get_location("Two Birds, One Arrow") + # we_need_to_go_deeper = self.get_location("We Need to Go Deeper") + whos_the_pillager_now = self.get_location("Who's the Pillager Now?") + getting_an_upgrade = self.get_location("Getting an Upgrade") + tactical_fishing = self.get_location("Tactical Fishing") + zombie_doctor = self.get_location("Zombie Doctor") + # the_city_at_the_end_of_the_game = self.get_location("The City at the End of the Game") + ice_bucket_challenge = self.get_location("Ice Bucket Challenge") + # remote_getaway = self.get_location("Remote Getaway") + into_fire = self.get_location("Into Fire") + war_pigs = self.get_location("War Pigs") + take_aim = self.get_location("Take Aim") + total_beelocation = self.get_location("Total Beelocation") + arbalistic = self.get_location("Arbalistic") + the_end_again = self.get_location("The End... Again...") + acquire_hardware = self.get_location("Acquire Hardware") + not_quite_nine_lives = self.get_location("Not Quite \"Nine\" Lives") + cover_me_with_diamonds = self.get_location("Cover Me with Diamonds") + skys_the_limit = self.get_location("Sky's the Limit") + hired_help = self.get_location("Hired Help") + # return_to_sender = self.get_location("Return to Sender") + sweet_dreams = self.get_location("Sweet Dreams") + you_need_a_mint = self.get_location("You Need a Mint") + # adventure = self.get_location("Adventure") + monsters_hunted = self.get_location("Monsters Hunted") + enchanter = self.get_location("Enchanter") + voluntary_exile = self.get_location("Voluntary Exile") + eye_spy = self.get_location("Eye Spy") + # enter_the_end = self.get_location("The End") + serious_dedication = self.get_location("Serious Dedication") + postmortal = self.get_location("Postmortal") + # monster_hunter = self.get_location("Monster Hunter") + adventuring_time = self.get_location("Adventuring Time") + # a_seedy_place = self.get_location("A Seedy Place") + # those_were_the_days = self.get_location("Those Were the Days") + hero_of_the_village = self.get_location("Hero of the Village") + hidden_in_the_depths = self.get_location("Hidden in the Depths") + beaconator = self.get_location("Beaconator") + withering_heights = self.get_location("Withering Heights") + a_balanced_diet = self.get_location("A Balanced Diet") + subspace_bubble = self.get_location("Subspace Bubble") + # husbandry = self.get_location("Husbandry") + country_lode_take_me_home = self.get_location("Country Lode, Take Me Home") + bee_our_guest = self.get_location("Bee Our Guest") + what_a_deal = self.get_location("What a Deal!") + uneasy_alliance = self.get_location("Uneasy Alliance") + diamonds = self.get_location("Diamonds!") + # a_terrible_fortress = self.get_location("A Terrible Fortress") + a_throwaway_joke = self.get_location("A Throwaway Joke") + # minecraft = self.get_location("Minecraft") + sticky_situation = self.get_location("Sticky Situation") + ol_betsy = self.get_location("Ol' Betsy") + cover_me_in_debris = self.get_location("Cover Me in Debris") + # is_this_the_end = self.get_location("The End?") + # the_parrots_and_the_bats = self.get_location("The Parrots and the Bats") + # a_complete_catalogue = self.get_location("A Complete Catalogue") + # getting_wood = self.get_location("Getting Wood") + # time_to_mine = self.get_location("Time to Mine!") + hot_topic = self.get_location("Hot Topic") + # bake_bread = self.get_location("Bake Bread") + the_lie = self.get_location("The Lie") + on_a_rail = self.get_location("On a Rail") + # time_to_strike = self.get_location("Time to Strike!") + # cow_tipper = self.get_location("Cow Tipper") + when_pigs_fly = self.get_location("When Pigs Fly") + overkill = self.get_location("Overkill") + librarian = self.get_location("Librarian") + overpowered = self.get_location("Overpowered") + wax_on = self.get_location("Wax On") + wax_off = self.get_location("Wax Off") + the_cutest_predator = self.get_location("The Cutest Predator") + the_healing_power_of_friendship = self.get_location("The Healing Power of Friendship") + is_it_a_bird = self.get_location("Is It a Bird?") + is_it_a_balloon = self.get_location("Is It a Balloon?") + is_it_a_plane = self.get_location("Is It a Plane?") + surge_protector = self.get_location("Surge Protector") + light_as_a_rabbit = self.get_location("Light as a Rabbit") + glow_and_behold = self.get_location("Glow and Behold!") + whatever_floats_your_goat = self.get_location("Whatever Floats Your Goat!") + caves_and_cliffs = self.get_location("Caves & Cliffs") + feels_like_home = self.get_location("Feels Like Home") + sound_of_music = self.get_location("Sound of Music") + star_trader = self.get_location("Star Trader") + birthday_song = self.get_location("Birthday Song") + bukkit_bukkit = self.get_location("Bukkit Bukkit") + # it_spreads = self.get_location("It Spreads") + # sneak_100 = self.get_location("Sneak 100") + when_the_squad_hops_into_town = self.get_location("When the Squad Hops into Town") + with_our_powers_combined = self.get_location("With Our Powers Combined!") + youve_got_a_friend_in_me = self.get_location("You've Got a Friend in Me") + smells_interesting = self.get_location("Smells Interesting") + little_sniffs = self.get_location("Little Sniffs") + planting_the_past = self.get_location("Planting the Past") + crafting_a_new_look = self.get_location("Crafting a New Look") + smithing_with_style = self.get_location("Smithing with Style") + respecting_the_remnants = self.get_location("Respecting the Remnants") + careful_restoration = self.get_location("Careful Restoration") + the_power_of_books = self.get_location("The Power of Books") + isnt_it_scute = self.get_location("Isn't It Scute?") + shear_brilliance = self.get_location("Shear Brilliance") + good_as_new = self.get_location("Good as New") + the_whole_pack = self.get_location("The Whole Pack") + # minecraft_trials_edition = self.get_location("Minecraft: Trial(s) Edition") + under_lock_and_key = self.get_location("Under Lock and Key") + blowback = self.get_location("Blowback") + who_needs_rockets = self.get_location("Who Needs Rockets?") + crafters_crafting_crafters = self.get_location("Crafters Crafting Crafters") + lighten_up = self.get_location("Lighten Up") + over_overkill = self.get_location("Over-Overkill") + revaulting = self.get_location("Revaulting") + stay_hydrated = self.get_location("Stay Hydrated!") + heart_transplanter = self.get_location("Heart Transplanter") + + self.set_rule(defeat_ender_dragon, kill_dragon) + self.set_rule(defeat_wither, kill_wither) + self.set_rule(obtain_blaze_rods, loot_fortress) + self.set_rule(who_is_cutting_onions, piglin_bartering) + self.set_rule(oh_shiny, piglin_bartering) + self.set_rule(suit_up, iron_armor) + self.set_rule(very_very_frightening, channeling & overworld_villagers) + self.set_rule(hot_stuff, bucket) + self.set_rule(free_the_end, kill_dragon) + self.set_rule(a_furious_cocktail, potions & fishing_rod & nether & village & beacon & trial_chambers) + self.set_rule(bring_home_the_beacon, beacon) + self.set_rule(not_today_thank_you, shield) + self.set_rule(isnt_it_iron_pick, iron_tools) + self.set_rule(local_brewery, potions) + self.set_rule(the_next_generation, kill_dragon) + self.set_rule(fishy_business, fishing_rod) + self.set_rule(this_boat_has_legs, saddle & fishing_rod) + self.set_rule(sniper_duel, bow) + self.set_rule(great_view_from_up_here, combat) + self.set_rule(how_did_we_get_here, potions & end_city & nether & monument & ancient_city & fishing_rod & bow + & beacon & beat_raid) + self.set_rule(bullseye, bow & iron_tools) + self.set_rule(spooky_scary_skeleton, loot_fortress) + self.set_rule(two_by_two, brush & monument & bucket & village) + self.set_rule(two_birds_one_arrow, crossbow & can_enchant) + self.set_rule(whos_the_pillager_now, crossbow) + self.set_rule(getting_an_upgrade, stone_tools) + self.set_rule(tactical_fishing, bucket) + self.set_rule(zombie_doctor, cure_zombie) + self.set_rule(ice_bucket_challenge, diamond_tools) + self.set_rule(into_fire, loot_fortress) + self.set_rule(war_pigs, combat) + self.set_rule(take_aim, bow) + self.set_rule(total_beelocation, silk_touch) + self.set_rule(arbalistic, crossbow & piercing_iv) + self.set_rule(the_end_again, kill_dragon) + self.set_rule(acquire_hardware, iron_ingots) + self.set_rule(not_quite_nine_lives, piglin_bartering & resource_blocks) + self.set_rule(cover_me_with_diamonds, diamond_armor) + self.set_rule(skys_the_limit, combat) + self.set_rule(hired_help, resource_blocks & iron_ingots) + self.set_rule(sweet_dreams, bed | village) + self.set_rule(you_need_a_mint, respawn_dragon & bottles) + self.set_rule(monsters_hunted, kill_dragon & kill_wither & beat_raid & bastion & end_city & trial_chambers & lead + & monument & ((potions & fishing_rod) | (can_enchant & bucket))) + self.set_rule(enchanter, can_enchant) + self.set_rule(voluntary_exile, combat) + self.set_rule(eye_spy, stronghold) + self.set_rule(serious_dedication, ancient_debris & netherite_scrap & gold_ingots & diamond_tools) + self.set_rule(postmortal, beat_raid) + self.set_rule(adventuring_time, can_adventure & monument & mansion & ancient_city & trail_ruins) + self.set_rule(hero_of_the_village, beat_raid) + self.set_rule(hidden_in_the_depths, ancient_debris) + self.set_rule(beaconator, beacon) + self.set_rule(withering_heights, kill_wither) + self.set_rule(a_balanced_diet, bottles & campfire & fishing_rod & enchanted_golden_apple & the_end) + self.set_rule(subspace_bubble, diamond_tools) + self.set_rule(country_lode_take_me_home, iron_tools) + self.set_rule(bee_our_guest, campfire & bottles) + self.set_rule(what_a_deal, village | cure_zombie) + self.set_rule(uneasy_alliance, diamond_tools & fishing_rod) + self.set_rule(diamonds, iron_tools) + self.set_rule(a_throwaway_joke, combat) + self.set_rule(sticky_situation, campfire & bottles) + self.set_rule(ol_betsy, crossbow) + self.set_rule(cover_me_in_debris, diamond_armor & Has("8 Netherite Scrap", count=2) & ancient_debris) + self.set_rule(hot_topic, furnace) + self.set_rule(the_lie, bucket) + self.set_rule(on_a_rail, iron_tools) + self.set_rule(when_pigs_fly, saddle & fishing_rod & can_adventure) + self.set_rule(overkill, (potions & (stone_tools | nether)) | mace) + self.set_rule(librarian, Has("Enchanting")) + self.set_rule(overpowered, enchanted_golden_apple) + self.set_rule(wax_on, campfire & copper_ingots) + self.set_rule(wax_off, trial_chambers | (campfire & copper_ingots)) + self.set_rule(the_cutest_predator, can_adventure & bucket) + self.set_rule(the_healing_power_of_friendship, can_adventure & bucket) + self.set_rule(is_it_a_bird, spyglass) + self.set_rule(is_it_a_balloon, spyglass) + self.set_rule(is_it_a_plane, spyglass & respawn_dragon) + self.set_rule(surge_protector, channeling & overworld_villagers) + self.set_rule(light_as_a_rabbit, can_adventure & bucket) + self.set_rule(glow_and_behold, can_adventure) + self.set_rule(whatever_floats_your_goat, can_adventure) + self.set_rule(caves_and_cliffs, bucket & iron_tools) + self.set_rule(feels_like_home, bucket & fishing_rod & saddle) + self.set_rule(sound_of_music, iron_tools & combat) + self.set_rule(star_trader, overworld_villagers & bucket & (nether | fortress | piglin_bartering)) + self.set_rule(birthday_song, bucket & iron_tools & (outpost | mansion)) + self.set_rule(bukkit_bukkit, bucket & can_adventure) + self.set_rule(when_the_squad_hops_into_town, can_adventure & lead & bucket) + self.set_rule(with_our_powers_combined, can_adventure & lead & bucket) + self.set_rule(youve_got_a_friend_in_me, outpost | (combat & mansion)) + self.set_rule(smells_interesting, brush) + self.set_rule(little_sniffs, brush) + self.set_rule(planting_the_past, brush) + self.set_rule(crafting_a_new_look, iron_ingots + & (loot_fortress | ancient_city | (trail_ruins & brush) + | (combat & (outpost | bastion | end_city | mansion | (monument & bucket & can_enchant))))) + self.set_rule(smithing_with_style, iron_ingots & trail_ruins & brush & loot_fortress & bastion & end_city & mansion + & ancient_city & monument & ((fishing_rod & potions) | (bucket & can_enchant))) + self.set_rule(respecting_the_remnants, brush & (monument | trail_ruins)) + self.set_rule(careful_restoration, brush & (monument | trail_ruins)) + self.set_rule(the_power_of_books, iron_tools) + self.set_rule(isnt_it_scute, can_adventure & brush) + self.set_rule(shear_brilliance, can_adventure & brush & iron_ingots) + self.set_rule(good_as_new, can_adventure & brush) + self.set_rule(the_whole_pack, can_adventure) + self.set_rule(under_lock_and_key, combat) + self.set_rule(blowback, combat) + self.set_rule(who_needs_rockets, combat) + self.set_rule(crafters_crafting_crafters, iron_tools) + self.set_rule(lighten_up, trial_chambers | (loot_fortress & iron_tools & resource_blocks)) + self.set_rule(over_overkill, ominous_vaults) + self.set_rule(revaulting, ominous_vaults) + self.set_rule(stay_hydrated, nether | piglin_bartering) + self.set_rule(heart_transplanter, can_adventure & (silk_touch | (combat & resource_blocks))) + + +def set_special_rules(self: "MinecraftWorld") -> None: multiworld = self.multiworld player = self.player - rules_lookup = get_rules_lookup(self, player) - - # Set entrance rules - for entrance_name, rule in rules_lookup["entrances"].items(): - multiworld.get_entrance(entrance_name, player).access_rule = rule - - # Set location rules - for location_name, rule in rules_lookup["locations"].items(): - multiworld.get_location(location_name, player).access_rule = rule - # Set rules surrounding completion bosses = self.options.required_bosses postgame_advancements = set() diff --git a/worlds/minecraft/__init__.py b/worlds/minecraft/__init__.py index 9e68ce4185b5..675c12521ec0 100644 --- a/worlds/minecraft/__init__.py +++ b/worlds/minecraft/__init__.py @@ -14,7 +14,7 @@ from .Options import MinecraftOptions from .Structures import shuffle_structures from .ItemPool import build_item_pool, get_junk_item_names -from .Rules import set_rules +from .Rules import set_all_rules from ..LauncherComponents import icon_paths client_version = 9 @@ -204,7 +204,7 @@ def create_regions(self) -> None: def create_items(self) -> None: self.multiworld.itempool += build_item_pool(self) - set_rules = set_rules + set_rules = set_all_rules def generate_output(self, output_directory: str) -> None: data = self._get_mc_data() diff --git a/worlds/minecraft/archipelago.json b/worlds/minecraft/archipelago.json index 1cc62f2d31af..d0f1289c2109 100644 --- a/worlds/minecraft/archipelago.json +++ b/worlds/minecraft/archipelago.json @@ -5,6 +5,6 @@ "Seafo", "cjmang" ], - "minimum_ap_version": "0.6.3", + "minimum_ap_version": "0.6.7", "world_version": "2.0.0" } \ No newline at end of file diff --git a/worlds/minecraft/test/TestAdvancements.py b/worlds/minecraft/test/TestAdvancements.py index e5c8cd08da80..50f5cf46d958 100644 --- a/worlds/minecraft/test/TestAdvancements.py +++ b/worlds/minecraft/test/TestAdvancements.py @@ -657,10 +657,17 @@ def test_42048(self): ["Monsters Hunted", False, [], ['Archery']], ["Monsters Hunted", False, [], ['Enchanting']], ["Monsters Hunted", False, [], ['Lead']], - ["Monsters Hunted", True, ['Progressive Resource Crafting', 'Progressive Weapons', 'Progressive Weapons', 'Progressive Tools', - 'Flint and Steel', 'Bucket', 'Progressive Tools', 'Progressive Tools', 'Progressive Weapons', - 'Progressive Armor', 'Progressive Armor', 'Brewing', 'Bottles', 'Enchanting', - 'Shield', 'Archery', 'Lead', '3 Ender Pearls', '3 Ender Pearls', '3 Ender Pearls', '3 Ender Pearls']], + ["Monsters Hunted", False, [], ['Bucket', 'Fishing Rod']], + ["Monsters Hunted", True, ['Progressive Weapons', 'Progressive Weapons', 'Progressive Weapons', 'Lead', + 'Progressive Resource Crafting', 'Flint and Steel', 'Brewing', 'Bottles', + 'Progressive Tools', 'Progressive Tools', 'Progressive Tools', 'Enchanting', + 'Progressive Armor', 'Progressive Armor', 'Shield', 'Archery', 'Bucket', + '3 Ender Pearls', '3 Ender Pearls', '3 Ender Pearls', '3 Ender Pearls']], + ["Monsters Hunted", True, ['Progressive Weapons', 'Progressive Weapons', 'Progressive Weapons', 'Lead', + 'Progressive Resource Crafting', 'Flint and Steel', 'Brewing', 'Bottles', + 'Progressive Tools', 'Progressive Tools', 'Progressive Tools', 'Enchanting', + 'Progressive Armor', 'Progressive Armor', 'Shield', 'Archery', 'Fishing Rod', + '3 Ender Pearls', '3 Ender Pearls', '3 Ender Pearls', '3 Ender Pearls']], ]) def test_42049(self): From 6ece02018d2fa1963be6cee5d72439e9cdedefbf Mon Sep 17 00:00:00 2001 From: Seatori <92278897+Seatori@users.noreply.github.com> Date: Mon, 16 Feb 2026 04:14:45 -0500 Subject: [PATCH 2/4] More tweaks --- worlds/minecraft/Rules.py | 17 ++++++++--------- worlds/minecraft/test/TestAdvancements.py | 4 +--- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/worlds/minecraft/Rules.py b/worlds/minecraft/Rules.py index 9136967d1de7..8766db32c80a 100644 --- a/worlds/minecraft/Rules.py +++ b/worlds/minecraft/Rules.py @@ -63,12 +63,12 @@ def set_main_rules(self: "MinecraftWorld") -> None: diamond_armor = Has("Progressive Armor", count=2) & iron_tools bow = Has("Archery") - resource_blocks = Has("Progressive Resource Crafting", count=2) crossbow = bow & iron_ingots + resource_blocks = Has("Progressive Resource Crafting", count=2) blaze_rods = Has("Blaze Rods") brewing = Has("Brewing") & blaze_rods can_enchant = Has("Enchanting") & diamond_tools - anvil = Has("Enchanting") & resource_blocks & iron_ingots + anvil = resource_blocks & iron_ingots enchanted_books = can_enchant & anvil bucket = Has("Bucket") & iron_ingots flint_and_steel = Has("Flint and Steel") & iron_ingots @@ -84,10 +84,11 @@ def set_main_rules(self: "MinecraftWorld") -> None: piercing_iv = Has("Piercing IV Book") & enchanted_books ender_pearls = Has("3 Ender Pearls") saddle = Has("Saddle") & iron_ingots + lead = Has("Lead") brush = Has("Brush") & copper_ingots - gold_ingots = iron_tools | nether & Has("Progressive Resource Crafting") - ancient_debris = potions & bed & diamond_tools + gold_ingots = iron_tools | (nether & Has("Progressive Resource Crafting")) + ancient_debris = nether & potions & bed & diamond_tools eye_of_ender = ender_pearls & brewing piglin_bartering = gold_ingots & (nether | bastion) @@ -115,7 +116,6 @@ def set_main_rules(self: "MinecraftWorld") -> None: can_adventure = easy_adventure | normal_adventure | hard spyglass = Has("Spyglass") & copper_ingots & can_adventure - lead = Has("Lead") & can_adventure stronghold = eye_of_ender & can_adventure easy_combat = easy & iron_weapons & iron_armor & shield @@ -258,7 +258,7 @@ def set_main_rules(self: "MinecraftWorld") -> None: # husbandry = self.get_location("Husbandry") country_lode_take_me_home = self.get_location("Country Lode, Take Me Home") bee_our_guest = self.get_location("Bee Our Guest") - what_a_deal = self.get_location("What a Deal!") + # what_a_deal = self.get_location("What a Deal!") uneasy_alliance = self.get_location("Uneasy Alliance") diamonds = self.get_location("Diamonds!") # a_terrible_fortress = self.get_location("A Terrible Fortress") @@ -386,7 +386,6 @@ def set_main_rules(self: "MinecraftWorld") -> None: self.set_rule(subspace_bubble, diamond_tools) self.set_rule(country_lode_take_me_home, iron_tools) self.set_rule(bee_our_guest, campfire & bottles) - self.set_rule(what_a_deal, village | cure_zombie) self.set_rule(uneasy_alliance, diamond_tools & fishing_rod) self.set_rule(diamonds, iron_tools) self.set_rule(a_throwaway_joke, combat) @@ -413,9 +412,9 @@ def set_main_rules(self: "MinecraftWorld") -> None: self.set_rule(whatever_floats_your_goat, can_adventure) self.set_rule(caves_and_cliffs, bucket & iron_tools) self.set_rule(feels_like_home, bucket & fishing_rod & saddle) - self.set_rule(sound_of_music, iron_tools & combat) + self.set_rule(sound_of_music, can_adventure & iron_tools & (combat | nether | ancient_city)) self.set_rule(star_trader, overworld_villagers & bucket & (nether | fortress | piglin_bartering)) - self.set_rule(birthday_song, bucket & iron_tools & (outpost | mansion)) + self.set_rule(birthday_song, bucket & iron_tools & (outpost | (combat & mansion))) self.set_rule(bukkit_bukkit, bucket & can_adventure) self.set_rule(when_the_squad_hops_into_town, can_adventure & lead & bucket) self.set_rule(with_our_powers_combined, can_adventure & lead & bucket) diff --git a/worlds/minecraft/test/TestAdvancements.py b/worlds/minecraft/test/TestAdvancements.py index 50f5cf46d958..b9477e315009 100644 --- a/worlds/minecraft/test/TestAdvancements.py +++ b/worlds/minecraft/test/TestAdvancements.py @@ -1314,9 +1314,7 @@ def test_42105(self): ["Sound of Music", False, [], ["Progressive Tools"]], ["Sound of Music", False, [], ["Progressive Resource Crafting"]], ["Sound of Music", False, [], ["Progressive Weapons"]], - ["Sound of Music", False, [], ["Progressive Armor", "Shield"]], - ["Sound of Music", True, ["Progressive Tools", "Progressive Tools", "Progressive Resource Crafting", "Progressive Weapons", "Progressive Armor"]], - ["Sound of Music", True, ["Progressive Tools", "Progressive Tools", "Progressive Resource Crafting", "Progressive Weapons", "Shield"]], + ["Sound of Music", True, ["Progressive Tools", "Progressive Tools", "Progressive Resource Crafting", "Progressive Weapons"]], ]) # bucket, nether, villager From 320b0cb805176cf539df55c924c8d12758a13d83 Mon Sep 17 00:00:00 2001 From: Seatori <92278897+Seatori@users.noreply.github.com> Date: Thu, 26 Feb 2026 15:04:50 -0500 Subject: [PATCH 3/4] Resin Clump parity --- worlds/minecraft/docs/en_Minecraft.md | 1 + 1 file changed, 1 insertion(+) diff --git a/worlds/minecraft/docs/en_Minecraft.md b/worlds/minecraft/docs/en_Minecraft.md index 026c390fb100..751cb1aede4d 100644 --- a/worlds/minecraft/docs/en_Minecraft.md +++ b/worlds/minecraft/docs/en_Minecraft.md @@ -117,4 +117,5 @@ or after completing both conditions. * Emerald Block * Copper Ingot * Copper Block + * Resin Clump * Resin Block From 7156e23dd44d3567c2966b0c88b6557f740eac58 Mon Sep 17 00:00:00 2001 From: Seatori <92278897+Seatori@users.noreply.github.com> Date: Thu, 12 Mar 2026 16:55:56 -0400 Subject: [PATCH 4/4] 1.21.11 changes --- worlds/minecraft/Rules.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/worlds/minecraft/Rules.py b/worlds/minecraft/Rules.py index 8766db32c80a..dbe7cd7a3475 100644 --- a/worlds/minecraft/Rules.py +++ b/worlds/minecraft/Rules.py @@ -326,6 +326,7 @@ def set_main_rules(self: "MinecraftWorld") -> None: revaulting = self.get_location("Revaulting") stay_hydrated = self.get_location("Stay Hydrated!") heart_transplanter = self.get_location("Heart Transplanter") + mob_kabob = self.get_location("Mob Kabob") self.set_rule(defeat_ender_dragon, kill_dragon) self.set_rule(defeat_wither, kill_wither) @@ -350,7 +351,7 @@ def set_main_rules(self: "MinecraftWorld") -> None: & beacon & beat_raid) self.set_rule(bullseye, bow & iron_tools) self.set_rule(spooky_scary_skeleton, loot_fortress) - self.set_rule(two_by_two, brush & monument & bucket & village) + self.set_rule(two_by_two, brush & monument & bucket & village & fishing_rod) self.set_rule(two_birds_one_arrow, crossbow & can_enchant) self.set_rule(whos_the_pillager_now, crossbow) self.set_rule(getting_an_upgrade, stone_tools) @@ -443,6 +444,7 @@ def set_main_rules(self: "MinecraftWorld") -> None: self.set_rule(revaulting, ominous_vaults) self.set_rule(stay_hydrated, nether | piglin_bartering) self.set_rule(heart_transplanter, can_adventure & (silk_touch | (combat & resource_blocks))) + self.set_rule(mob_kabob, furnace) def set_special_rules(self: "MinecraftWorld") -> None: