diff --git a/BaseClasses.py b/BaseClasses.py index 884a31df..e03446de 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -880,13 +880,12 @@ class CollectionState(object): self.has('Progressive Armor', player) and self.has('Shield', player) def can_kill_wither(self, player: int): - build_wither = self.fortress_loot(player) and (self.can_reach('The Nether', 'Region', player) or self.can_piglin_trade(player)) normal_kill = self.has("Progressive Weapons", player, 3) and self.has("Progressive Armor", player, 2) and self.can_brew_potions(player) and self.can_enchant(player) if self.combat_difficulty(player) == 'easy': - return build_wither and normal_kill and self.has('Archery', player) + return self.fortress_loot(player) and normal_kill and self.has('Archery', player) elif self.combat_difficulty(player) == 'hard': # cheese kill using bedrock ceilings - return build_wither and (normal_kill or self.can_reach('The Nether', 'Region', player) or self.can_reach('The End', 'Region', player)) - return build_wither and normal_kill + return self.fortress_loot(player) and (normal_kill or self.can_reach('The Nether', 'Region', player) or self.can_reach('The End', 'Region', player)) + return self.fortress_loot(player) and normal_kill def can_kill_ender_dragon(self, player: int): if self.combat_difficulty(player) == 'easy': diff --git a/MultiMystery.py b/MultiMystery.py index 72e76560..e84b3bc3 100644 --- a/MultiMystery.py +++ b/MultiMystery.py @@ -40,6 +40,7 @@ if __name__ == "__main__": create_spoiler = multi_mystery_options["create_spoiler"] zip_roms = multi_mystery_options["zip_roms"] zip_diffs = multi_mystery_options["zip_diffs"] + zip_apmcs = multi_mystery_options["zip_apmcs"] zip_spoiler = multi_mystery_options["zip_spoiler"] zip_multidata = multi_mystery_options["zip_multidata"] zip_format = multi_mystery_options["zip_format"] @@ -132,7 +133,7 @@ if __name__ == "__main__": asyncio.run(MultiClient.run_game(os.path.join(output_path, file))) break - if any((zip_roms, zip_multidata, zip_spoiler, zip_diffs)): + if any((zip_roms, zip_multidata, zip_spoiler, zip_diffs, zip_apmcs)): import zipfile compression = {1: zipfile.ZIP_DEFLATED, @@ -177,6 +178,13 @@ if __name__ == "__main__": remove_zipped_file(file) + def _handle_apmc_file(file: str): + if zip_apmcs: + pack_file(file) + if zip_apmcs == 2: + remove_zipped_file(file) + + with concurrent.futures.ThreadPoolExecutor() as pool: futures = [] with zipfile.ZipFile(zipname, "w", compression=compression, compresslevel=9) as zf: @@ -186,6 +194,8 @@ if __name__ == "__main__": futures.append(pool.submit(_handle_sfc_file, file)) elif file.endswith(".apbp"): futures.append(pool.submit(_handle_diff_file, file)) + elif file.endswith(".apmc"): + futures.append(pool.submit(_handle_apmc_file, file)) if zip_multidata and os.path.exists(os.path.join(output_path, multidataname)): pack_file(multidataname) diff --git a/host.yaml b/host.yaml index 46e13d7f..89651ae8 100644 --- a/host.yaml +++ b/host.yaml @@ -81,6 +81,11 @@ multi_mystery_options: # -1 -> Create them without zipping # 2 -> Delete the non-zipped one. zip_diffs: 2 + # Zip apmc files for Minecraft + # 0 -> Don't zip + # 1 -> Create a zip + # 2 -> Create a zip and delete apmc files inside of it + zip_apmcs: 1 # Zip spoiler log # 1 -> Include the spoiler log in the zip # 2 -> Delete the non-zipped one diff --git a/test/minecraft/TestAdvancements.py b/test/minecraft/TestAdvancements.py index 2306f9e9..8f2ed075 100644 --- a/test/minecraft/TestAdvancements.py +++ b/test/minecraft/TestAdvancements.py @@ -89,15 +89,19 @@ class TestAdvancements(TestMinecraft): ["A Furious Cocktail", False, [], ['Brewing']], ["A Furious Cocktail", False, [], ['Bottles']], ["A Furious Cocktail", False, [], ['Fishing Rod']], - ["A Furious Cocktail", False, ['Progressive Tools', 'Progressive Tools'], ['Bucket', 'Progressive Tools']], - ["A Furious Cocktail", True, ['Ingot Crafting', 'Progressive Tools', 'Flint and Steel', 'Bucket', - 'Progressive Weapons', 'Progressive Armor', 'Brewing', 'Bottles', 'Fishing Rod']], + ["A Furious Cocktail", False, ['Progressive Tools', 'Progressive Tools'], ['Progressive Tools']], ["A Furious Cocktail", True, ['Ingot Crafting', 'Progressive Tools', 'Flint and Steel', 'Progressive Tools', 'Progressive Tools', - 'Progressive Weapons', 'Progressive Armor', 'Brewing', 'Bottles', 'Fishing Rod']], - ["A Furious Cocktail", True, ['Ingot Crafting', 'Progressive Tools', 'Flint and Steel', 'Bucket', - 'Progressive Weapons', 'Shield', 'Brewing', 'Bottles', 'Fishing Rod']], - ["A Furious Cocktail", True, ['Ingot Crafting', 'Progressive Tools', 'Flint and Steel', 'Progressive Tools', 'Progressive Tools', - 'Progressive Weapons', 'Shield', 'Brewing', 'Bottles', 'Fishing Rod']], + 'Progressive Weapons', 'Progressive Weapons', 'Progressive Weapons', + 'Progressive Armor', 'Progressive Armor', + 'Enchanting', 'Brewing', 'Bottles', 'Resource Blocks', 'Fishing Rod']], + # ["A Furious Cocktail", True, ['Ingot Crafting', 'Progressive Tools', 'Flint and Steel', 'Bucket', + # 'Progressive Weapons', 'Progressive Armor', 'Brewing', 'Bottles', 'Fishing Rod']], + # ["A Furious Cocktail", True, ['Ingot Crafting', 'Progressive Tools', 'Flint and Steel', 'Progressive Tools', 'Progressive Tools', + # 'Progressive Weapons', 'Progressive Armor', 'Brewing', 'Bottles', 'Fishing Rod']], + # ["A Furious Cocktail", True, ['Ingot Crafting', 'Progressive Tools', 'Flint and Steel', 'Bucket', + # 'Progressive Weapons', 'Shield', 'Brewing', 'Bottles', 'Fishing Rod']], + # ["A Furious Cocktail", True, ['Ingot Crafting', 'Progressive Tools', 'Flint and Steel', 'Progressive Tools', 'Progressive Tools', + # 'Progressive Weapons', 'Shield', 'Brewing', 'Bottles', 'Fishing Rod']], ]) def test_42007(self): @@ -934,7 +938,8 @@ class TestAdvancements(TestMinecraft): ["Uneasy Alliance", False, [], ['Ingot Crafting']], ["Uneasy Alliance", False, [], ['Flint and Steel']], ["Uneasy Alliance", False, [], ['Progressive Tools', 'Progressive Tools'], ['Progressive Tools']], - ["Uneasy Alliance", True, ['Progressive Tools', 'Progressive Tools', 'Progressive Tools', 'Flint and Steel', 'Ingot Crafting']], + ["Uneasy Alliance", False, [], ['Fishing Rod']], + ["Uneasy Alliance", True, ['Progressive Tools', 'Progressive Tools', 'Progressive Tools', 'Flint and Steel', 'Ingot Crafting', 'Fishing Rod']], ]) def test_42070(self): @@ -1076,8 +1081,8 @@ class TestAdvancements(TestMinecraft): self.run_location_tests([ ["On a Rail", False, []], ["On a Rail", False, [], ['Ingot Crafting']], - ["On a Rail", False, [], ['Progressive Tools']], - ["On a Rail", True, ['Ingot Crafting', 'Progressive Tools']], + ["On a Rail", False, ['Progressive Tools'], ['Progressive Tools', 'Progressive Tools']], + ["On a Rail", True, ['Ingot Crafting', 'Progressive Tools', 'Progressive Tools']], ]) def test_42086(self): diff --git a/worlds/minecraft/Rules.py b/worlds/minecraft/Rules.py index ba9bbc04..44992188 100644 --- a/worlds/minecraft/Rules.py +++ b/worlds/minecraft/Rules.py @@ -45,7 +45,11 @@ def set_rules(world: MultiWorld, player: int): 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)) 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)) - set_rule(world.get_location("A Furious Cocktail", player), lambda state: state.can_brew_potions(player) and state.has("Fishing Rod", 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)) @@ -116,7 +120,7 @@ def set_rules(world: MultiWorld, player: int): 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)) + 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 @@ -134,10 +138,10 @@ def set_rules(world: MultiWorld, player: int): 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)) + 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) and state.has("Fishing Rod", player) and state.can_adventure(player)) # saddles in fortress chests - set_rule(world.get_location("Overkill", player), lambda state: state.can_brew_potions(player) and state.has("Progressive Weapons", player)) # strength 1, stone axe crit + 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)) diff --git a/worlds/minecraft/__init__.py b/worlds/minecraft/__init__.py index 6c7e2562..676a72d0 100644 --- a/worlds/minecraft/__init__.py +++ b/worlds/minecraft/__init__.py @@ -9,12 +9,9 @@ from Options import minecraft_options client_version = (0, 3) -def generate_mc_data(world: MultiWorld, player: int): - import base64, json - from Utils import output_path - +def get_mc_data(world: MultiWorld, player: int): exits = ["Overworld Structure 1", "Overworld Structure 2", "Nether Structure 1", "Nether Structure 2", "The End Structure"] - data = { + return { 'world_seed': Random(world.rom_seeds[player]).getrandbits(32), # consistent and doesn't interfere with other generation 'seed_name': world.seed_name, 'player_name': world.get_player_names(player), @@ -23,16 +20,20 @@ def generate_mc_data(world: MultiWorld, player: int): 'structures': {exit: world.get_entrance(exit, player).connected_region.name for exit in exits} } +def generate_mc_data(world: MultiWorld, player: int): + import base64, json + from Utils import output_path + + data = get_mc_data(world, player) filename = f"AP_{world.seed_name}_P{player}_{world.get_player_names(player)}.apmc" with open(output_path(filename), 'wb') as f: f.write(base64.b64encode(bytes(json.dumps(data), 'utf-8'))) def fill_minecraft_slot_data(world: MultiWorld, player: int): - slot_data = {} + slot_data = get_mc_data(world, player) for option_name in minecraft_options: option = getattr(world, option_name)[player] slot_data[option_name] = int(option.value) - slot_data['client_version'] = client_version return slot_data # Generates the item pool given the table and frequencies in Items.py.