Minecraft Randomizer

Squash merge, original Commits:

* Minecraft locations, items, and generation without logic

* added id lookup for minecraft

* typing import fix in minecraft/Items.py

* fix 2

* implementing Minecraft options and hard/postgame advancement exclusion

* first logic pass (75/80)

* logic pass 2 and proper completion conditions

* added insane difficulty pool, modified method of excluding item pools for easier extension

* bump network_data_package version

* minecraft testing framework

* switch Ancient Debris to Netherite Scrap to avoid advancement triggering on receiving that item

* Testing now functions, split tests up by advancement pane, added some story tests

* Newer testing framework: every advancement gets its own function, for ease of testing

* fixed logic for The End... Again...

* changed option names to "include_hard_advancements" etc.

* village/pillager-related advancements now require can_adventure: weapon + food

* a few minecraft tests

* rename "Flint & Steel" to "Flint and Steel" for parity with in-game name

* additional MC tests

* more tests, mostly nether-related tests

* more tests, removed anvil path for Two Birds One Arrow

* include Minecraft slot data, and a world seed for each Minecraft player slot

* Added new items: ender pearls, lapis, porkchops

* All remaining Minecraft tests

* formatting of Minecraft tests and logic for better readability

* require Wither kill for Monsters Hunted

* properly removed 8 Emeralds item from item pool

* enchanting required for wither; fishing rod required for water breathing; water breathing required for elder guardian kill

* Added 12 new advancements (ported from old achievement system)

* renamed "On a Rail" for consistency with modern advancements

* tests for the new advancements

* moved slot_data generation for minecraft into worlds/minecraft/__init__.py, added logic_version to slot_data

* output minecraft options in the spoiler log

* modified advancement goal values for new advancements

* make non-native Minecraft items appear as Shovel in ALttP, and unknown-game items as Power Stars

* fixed glowstone block logic for Not Quite Nine Lives

* setup for shuffling MC structures: building ER world and shuffling regions/entrances

* ensured Nether Fortresses can't be placed in the End

* finished logic for structure randomization

* fixed nonnative items always showing up as Hammers in ALttP shops

* output minecraft structure info in the spoiler

* generate .apmc file for communication with MC client

* fixed structure rando always using the same seed

* move stuff to worlds/minecraft/Regions.py

* make output apmc file have consistent name with other files

* added minecraft bottle macro; fixed tests imports

* generalizing MC region generation

* restructured structure shuffling in preparation for structure plando

* only output structure rando info in spoiler if they are shuffled

* Force structure rando to always be off, for the stable release

* added Minecraft options to player settings

* formally added combat_difficulty as an option

* Added Ender Dragon into playthrough, cleaned up goal map

* Added new difficulties: Easy, Normal, Hard combat

* moved .apmc generation time to prevent outputs on failed generation

* updated tests for new combat logic

* Fixed bug causing generation to fail; removed Nether Fortress event since it should no longer be needed with the fix

* moved all MC-specific functions into gen_minecraft

* renamed "logic_version" to "client_version"

* bug fixes
properly flagged event locations/items with id None
moved generation back to Main.py to fix mysterious generation failures

* moved link_minecraft_regions into minecraft init, left create_regions in Main for caching

* added seed_name, player_name, client_version to apmc file

* reenabled structure shuffle

* added entrance tests for minecraft

Co-authored-by: achuang <alexander.w.chuang@gmail.com>
This commit is contained in:
espeon65536
2021-05-08 07:38:57 -04:00
committed by GitHub
parent eb2a3009f4
commit 2f7e532f4f
15 changed files with 2005 additions and 15 deletions

143
worlds/minecraft/Rules.py Normal file
View File

@@ -0,0 +1,143 @@
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
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
(location.name not in postgame_advancements) and
location.can_reach(state)]
# 92 total advancements, 16 are typically excluded, 1 is Free the End. Goal is to complete X advancements and then Free the End.
goal_map = {
'few': 30,
'normal': 50,
'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)
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
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("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))
set_rule(world.get_entrance("Nether Structure 2", player), lambda state: state.can_adventure(player))
set_rule(world.get_entrance("The End Structure", player), lambda state: state.can_adventure(player))
set_rule(world.get_location("Ender Dragon", player), lambda state: can_complete(state))
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))
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("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("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: state.fortress_loot(player) and state.has("Fishing Rod", player))
set_rule(world.get_location("This Boat Has Legs", player), lambda state: state.fortress_loot(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("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("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("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("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("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("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("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("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("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("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("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("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("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("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_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("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("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))
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("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))