diff --git a/BaseClasses.py b/BaseClasses.py index 2724bf29..13e7c508 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -147,6 +147,9 @@ class MultiWorld(): for option_set in Options.option_sets: for option in option_set: setattr(self, option, getattr(args, option, {})) + for world in AutoWorld.AutoWorldRegister.world_types.values(): + for option in world.options: + setattr(self, option, getattr(args, option, {})) for player in self.player_ids: self.custom_data[player] = {} self.worlds[player] = AutoWorld.AutoWorldRegister.world_types[self.game[player]](self, player) @@ -1501,22 +1504,14 @@ class Spoiler(object): outfile.write('Progression Balanced: %s\n' % ( 'Yes' if self.metadata['progression_balancing'][player] else 'No')) outfile.write('Accessibility: %s\n' % self.metadata['accessibility'][player]) - if player in self.world.hk_player_ids: - for hk_option in Options.hollow_knight_options: - res = getattr(self.world, hk_option)[player] - outfile.write(f'{hk_option+":":33}{res}\n') - - elif player in self.world.factorio_player_ids: - for f_option in Options.factorio_options: + options = self.world.worlds[player].options + if options: + for f_option in options: res = getattr(self.world, f_option)[player] outfile.write(f'{f_option+":":33}{bool_to_text(res) if type(res) == Options.Toggle else res.get_option_name()}\n') - elif player in self.world.minecraft_player_ids: - for mc_option in Options.minecraft_options: - res = getattr(self.world, mc_option)[player] - outfile.write(f'{mc_option+":":33}{bool_to_text(res) if type(res) == Options.Toggle else res.get_option_name()}\n') - elif player in self.world.alttp_player_ids: + if player in self.world.alttp_player_ids: for team in range(self.world.teams): outfile.write('%s%s\n' % ( f"Hash - {self.world.player_names[player][team]} (Team {team + 1}): " if diff --git a/Main.py b/Main.py index f21c50f8..c237cf6a 100644 --- a/Main.py +++ b/Main.py @@ -519,10 +519,9 @@ def main(args, seed=None): if player not in world.alttp_player_ids: connect_names[name] = (i, player) if world.hk_player_ids: - import Options for slot in world.hk_player_ids: slots_data = slot_data[slot] = {} - for option_name in Options.hollow_knight_options: + for option_name in world.worlds[slot].options: option = getattr(world, option_name)[slot] slots_data[option_name] = int(option.value) for slot in world.minecraft_player_ids: diff --git a/Mystery.py b/Mystery.py index 0109e515..60cedea7 100644 --- a/Mystery.py +++ b/Mystery.py @@ -548,35 +548,27 @@ def roll_settings(weights: dict, plando_options: typing.Set[str] = frozenset(("b if ret.game == "A Link to the Past": roll_alttp_settings(ret, game_weights, plando_options) - elif ret.game == "Hollow Knight": - for option_name, option in Options.hollow_knight_options.items(): - setattr(ret, option_name, option.from_any(get_choice(option_name, game_weights))) - elif ret.game == "Factorio": - for option_name, option in Options.factorio_options.items(): + elif ret.game in AutoWorldRegister.world_types: + for option_name, option in AutoWorldRegister.world_types[ret.game].options.items(): if option_name in game_weights: - if issubclass(option, Options.OptionDict): # get_choice should probably land in the Option class + if issubclass(option, Options.OptionDict): setattr(ret, option_name, option.from_any(game_weights[option_name])) else: setattr(ret, option_name, option.from_any(get_choice(option_name, game_weights))) else: setattr(ret, option_name, option(option.default)) - elif ret.game == "Minecraft": - for option_name, option in Options.minecraft_options.items(): - if option_name in game_weights: - setattr(ret, option_name, option.from_any(get_choice(option_name, game_weights))) - else: - setattr(ret, option_name, option(option.default)) - # bad hardcoded behavior to make this work for now - ret.plando_connections = [] - if "connections" in plando_options: - options = game_weights.get("plando_connections", []) - for placement in options: - if roll_percentage(get_choice("percentage", placement, 100)): - ret.plando_connections.append(PlandoConnection( - get_choice("entrance", placement), - get_choice("exit", placement), - get_choice("direction", placement, "both") - )) + if ret.game == "Minecraft": + # bad hardcoded behavior to make this work for now + ret.plando_connections = [] + if "connections" in plando_options: + options = game_weights.get("plando_connections", []) + for placement in options: + if roll_percentage(get_choice("percentage", placement, 100)): + ret.plando_connections.append(PlandoConnection( + get_choice("entrance", placement), + get_choice("exit", placement), + get_choice("direction", placement, "both") + )) else: raise Exception(f"Unsupported game {ret.game}") return ret diff --git a/Options.py b/Options.py index 5052a4fa..9a8d59e7 100644 --- a/Options.py +++ b/Options.py @@ -296,157 +296,12 @@ alttp_options: typing.Dict[str, type(Option)] = { "shop_item_slots": ShopItemSlots, } - - -hollow_knight_randomize_options: typing.Dict[str, type(Option)] = { - "RandomizeDreamers": DefaultOnToggle, - "RandomizeSkills": DefaultOnToggle, - "RandomizeCharms": DefaultOnToggle, - "RandomizeKeys": DefaultOnToggle, - "RandomizeGeoChests": Toggle, - "RandomizeMaskShards": DefaultOnToggle, - "RandomizeVesselFragments": DefaultOnToggle, - "RandomizeCharmNotches": Toggle, - "RandomizePaleOre": DefaultOnToggle, - "RandomizeRancidEggs": Toggle, - "RandomizeRelics": DefaultOnToggle, - "RandomizeMaps": Toggle, - "RandomizeStags": Toggle, - "RandomizeGrubs": Toggle, - "RandomizeWhisperingRoots": Toggle, - "RandomizeRocks": Toggle, - "RandomizeSoulTotems": Toggle, - "RandomizePalaceTotems": Toggle, - "RandomizeLoreTablets": Toggle, - "RandomizeLifebloodCocoons": Toggle, - "RandomizeFlames": Toggle -} - -hollow_knight_skip_options: typing.Dict[str, type(Option)] = { - "MILDSKIPS": Toggle, - "SPICYSKIPS": Toggle, - "FIREBALLSKIPS": Toggle, - "ACIDSKIPS": Toggle, - "SPIKETUNNELS": Toggle, - "DARKROOMS": Toggle, - "CURSED": Toggle, - "SHADESKIPS": Toggle, -} - -hollow_knight_options: typing.Dict[str, type(Option)] = {**hollow_knight_randomize_options, - **hollow_knight_skip_options} - - -class MaxSciencePack(Choice): - option_automation_science_pack = 0 - option_logistic_science_pack = 1 - option_military_science_pack = 2 - option_chemical_science_pack = 3 - option_production_science_pack = 4 - option_utility_science_pack = 5 - option_space_science_pack = 6 - default = 6 - - def get_allowed_packs(self): - return {option.replace("_", "-") for option, value in self.options.items() if value <= self.value} - \ - {"space-science-pack"} # with rocket launch being the goal, post-launch techs don't make sense - - -class TechCost(Choice): - option_very_easy = 0 - option_easy = 1 - option_kind = 2 - option_normal = 3 - option_hard = 4 - option_very_hard = 5 - option_insane = 6 - default = 3 - - -class FreeSamples(Choice): - option_none = 0 - option_single_craft = 1 - option_half_stack = 2 - option_stack = 3 - default = 3 - - -class TechTreeLayout(Choice): - option_single = 0 - option_small_diamonds = 1 - option_medium_diamonds = 2 - option_large_diamonds = 3 - option_small_pyramids = 4 - option_medium_pyramids = 5 - option_large_pyramids = 6 - option_small_funnels = 7 - option_medium_funnels = 8 - option_large_funnels = 9 - option_funnels = 4 - alias_pyramid = 6 - alias_funnel = 9 - default = 0 - - -class TechTreeInformation(Choice): - option_none = 0 - option_advancement = 1 - option_full = 2 - default = 2 - - -class RecipeTime(Choice): - option_vanilla = 0 - option_fast = 1 - option_normal = 2 - option_slow = 4 - option_chaos = 5 - - -class FactorioStartItems(OptionDict): - default = {"burner-mining-drill": 19, "stone-furnace": 19} - - -factorio_options: typing.Dict[str, type(Option)] = { - "max_science_pack": MaxSciencePack, - "tech_tree_layout": TechTreeLayout, - "tech_cost": TechCost, - "free_samples": FreeSamples, - "tech_tree_information": TechTreeInformation, - "starting_items": FactorioStartItems, - "recipe_time": RecipeTime, - "imported_blueprints": DefaultOnToggle, -} - - -class AdvancementGoal(Choice): - option_few = 0 - option_normal = 1 - option_many = 2 - default = 1 - - -class CombatDifficulty(Choice): - option_easy = 0 - option_normal = 1 - option_hard = 2 - default = 1 - - -minecraft_options: typing.Dict[str, type(Option)] = { - "advancement_goal": AdvancementGoal, - "combat_difficulty": CombatDifficulty, - "include_hard_advancements": Toggle, - "include_insane_advancements": Toggle, - "include_postgame_advancements": Toggle, - "shuffle_structures": Toggle -} - +# replace with World.options option_sets = ( - minecraft_options, - factorio_options, + # minecraft_options, + # factorio_options, alttp_options, - hollow_knight_options + # hollow_knight_options ) if __name__ == "__main__": diff --git a/test/hollow_knight/__init__.py b/test/hollow_knight/__init__.py index 39a155d0..d12f521c 100644 --- a/test/hollow_knight/__init__.py +++ b/test/hollow_knight/__init__.py @@ -1,3 +1,4 @@ +import worlds.hk.Options from BaseClasses import MultiWorld from worlds.hk.Regions import create_regions from worlds.hk import gen_hollow @@ -9,10 +10,9 @@ class TestVanilla(TestBase): def setUp(self): self.world = MultiWorld(1) self.world.game[1] = "Hollow Knight" - import Options - for hk_option in Options.hollow_knight_randomize_options: + for hk_option in worlds.hk.Options.hollow_knight_randomize_options: setattr(self.world, hk_option, {1: True}) - for hk_option, option in Options.hollow_knight_skip_options.items(): + for hk_option, option in worlds.hk.Options.hollow_knight_skip_options.items(): setattr(self.world, hk_option, {1: option.default}) create_regions(self.world, 1) gen_hollow(self.world, 1) \ No newline at end of file diff --git a/test/minecraft/TestMinecraft.py b/test/minecraft/TestMinecraft.py index 375de5f5..56ec7306 100644 --- a/test/minecraft/TestMinecraft.py +++ b/test/minecraft/TestMinecraft.py @@ -1,3 +1,4 @@ +import worlds.minecraft.Options from test.TestBase import TestBase from BaseClasses import MultiWorld from worlds.minecraft import minecraft_gen_item_pool @@ -31,9 +32,9 @@ class TestMinecraft(TestBase): exclusion_pools = ['hard', 'insane', 'postgame'] for pool in exclusion_pools: setattr(self.world, f"include_{pool}_advancements", [False, False]) - setattr(self.world, "advancement_goal", [0, Options.AdvancementGoal(value=0)]) + setattr(self.world, "advancement_goal", [0, worlds.minecraft.Options.AdvancementGoal(value=0)]) setattr(self.world, "shuffle_structures", [False, False]) - setattr(self.world, "combat_difficulty", [0, Options.CombatDifficulty(value=1)]) + setattr(self.world, "combat_difficulty", [0, worlds.minecraft.Options.CombatDifficulty(value=1)]) minecraft_create_regions(self.world, 1) link_minecraft_structures(self.world, 1) minecraft_gen_item_pool(self.world, 1) diff --git a/worlds/AutoWorld.py b/worlds/AutoWorld.py index d27b324b..8f94d257 100644 --- a/worlds/AutoWorld.py +++ b/worlds/AutoWorld.py @@ -27,6 +27,7 @@ class World(metaclass=AutoWorldRegister): world: MultiWorld player: int + options: dict = {} def __init__(self, world: MultiWorld, player: int): self.world = world diff --git a/worlds/alttp/Rom.py b/worlds/alttp/Rom.py index 591c4e5b..443b1f99 100644 --- a/worlds/alttp/Rom.py +++ b/worlds/alttp/Rom.py @@ -751,18 +751,11 @@ bonk_addresses = [0x4CF6C, 0x4CFBA, 0x4CFE0, 0x4CFFB, 0x4D018, 0x4D01B, 0x4D028, 0x4D3F8, 0x4D416, 0x4D420, 0x4D423, 0x4D42D, 0x4D449, 0x4D48C, 0x4D4D9, 0x4D4DC, 0x4D4E3, 0x4D504, 0x4D507, 0x4D55E, 0x4D56A] -def get_nonnative_item_sprite(game: str) -> int: + +def get_nonnative_item_sprite(item: str) -> int: return 0x6B # set all non-native sprites to Power Star as per 13 to 2 vote at # https://discord.com/channels/731205301247803413/827141303330406408/852102450822905886 -# def get_nonnative_item_sprite(game): -# game_to_id = { -# "Factorio": 0x09, # Hammer -# "Hollow Knight": 0x21, # Bug Catching Net -# "Minecraft": 0x13, # Shovel -# } -# return game_to_id.get(game, 0x6B) # default to Power Star - def patch_rom(world, rom, player, team, enemized): local_random = world.slot_seeds[player] @@ -1724,20 +1717,7 @@ def write_custom_shops(rom, world, player): if item is None: break if not item['item'] in item_table: # item not native to ALTTP - # This is a terrible way to do this, please fix later - from worlds.hk.Items import lookup_id_to_name as hk_lookup - from worlds.factorio.Technologies import lookup_id_to_name as factorio_lookup - from worlds.minecraft.Items import lookup_id_to_name as mc_lookup - item_name = item['item'] - if item_name in hk_lookup.values(): - item_game = 'Hollow Knight' - elif item_name in factorio_lookup.values(): - item_game = 'Factorio' - elif item_name in mc_lookup.values(): - item_game = 'Minecraft' - else: - item_game = 'Generic' - item_code = get_nonnative_item_sprite(item_game) + item_code = get_nonnative_item_sprite(item['item']) else: item_code = ItemFactory(item['item'], player).code if item['item'] == 'Single Arrow' and item['player'] == 0 and world.retro[player]: diff --git a/worlds/factorio/Mod.py b/worlds/factorio/Mod.py index 6d5a3d9e..cd50702e 100644 --- a/worlds/factorio/Mod.py +++ b/worlds/factorio/Mod.py @@ -9,7 +9,7 @@ import json import jinja2 import Utils import shutil -import Options +from . import Options from BaseClasses import MultiWorld from .Technologies import tech_table, rocket_recipes, recipes, free_sample_blacklist diff --git a/worlds/factorio/Options.py b/worlds/factorio/Options.py new file mode 100644 index 00000000..3647841c --- /dev/null +++ b/worlds/factorio/Options.py @@ -0,0 +1,85 @@ +import typing + +from Options import Choice, OptionDict, Option, DefaultOnToggle + + +class MaxSciencePack(Choice): + option_automation_science_pack = 0 + option_logistic_science_pack = 1 + option_military_science_pack = 2 + option_chemical_science_pack = 3 + option_production_science_pack = 4 + option_utility_science_pack = 5 + option_space_science_pack = 6 + default = 6 + + def get_allowed_packs(self): + return {option.replace("_", "-") for option, value in self.options.items() if value <= self.value} - \ + {"space-science-pack"} # with rocket launch being the goal, post-launch techs don't make sense + + +class TechCost(Choice): + option_very_easy = 0 + option_easy = 1 + option_kind = 2 + option_normal = 3 + option_hard = 4 + option_very_hard = 5 + option_insane = 6 + default = 3 + + +class FreeSamples(Choice): + option_none = 0 + option_single_craft = 1 + option_half_stack = 2 + option_stack = 3 + default = 3 + + +class TechTreeLayout(Choice): + option_single = 0 + option_small_diamonds = 1 + option_medium_diamonds = 2 + option_large_diamonds = 3 + option_small_pyramids = 4 + option_medium_pyramids = 5 + option_large_pyramids = 6 + option_small_funnels = 7 + option_medium_funnels = 8 + option_large_funnels = 9 + option_funnels = 4 + alias_pyramid = 6 + alias_funnel = 9 + default = 0 + + +class TechTreeInformation(Choice): + option_none = 0 + option_advancement = 1 + option_full = 2 + default = 2 + + +class RecipeTime(Choice): + option_vanilla = 0 + option_fast = 1 + option_normal = 2 + option_slow = 4 + option_chaos = 5 + + +class FactorioStartItems(OptionDict): + default = {"burner-mining-drill": 19, "stone-furnace": 19} + + +factorio_options: typing.Dict[str, type(Option)] = { + "max_science_pack": MaxSciencePack, + "tech_tree_layout": TechTreeLayout, + "tech_cost": TechCost, + "free_samples": FreeSamples, + "tech_tree_information": TechTreeInformation, + "starting_items": FactorioStartItems, + "recipe_time": RecipeTime, + "imported_blueprints": DefaultOnToggle, +} \ No newline at end of file diff --git a/worlds/factorio/Shapes.py b/worlds/factorio/Shapes.py index 481b64cf..4b8a3c3d 100644 --- a/worlds/factorio/Shapes.py +++ b/worlds/factorio/Shapes.py @@ -1,7 +1,6 @@ from typing import Dict, List, Set -from BaseClasses import MultiWorld -from Options import TechTreeLayout +from worlds.factorio.Options import TechTreeLayout funnel_layers = {TechTreeLayout.option_small_funnels: 3, TechTreeLayout.option_medium_funnels: 4, diff --git a/worlds/factorio/Technologies.py b/worlds/factorio/Technologies.py index 06e265b6..a00a189b 100644 --- a/worlds/factorio/Technologies.py +++ b/worlds/factorio/Technologies.py @@ -4,11 +4,12 @@ from typing import Dict, Set, FrozenSet import os import json -import Options import Utils import logging import functools +from . import Options + factorio_id = 2 ** 17 source_folder = Utils.local_path("data", "factorio") diff --git a/worlds/factorio/__init__.py b/worlds/factorio/__init__.py index f925f68a..ec6bf1da 100644 --- a/worlds/factorio/__init__.py +++ b/worlds/factorio/__init__.py @@ -5,7 +5,7 @@ from .Technologies import tech_table, recipe_sources, technology_table, advancem all_ingredient_names, required_technologies, get_rocket_requirements, rocket_recipes from .Shapes import get_shapes from .Mod import generate_mod - +from .Options import factorio_options class Factorio(World): game: str = "Factorio" @@ -80,6 +80,8 @@ class Factorio(World): world.completion_condition[player] = lambda state: state.has('Victory', player) + options = factorio_options + def set_custom_technologies(world: MultiWorld, player: int): custom_technologies = {} allowed_packs = world.max_science_pack[player].get_allowed_packs() diff --git a/worlds/hk/Options.py b/worlds/hk/Options.py new file mode 100644 index 00000000..e2be94fa --- /dev/null +++ b/worlds/hk/Options.py @@ -0,0 +1,39 @@ +import typing + +from Options import Option, DefaultOnToggle, Toggle + +hollow_knight_randomize_options: typing.Dict[str, type(Option)] = { + "RandomizeDreamers": DefaultOnToggle, + "RandomizeSkills": DefaultOnToggle, + "RandomizeCharms": DefaultOnToggle, + "RandomizeKeys": DefaultOnToggle, + "RandomizeGeoChests": Toggle, + "RandomizeMaskShards": DefaultOnToggle, + "RandomizeVesselFragments": DefaultOnToggle, + "RandomizeCharmNotches": Toggle, + "RandomizePaleOre": DefaultOnToggle, + "RandomizeRancidEggs": Toggle, + "RandomizeRelics": DefaultOnToggle, + "RandomizeMaps": Toggle, + "RandomizeStags": Toggle, + "RandomizeGrubs": Toggle, + "RandomizeWhisperingRoots": Toggle, + "RandomizeRocks": Toggle, + "RandomizeSoulTotems": Toggle, + "RandomizePalaceTotems": Toggle, + "RandomizeLoreTablets": Toggle, + "RandomizeLifebloodCocoons": Toggle, + "RandomizeFlames": Toggle +} +hollow_knight_skip_options: typing.Dict[str, type(Option)] = { + "MILDSKIPS": Toggle, + "SPICYSKIPS": Toggle, + "FIREBALLSKIPS": Toggle, + "ACIDSKIPS": Toggle, + "SPIKETUNNELS": Toggle, + "DARKROOMS": Toggle, + "CURSED": Toggle, + "SHADESKIPS": Toggle, +} +hollow_knight_options: typing.Dict[str, type(Option)] = {**hollow_knight_randomize_options, + **hollow_knight_skip_options} \ No newline at end of file diff --git a/worlds/minecraft/Options.py b/worlds/minecraft/Options.py new file mode 100644 index 00000000..8dd6ba2d --- /dev/null +++ b/worlds/minecraft/Options.py @@ -0,0 +1,27 @@ +import typing + +from Options import Choice, Option, Toggle + + +class AdvancementGoal(Choice): + option_few = 0 + option_normal = 1 + option_many = 2 + default = 1 + + +class CombatDifficulty(Choice): + option_easy = 0 + option_normal = 1 + option_hard = 2 + default = 1 + + +minecraft_options: typing.Dict[str, type(Option)] = { + "advancement_goal": AdvancementGoal, + "combat_difficulty": CombatDifficulty, + "include_hard_advancements": Toggle, + "include_insane_advancements": Toggle, + "include_postgame_advancements": Toggle, + "shuffle_structures": Toggle +} \ No newline at end of file diff --git a/worlds/minecraft/Rules.py b/worlds/minecraft/Rules.py index b4a58476..d986844f 100644 --- a/worlds/minecraft/Rules.py +++ b/worlds/minecraft/Rules.py @@ -1,17 +1,16 @@ from ..generic.Rules import set_rule from .Locations import exclusion_table, events_table -from BaseClasses import Region, Entrance, Location, MultiWorld, Item -from Options import AdvancementGoal +from BaseClasses import MultiWorld + def set_rules(world: MultiWorld, player: int): - def reachable_locations(state): postgame_advancements = set(exclusion_table['postgame'].keys()) postgame_advancements.add('Free the End') for event in events_table.keys(): postgame_advancements.add(event) - return [location for location in world.get_locations() if - (player is None or location.player == player) and + return [location for location in world.get_locations() if + (player is None or location.player == player) and (location.name not in postgame_advancements) and location.can_reach(state)] @@ -19,18 +18,22 @@ def set_rules(world: MultiWorld, player: int): goal_map = { 'few': 30, 'normal': 50, - 'many': 70 + 'many': 70 } goal = goal_map[getattr(world, 'advancement_goal')[player].get_option_name()] - can_complete = lambda state: len(reachable_locations(state)) >= goal and state.can_reach('The End', 'Region', player) and state.can_kill_ender_dragon(player) + can_complete = lambda state: len(reachable_locations(state)) >= goal and state.can_reach('The End', 'Region', + player) and state.can_kill_ender_dragon( + player) - if world.logic[player] != 'nologic': + if world.logic[player] != 'nologic': world.completion_condition[player] = lambda state: state.has('Victory', player) - set_rule(world.get_entrance("Nether Portal", player), lambda state: state.has('Flint and Steel', player) and - (state.has('Bucket', player) or state.has('Progressive Tools', player, 3)) and + set_rule(world.get_entrance("Nether Portal", player), lambda state: state.has('Flint and Steel', player) and + (state.has('Bucket', player) or state.has( + 'Progressive Tools', player, 3)) and state.has_iron_ingots(player)) - set_rule(world.get_entrance("End Portal", player), lambda state: state.enter_stronghold(player) and state.has('3 Ender Pearls', player, 4)) + set_rule(world.get_entrance("End Portal", player), + lambda state: state.enter_stronghold(player) and state.has('3 Ender Pearls', player, 4)) set_rule(world.get_entrance("Overworld Structure 1", player), lambda state: state.can_adventure(player)) set_rule(world.get_entrance("Overworld Structure 2", player), lambda state: state.can_adventure(player)) set_rule(world.get_entrance("Nether Structure 1", player), lambda state: state.can_adventure(player)) @@ -41,108 +44,178 @@ def set_rules(world: MultiWorld, player: int): set_rule(world.get_location("Who is Cutting Onions?", player), lambda state: state.can_piglin_trade(player)) set_rule(world.get_location("Oh Shiny", player), lambda state: state.can_piglin_trade(player)) - set_rule(world.get_location("Suit Up", player), lambda state: state.has("Progressive Armor", player) and state.has_iron_ingots(player)) - set_rule(world.get_location("Very Very Frightening", player), lambda state: state.has("Channeling Book", player) and state.can_use_anvil(player) and state.can_enchant(player) and \ - ((world.get_region('Village', player).entrances[0].parent_region.name != 'The End' and state.can_reach('Village', 'Region', player)) or state.can_reach('Zombie Doctor', 'Location', player))) # need villager into the overworld for lightning strike - set_rule(world.get_location("Hot Stuff", player), lambda state: state.has("Bucket", player) and state.has_iron_ingots(player)) - set_rule(world.get_location("Free the End", player), lambda state: can_complete(state) and state.has('Ingot Crafting', player) and state.can_reach('The Nether', 'Region', player)) - set_rule(world.get_location("A Furious Cocktail", player), lambda state: state.can_brew_potions(player) and - state.has("Fishing Rod", player) and # Water Breathing - state.can_reach('The Nether', 'Region', player) and # Regeneration, Fire Resistance, gold nuggets - state.can_reach('Village', 'Region', player) and # Night Vision, Invisibility - state.can_reach('Bring Home the Beacon', 'Location', player)) # Resistance + set_rule(world.get_location("Suit Up", player), + lambda state: state.has("Progressive Armor", player) and state.has_iron_ingots(player)) + set_rule(world.get_location("Very Very Frightening", player), + lambda state: state.has("Channeling Book", player) and state.can_use_anvil(player) and state.can_enchant( + player) and \ + ((world.get_region('Village', player).entrances[ + 0].parent_region.name != 'The End' and state.can_reach('Village', 'Region', + player)) or state.can_reach( + 'Zombie Doctor', 'Location', + player))) # need villager into the overworld for lightning strike + set_rule(world.get_location("Hot Stuff", player), + lambda state: state.has("Bucket", player) and state.has_iron_ingots(player)) + set_rule(world.get_location("Free the End", player), + lambda state: can_complete(state) and state.has('Ingot Crafting', player) and state.can_reach('The Nether', + 'Region', + player)) + set_rule(world.get_location("A Furious Cocktail", player), lambda state: state.can_brew_potions(player) and + state.has("Fishing Rod", + player) and # Water Breathing + state.can_reach('The Nether', 'Region', + player) and # Regeneration, Fire Resistance, gold nuggets + state.can_reach('Village', 'Region', + player) and # Night Vision, Invisibility + state.can_reach('Bring Home the Beacon', + 'Location', + player)) # Resistance set_rule(world.get_location("Best Friends Forever", player), lambda state: True) - set_rule(world.get_location("Bring Home the Beacon", player), lambda state: state.can_kill_wither(player) and state.has_diamond_pickaxe(player) and - state.has("Ingot Crafting", player) and state.has("Resource Blocks", player)) - set_rule(world.get_location("Not Today, Thank You", player), lambda state: state.has("Shield", player) and state.has_iron_ingots(player)) - set_rule(world.get_location("Isn't It Iron Pick", player), lambda state: state.has("Progressive Tools", player, 2) and state.has_iron_ingots(player)) + set_rule(world.get_location("Bring Home the Beacon", player), + lambda state: state.can_kill_wither(player) and state.has_diamond_pickaxe(player) and + state.has("Ingot Crafting", player) and state.has("Resource Blocks", player)) + set_rule(world.get_location("Not Today, Thank You", player), + lambda state: state.has("Shield", player) and state.has_iron_ingots(player)) + set_rule(world.get_location("Isn't It Iron Pick", player), + lambda state: state.has("Progressive Tools", player, 2) and state.has_iron_ingots(player)) set_rule(world.get_location("Local Brewery", player), lambda state: state.can_brew_potions(player)) set_rule(world.get_location("The Next Generation", player), lambda state: can_complete(state)) set_rule(world.get_location("Fishy Business", player), lambda state: state.has("Fishing Rod", player)) set_rule(world.get_location("Hot Tourist Destinations", player), lambda state: True) - set_rule(world.get_location("This Boat Has Legs", player), lambda state: (state.fortress_loot(player) or state.complete_raid(player)) and state.has("Fishing Rod", player)) + set_rule(world.get_location("This Boat Has Legs", player), + lambda state: (state.fortress_loot(player) or state.complete_raid(player)) and state.has("Fishing Rod", + player)) set_rule(world.get_location("Sniper Duel", player), lambda state: state.has("Archery", player)) set_rule(world.get_location("Nether", player), lambda state: True) set_rule(world.get_location("Great View From Up Here", player), lambda state: state.basic_combat(player)) - set_rule(world.get_location("How Did We Get Here?", player), lambda state: state.can_brew_potions(player) and state.has_gold_ingots(player) and # most effects; Absorption - state.can_reach('End City', 'Region', player) and state.can_reach('The Nether', 'Region', player) and # Levitation; potion ingredients - state.has("Fishing Rod", player) and state.has("Archery", player) and # Pufferfish, Nautilus Shells; spectral arrows - state.can_reach("Bring Home the Beacon", "Location", player) and # Haste - state.can_reach("Hero of the Village", "Location", player)) # Bad Omen, Hero of the Village - set_rule(world.get_location("Bullseye", player), lambda state: state.has("Archery", player) and state.has("Progressive Tools", player, 2) and state.has_iron_ingots(player)) + set_rule(world.get_location("How Did We Get Here?", player), + lambda state: state.can_brew_potions(player) and state.has_gold_ingots( + player) and # most effects; Absorption + state.can_reach('End City', 'Region', player) and state.can_reach('The Nether', 'Region', + player) and # Levitation; potion ingredients + state.has("Fishing Rod", player) and state.has("Archery", + player) and # Pufferfish, Nautilus Shells; spectral arrows + state.can_reach("Bring Home the Beacon", "Location", player) and # Haste + state.can_reach("Hero of the Village", "Location", player)) # Bad Omen, Hero of the Village + set_rule(world.get_location("Bullseye", player), + lambda state: state.has("Archery", player) and state.has("Progressive Tools", player, + 2) and state.has_iron_ingots(player)) set_rule(world.get_location("Spooky Scary Skeleton", player), lambda state: state.basic_combat(player)) - set_rule(world.get_location("Two by Two", player), lambda state: state.has_iron_ingots(player) and state.can_adventure(player)) # shears > seagrass > turtles; nether > striders; gold carrots > horses skips ingots + set_rule(world.get_location("Two by Two", player), + lambda state: state.has_iron_ingots(player) and state.can_adventure( + player)) # shears > seagrass > turtles; nether > striders; gold carrots > horses skips ingots set_rule(world.get_location("Stone Age", player), lambda state: True) - set_rule(world.get_location("Two Birds, One Arrow", player), lambda state: state.craft_crossbow(player) and state.can_enchant(player)) + set_rule(world.get_location("Two Birds, One Arrow", player), + lambda state: state.craft_crossbow(player) and state.can_enchant(player)) set_rule(world.get_location("We Need to Go Deeper", player), lambda state: True) set_rule(world.get_location("Who's the Pillager Now?", player), lambda state: state.craft_crossbow(player)) set_rule(world.get_location("Getting an Upgrade", player), lambda state: state.has("Progressive Tools", player)) - set_rule(world.get_location("Tactical Fishing", player), lambda state: state.has("Bucket", player) and state.has_iron_ingots(player)) - set_rule(world.get_location("Zombie Doctor", player), lambda state: state.can_brew_potions(player) and state.has_gold_ingots(player)) + set_rule(world.get_location("Tactical Fishing", player), + lambda state: state.has("Bucket", player) and state.has_iron_ingots(player)) + set_rule(world.get_location("Zombie Doctor", player), + lambda state: state.can_brew_potions(player) and state.has_gold_ingots(player)) set_rule(world.get_location("The City at the End of the Game", player), lambda state: True) set_rule(world.get_location("Ice Bucket Challenge", player), lambda state: state.has_diamond_pickaxe(player)) set_rule(world.get_location("Remote Getaway", player), lambda state: True) set_rule(world.get_location("Into Fire", player), lambda state: state.basic_combat(player)) set_rule(world.get_location("War Pigs", player), lambda state: state.basic_combat(player)) set_rule(world.get_location("Take Aim", player), lambda state: state.has("Archery", player)) - set_rule(world.get_location("Total Beelocation", player), lambda state: state.has("Silk Touch Book", player) and state.can_use_anvil(player) and state.can_enchant(player)) - set_rule(world.get_location("Arbalistic", player), lambda state: state.craft_crossbow(player) and state.has("Piercing IV Book", player) and - state.can_use_anvil(player) and state.can_enchant(player)) - set_rule(world.get_location("The End... Again...", player), lambda state: can_complete(state) and state.has("Ingot Crafting", player) and state.can_reach('The Nether', 'Region', player)) # furnace for glass, nether for ghast tears + set_rule(world.get_location("Total Beelocation", player), + lambda state: state.has("Silk Touch Book", player) and state.can_use_anvil(player) and state.can_enchant( + player)) + set_rule(world.get_location("Arbalistic", player), + lambda state: state.craft_crossbow(player) and state.has("Piercing IV Book", player) and + state.can_use_anvil(player) and state.can_enchant(player)) + set_rule(world.get_location("The End... Again...", player), + lambda state: can_complete(state) and state.has("Ingot Crafting", player) and state.can_reach('The Nether', + 'Region', + player)) # furnace for glass, nether for ghast tears set_rule(world.get_location("Acquire Hardware", player), lambda state: state.has_iron_ingots(player)) - set_rule(world.get_location("Not Quite \"Nine\" Lives", player), lambda state: state.can_piglin_trade(player) and state.has("Resource Blocks", player)) - set_rule(world.get_location("Cover Me With Diamonds", player), lambda state: state.has("Progressive Armor", player, 2) and state.can_reach("Diamonds!", "Location", player)) + set_rule(world.get_location("Not Quite \"Nine\" Lives", player), + lambda state: state.can_piglin_trade(player) and state.has("Resource Blocks", player)) + set_rule(world.get_location("Cover Me With Diamonds", player), + lambda state: state.has("Progressive Armor", player, 2) and state.can_reach("Diamonds!", "Location", + player)) set_rule(world.get_location("Sky's the Limit", player), lambda state: state.basic_combat(player)) - set_rule(world.get_location("Hired Help", player), lambda state: state.has("Resource Blocks", player) and state.has_iron_ingots(player)) + set_rule(world.get_location("Hired Help", player), + lambda state: state.has("Resource Blocks", player) and state.has_iron_ingots(player)) set_rule(world.get_location("Return to Sender", player), lambda state: True) - set_rule(world.get_location("Sweet Dreams", player), lambda state: state.has("Bed", player) or state.can_reach('Village', 'Region', player)) - set_rule(world.get_location("You Need a Mint", player), lambda state: can_complete(state) and state.has_bottle_mc(player)) + set_rule(world.get_location("Sweet Dreams", player), + lambda state: state.has("Bed", player) or state.can_reach('Village', 'Region', player)) + set_rule(world.get_location("You Need a Mint", player), + lambda state: can_complete(state) and state.has_bottle_mc(player)) set_rule(world.get_location("Adventure", player), lambda state: True) - set_rule(world.get_location("Monsters Hunted", player), lambda state: can_complete(state) and state.can_kill_wither(player) and state.has("Fishing Rod", player)) # pufferfish for Water Breathing + set_rule(world.get_location("Monsters Hunted", player), + lambda state: can_complete(state) and state.can_kill_wither(player) and state.has("Fishing Rod", + player)) # pufferfish for Water Breathing set_rule(world.get_location("Enchanter", player), lambda state: state.can_enchant(player)) set_rule(world.get_location("Voluntary Exile", player), lambda state: state.basic_combat(player)) set_rule(world.get_location("Eye Spy", player), lambda state: state.enter_stronghold(player)) set_rule(world.get_location("The End", player), lambda state: True) - set_rule(world.get_location("Serious Dedication", player), lambda state: state.can_reach("Hidden in the Depths", "Location", player) and state.has_gold_ingots(player)) + set_rule(world.get_location("Serious Dedication", player), + lambda state: state.can_reach("Hidden in the Depths", "Location", player) and state.has_gold_ingots( + player)) set_rule(world.get_location("Postmortal", player), lambda state: state.complete_raid(player)) set_rule(world.get_location("Monster Hunter", player), lambda state: True) set_rule(world.get_location("Adventuring Time", player), lambda state: state.can_adventure(player)) set_rule(world.get_location("A Seedy Place", player), lambda state: True) set_rule(world.get_location("Those Were the Days", player), lambda state: True) set_rule(world.get_location("Hero of the Village", player), lambda state: state.complete_raid(player)) - set_rule(world.get_location("Hidden in the Depths", player), lambda state: state.can_brew_potions(player) and state.has("Bed", player) and state.has_diamond_pickaxe(player)) # bed mining :) - set_rule(world.get_location("Beaconator", player), lambda state: state.can_kill_wither(player) and state.has_diamond_pickaxe(player) and - state.has("Ingot Crafting", player) and state.has("Resource Blocks", player)) + set_rule(world.get_location("Hidden in the Depths", player), + lambda state: state.can_brew_potions(player) and state.has("Bed", player) and state.has_diamond_pickaxe( + player)) # bed mining :) + set_rule(world.get_location("Beaconator", player), + lambda state: state.can_kill_wither(player) and state.has_diamond_pickaxe(player) and + state.has("Ingot Crafting", player) and state.has("Resource Blocks", player)) set_rule(world.get_location("Withering Heights", player), lambda state: state.can_kill_wither(player)) - set_rule(world.get_location("A Balanced Diet", player), lambda state: state.has_bottle_mc(player) and state.has_gold_ingots(player) and # honey bottle; gapple - state.has("Resource Blocks", player) and state.can_reach('The End', 'Region', player)) # notch apple, chorus fruit + set_rule(world.get_location("A Balanced Diet", player), + lambda state: state.has_bottle_mc(player) and state.has_gold_ingots(player) and # honey bottle; gapple + state.has("Resource Blocks", player) and state.can_reach('The End', 'Region', + player)) # notch apple, chorus fruit set_rule(world.get_location("Subspace Bubble", player), lambda state: state.has_diamond_pickaxe(player)) set_rule(world.get_location("Husbandry", player), lambda state: True) - set_rule(world.get_location("Country Lode, Take Me Home", player), lambda state: state.can_reach("Hidden in the Depths", "Location", player) and state.has_gold_ingots(player)) - set_rule(world.get_location("Bee Our Guest", player), lambda state: state.has("Campfire", player) and state.has_bottle_mc(player)) + set_rule(world.get_location("Country Lode, Take Me Home", player), + lambda state: state.can_reach("Hidden in the Depths", "Location", player) and state.has_gold_ingots( + player)) + set_rule(world.get_location("Bee Our Guest", player), + lambda state: state.has("Campfire", player) and state.has_bottle_mc(player)) set_rule(world.get_location("What a Deal!", player), lambda state: True) - set_rule(world.get_location("Uneasy Alliance", player), lambda state: state.has_diamond_pickaxe(player) and state.has('Fishing Rod', player)) - set_rule(world.get_location("Diamonds!", player), lambda state: state.has("Progressive Tools", player, 2) and state.has_iron_ingots(player)) - set_rule(world.get_location("A Terrible Fortress", player), lambda state: True) # since you don't have to fight anything - set_rule(world.get_location("A Throwaway Joke", player), lambda state: True) # kill drowned + set_rule(world.get_location("Uneasy Alliance", player), + lambda state: state.has_diamond_pickaxe(player) and state.has('Fishing Rod', player)) + set_rule(world.get_location("Diamonds!", player), + lambda state: state.has("Progressive Tools", player, 2) and state.has_iron_ingots(player)) + set_rule(world.get_location("A Terrible Fortress", player), + lambda state: True) # since you don't have to fight anything + set_rule(world.get_location("A Throwaway Joke", player), lambda state: True) # kill drowned set_rule(world.get_location("Minecraft", player), lambda state: True) - set_rule(world.get_location("Sticky Situation", player), lambda state: state.has("Campfire", player) and state.has_bottle_mc(player)) + set_rule(world.get_location("Sticky Situation", player), + lambda state: state.has("Campfire", player) and state.has_bottle_mc(player)) set_rule(world.get_location("Ol' Betsy", player), lambda state: state.craft_crossbow(player)) - set_rule(world.get_location("Cover Me in Debris", player), lambda state: state.has("Progressive Armor", player, 2) and - state.has("8 Netherite Scrap", player, 2) and state.has("Ingot Crafting", player) and - state.can_reach("Diamonds!", "Location", player) and state.can_reach("Hidden in the Depths", "Location", player)) + set_rule(world.get_location("Cover Me in Debris", player), + lambda state: state.has("Progressive Armor", player, 2) and + state.has("8 Netherite Scrap", player, 2) and state.has("Ingot Crafting", player) and + state.can_reach("Diamonds!", "Location", player) and state.can_reach("Hidden in the Depths", + "Location", player)) set_rule(world.get_location("The End?", player), lambda state: True) set_rule(world.get_location("The Parrots and the Bats", player), lambda state: True) - set_rule(world.get_location("A Complete Catalogue", player), lambda state: True) # kill fish for raw + set_rule(world.get_location("A Complete Catalogue", player), lambda state: True) # kill fish for raw set_rule(world.get_location("Getting Wood", player), lambda state: True) set_rule(world.get_location("Time to Mine!", player), lambda state: True) set_rule(world.get_location("Hot Topic", player), lambda state: state.has("Ingot Crafting", player)) set_rule(world.get_location("Bake Bread", player), lambda state: True) - set_rule(world.get_location("The Lie", player), lambda state: state.has_iron_ingots(player) and state.has("Bucket", player)) - set_rule(world.get_location("On a Rail", player), lambda state: state.has_iron_ingots(player) and state.has('Progressive Tools', player, 2)) # powered rails + set_rule(world.get_location("The Lie", player), + lambda state: state.has_iron_ingots(player) and state.has("Bucket", player)) + set_rule(world.get_location("On a Rail", player), + lambda state: state.has_iron_ingots(player) and state.has('Progressive Tools', player, 2)) # powered rails set_rule(world.get_location("Time to Strike!", player), lambda state: True) set_rule(world.get_location("Cow Tipper", player), lambda state: True) - set_rule(world.get_location("When Pigs Fly", player), lambda state: (state.fortress_loot(player) or state.complete_raid(player)) and state.has("Fishing Rod", player) and state.can_adventure(player)) - set_rule(world.get_location("Overkill", player), lambda state: state.can_brew_potions(player) and (state.has("Progressive Weapons", player) or state.can_reach('The Nether', 'Region', player))) # strength 1 + stone axe crit OR strength 2 + wood axe crit + set_rule(world.get_location("When Pigs Fly", player), + lambda state: (state.fortress_loot(player) or state.complete_raid(player)) and state.has("Fishing Rod", + player) and state.can_adventure( + player)) + set_rule(world.get_location("Overkill", player), lambda state: state.can_brew_potions(player) and ( + state.has("Progressive Weapons", player) or state.can_reach('The Nether', 'Region', + player))) # strength 1 + stone axe crit OR strength 2 + wood axe crit set_rule(world.get_location("Librarian", player), lambda state: state.has("Enchanting", player)) - set_rule(world.get_location("Overpowered", player), lambda state: state.has("Resource Blocks", player) and state.has_gold_ingots(player)) + set_rule(world.get_location("Overpowered", player), + lambda state: state.has("Resource Blocks", player) and state.has_gold_ingots(player)) diff --git a/worlds/minecraft/__init__.py b/worlds/minecraft/__init__.py index f81c2bcf..91d0f0db 100644 --- a/worlds/minecraft/__init__.py +++ b/worlds/minecraft/__init__.py @@ -1,16 +1,16 @@ -from random import Random from .Items import MinecraftItem, item_table, item_frequencies from .Locations import exclusion_table, events_table from .Regions import link_minecraft_structures from .Rules import set_rules from BaseClasses import MultiWorld -from Options import minecraft_options +from .Options import minecraft_options from ..AutoWorld import World class MinecraftWorld(World): game: str = "Minecraft" + options = minecraft_options client_version = (0, 3)